/[packages]/cauldron/firefox/current/SOURCES/mozilla-kde.patch
ViewVC logotype

Contents of /cauldron/firefox/current/SOURCES/mozilla-kde.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 724612 - (show annotations) (download)
Thu Sep 25 14:22:06 2014 UTC (9 years, 6 months ago) by doktor5000
File size: 132941 byte(s)
- update to 31.1.1esr
- updated, rediffed and reenabled KDE integration patches
  o updated current upstream location for subsequent updates
- temporarily enabled clobber to enable build (SILENT)
  o filed https://bugzilla.mozilla.org/show_bug.cgi?id=1072893 (SILENT)
- fixed URL to reenable automatic download (SILENT)
1 Description: Add KDE integration to Firefox (toolkit parts)
2 Author: Wolfgang Rosenauer <wolfgang@rosenauer.org>
3 Author: Lubos Lunak <lunak@suse.com>
4 Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=140751
5 https://bugzilla.novell.com/show_bug.cgi?id=170055
6
7 diff --git a/modules/libpref/src/Makefile.in b/modules/libpref/src/Makefile.in
8 --- a/modules/libpref/src/Makefile.in
9 +++ b/modules/libpref/src/Makefile.in
10 @@ -21,13 +21,15 @@ endif
11 ifdef MOZ_SERVICES_HEALTHREPORT
12 ifneq (android,$(MOZ_WIDGET_TOOLKIT))
13 grepref_files += $(topsrcdir)/services/healthreport/healthreport-prefs.js
14 else
15 grepref_files += $(topsrcdir)/mobile/android/chrome/content/healthreport-prefs.js
16 endif
17 endif
18
19 +LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
20 +
21 greprefs.js: $(grepref_files)
22 $(call py_action,preprocessor,$(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $^ -o $@)
23
24 libs:: greprefs.js
25 $(INSTALL) $^ $(DIST)/bin/
26 diff --git a/modules/libpref/src/Preferences.cpp b/modules/libpref/src/Preferences.cpp
27 --- a/modules/libpref/src/Preferences.cpp
28 +++ b/modules/libpref/src/Preferences.cpp
29 @@ -27,16 +27,17 @@
30 #include "nsIZipReader.h"
31 #include "nsPrefBranch.h"
32 #include "nsXPIDLString.h"
33 #include "nsCRT.h"
34 #include "nsCOMArray.h"
35 #include "nsXPCOMCID.h"
36 #include "nsAutoPtr.h"
37 #include "nsPrintfCString.h"
38 +#include "nsKDEUtils.h"
39
40 #include "nsQuickSort.h"
41 #include "pldhash.h"
42
43 #include "prefapi.h"
44 #include "prefread.h"
45 #include "prefapi_private_data.h"
46
47 @@ -1134,16 +1135,34 @@ pref_LoadPrefsInDir(nsIFile* aDir, char
48
49 static nsresult pref_LoadPrefsInDirList(const char *listId)
50 {
51 nsresult rv;
52 nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
53 if (NS_FAILED(rv))
54 return rv;
55
56 + // make sure we load these special files after all the others
57 + static const char* specialFiles[] = {
58 +#if defined(XP_UNIX)
59 + ""
60 +#endif
61 + };
62 +
63 + if (nsKDEUtils::kdeSession()) {
64 + for(int i = 0;
65 + i < MOZ_ARRAY_LENGTH(specialFiles);
66 + ++i ) {
67 + if (*specialFiles[ i ] == '\0') {
68 + specialFiles[ i ] = "kde.js";
69 + break;
70 + }
71 + }
72 + }
73 +
74 nsCOMPtr<nsISimpleEnumerator> list;
75 dirSvc->Get(listId,
76 NS_GET_IID(nsISimpleEnumerator),
77 getter_AddRefs(list));
78 if (!list)
79 return NS_OK;
80
81 bool hasMore;
82 @@ -1159,17 +1178,17 @@ static nsresult pref_LoadPrefsInDirList(
83
84 nsAutoCString leaf;
85 path->GetNativeLeafName(leaf);
86
87 // Do we care if a file provided by this process fails to load?
88 if (Substring(leaf, leaf.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi")))
89 ReadExtensionPrefs(path);
90 else
91 - pref_LoadPrefsInDir(path, nullptr, 0);
92 + pref_LoadPrefsInDir(path, specialFiles, MOZ_ARRAY_LENGTH(specialFiles));
93 }
94 return NS_OK;
95 }
96
97 static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
98 {
99 nsZipItemPtr<char> manifest(jarReader, name, true);
100 NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
101 @@ -1263,26 +1282,38 @@ static nsresult pref_InitInitialObjects(
102 /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
103 static const char* specialFiles[] = {
104 #if defined(XP_MACOSX)
105 "macprefs.js"
106 #elif defined(XP_WIN)
107 "winpref.js"
108 #elif defined(XP_UNIX)
109 "unix.js"
110 + , "" // placeholder for KDE (empty is otherwise harmless)
111 #if defined(VMS)
112 , "openvms.js"
113 #elif defined(_AIX)
114 , "aix.js"
115 #endif
116 #elif defined(XP_BEOS)
117 "beos.js"
118 #endif
119 };
120
121 + if(nsKDEUtils::kdeSession()) { // TODO what if some setup actually requires the helper?
122 + for(int i = 0;
123 + i < MOZ_ARRAY_LENGTH(specialFiles);
124 + ++i ) {
125 + if( *specialFiles[ i ] == '\0' ) {
126 + specialFiles[ i ] = "kde.js";
127 + break;
128 + }
129 + }
130 + }
131 +
132 rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles));
133 if (NS_FAILED(rv))
134 NS_WARNING("Error parsing application default preferences.");
135
136 // Load jar:$app/omni.jar!/defaults/preferences/*.js
137 // or jar:$gre/omni.jar!/defaults/preferences/*.js.
138 nsRefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
139 // GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
140 diff --git a/python/mozbuild/mozpack/chrome/flags.py b/python/mozbuild/mozpack/chrome/flags.py
141 --- a/python/mozbuild/mozpack/chrome/flags.py
142 +++ b/python/mozbuild/mozpack/chrome/flags.py
143 @@ -208,16 +208,17 @@ class Flags(OrderedDict):
144 'platformversion': VersionFlag,
145 'contentaccessible': Flag,
146 'os': StringFlag,
147 'osversion': VersionFlag,
148 'abi': StringFlag,
149 'platform': Flag,
150 'xpcnativewrappers': Flag,
151 'tablet': Flag,
152 + 'desktop': StringFlag,
153 }
154 RE = re.compile(r'([!<>=]+)')
155
156 def __init__(self, *flags):
157 '''
158 Initialize a set of flags given in string form.
159 flags = Flags('contentaccessible=yes', 'appversion>=3.5')
160 '''
161 diff --git a/python/mozbuild/mozpack/chrome/manifest.py b/python/mozbuild/mozpack/chrome/manifest.py
162 --- a/python/mozbuild/mozpack/chrome/manifest.py
163 +++ b/python/mozbuild/mozpack/chrome/manifest.py
164 @@ -30,16 +30,17 @@ class ManifestEntry(object):
165 allowed_flags = [
166 'application',
167 'platformversion',
168 'os',
169 'osversion',
170 'abi',
171 'xpcnativewrappers',
172 'tablet',
173 + 'desktop',
174 ]
175
176 def __init__(self, base, *flags):
177 '''
178 Initialize a manifest entry with the given base path and flags.
179 '''
180 self.base = base
181 self.flags = Flags(*flags)
182 diff --git a/toolkit/components/downloads/Makefile.in b/toolkit/components/downloads/Makefile.in
183 --- a/toolkit/components/downloads/Makefile.in
184 +++ b/toolkit/components/downloads/Makefile.in
185 @@ -1,9 +1,9 @@
186 #
187 # This Source Code Form is subject to the terms of the Mozilla Public
188 # License, v. 2.0. If a copy of the MPL was not distributed with this
189 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
190
191 include $(topsrcdir)/config/rules.mk
192
193 CXXFLAGS += $(TK_CFLAGS)
194 -
195 +LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
196 diff --git a/toolkit/components/downloads/nsDownloadManager.cpp b/toolkit/components/downloads/nsDownloadManager.cpp
197 --- a/toolkit/components/downloads/nsDownloadManager.cpp
198 +++ b/toolkit/components/downloads/nsDownloadManager.cpp
199 @@ -43,16 +43,20 @@
200 #ifdef XP_WIN
201 #include <shlobj.h>
202 #include "nsWindowsHelpers.h"
203 #ifdef DOWNLOAD_SCANNER
204 #include "nsDownloadScanner.h"
205 #endif
206 #endif
207
208 +#if defined(XP_UNIX) && !defined(XP_MACOSX)
209 +#include "nsKDEUtils.h"
210 +#endif
211 +
212 #ifdef XP_MACOSX
213 #include <CoreFoundation/CoreFoundation.h>
214 #endif
215
216 #ifdef MOZ_WIDGET_ANDROID
217 #include "AndroidBridge.h"
218 using namespace mozilla::widget::android;
219 #endif
220 @@ -2722,16 +2726,25 @@ nsDownload::SetState(DownloadState aStat
221 nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID));
222
223 // Master pref to control this function.
224 bool showTaskbarAlert = true;
225 if (pref)
226 pref->GetBoolPref(PREF_BDM_SHOWALERTONCOMPLETE, &showTaskbarAlert);
227
228 if (showTaskbarAlert) {
229 + if( nsKDEUtils::kdeSupport()) {
230 + nsTArray<nsCString> command;
231 + command.AppendElement( NS_LITERAL_CSTRING( "DOWNLOADFINISHED" ));
232 + nsAutoString displayName;
233 + GetDisplayName( displayName );
234 + command.AppendElement( nsAutoCString( ToNewUTF8String( displayName )));
235 + nsKDEUtils::command( command );
236 + } else {
237 + // begin non-KDE block
238 int32_t alertInterval = 2000;
239 if (pref)
240 pref->GetIntPref(PREF_BDM_SHOWALERTINTERVAL, &alertInterval);
241
242 int64_t alertIntervalUSec = alertInterval * PR_USEC_PER_MSEC;
243 int64_t goat = PR_Now() - mStartTime;
244 showTaskbarAlert = goat > alertIntervalUSec;
245
246 @@ -2759,19 +2772,20 @@ nsDownload::SetState(DownloadState aStat
247 // because if it is, they'll click open the download manager and
248 // the items they downloaded will have been removed.
249 alerts->ShowAlertNotification(
250 NS_LITERAL_STRING(DOWNLOAD_MANAGER_ALERT_ICON), title,
251 message, !removeWhenDone,
252 mPrivate ? NS_LITERAL_STRING("private") : NS_LITERAL_STRING("non-private"),
253 mDownloadManager, EmptyString(), NS_LITERAL_STRING("auto"),
254 EmptyString(), nullptr);
255 - }
256 + }
257 }
258 }
259 + }
260
261 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
262 nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mTarget);
263 nsCOMPtr<nsIFile> file;
264 nsAutoString path;
265
266 if (fileURL &&
267 NS_SUCCEEDED(fileURL->GetFile(getter_AddRefs(file))) &&
268 diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn
269 --- a/toolkit/content/jar.mn
270 +++ b/toolkit/content/jar.mn
271 @@ -58,29 +58,33 @@ toolkit.jar:
272 content/global/viewZoomOverlay.js (viewZoomOverlay.js)
273 *+ content/global/bindings/autocomplete.xml (widgets/autocomplete.xml)
274 content/global/bindings/browser.xml (widgets/browser.xml)
275 content/global/bindings/button.xml (widgets/button.xml)
276 content/global/bindings/checkbox.xml (widgets/checkbox.xml)
277 content/global/bindings/colorpicker.xml (widgets/colorpicker.xml)
278 content/global/bindings/datetimepicker.xml (widgets/datetimepicker.xml)
279 *+ content/global/bindings/dialog.xml (widgets/dialog.xml)
280 +*+ content/global/bindings/dialog-kde.xml (widgets/dialog-kde.xml)
281 +% override chrome://global/content/bindings/dialog.xml chrome://global/content/bindings/dialog-kde.xml desktop=kde
282 content/global/bindings/editor.xml (widgets/editor.xml)
283 content/global/bindings/expander.xml (widgets/expander.xml)
284 * content/global/bindings/filefield.xml (widgets/filefield.xml)
285 *+ content/global/bindings/findbar.xml (widgets/findbar.xml)
286 content/global/bindings/general.xml (widgets/general.xml)
287 content/global/bindings/groupbox.xml (widgets/groupbox.xml)
288 *+ content/global/bindings/listbox.xml (widgets/listbox.xml)
289 content/global/bindings/menu.xml (widgets/menu.xml)
290 content/global/bindings/menulist.xml (widgets/menulist.xml)
291 content/global/bindings/notification.xml (widgets/notification.xml)
292 content/global/bindings/numberbox.xml (widgets/numberbox.xml)
293 * content/global/bindings/popup.xml (widgets/popup.xml)
294 *+ content/global/bindings/preferences.xml (widgets/preferences.xml)
295 +*+ content/global/bindings/preferences-kde.xml (widgets/preferences-kde.xml)
296 +% override chrome://global/content/bindings/preferences.xml chrome://global/content/bindings/preferences-kde.xml desktop=kde
297 content/global/bindings/progressmeter.xml (widgets/progressmeter.xml)
298 content/global/bindings/radio.xml (widgets/radio.xml)
299 content/global/bindings/remote-browser.xml (widgets/remote-browser.xml)
300 content/global/bindings/resizer.xml (widgets/resizer.xml)
301 content/global/bindings/richlistbox.xml (widgets/richlistbox.xml)
302 content/global/bindings/scale.xml (widgets/scale.xml)
303 content/global/bindings/scrollbar.xml (widgets/scrollbar.xml)
304 content/global/bindings/scrollbox.xml (widgets/scrollbox.xml)
305 diff --git a/toolkit/content/widgets/dialog-kde.xml b/toolkit/content/widgets/dialog-kde.xml
306 new file mode 100644
307 --- /dev/null
308 +++ b/toolkit/content/widgets/dialog-kde.xml
309 @@ -0,0 +1,449 @@
310 +<?xml version="1.0"?>
311 +<!-- This Source Code Form is subject to the terms of the Mozilla Public
312 + - License, v. 2.0. If a copy of the MPL was not distributed with this
313 + - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
314 +
315 +
316 +<bindings id="dialogBindings"
317 + xmlns="http://www.mozilla.org/xbl"
318 + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
319 + xmlns:xbl="http://www.mozilla.org/xbl">
320 +
321 + <binding id="dialog" extends="chrome://global/content/bindings/general.xml#root-element">
322 + <resources>
323 + <stylesheet src="chrome://global/skin/dialog.css"/>
324 + </resources>
325 + <content>
326 + <xul:vbox class="box-inherit dialog-content-box" flex="1">
327 + <children/>
328 + </xul:vbox>
329 +
330 + <xul:hbox class="dialog-button-box" anonid="buttons"
331 + xbl:inherits="pack=buttonpack,align=buttonalign,dir=buttondir,orient=buttonorient"
332 +#ifdef XP_UNIX_GNOME
333 + >
334 + <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
335 + <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
336 + <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
337 + <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
338 + <xul:spacer anonid="spacer" flex="1"/>
339 + <xul:button dlgtype="cancel" class="dialog-button"/>
340 + <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
341 +#elif XP_UNIX
342 + >
343 + <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
344 + <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
345 + <xul:spacer anonid="spacer" flex="1" hidden="true"/>
346 + <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
347 + <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
348 + <xul:button dlgtype="cancel" class="dialog-button"/>
349 + <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
350 +#else
351 + pack="end">
352 + <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
353 + <xul:spacer anonid="spacer" flex="1" hidden="true"/>
354 + <xul:button dlgtype="accept" class="dialog-button" xbl:inherits="disabled=buttondisabledaccept"/>
355 + <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
356 + <xul:button dlgtype="cancel" class="dialog-button"/>
357 + <xul:button dlgtype="help" class="dialog-button" hidden="true"/>
358 + <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
359 +#endif
360 + </xul:hbox>
361 + </content>
362 +
363 + <implementation>
364 + <field name="_mStrBundle">null</field>
365 + <field name="_closeHandler">(function(event) {
366 + if (!document.documentElement.cancelDialog())
367 + event.preventDefault();
368 + })</field>
369 +
370 + <property name="buttons"
371 + onget="return this.getAttribute('buttons');"
372 + onset="this._configureButtons(val); return val;"/>
373 +
374 + <property name="defaultButton">
375 + <getter>
376 + <![CDATA[
377 + if (this.hasAttribute("defaultButton"))
378 + return this.getAttribute("defaultButton");
379 + else // default to the accept button
380 + return "accept";
381 + ]]>
382 + </getter>
383 + <setter>
384 + <![CDATA[
385 + this._setDefaultButton(val);
386 + return val;
387 + ]]>
388 + </setter>
389 + </property>
390 +
391 + <method name="acceptDialog">
392 + <body>
393 + <![CDATA[
394 + return this._doButtonCommand("accept");
395 + ]]>
396 + </body>
397 + </method>
398 +
399 + <method name="cancelDialog">
400 + <body>
401 + <![CDATA[
402 + return this._doButtonCommand("cancel");
403 + ]]>
404 + </body>
405 + </method>
406 +
407 + <method name="getButton">
408 + <parameter name="aDlgType"/>
409 + <body>
410 + <![CDATA[
411 + return this._buttons[aDlgType];
412 + ]]>
413 + </body>
414 + </method>
415 +
416 + <method name="moveToAlertPosition">
417 + <body>
418 + <![CDATA[
419 + // hack. we need this so the window has something like its final size
420 + if (window.outerWidth == 1) {
421 + dump("Trying to position a sizeless window; caller should have called sizeToContent() or sizeTo(). See bug 75649.\n");
422 + sizeToContent();
423 + }
424 +
425 + var xOffset = (opener.outerWidth - window.outerWidth) / 2;
426 + var yOffset = opener.outerHeight / 5;
427 +
428 + var newX = opener.screenX + xOffset;
429 + var newY = opener.screenY + yOffset;
430 +
431 + // ensure the window is fully onscreen (if smaller than the screen)
432 + if (newX < screen.availLeft)
433 + newX = screen.availLeft + 20;
434 + if ((newX + window.outerWidth) > (screen.availLeft + screen.availWidth))
435 + newX = (screen.availLeft + screen.availWidth) - window.outerWidth - 20;
436 +
437 + if (newY < screen.availTop)
438 + newY = screen.availTop + 20;
439 + if ((newY + window.outerHeight) > (screen.availTop + screen.availHeight))
440 + newY = (screen.availTop + screen.availHeight) - window.outerHeight - 60;
441 +
442 + window.moveTo( newX, newY );
443 + ]]>
444 + </body>
445 + </method>
446 +
447 + <method name="centerWindowOnScreen">
448 + <body>
449 + <![CDATA[
450 + var xOffset = screen.availWidth/2 - window.outerWidth/2;
451 + var yOffset = screen.availHeight/2 - window.outerHeight/2; //(opener.outerHeight *2)/10;
452 +
453 + xOffset = xOffset > 0 ? xOffset : 0;
454 + yOffset = yOffset > 0 ? yOffset : 0;
455 + window.moveTo(xOffset, yOffset);
456 + ]]>
457 + </body>
458 + </method>
459 +
460 + <constructor>
461 + <![CDATA[
462 + this._configureButtons(this.buttons);
463 +
464 + // listen for when window is closed via native close buttons
465 + window.addEventListener("close", this._closeHandler, false);
466 +
467 + // for things that we need to initialize after onload fires
468 + window.addEventListener("load", this.postLoadInit, false);
469 +
470 + window.moveToAlertPosition = this.moveToAlertPosition;
471 + window.centerWindowOnScreen = this.centerWindowOnScreen;
472 + ]]>
473 + </constructor>
474 +
475 + <method name="postLoadInit">
476 + <parameter name="aEvent"/>
477 + <body>
478 + <![CDATA[
479 + function focusInit() {
480 + const dialog = document.documentElement;
481 + const defaultButton = dialog.getButton(dialog.defaultButton);
482 + // give focus to the first focusable element in the dialog
483 + if (!document.commandDispatcher.focusedElement) {
484 + document.commandDispatcher.advanceFocusIntoSubtree(dialog);
485 +
486 + var focusedElt = document.commandDispatcher.focusedElement;
487 + if (focusedElt) {
488 + var initialFocusedElt = focusedElt;
489 + while (focusedElt.localName == "tab" ||
490 + focusedElt.getAttribute("noinitialfocus") == "true") {
491 + document.commandDispatcher.advanceFocusIntoSubtree(focusedElt);
492 + focusedElt = document.commandDispatcher.focusedElement;
493 + if (focusedElt == initialFocusedElt)
494 + break;
495 + }
496 +
497 + if (initialFocusedElt.localName == "tab") {
498 + if (focusedElt.hasAttribute("dlgtype")) {
499 + // We don't want to focus on anonymous OK, Cancel, etc. buttons,
500 + // so return focus to the tab itself
501 + initialFocusedElt.focus();
502 + }
503 + }
504 +#ifndef XP_MACOSX
505 + else if (focusedElt.hasAttribute("dlgtype") && focusedElt != defaultButton) {
506 + defaultButton.focus();
507 + }
508 +#endif
509 + }
510 + }
511 +
512 + try {
513 + if (defaultButton)
514 + window.notifyDefaultButtonLoaded(defaultButton);
515 + } catch (e) { }
516 + }
517 +
518 + // Give focus after onload completes, see bug 103197.
519 + setTimeout(focusInit, 0);
520 + ]]>
521 + </body>
522 + </method>
523 +
524 + <property name="mStrBundle">
525 + <getter>
526 + <![CDATA[
527 + if (!this._mStrBundle) {
528 + // need to create string bundle manually instead of using <xul:stringbundle/>
529 + // see bug 63370 for details
530 + this._mStrBundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
531 + .getService(Components.interfaces.nsIStringBundleService)
532 + .createBundle("chrome://global/locale/dialog.properties");
533 + }
534 + return this._mStrBundle;
535 + ]]></getter>
536 + </property>
537 +
538 + <method name="_configureButtons">
539 + <parameter name="aButtons"/>
540 + <body>
541 + <![CDATA[
542 + // by default, get all the anonymous button elements
543 + var buttons = {};
544 + this._buttons = buttons;
545 + buttons.accept = document.getAnonymousElementByAttribute(this, "dlgtype", "accept");
546 + buttons.cancel = document.getAnonymousElementByAttribute(this, "dlgtype", "cancel");
547 + buttons.extra1 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra1");
548 + buttons.extra2 = document.getAnonymousElementByAttribute(this, "dlgtype", "extra2");
549 + buttons.help = document.getAnonymousElementByAttribute(this, "dlgtype", "help");
550 + buttons.disclosure = document.getAnonymousElementByAttribute(this, "dlgtype", "disclosure");
551 +
552 + // look for any overriding explicit button elements
553 + var exBtns = this.getElementsByAttribute("dlgtype", "*");
554 + var dlgtype;
555 + var i;
556 + for (i = 0; i < exBtns.length; ++i) {
557 + dlgtype = exBtns[i].getAttribute("dlgtype");
558 + buttons[dlgtype].hidden = true; // hide the anonymous button
559 + buttons[dlgtype] = exBtns[i];
560 + }
561 +
562 + // add the label and oncommand handler to each button
563 + for (dlgtype in buttons) {
564 + var button = buttons[dlgtype];
565 + button.addEventListener("command", this._handleButtonCommand, true);
566 +
567 + // don't override custom labels with pre-defined labels on explicit buttons
568 + if (!button.hasAttribute("label")) {
569 + // dialog attributes override the default labels in dialog.properties
570 + if (this.hasAttribute("buttonlabel"+dlgtype)) {
571 + button.setAttribute("label", this.getAttribute("buttonlabel"+dlgtype));
572 + if (this.hasAttribute("buttonaccesskey"+dlgtype))
573 + button.setAttribute("accesskey", this.getAttribute("buttonaccesskey"+dlgtype));
574 + } else if (dlgtype != "extra1" && dlgtype != "extra2") {
575 + button.setAttribute("label", this.mStrBundle.GetStringFromName("button-"+dlgtype));
576 + var accessKey = this.mStrBundle.GetStringFromName("accesskey-"+dlgtype);
577 + if (accessKey)
578 + button.setAttribute("accesskey", accessKey);
579 + }
580 + }
581 + // allow specifying alternate icons in the dialog header
582 + if (!button.hasAttribute("icon")) {
583 + // if there's an icon specified, use that
584 + if (this.hasAttribute("buttonicon"+dlgtype))
585 + button.setAttribute("icon", this.getAttribute("buttonicon"+dlgtype));
586 + // otherwise set defaults
587 + else
588 + switch (dlgtype) {
589 + case "accept":
590 + button.setAttribute("icon","accept");
591 + break;
592 + case "cancel":
593 + button.setAttribute("icon","cancel");
594 + break;
595 + case "disclosure":
596 + button.setAttribute("icon","properties");
597 + break;
598 + case "help":
599 + button.setAttribute("icon","help");
600 + break;
601 + default:
602 + break;
603 + }
604 + }
605 + }
606 +
607 + // ensure that hitting enter triggers the default button command
608 + this.defaultButton = this.defaultButton;
609 +
610 + // if there is a special button configuration, use it
611 + if (aButtons) {
612 + // expect a comma delimited list of dlgtype values
613 + var list = aButtons.split(",");
614 +
615 + // mark shown dlgtypes as true
616 + var shown = { accept: false, cancel: false, help: false,
617 + disclosure: false, extra1: false, extra2: false };
618 + for (i = 0; i < list.length; ++i)
619 + shown[list[i].replace(/ /g, "")] = true;
620 +
621 + // hide/show the buttons we want
622 + for (dlgtype in buttons)
623 + buttons[dlgtype].hidden = !shown[dlgtype];
624 +
625 +#ifdef XP_WIN
626 +# show the spacer on Windows only when the extra2 button is present
627 + var spacer = document.getAnonymousElementByAttribute(this, "anonid", "spacer");
628 + spacer.removeAttribute("hidden");
629 + spacer.setAttribute("flex", shown["extra2"]?"1":"0");
630 +#endif
631 +
632 + }
633 + ]]>
634 + </body>
635 + </method>
636 +
637 + <method name="_setDefaultButton">
638 + <parameter name="aNewDefault"/>
639 + <body>
640 + <![CDATA[
641 + // remove the default attribute from the previous default button, if any
642 + var oldDefaultButton = this.getButton(this.defaultButton);
643 + if (oldDefaultButton)
644 + oldDefaultButton.removeAttribute("default");
645 +
646 + var newDefaultButton = this.getButton(aNewDefault);
647 + if (newDefaultButton) {
648 + this.setAttribute("defaultButton", aNewDefault);
649 + newDefaultButton.setAttribute("default", "true");
650 + }
651 + else {
652 + this.setAttribute("defaultButton", "none");
653 + if (aNewDefault != "none")
654 + dump("invalid new default button: " + aNewDefault + ", assuming: none\n");
655 + }
656 + ]]>
657 + </body>
658 + </method>
659 +
660 + <method name="_handleButtonCommand">
661 + <parameter name="aEvent"/>
662 + <body>
663 + <![CDATA[
664 + return document.documentElement._doButtonCommand(
665 + aEvent.target.getAttribute("dlgtype"));
666 + ]]>
667 + </body>
668 + </method>
669 +
670 + <method name="_doButtonCommand">
671 + <parameter name="aDlgType"/>
672 + <body>
673 + <![CDATA[
674 + var button = this.getButton(aDlgType);
675 + if (!button.disabled) {
676 + var noCancel = this._fireButtonEvent(aDlgType);
677 + if (noCancel) {
678 + if (aDlgType == "accept" || aDlgType == "cancel")
679 + window.close();
680 + }
681 + return noCancel;
682 + }
683 + return true;
684 + ]]>
685 + </body>
686 + </method>
687 +
688 + <method name="_fireButtonEvent">
689 + <parameter name="aDlgType"/>
690 + <body>
691 + <![CDATA[
692 + var event = document.createEvent("Events");
693 + event.initEvent("dialog"+aDlgType, true, true);
694 +
695 + // handle dom event handlers
696 + var noCancel = this.dispatchEvent(event);
697 +
698 + // handle any xml attribute event handlers
699 + var handler = this.getAttribute("ondialog"+aDlgType);
700 + if (handler != "") {
701 + var fn = new Function("event", handler);
702 + var returned = fn(event);
703 + if (returned == false)
704 + noCancel = false;
705 + }
706 +
707 + return noCancel;
708 + ]]>
709 + </body>
710 + </method>
711 +
712 + <method name="_hitEnter">
713 + <parameter name="evt"/>
714 + <body>
715 + <![CDATA[
716 + if (evt.defaultPrevented)
717 + return;
718 +
719 + var btn = this.getButton(this.defaultButton);
720 + if (btn)
721 + this._doButtonCommand(this.defaultButton);
722 + ]]>
723 + </body>
724 + </method>
725 +
726 + </implementation>
727 +
728 + <handlers>
729 + <handler event="keypress" keycode="VK_RETURN"
730 + group="system" action="this._hitEnter(event);"/>
731 + <handler event="keypress" keycode="VK_ESCAPE" group="system">
732 + if (!event.defaultPrevented)
733 + this.cancelDialog();
734 + </handler>
735 +#ifdef XP_MACOSX
736 + <handler event="keypress" key="." modifiers="meta" phase="capturing" action="this.cancelDialog();"/>
737 +#else
738 + <handler event="focus" phase="capturing">
739 + var btn = this.getButton(this.defaultButton);
740 + if (btn)
741 + btn.setAttribute("default", event.originalTarget == btn || !(event.originalTarget instanceof Components.interfaces.nsIDOMXULButtonElement));
742 + </handler>
743 +#endif
744 + </handlers>
745 +
746 + </binding>
747 +
748 + <binding id="dialogheader">
749 + <resources>
750 + <stylesheet src="chrome://global/skin/dialog.css"/>
751 + </resources>
752 + <content>
753 + <xul:label class="dialogheader-title" xbl:inherits="value=title,crop" crop="right" flex="1"/>
754 + <xul:label class="dialogheader-description" xbl:inherits="value=description"/>
755 + </content>
756 + </binding>
757 +
758 +</bindings>
759 diff --git a/toolkit/content/widgets/preferences-kde.xml b/toolkit/content/widgets/preferences-kde.xml
760 new file mode 100644
761 --- /dev/null
762 +++ b/toolkit/content/widgets/preferences-kde.xml
763 @@ -0,0 +1,1333 @@
764 +<?xml version="1.0"?>
765 +
766 +<!DOCTYPE bindings [
767 + <!ENTITY % preferencesDTD SYSTEM "chrome://global/locale/preferences.dtd">
768 + %preferencesDTD;
769 + <!ENTITY % globalKeysDTD SYSTEM "chrome://global/locale/globalKeys.dtd">
770 + %globalKeysDTD;
771 +]>
772 +
773 +<bindings id="preferencesBindings"
774 + xmlns="http://www.mozilla.org/xbl"
775 + xmlns:xbl="http://www.mozilla.org/xbl"
776 + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
777 +
778 +#
779 +# = Preferences Window Framework
780 +#
781 +# The syntax for use looks something like:
782 +#
783 +# <prefwindow>
784 +# <prefpane id="prefPaneA">
785 +# <preferences>
786 +# <preference id="preference1" name="app.preference1" type="bool" onchange="foo();"/>
787 +# <preference id="preference2" name="app.preference2" type="bool" useDefault="true"/>
788 +# </preferences>
789 +# <checkbox label="Preference" preference="preference1"/>
790 +# </prefpane>
791 +# </prefwindow>
792 +#
793 +
794 + <binding id="preferences">
795 + <implementation implements="nsIObserver">
796 + <method name="observe">
797 + <parameter name="aSubject"/>
798 + <parameter name="aTopic"/>
799 + <parameter name="aData"/>
800 + <body>
801 + <![CDATA[
802 + for (var i = 0; i < this.childNodes.length; ++i) {
803 + var preference = this.childNodes[i];
804 + if (preference.name == aData) {
805 + preference.value = preference.valueFromPreferences;
806 + }
807 + }
808 + ]]>
809 + </body>
810 + </method>
811 +
812 + <method name="fireChangedEvent">
813 + <parameter name="aPreference"/>
814 + <body>
815 + <![CDATA[
816 + // Value changed, synthesize an event
817 + try {
818 + var event = document.createEvent("Events");
819 + event.initEvent("change", true, true);
820 + aPreference.dispatchEvent(event);
821 + }
822 + catch (e) {
823 + Components.utils.reportError(e);
824 + }
825 + ]]>
826 + </body>
827 + </method>
828 +
829 + <field name="service">
830 + Components.classes["@mozilla.org/preferences-service;1"]
831 + .getService(Components.interfaces.nsIPrefService);
832 + </field>
833 + <field name="rootBranch">
834 + Components.classes["@mozilla.org/preferences-service;1"]
835 + .getService(Components.interfaces.nsIPrefBranch);
836 + </field>
837 + <field name="defaultBranch">
838 + this.service.getDefaultBranch("");
839 + </field>
840 + <field name="rootBranchInternal">
841 + Components.classes["@mozilla.org/preferences-service;1"]
842 + .getService(Components.interfaces.nsIPrefBranchInternal);
843 + </field>
844 + <property name="type" readonly="true">
845 + <getter>
846 + <![CDATA[
847 + return document.documentElement.type || "";
848 + ]]>
849 + </getter>
850 + </property>
851 + <property name="instantApply" readonly="true">
852 + <getter>
853 + <![CDATA[
854 + var doc = document.documentElement;
855 + return this.type == "child" ? doc.instantApply
856 + : doc.instantApply || this.rootBranch.getBoolPref("browser.preferences.instantApply");
857 + ]]>
858 + </getter>
859 + </property>
860 + </implementation>
861 + </binding>
862 +
863 + <binding id="preference">
864 + <implementation>
865 + <constructor>
866 + <![CDATA[
867 + // if the element has been inserted without the name attribute set,
868 + // we have nothing to do here
869 + if (!this.name)
870 + return;
871 +
872 + this.preferences.rootBranchInternal
873 + .addObserver(this.name, this.preferences, false);
874 + // In non-instant apply mode, we must try and use the last saved state
875 + // from any previous opens of a child dialog instead of the value from
876 + // preferences, to pick up any edits a user may have made.
877 + if (this.preferences.type == "child" &&
878 + !this.instantApply && window.opener) {
879 + var pdoc = window.opener.document;
880 +
881 + // Try to find a preference element for the same preference.
882 + var preference = null;
883 + var parentPreferences = pdoc.getElementsByTagName("preferences");
884 + for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
885 + var parentPrefs = parentPreferences[k]
886 + .getElementsByAttribute("name", this.name);
887 + for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
888 + if (parentPrefs[l].localName == "preference")
889 + preference = parentPrefs[l];
890 + }
891 + }
892 + this._setValue(preference ? preference.value
893 + : this.valueFromPreferences, false);
894 + }
895 + else
896 + this._setValue(this.valueFromPreferences, false);
897 + ]]>
898 + </constructor>
899 + <destructor>
900 + this.preferences.rootBranchInternal
901 + .removeObserver(this.name, this.preferences);
902 + </destructor>
903 +
904 + <property name="instantApply">
905 + <getter>
906 + return this.getAttribute("instantApply") == "true" || this.preferences.instantApply;
907 + </getter>
908 + </property>
909 +
910 + <property name="preferences" onget="return this.parentNode"/>
911 + <property name="name" onget="return this.getAttribute('name');">
912 + <setter>
913 + if (val == this.name)
914 + return val;
915 +
916 + this.preferences.rootBranchInternal
917 + .removeObserver(this.name, this.preferences);
918 + this.setAttribute('name', val);
919 + this.preferences.rootBranchInternal
920 + .addObserver(val, this.preferences, false);
921 +
922 + return val;
923 + </setter>
924 + </property>
925 + <property name="type" onget="return this.getAttribute('type');"
926 + onset="this.setAttribute('type', val); return val;"/>
927 + <property name="inverted" onget="return this.getAttribute('inverted') == 'true';"
928 + onset="this.setAttribute('inverted', val); return val;"/>
929 + <property name="readonly" onget="return this.getAttribute('readonly') == 'true';"
930 + onset="this.setAttribute('readonly', val); return val;"/>
931 +
932 + <field name="_value">null</field>
933 + <method name="_setValue">
934 + <parameter name="aValue"/>
935 + <parameter name="aUpdate"/>
936 + <body>
937 + <![CDATA[
938 + if (aUpdate && this.value !== aValue) {
939 + this._value = aValue;
940 + if (this.instantApply)
941 + this.valueFromPreferences = aValue;
942 + this.preferences.fireChangedEvent(this);
943 + }
944 + else if (!aUpdate) {
945 + this._value = aValue;
946 + this.updateElements();
947 + }
948 + return aValue;
949 + ]]>
950 + </body>
951 + </method>
952 + <property name="value" onget="return this._value" onset="return this._setValue(val, true);"/>
953 +
954 + <property name="locked">
955 + <getter>
956 + return this.preferences.rootBranch.prefIsLocked(this.name);
957 + </getter>
958 + </property>
959 +
960 + <property name="disabled">
961 + <getter>
962 + return this.getAttribute("disabled") == "true";
963 + </getter>
964 + <setter>
965 + <![CDATA[
966 + if (val)
967 + this.setAttribute("disabled", "true");
968 + else
969 + this.removeAttribute("disabled");
970 +
971 + if (!this.id)
972 + return val;
973 +
974 + var elements = document.getElementsByAttribute("preference", this.id);
975 + for (var i = 0; i < elements.length; ++i) {
976 + elements[i].disabled = val;
977 +
978 + var labels = document.getElementsByAttribute("control", elements[i].id);
979 + for (var j = 0; j < labels.length; ++j)
980 + labels[j].disabled = val;
981 + }
982 +
983 + return val;
984 + ]]>
985 + </setter>
986 + </property>
987 +
988 + <property name="tabIndex">
989 + <getter>
990 + return parseInt(this.getAttribute("tabindex"));
991 + </getter>
992 + <setter>
993 + <![CDATA[
994 + if (val)
995 + this.setAttribute("tabindex", val);
996 + else
997 + this.removeAttribute("tabindex");
998 +
999 + if (!this.id)
1000 + return val;
1001 +
1002 + var elements = document.getElementsByAttribute("preference", this.id);
1003 + for (var i = 0; i < elements.length; ++i) {
1004 + elements[i].tabIndex = val;
1005 +
1006 + var labels = document.getElementsByAttribute("control", elements[i].id);
1007 + for (var j = 0; j < labels.length; ++j)
1008 + labels[j].tabIndex = val;
1009 + }
1010 +
1011 + return val;
1012 + ]]>
1013 + </setter>
1014 + </property>
1015 +
1016 + <property name="hasUserValue">
1017 + <getter>
1018 + <![CDATA[
1019 + return this.preferences.rootBranch.prefHasUserValue(this.name) &&
1020 + this.value !== undefined;
1021 + ]]>
1022 + </getter>
1023 + </property>
1024 +
1025 + <method name="reset">
1026 + <body>
1027 + // defer reset until preference update
1028 + this.value = undefined;
1029 + </body>
1030 + </method>
1031 +
1032 + <field name="_useDefault">false</field>
1033 + <property name="defaultValue">
1034 + <getter>
1035 + <![CDATA[
1036 + this._useDefault = true;
1037 + var val = this.valueFromPreferences;
1038 + this._useDefault = false;
1039 + return val;
1040 + ]]>
1041 + </getter>
1042 + </property>
1043 +
1044 + <property name="_branch">
1045 + <getter>
1046 + return this._useDefault ? this.preferences.defaultBranch : this.preferences.rootBranch;
1047 + </getter>
1048 + </property>
1049 +
1050 + <field name="batching">false</field>
1051 +
1052 + <method name="_reportUnknownType">
1053 + <body>
1054 + <![CDATA[
1055 + var consoleService = Components.classes["@mozilla.org/consoleservice;1"]
1056 + .getService(Components.interfaces.nsIConsoleService);
1057 + var msg = "<preference> with id='" + this.id + "' and name='" +
1058 + this.name + "' has unknown type '" + this.type + "'.";
1059 + consoleService.logStringMessage(msg);
1060 + ]]>
1061 + </body>
1062 + </method>
1063 +
1064 + <property name="valueFromPreferences">
1065 + <getter>
1066 + <![CDATA[
1067 + try {
1068 + // Force a resync of value with preferences.
1069 + switch (this.type) {
1070 + case "int":
1071 + return this._branch.getIntPref(this.name);
1072 + case "bool":
1073 + var val = this._branch.getBoolPref(this.name);
1074 + return this.inverted ? !val : val;
1075 + case "wstring":
1076 + return this._branch
1077 + .getComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString)
1078 + .data;
1079 + case "string":
1080 + case "unichar":
1081 + return this._branch
1082 + .getComplexValue(this.name, Components.interfaces.nsISupportsString)
1083 + .data;
1084 + case "fontname":
1085 + var family = this._branch
1086 + .getComplexValue(this.name, Components.interfaces.nsISupportsString)
1087 + .data;
1088 + var fontEnumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"]
1089 + .createInstance(Components.interfaces.nsIFontEnumerator);
1090 + return fontEnumerator.getStandardFamilyName(family);
1091 + case "file":
1092 + var f = this._branch
1093 + .getComplexValue(this.name, Components.interfaces.nsILocalFile);
1094 + return f;
1095 + default:
1096 + this._reportUnknownType();
1097 + }
1098 + }
1099 + catch (e) { }
1100 + return null;
1101 + ]]>
1102 + </getter>
1103 + <setter>
1104 + <![CDATA[
1105 + // Exit early if nothing to do.
1106 + if (this.readonly || this.valueFromPreferences == val)
1107 + return val;
1108 +
1109 + // The special value undefined means 'reset preference to default'.
1110 + if (val === undefined) {
1111 + this.preferences.rootBranch.clearUserPref(this.name);
1112 + return val;
1113 + }
1114 +
1115 + // Force a resync of preferences with value.
1116 + switch (this.type) {
1117 + case "int":
1118 + this.preferences.rootBranch.setIntPref(this.name, val);
1119 + break;
1120 + case "bool":
1121 + this.preferences.rootBranch.setBoolPref(this.name, this.inverted ? !val : val);
1122 + break;
1123 + case "wstring":
1124 + var pls = Components.classes["@mozilla.org/pref-localizedstring;1"]
1125 + .createInstance(Components.interfaces.nsIPrefLocalizedString);
1126 + pls.data = val;
1127 + this.preferences.rootBranch
1128 + .setComplexValue(this.name, Components.interfaces.nsIPrefLocalizedString, pls);
1129 + break;
1130 + case "string":
1131 + case "unichar":
1132 + case "fontname":
1133 + var iss = Components.classes["@mozilla.org/supports-string;1"]
1134 + .createInstance(Components.interfaces.nsISupportsString);
1135 + iss.data = val;
1136 + this.preferences.rootBranch
1137 + .setComplexValue(this.name, Components.interfaces.nsISupportsString, iss);
1138 + break;
1139 + case "file":
1140 + var lf;
1141 + if (typeof(val) == "string") {
1142 + lf = Components.classes["@mozilla.org/file/local;1"]
1143 + .createInstance(Components.interfaces.nsILocalFile);
1144 + lf.persistentDescriptor = val;
1145 + if (!lf.exists())
1146 + lf.initWithPath(val);
1147 + }
1148 + else
1149 + lf = val.QueryInterface(Components.interfaces.nsILocalFile);
1150 + this.preferences.rootBranch
1151 + .setComplexValue(this.name, Components.interfaces.nsILocalFile, lf);
1152 + break;
1153 + default:
1154 + this._reportUnknownType();
1155 + }
1156 + if (!this.batching)
1157 + this.preferences.service.savePrefFile(null);
1158 + return val;
1159 + ]]>
1160 + </setter>
1161 + </property>
1162 +
1163 + <method name="setElementValue">
1164 + <parameter name="aElement"/>
1165 + <body>
1166 + <![CDATA[
1167 + if (this.locked)
1168 + aElement.disabled = true;
1169 +
1170 + if (!this.isElementEditable(aElement))
1171 + return;
1172 +
1173 + var rv = undefined;
1174 + if (aElement.hasAttribute("onsyncfrompreference")) {
1175 + // Value changed, synthesize an event
1176 + try {
1177 + var event = document.createEvent("Events");
1178 + event.initEvent("syncfrompreference", true, true);
1179 + var f = new Function ("event",
1180 + aElement.getAttribute("onsyncfrompreference"));
1181 + rv = f.call(aElement, event);
1182 + }
1183 + catch (e) {
1184 + Components.utils.reportError(e);
1185 + }
1186 + }
1187 + var val = rv !== undefined ? rv : (this.instantApply ? this.valueFromPreferences : this.value);
1188 + // if the preference is marked for reset, show default value in UI
1189 + if (val === undefined)
1190 + val = this.defaultValue;
1191 +
1192 + /**
1193 + * Initialize a UI element property with a value. Handles the case
1194 + * where an element has not yet had a XBL binding attached for it and
1195 + * the property setter does not yet exist by setting the same attribute
1196 + * on the XUL element using DOM apis and assuming the element's
1197 + * constructor or property getters appropriately handle this state.
1198 + */
1199 + function setValue(element, attribute, value) {
1200 + if (attribute in element)
1201 + element[attribute] = value;
1202 + else
1203 + element.setAttribute(attribute, value);
1204 + }
1205 + if (aElement.localName == "checkbox" ||
1206 + aElement.localName == "listitem")
1207 + setValue(aElement, "checked", val);
1208 + else if (aElement.localName == "colorpicker")
1209 + setValue(aElement, "color", val);
1210 + else if (aElement.localName == "textbox") {
1211 + // XXXmano Bug 303998: Avoid a caret placement issue if either the
1212 + // preference observer or its setter calls updateElements as a result
1213 + // of the input event handler.
1214 + if (aElement.value !== val)
1215 + setValue(aElement, "value", val);
1216 + }
1217 + else
1218 + setValue(aElement, "value", val);
1219 + ]]>
1220 + </body>
1221 + </method>
1222 +
1223 + <method name="getElementValue">
1224 + <parameter name="aElement"/>
1225 + <body>
1226 + <![CDATA[
1227 + if (aElement.hasAttribute("onsynctopreference")) {
1228 + // Value changed, synthesize an event
1229 + try {
1230 + var event = document.createEvent("Events");
1231 + event.initEvent("synctopreference", true, true);
1232 + var f = new Function ("event",
1233 + aElement.getAttribute("onsynctopreference"));
1234 + var rv = f.call(aElement, event);
1235 + if (rv !== undefined)
1236 + return rv;
1237 + }
1238 + catch (e) {
1239 + Components.utils.reportError(e);
1240 + }
1241 + }
1242 +
1243 + /**
1244 + * Read the value of an attribute from an element, assuming the
1245 + * attribute is a property on the element's node API. If the property
1246 + * is not present in the API, then assume its value is contained in
1247 + * an attribute, as is the case before a binding has been attached.
1248 + */
1249 + function getValue(element, attribute) {
1250 + if (attribute in element)
1251 + return element[attribute];
1252 + return element.getAttribute(attribute);
1253 + }
1254 + if (aElement.localName == "checkbox" ||
1255 + aElement.localName == "listitem")
1256 + var value = getValue(aElement, "checked");
1257 + else if (aElement.localName == "colorpicker")
1258 + value = getValue(aElement, "color");
1259 + else
1260 + value = getValue(aElement, "value");
1261 +
1262 + switch (this.type) {
1263 + case "int":
1264 + return parseInt(value, 10) || 0;
1265 + case "bool":
1266 + return typeof(value) == "boolean" ? value : value == "true";
1267 + }
1268 + return value;
1269 + ]]>
1270 + </body>
1271 + </method>
1272 +
1273 + <method name="isElementEditable">
1274 + <parameter name="aElement"/>
1275 + <body>
1276 + <![CDATA[
1277 + switch (aElement.localName) {
1278 + case "checkbox":
1279 + case "colorpicker":
1280 + case "radiogroup":
1281 + case "textbox":
1282 + case "listitem":
1283 + case "listbox":
1284 + case "menulist":
1285 + return true;
1286 + }
1287 + return aElement.getAttribute("preference-editable") == "true";
1288 + ]]>
1289 + </body>
1290 + </method>
1291 +
1292 + <method name="updateElements">
1293 + <body>
1294 + <![CDATA[
1295 + if (!this.id)
1296 + return;
1297 +
1298 + // This "change" event handler tracks changes made to preferences by
1299 + // sources other than the user in this window.
1300 + var elements = document.getElementsByAttribute("preference", this.id);
1301 + for (var i = 0; i < elements.length; ++i)
1302 + this.setElementValue(elements[i]);
1303 + ]]>
1304 + </body>
1305 + </method>
1306 + </implementation>
1307 +
1308 + <handlers>
1309 + <handler event="change">
1310 + this.updateElements();
1311 + </handler>
1312 + </handlers>
1313 + </binding>
1314 +
1315 + <binding id="prefwindow"
1316 + extends="chrome://global/content/bindings/dialog.xml#dialog">
1317 + <resources>
1318 + <stylesheet src="chrome://global/skin/preferences.css"/>
1319 + </resources>
1320 + <content dlgbuttons="accept,cancel" persist="lastSelected screenX screenY"
1321 + closebuttonlabel="&preferencesCloseButton.label;"
1322 + closebuttonaccesskey="&preferencesCloseButton.accesskey;"
1323 + role="dialog"
1324 +#ifdef XP_WIN
1325 + title="&preferencesDefaultTitleWin.title;">
1326 +#else
1327 + title="&preferencesDefaultTitleMac.title;">
1328 +#endif
1329 + <xul:windowdragbox orient="vertical">
1330 + <xul:radiogroup anonid="selector" orient="horizontal" class="paneSelector chromeclass-toolbar"
1331 + role="listbox"/> <!-- Expose to accessibility APIs as a listbox -->
1332 + </xul:windowdragbox>
1333 + <xul:hbox flex="1" class="paneDeckContainer">
1334 + <xul:deck anonid="paneDeck" flex="1">
1335 + <children includes="prefpane"/>
1336 + </xul:deck>
1337 + </xul:hbox>
1338 + <xul:hbox anonid="dlg-buttons" class="prefWindow-dlgbuttons" pack="end">
1339 +#ifdef XP_UNIX_GNOME
1340 + <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
1341 + <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
1342 + <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
1343 + <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
1344 + <xul:spacer anonid="spacer" flex="1"/>
1345 + <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
1346 + <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
1347 +#elif XP_UNIX
1348 + <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
1349 + <xul:spacer anonid="spacer" flex="1"/>
1350 + <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
1351 + <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
1352 + <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
1353 + <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
1354 + <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
1355 +#else
1356 + <xul:button dlgtype="extra2" class="dialog-button" hidden="true"/>
1357 + <xul:spacer anonid="spacer" flex="1"/>
1358 + <xul:button dlgtype="accept" class="dialog-button" icon="accept"/>
1359 + <xul:button dlgtype="extra1" class="dialog-button" hidden="true"/>
1360 + <xul:button dlgtype="cancel" class="dialog-button" icon="cancel"/>
1361 + <xul:button dlgtype="help" class="dialog-button" hidden="true" icon="help"/>
1362 + <xul:button dlgtype="disclosure" class="dialog-button" hidden="true"/>
1363 +#endif
1364 + </xul:hbox>
1365 + <xul:hbox>
1366 + <children/>
1367 + </xul:hbox>
1368 + </content>
1369 + <implementation implements="nsITimerCallback">
1370 + <constructor>
1371 + <![CDATA[
1372 + if (this.type != "child") {
1373 + var psvc = Components.classes["@mozilla.org/preferences-service;1"]
1374 + .getService(Components.interfaces.nsIPrefBranch);
1375 + this.instantApply = psvc.getBoolPref("browser.preferences.instantApply");
1376 + if (this.instantApply) {
1377 + var docElt = document.documentElement;
1378 + var acceptButton = docElt.getButton("accept");
1379 + acceptButton.hidden = true;
1380 + var cancelButton = docElt.getButton("cancel");
1381 +#ifdef XP_MACOSX
1382 + // no buttons on Mac except Help
1383 + cancelButton.hidden = true;
1384 + // Move Help button to the end
1385 + document.getAnonymousElementByAttribute(this, "anonid", "spacer").hidden = true;
1386 + // Also, don't fire onDialogAccept on enter
1387 + acceptButton.disabled = true;
1388 +#else
1389 + // morph the Cancel button into the Close button
1390 + cancelButton.setAttribute ("icon", "close");
1391 + cancelButton.label = docElt.getAttribute("closebuttonlabel");
1392 + cancelButton.accesskey = docElt.getAttribute("closebuttonaccesskey");
1393 +#endif
1394 + }
1395 + }
1396 + this.setAttribute("animated", this._shouldAnimate ? "true" : "false");
1397 + var panes = this.preferencePanes;
1398 +
1399 + var lastPane = null;
1400 + if (this.lastSelected) {
1401 + lastPane = document.getElementById(this.lastSelected);
1402 + if (!lastPane) {
1403 + this.lastSelected = "";
1404 + }
1405 + }
1406 +
1407 + var paneToLoad;
1408 + if ("arguments" in window && window.arguments[0] && document.getElementById(window.arguments[0]) && document.getElementById(window.arguments[0]).nodeName == "prefpane") {
1409 + paneToLoad = document.getElementById(window.arguments[0]);
1410 + this.lastSelected = paneToLoad.id;
1411 + }
1412 + else if (lastPane)
1413 + paneToLoad = lastPane;
1414 + else
1415 + paneToLoad = panes[0];
1416 +
1417 + for (var i = 0; i < panes.length; ++i) {
1418 + this._makePaneButton(panes[i]);
1419 + if (panes[i].loaded) {
1420 + // Inline pane content, fire load event to force initialization.
1421 + this._fireEvent("paneload", panes[i]);
1422 + }
1423 + }
1424 + this.showPane(paneToLoad);
1425 +
1426 + if (panes.length == 1)
1427 + this._selector.setAttribute("collapsed", "true");
1428 + ]]>
1429 + </constructor>
1430 +
1431 + <destructor>
1432 + <![CDATA[
1433 + // Release timers to avoid reference cycles.
1434 + if (this._animateTimer) {
1435 + this._animateTimer.cancel();
1436 + this._animateTimer = null;
1437 + }
1438 + if (this._fadeTimer) {
1439 + this._fadeTimer.cancel();
1440 + this._fadeTimer = null;
1441 + }
1442 + ]]>
1443 + </destructor>
1444 +
1445 + <field name="instantApply">false</field>
1446 +
1447 + <property name="preferencePanes"
1448 + onget="return this.getElementsByTagName('prefpane');"/>
1449 +
1450 + <property name="type" onget="return this.getAttribute('type');"/>
1451 + <property name="_paneDeck"
1452 + onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'paneDeck');"/>
1453 + <property name="_paneDeckContainer"
1454 + onget="return document.getAnonymousElementByAttribute(this, 'class', 'paneDeckContainer');"/>
1455 + <property name="_selector"
1456 + onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'selector');"/>
1457 + <property name="lastSelected"
1458 + onget="return this.getAttribute('lastSelected');">
1459 + <setter>
1460 + this.setAttribute("lastSelected", val);
1461 + document.persist(this.id, "lastSelected");
1462 + return val;
1463 + </setter>
1464 + </property>
1465 + <property name="currentPane"
1466 + onset="return this._currentPane = val;">
1467 + <getter>
1468 + if (!this._currentPane)
1469 + this._currentPane = this.preferencePanes[0];
1470 +
1471 + return this._currentPane;
1472 + </getter>
1473 + </property>
1474 + <field name="_currentPane">null</field>
1475 +
1476 +
1477 + <method name="_makePaneButton">
1478 + <parameter name="aPaneElement"/>
1479 + <body>
1480 + <![CDATA[
1481 + var radio = document.createElement("radio");
1482 + radio.setAttribute("pane", aPaneElement.id);
1483 + radio.setAttribute("label", aPaneElement.label);
1484 + // Expose preference group choice to accessibility APIs as an unchecked list item
1485 + // The parent group is exposed to accessibility APIs as a list
1486 + if (aPaneElement.image)
1487 + radio.setAttribute("src", aPaneElement.image);
1488 + radio.style.listStyleImage = aPaneElement.style.listStyleImage;
1489 + this._selector.appendChild(radio);
1490 + return radio;
1491 + ]]>
1492 + </body>
1493 + </method>
1494 +
1495 + <method name="showPane">
1496 + <parameter name="aPaneElement"/>
1497 + <body>
1498 + <![CDATA[
1499 + if (!aPaneElement)
1500 + return;
1501 +
1502 + this._selector.selectedItem = document.getAnonymousElementByAttribute(this, "pane", aPaneElement.id);
1503 + if (!aPaneElement.loaded) {
1504 + let OverlayLoadObserver = function(aPane)
1505 + {
1506 + this._pane = aPane;
1507 + }
1508 + OverlayLoadObserver.prototype = {
1509 + _outer: this,
1510 + observe: function (aSubject, aTopic, aData)
1511 + {
1512 + this._pane.loaded = true;
1513 + this._outer._fireEvent("paneload", this._pane);
1514 + this._outer._selectPane(this._pane);
1515 + }
1516 + };
1517 +
1518 + var obs = new OverlayLoadObserver(aPaneElement);
1519 + document.loadOverlay(aPaneElement.src, obs);
1520 + }
1521 + else
1522 + this._selectPane(aPaneElement);
1523 + ]]>
1524 + </body>
1525 + </method>
1526 +
1527 + <method name="_fireEvent">
1528 + <parameter name="aEventName"/>
1529 + <parameter name="aTarget"/>
1530 + <body>
1531 + <![CDATA[
1532 + // Panel loaded, synthesize a load event.
1533 + try {
1534 + var event = document.createEvent("Events");
1535 + event.initEvent(aEventName, true, true);
1536 + var cancel = !aTarget.dispatchEvent(event);
1537 + if (aTarget.hasAttribute("on" + aEventName)) {
1538 + var fn = new Function ("event", aTarget.getAttribute("on" + aEventName));
1539 + var rv = fn.call(aTarget, event);
1540 + if (rv == false)
1541 + cancel = true;
1542 + }
1543 + return !cancel;
1544 + }
1545 + catch (e) {
1546 + Components.utils.reportError(e);
1547 + }
1548 + return false;
1549 + ]]>
1550 + </body>
1551 + </method>
1552 +
1553 + <field name="_initialized">false</field>
1554 + <method name="_selectPane">
1555 + <parameter name="aPaneElement"/>
1556 + <body>
1557 + <![CDATA[
1558 +#ifdef XP_MACOSX
1559 + var paneTitle = aPaneElement.label;
1560 + if (paneTitle != "")
1561 + document.title = paneTitle;
1562 +#endif
1563 + var helpButton = document.documentElement.getButton("help");
1564 + if (aPaneElement.helpTopic)
1565 + helpButton.hidden = false;
1566 + else
1567 + helpButton.hidden = true;
1568 +
1569 + // Find this pane's index in the deck and set the deck's
1570 + // selectedIndex to that value to switch to it.
1571 + var prefpanes = this.preferencePanes;
1572 + for (var i = 0; i < prefpanes.length; ++i) {
1573 + if (prefpanes[i] == aPaneElement) {
1574 + this._paneDeck.selectedIndex = i;
1575 +
1576 + if (this.type != "child") {
1577 + if (aPaneElement.hasAttribute("flex") && this._shouldAnimate &&
1578 + prefpanes.length > 1)
1579 + aPaneElement.removeAttribute("flex");
1580 + // Calling sizeToContent after the first prefpane is loaded
1581 + // will size the windows contents so style information is
1582 + // available to calculate correct sizing.
1583 + if (!this._initialized && prefpanes.length > 1) {
1584 + if (this._shouldAnimate)
1585 + this.style.minHeight = 0;
1586 + window.sizeToContent();
1587 + }
1588 +
1589 + var oldPane = this.lastSelected ? document.getElementById(this.lastSelected) : this.preferencePanes[0];
1590 + oldPane.selected = !(aPaneElement.selected = true);
1591 + this.lastSelected = aPaneElement.id;
1592 + this.currentPane = aPaneElement;
1593 + this._initialized = true;
1594 +
1595 + // Only animate if we've switched between prefpanes
1596 + if (this._shouldAnimate && oldPane.id != aPaneElement.id) {
1597 + aPaneElement.style.opacity = 0.0;
1598 + this.animate(oldPane, aPaneElement);
1599 + }
1600 + else if (!this._shouldAnimate && prefpanes.length > 1) {
1601 + var targetHeight = parseInt(window.getComputedStyle(this._paneDeckContainer, "").height);
1602 + var verticalPadding = parseInt(window.getComputedStyle(aPaneElement, "").paddingTop);
1603 + verticalPadding += parseInt(window.getComputedStyle(aPaneElement, "").paddingBottom);
1604 + if (aPaneElement.contentHeight > targetHeight - verticalPadding) {
1605 + // To workaround the bottom border of a groupbox from being
1606 + // cutoff an hbox with a class of bottomBox may enclose it.
1607 + // This needs to include its padding to resize properly.
1608 + // See bug 394433
1609 + var bottomPadding = 0;
1610 + var bottomBox = aPaneElement.getElementsByAttribute("class", "bottomBox")[0];
1611 + if (bottomBox)
1612 + bottomPadding = parseInt(window.getComputedStyle(bottomBox, "").paddingBottom);
1613 + window.innerHeight += bottomPadding + verticalPadding + aPaneElement.contentHeight - targetHeight;
1614 + }
1615 +
1616 + // XXX rstrong - extend the contents of the prefpane to
1617 + // prevent elements from being cutoff (see bug 349098).
1618 + if (aPaneElement.contentHeight + verticalPadding < targetHeight)
1619 + aPaneElement._content.style.height = targetHeight - verticalPadding + "px";
1620 + }
1621 + }
1622 + break;
1623 + }
1624 + }
1625 + ]]>
1626 + </body>
1627 + </method>
1628 +
1629 + <property name="_shouldAnimate">
1630 + <getter>
1631 + <![CDATA[
1632 + var psvc = Components.classes["@mozilla.org/preferences-service;1"]
1633 + .getService(Components.interfaces.nsIPrefBranch);
1634 +#ifdef XP_MACOSX
1635 + var animate = true;
1636 +#else
1637 + var animate = false;
1638 +#endif
1639 + try {
1640 + animate = psvc.getBoolPref("browser.preferences.animateFadeIn");
1641 + }
1642 + catch (e) { }
1643 + return animate;
1644 + ]]>
1645 + </getter>
1646 + </property>
1647 +
1648 + <method name="animate">
1649 + <parameter name="aOldPane"/>
1650 + <parameter name="aNewPane"/>
1651 + <body>
1652 + <![CDATA[
1653 + // if we are already resizing, use currentHeight
1654 + var oldHeight = this._currentHeight ? this._currentHeight : aOldPane.contentHeight;
1655 +
1656 + this._multiplier = aNewPane.contentHeight > oldHeight ? 1 : -1;
1657 + var sizeDelta = Math.abs(oldHeight - aNewPane.contentHeight);
1658 + this._animateRemainder = sizeDelta % this._animateIncrement;
1659 +
1660 + this._setUpAnimationTimer(oldHeight);
1661 + ]]>
1662 + </body>
1663 + </method>
1664 +
1665 + <property name="_sizeIncrement">
1666 + <getter>
1667 + <![CDATA[
1668 + var lastSelectedPane = document.getElementById(this.lastSelected);
1669 + var increment = this._animateIncrement * this._multiplier;
1670 + var newHeight = this._currentHeight + increment;
1671 + if ((this._multiplier > 0 && this._currentHeight >= lastSelectedPane.contentHeight) ||
1672 + (this._multiplier < 0 && this._currentHeight <= lastSelectedPane.contentHeight))
1673 + return 0;
1674 +
1675 + if ((this._multiplier > 0 && newHeight > lastSelectedPane.contentHeight) ||
1676 + (this._multiplier < 0 && newHeight < lastSelectedPane.contentHeight))
1677 + increment = this._animateRemainder * this._multiplier;
1678 + return increment;
1679 + ]]>
1680 + </getter>
1681 + </property>
1682 +
1683 + <method name="notify">
1684 + <parameter name="aTimer"/>
1685 + <body>
1686 + <![CDATA[
1687 + if (!document)
1688 + aTimer.cancel();
1689 +
1690 + if (aTimer == this._animateTimer) {
1691 + var increment = this._sizeIncrement;
1692 + if (increment != 0) {
1693 + window.innerHeight += increment;
1694 + this._currentHeight += increment;
1695 + }
1696 + else {
1697 + aTimer.cancel();
1698 + this._setUpFadeTimer();
1699 + }
1700 + } else if (aTimer == this._fadeTimer) {
1701 + var elt = document.getElementById(this.lastSelected);
1702 + var newOpacity = parseFloat(window.getComputedStyle(elt, "").opacity) + this._fadeIncrement;
1703 + if (newOpacity < 1.0)
1704 + elt.style.opacity = newOpacity;
1705 + else {
1706 + aTimer.cancel();
1707 + elt.style.opacity = 1.0;
1708 + }
1709 + }
1710 + ]]>
1711 + </body>
1712 + </method>
1713 +
1714 + <method name="_setUpAnimationTimer">
1715 + <parameter name="aStartHeight"/>
1716 + <body>
1717 + <![CDATA[
1718 + if (!this._animateTimer)
1719 + this._animateTimer = Components.classes["@mozilla.org/timer;1"]
1720 + .createInstance(Components.interfaces.nsITimer);
1721 + else
1722 + this._animateTimer.cancel();
1723 + this._currentHeight = aStartHeight;
1724 +
1725 + this._animateTimer.initWithCallback(this, this._animateDelay,
1726 + Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
1727 + ]]>
1728 + </body>
1729 + </method>
1730 +
1731 + <method name="_setUpFadeTimer">
1732 + <body>
1733 + <![CDATA[
1734 + if (!this._fadeTimer)
1735 + this._fadeTimer = Components.classes["@mozilla.org/timer;1"]
1736 + .createInstance(Components.interfaces.nsITimer);
1737 + else
1738 + this._fadeTimer.cancel();
1739 +
1740 + this._fadeTimer.initWithCallback(this, this._fadeDelay,
1741 + Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
1742 + ]]>
1743 + </body>
1744 + </method>
1745 +
1746 + <field name="_animateTimer">null</field>
1747 + <field name="_fadeTimer">null</field>
1748 + <field name="_animateDelay">15</field>
1749 + <field name="_animateIncrement">40</field>
1750 + <field name="_fadeDelay">5</field>
1751 + <field name="_fadeIncrement">0.40</field>
1752 + <field name="_animateRemainder">0</field>
1753 + <field name="_currentHeight">0</field>
1754 + <field name="_multiplier">0</field>
1755 +
1756 + <method name="addPane">
1757 + <parameter name="aPaneElement"/>
1758 + <body>
1759 + <![CDATA[
1760 + this.appendChild(aPaneElement);
1761 +
1762 + // Set up pane button
1763 + this._makePaneButton(aPaneElement);
1764 + ]]>
1765 + </body>
1766 + </method>
1767 +
1768 + <method name="openSubDialog">
1769 + <parameter name="aURL"/>
1770 + <parameter name="aFeatures"/>
1771 + <parameter name="aParams"/>
1772 + <body>
1773 + return openDialog(aURL, "", "modal,centerscreen,resizable=no" + (aFeatures != "" ? ("," + aFeatures) : ""), aParams);
1774 + </body>
1775 + </method>
1776 +
1777 + <method name="openWindow">
1778 + <parameter name="aWindowType"/>
1779 + <parameter name="aURL"/>
1780 + <parameter name="aFeatures"/>
1781 + <parameter name="aParams"/>
1782 + <body>
1783 + <![CDATA[
1784 + var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
1785 + .getService(Components.interfaces.nsIWindowMediator);
1786 + var win = aWindowType ? wm.getMostRecentWindow(aWindowType) : null;
1787 + if (win) {
1788 + if ("initWithParams" in win)
1789 + win.initWithParams(aParams);
1790 + win.focus();
1791 + }
1792 + else {
1793 + var features = "resizable,dialog=no,centerscreen" + (aFeatures != "" ? ("," + aFeatures) : "");
1794 + var parentWindow = (this.instantApply || !window.opener || window.opener.closed) ? window : window.opener;
1795 + win = parentWindow.openDialog(aURL, "_blank", features, aParams);
1796 + }
1797 + return win;
1798 + ]]>
1799 + </body>
1800 + </method>
1801 + </implementation>
1802 + <handlers>
1803 + <handler event="dialogaccept">
1804 + <![CDATA[
1805 + if (!this._fireEvent("beforeaccept", this)){
1806 + return false;
1807 + }
1808 +
1809 + if (this.type == "child" && window.opener) {
1810 + var psvc = Components.classes["@mozilla.org/preferences-service;1"]
1811 + .getService(Components.interfaces.nsIPrefBranch);
1812 + var instantApply = psvc.getBoolPref("browser.preferences.instantApply");
1813 + if (instantApply) {
1814 + var panes = this.preferencePanes;
1815 + for (var i = 0; i < panes.length; ++i)
1816 + panes[i].writePreferences(true);
1817 + }
1818 + else {
1819 + // Clone all the preferences elements from the child document and
1820 + // insert them into the pane collection of the parent.
1821 + var pdoc = window.opener.document;
1822 + if (pdoc.documentElement.localName == "prefwindow") {
1823 + var currentPane = pdoc.documentElement.currentPane;
1824 + var id = window.location.href + "#childprefs";
1825 + var childPrefs = pdoc.getElementById(id);
1826 + if (!childPrefs) {
1827 + var childPrefs = pdoc.createElement("preferences");
1828 + currentPane.appendChild(childPrefs);
1829 + childPrefs.id = id;
1830 + }
1831 + var panes = this.preferencePanes;
1832 + for (var i = 0; i < panes.length; ++i) {
1833 + var preferences = panes[i].preferences;
1834 + for (var j = 0; j < preferences.length; ++j) {
1835 + // Try to find a preference element for the same preference.
1836 + var preference = null;
1837 + var parentPreferences = pdoc.getElementsByTagName("preferences");
1838 + for (var k = 0; (k < parentPreferences.length && !preference); ++k) {
1839 + var parentPrefs = parentPreferences[k]
1840 + .getElementsByAttribute("name", preferences[j].name);
1841 + for (var l = 0; (l < parentPrefs.length && !preference); ++l) {
1842 + if (parentPrefs[l].localName == "preference")
1843 + preference = parentPrefs[l];
1844 + }
1845 + }
1846 + if (!preference) {
1847 + // No matching preference in the parent window.
1848 + preference = pdoc.createElement("preference");
1849 + childPrefs.appendChild(preference);
1850 + preference.name = preferences[j].name;
1851 + preference.type = preferences[j].type;
1852 + preference.inverted = preferences[j].inverted;
1853 + preference.readonly = preferences[j].readonly;
1854 + preference.disabled = preferences[j].disabled;
1855 + }
1856 + preference.value = preferences[j].value;
1857 + }
1858 + }
1859 + }
1860 + }
1861 + }
1862 + else {
1863 + var panes = this.preferencePanes;
1864 + for (var i = 0; i < panes.length; ++i)
1865 + panes[i].writePreferences(false);
1866 +
1867 + var psvc = Components.classes["@mozilla.org/preferences-service;1"]
1868 + .getService(Components.interfaces.nsIPrefService);
1869 + psvc.savePrefFile(null);
1870 + }
1871 +
1872 + return true;
1873 + ]]>
1874 + </handler>
1875 + <handler event="command">
1876 + if (event.originalTarget.hasAttribute("pane")) {
1877 + var pane = document.getElementById(event.originalTarget.getAttribute("pane"));
1878 + this.showPane(pane);
1879 + }
1880 + </handler>
1881 +
1882 + <handler event="keypress" key="&windowClose.key;" modifiers="accel" phase="capturing">
1883 + <![CDATA[
1884 + if (this.instantApply)
1885 + window.close();
1886 + event.stopPropagation();
1887 + event.preventDefault();
1888 + ]]>
1889 + </handler>
1890 +
1891 + <handler event="keypress"
1892 +#ifdef XP_MACOSX
1893 + key="&openHelpMac.commandkey;" modifiers="accel"
1894 +#else
1895 + keycode="&openHelp.commandkey;"
1896 +#endif
1897 + phase="capturing">
1898 + <![CDATA[
1899 + var helpButton = this.getButton("help");
1900 + if (helpButton.disabled || helpButton.hidden)
1901 + return;
1902 + this._fireEvent("dialoghelp", this);
1903 + event.stopPropagation();
1904 + event.preventDefault();
1905 + ]]>
1906 + </handler>
1907 + </handlers>
1908 + </binding>
1909 +
1910 + <binding id="prefpane">
1911 + <resources>
1912 + <stylesheet src="chrome://global/skin/preferences.css"/>
1913 + </resources>
1914 + <content>
1915 + <xul:vbox class="content-box" xbl:inherits="flex">
1916 + <children/>
1917 + </xul:vbox>
1918 + </content>
1919 + <implementation>
1920 + <method name="writePreferences">
1921 + <parameter name="aFlushToDisk"/>
1922 + <body>
1923 + <![CDATA[
1924 + // Write all values to preferences.
1925 + var preferences = this.preferences;
1926 + for (var i = 0; i < preferences.length; ++i) {
1927 + var preference = preferences[i];
1928 + preference.batching = true;
1929 + preference.valueFromPreferences = preference.value;
1930 + preference.batching = false;
1931 + }
1932 + if (aFlushToDisk) {
1933 + var psvc = Components.classes["@mozilla.org/preferences-service;1"]
1934 + .getService(Components.interfaces.nsIPrefService);
1935 + psvc.savePrefFile(null);
1936 + }
1937 + ]]>
1938 + </body>
1939 + </method>
1940 +
1941 + <property name="src"
1942 + onget="return this.getAttribute('src');"
1943 + onset="this.setAttribute('src', val); return val;"/>
1944 + <property name="selected"
1945 + onget="return this.getAttribute('selected') == 'true';"
1946 + onset="this.setAttribute('selected', val); return val;"/>
1947 + <property name="image"
1948 + onget="return this.getAttribute('image');"
1949 + onset="this.setAttribute('image', val); return val;"/>
1950 + <property name="label"
1951 + onget="return this.getAttribute('label');"
1952 + onset="this.setAttribute('label', val); return val;"/>
1953 +
1954 + <property name="preferenceElements"
1955 + onget="return this.getElementsByAttribute('preference', '*');"/>
1956 + <property name="preferences"
1957 + onget="return this.getElementsByTagName('preference');"/>
1958 +
1959 + <property name="helpTopic">
1960 + <getter>
1961 + <![CDATA[
1962 + // if there are tabs, and the selected tab provides a helpTopic, return that
1963 + var box = this.getElementsByTagName("tabbox");
1964 + if (box[0]) {
1965 + var tab = box[0].selectedTab;
1966 + if (tab && tab.hasAttribute("helpTopic"))
1967 + return tab.getAttribute("helpTopic");
1968 + }
1969 +
1970 + // otherwise, return the helpTopic of the current panel
1971 + return this.getAttribute("helpTopic");
1972 + ]]>
1973 + </getter>
1974 + </property>
1975 +
1976 + <field name="_loaded">false</field>
1977 + <property name="loaded"
1978 + onget="return !this.src ? true : this._loaded;"
1979 + onset="this._loaded = val; return val;"/>
1980 +
1981 + <method name="preferenceForElement">
1982 + <parameter name="aElement"/>
1983 + <body>
1984 + return document.getElementById(aElement.getAttribute("preference"));
1985 + </body>
1986 + </method>
1987 +
1988 + <method name="getPreferenceElement">
1989 + <parameter name="aStartElement"/>
1990 + <body>
1991 + <![CDATA[
1992 + var temp = aStartElement;
1993 + while (temp && temp.nodeType == Node.ELEMENT_NODE &&
1994 + !temp.hasAttribute("preference"))
1995 + temp = temp.parentNode;
1996 + return temp.nodeType == Node.ELEMENT_NODE ? temp : aStartElement;
1997 + ]]>
1998 + </body>
1999 + </method>
2000 +
2001 + <method name="userChangedValue">
2002 + <parameter name="aElement"/>
2003 + <body>
2004 + <![CDATA[
2005 + var element = this.getPreferenceElement(aElement);
2006 + if (element.hasAttribute("preference")) {
2007 + var preference = document.getElementById(element.getAttribute("preference"));
2008 + var prefVal = preference.getElementValue(element);
2009 + preference.value = prefVal;
2010 + }
2011 + ]]>
2012 + </body>
2013 + </method>
2014 +
2015 + <property name="contentHeight">
2016 + <getter>
2017 + var targetHeight = parseInt(window.getComputedStyle(this._content, "").height);
2018 + targetHeight += parseInt(window.getComputedStyle(this._content, "").marginTop);
2019 + targetHeight += parseInt(window.getComputedStyle(this._content, "").marginBottom);
2020 + return targetHeight;
2021 + </getter>
2022 + </property>
2023 + <field name="_content">
2024 + document.getAnonymousElementByAttribute(this, "class", "content-box");
2025 + </field>
2026 + </implementation>
2027 + <handlers>
2028 + <handler event="command">
2029 + // This "command" event handler tracks changes made to preferences by
2030 + // the user in this window.
2031 + if (event.sourceEvent)
2032 + event = event.sourceEvent;
2033 + this.userChangedValue(event.target);
2034 + </handler>
2035 + <handler event="select">
2036 + // This "select" event handler tracks changes made to colorpicker
2037 + // preferences by the user in this window.
2038 + if (event.target.localName == "colorpicker")
2039 + this.userChangedValue(event.target);
2040 + </handler>
2041 + <handler event="change">
2042 + // This "change" event handler tracks changes made to preferences by
2043 + // the user in this window.
2044 + this.userChangedValue(event.target);
2045 + </handler>
2046 + <handler event="input">
2047 + // This "input" event handler tracks changes made to preferences by
2048 + // the user in this window.
2049 + this.userChangedValue(event.target);
2050 + </handler>
2051 + <handler event="paneload">
2052 + <![CDATA[
2053 + // Initialize all values from preferences.
2054 + var elements = this.preferenceElements;
2055 + for (var i = 0; i < elements.length; ++i) {
2056 + try {
2057 + var preference = this.preferenceForElement(elements[i]);
2058 + preference.setElementValue(elements[i]);
2059 + }
2060 + catch (e) {
2061 + dump("*** No preference found for " + elements[i].getAttribute("preference") + "\n");
2062 + }
2063 + }
2064 + ]]>
2065 + </handler>
2066 + </handlers>
2067 + </binding>
2068 +
2069 + <binding id="panebutton" role="xul:listitem"
2070 + extends="chrome://global/content/bindings/radio.xml#radio">
2071 + <resources>
2072 + <stylesheet src="chrome://global/skin/preferences.css"/>
2073 + </resources>
2074 + <content>
2075 + <xul:image class="paneButtonIcon" xbl:inherits="src"/>
2076 + <xul:label class="paneButtonLabel" xbl:inherits="value=label"/>
2077 + </content>
2078 + </binding>
2079 +
2080 +</bindings>
2081 +
2082 +# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2083 +# This Source Code Form is subject to the terms of the Mozilla Public
2084 +# License, v. 2.0. If a copy of the MPL was not distributed with this
2085 +# file, You can obtain one at http://mozilla.org/MPL/2.0/.
2086 +
2087 +#
2088 +# This is PrefWindow 6. The Code Could Well Be Ready, Are You?
2089 +#
2090 +# Historical References:
2091 +# PrefWindow V (February 1, 2003)
2092 +# PrefWindow IV (April 24, 2000)
2093 +# PrefWindow III (January 6, 2000)
2094 +# PrefWindow II (???)
2095 +# PrefWindow I (June 4, 1999)
2096 +#
2097 diff --git a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
2098 --- a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
2099 +++ b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp
2100 @@ -14,16 +14,18 @@
2101 #include "prenv.h"
2102 #include "nsPrintfCString.h"
2103 #include "nsNetUtil.h"
2104 #include "nsISupportsPrimitives.h"
2105 #include "nsIGSettingsService.h"
2106 #include "nsInterfaceHashtable.h"
2107 #include "mozilla/Attributes.h"
2108 #include "nsIURI.h"
2109 +#include "nsVoidArray.h"
2110 +#include "nsKDEUtils.h"
2111
2112 class nsUnixSystemProxySettings MOZ_FINAL : public nsISystemProxySettings {
2113 public:
2114 NS_DECL_ISUPPORTS
2115 NS_DECL_NSISYSTEMPROXYSETTINGS
2116
2117 nsUnixSystemProxySettings()
2118 : mSchemeProxySettings(5)
2119 @@ -38,16 +40,17 @@ private:
2120 nsCOMPtr<nsIGSettingsService> mGSettings;
2121 nsCOMPtr<nsIGSettingsCollection> mProxySettings;
2122 nsInterfaceHashtable<nsCStringHashKey, nsIGSettingsCollection> mSchemeProxySettings;
2123 bool IsProxyMode(const char* aMode);
2124 nsresult SetProxyResultFromGConf(const char* aKeyBase, const char* aType, nsACString& aResult);
2125 nsresult GetProxyFromGConf(const nsACString& aScheme, const nsACString& aHost, int32_t aPort, nsACString& aResult);
2126 nsresult GetProxyFromGSettings(const nsACString& aScheme, const nsACString& aHost, int32_t aPort, nsACString& aResult);
2127 nsresult SetProxyResultFromGSettings(const char* aKeyBase, const char* aType, nsACString& aResult);
2128 + nsresult GetProxyFromKDE(const nsACString& aScheme, const nsACString& aHost, PRInt32 aPort, nsACString& aResult);
2129 };
2130
2131 NS_IMPL_ISUPPORTS(nsUnixSystemProxySettings, nsISystemProxySettings)
2132
2133 NS_IMETHODIMP
2134 nsUnixSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
2135 {
2136 // dbus prevents us from being threadsafe, but this routine should not block anyhow
2137 @@ -504,16 +507,19 @@ nsUnixSystemProxySettings::GetProxyFromG
2138
2139 nsresult
2140 nsUnixSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
2141 const nsACString & aScheme,
2142 const nsACString & aHost,
2143 const int32_t aPort,
2144 nsACString & aResult)
2145 {
2146 + if (nsKDEUtils::kdeSupport())
2147 + return GetProxyFromKDE(aScheme, aHost, aPort, aResult);
2148 +
2149 if (mProxySettings) {
2150 nsresult rv = GetProxyFromGSettings(aScheme, aHost, aPort, aResult);
2151 if (NS_SUCCEEDED(rv))
2152 return rv;
2153 }
2154 if (mGConf)
2155 return GetProxyFromGConf(aScheme, aHost, aPort, aResult);
2156
2157 @@ -539,8 +545,34 @@ static const mozilla::Module::ContractID
2158
2159 static const mozilla::Module kUnixProxyModule = {
2160 mozilla::Module::kVersion,
2161 kUnixProxyCIDs,
2162 kUnixProxyContracts
2163 };
2164
2165 NSMODULE_DEFN(nsUnixProxyModule) = &kUnixProxyModule;
2166 +
2167 +nsresult
2168 +nsUnixSystemProxySettings::GetProxyFromKDE(const nsACString& aScheme,
2169 + const nsACString& aHost,
2170 + PRInt32 aPort,
2171 + nsACString& aResult)
2172 +{
2173 + nsAutoCString url;
2174 + url = aScheme;
2175 + url += "://";
2176 + url += aHost;
2177 + if( aPort >= 0 )
2178 + {
2179 + url += ":";
2180 + url += nsPrintfCString("%d", aPort);
2181 + }
2182 + nsTArray<nsCString> command;
2183 + command.AppendElement( NS_LITERAL_CSTRING( "GETPROXY" ));
2184 + command.AppendElement( url );
2185 + nsTArray<nsCString> result;
2186 + if( !nsKDEUtils::command( command, &result ) || result.Length() != 1 )
2187 + return NS_ERROR_FAILURE;
2188 + aResult = result[0];
2189 + return NS_OK;
2190 +}
2191 +
2192 diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build
2193 --- a/toolkit/xre/moz.build
2194 +++ b/toolkit/xre/moz.build
2195 @@ -43,17 +43,19 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt
2196 GENERATED_SOURCES += [
2197 'moc_nsNativeAppSupportQt.cpp',
2198 ]
2199 SOURCES += [
2200 'nsNativeAppSupportQt.cpp',
2201 'nsQAppInstance.cpp',
2202 ]
2203 elif CONFIG['MOZ_ENABLE_GTK']:
2204 + EXPORTS += ['nsKDEUtils.h']
2205 UNIFIED_SOURCES += [
2206 + 'nsKDEUtils.cpp',
2207 'nsNativeAppSupportUnix.cpp',
2208 ]
2209 else:
2210 UNIFIED_SOURCES += [
2211 'nsNativeAppSupportDefault.cpp',
2212 ]
2213
2214 if CONFIG['MOZ_X11']:
2215 diff --git a/toolkit/xre/nsKDEUtils.cpp b/toolkit/xre/nsKDEUtils.cpp
2216 new file mode 100644
2217 --- /dev/null
2218 +++ b/toolkit/xre/nsKDEUtils.cpp
2219 @@ -0,0 +1,339 @@
2220 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2221 +/* This Source Code Form is subject to the terms of the Mozilla Public
2222 + * License, v. 2.0. If a copy of the MPL was not distributed with this
2223 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
2224 +
2225 +#include "nsKDEUtils.h"
2226 +#include "nsIWidget.h"
2227 +#include "nsISupportsPrimitives.h"
2228 +#include "nsIMutableArray.h"
2229 +#include "nsComponentManagerUtils.h"
2230 +#include "nsArrayUtils.h"
2231 +
2232 +#include <gtk/gtk.h>
2233 +
2234 +#include <limits.h>
2235 +#include <stdio.h>
2236 +#include <sys/wait.h>
2237 +#include <sys/resource.h>
2238 +#include <unistd.h>
2239 +#include <X11/Xlib.h>
2240 +
2241 +//#define DEBUG_KDE
2242 +#ifdef DEBUG_KDE
2243 +#define KMOZILLAHELPER "kmozillahelper"
2244 +#else
2245 +// not need for lib64, it's a binary
2246 +#define KMOZILLAHELPER "/usr/lib/mozilla/kmozillahelper"
2247 +#endif
2248 +
2249 +#define KMOZILLAHELPER_VERSION 6
2250 +#define MAKE_STR2( n ) #n
2251 +#define MAKE_STR( n ) MAKE_STR2( n )
2252 +
2253 +static bool getKdeSession()
2254 + {
2255 + Display* dpy = XOpenDisplay( NULL );
2256 + if( dpy == NULL )
2257 + return false;
2258 + Atom kde_full_session = XInternAtom( dpy, "KDE_FULL_SESSION", True );
2259 + bool kde = false;
2260 + if( kde_full_session != None )
2261 + {
2262 + int cnt;
2263 + if( Atom* props = XListProperties( dpy, DefaultRootWindow( dpy ), &cnt ))
2264 + {
2265 + for( int i = 0;
2266 + i < cnt;
2267 + ++i )
2268 + {
2269 + if( props[ i ] == kde_full_session )
2270 + {
2271 + kde = true;
2272 +#ifdef DEBUG_KDE
2273 + fprintf( stderr, "KDE SESSION %d\n", kde );
2274 +#endif
2275 + break;
2276 + }
2277 + }
2278 + XFree( props );
2279 + }
2280 + }
2281 + XCloseDisplay( dpy );
2282 + return kde;
2283 + }
2284 +
2285 +static bool getKdeSupport()
2286 + {
2287 + nsTArray<nsCString> command;
2288 + command.AppendElement( NS_LITERAL_CSTRING( "CHECK" ));
2289 + command.AppendElement( NS_LITERAL_CSTRING( MAKE_STR( KMOZILLAHELPER_VERSION )));
2290 + bool kde = nsKDEUtils::command( command );
2291 +#ifdef DEBUG_KDE
2292 + fprintf( stderr, "KDE RUNNING %d\n", kde );
2293 +#endif
2294 + return kde;
2295 + }
2296 +
2297 +nsKDEUtils::nsKDEUtils()
2298 + : commandFile( NULL )
2299 + , replyFile( NULL )
2300 + {
2301 + }
2302 +
2303 +nsKDEUtils::~nsKDEUtils()
2304 + {
2305 +// closeHelper(); not actually useful, exiting will close the fd too
2306 + }
2307 +
2308 +nsKDEUtils* nsKDEUtils::self()
2309 + {
2310 + static nsKDEUtils s;
2311 + return &s;
2312 + }
2313 +
2314 +static bool helperRunning = false;
2315 +static bool helperFailed = false;
2316 +
2317 +bool nsKDEUtils::kdeSession()
2318 + {
2319 + static bool session = getKdeSession();
2320 + return session;
2321 + }
2322 +
2323 +bool nsKDEUtils::kdeSupport()
2324 + {
2325 + static bool support = kdeSession() && getKdeSupport();
2326 + return support && helperRunning;
2327 + }
2328 +
2329 +struct nsKDECommandData
2330 + {
2331 + FILE* file;
2332 + nsTArray<nsCString>* output;
2333 + GMainLoop* loop;
2334 + bool success;
2335 + };
2336 +
2337 +static gboolean kdeReadFunc( GIOChannel*, GIOCondition, gpointer data )
2338 + {
2339 + nsKDECommandData* p = static_cast< nsKDECommandData* >( data );
2340 + char buf[ 8192 ]; // TODO big enough
2341 + bool command_done = false;
2342 + bool command_failed = false;
2343 + while( !command_done && !command_failed && fgets( buf, 8192, p->file ) != NULL )
2344 + { // TODO what if the kernel splits a line into two chunks?
2345 +//#ifdef DEBUG_KDE
2346 +// fprintf( stderr, "READ: %s %d\n", buf, feof( p->file ));
2347 +//#endif
2348 + if( char* eol = strchr( buf, '\n' ))
2349 + *eol = '\0';
2350 + command_done = ( strcmp( buf, "\\1" ) == 0 );
2351 + command_failed = ( strcmp( buf, "\\0" ) == 0 );
2352 + nsAutoCString line( buf );
2353 + line.ReplaceSubstring( "\\n", "\n" );
2354 + line.ReplaceSubstring( "\\" "\\", "\\" ); // \\ -> \ , i.e. unescape
2355 + if( p->output && !( command_done || command_failed ))
2356 + p->output->AppendElement( nsCString( buf )); // TODO utf8?
2357 + }
2358 + bool quit = false;
2359 + if( feof( p->file ) || command_failed )
2360 + {
2361 + quit = true;
2362 + p->success = false;
2363 + }
2364 + if( command_done )
2365 + { // reading one reply finished
2366 + quit = true;
2367 + p->success = true;
2368 + }
2369 + if( quit )
2370 + {
2371 + if( p->loop )
2372 + g_main_loop_quit( p->loop );
2373 + return FALSE;
2374 + }
2375 + return TRUE;
2376 + }
2377 +
2378 +bool nsKDEUtils::command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output )
2379 + {
2380 + return self()->internalCommand( command, NULL, false, output );
2381 + }
2382 +
2383 +bool nsKDEUtils::command( nsIArray* command, nsIArray** output)
2384 + {
2385 + nsTArray<nsCString> in;
2386 + PRUint32 length;
2387 + command->GetLength( &length );
2388 + for ( PRUint32 i = 0; i < length; i++ )
2389 + {
2390 + nsCOMPtr<nsISupportsCString> str = do_QueryElementAt( command, i );
2391 + if( str )
2392 + {
2393 + nsAutoCString s;
2394 + str->GetData( s );
2395 + in.AppendElement( s );
2396 + }
2397 + }
2398 +
2399 + nsTArray<nsCString> out;
2400 + bool ret = self()->internalCommand( in, NULL, false, &out );
2401 +
2402 + if ( !output ) return ret;
2403 +
2404 + nsCOMPtr<nsIMutableArray> result = do_CreateInstance( NS_ARRAY_CONTRACTID );
2405 + if ( !result ) return false;
2406 +
2407 + for ( PRUint32 i = 0; i < out.Length(); i++ )
2408 + {
2409 + nsCOMPtr<nsISupportsCString> rstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID );
2410 + if ( !rstr ) return false;
2411 +
2412 + rstr->SetData( out[i] );
2413 + result->AppendElement( rstr, false );
2414 + }
2415 +
2416 + NS_ADDREF( *output = result);
2417 + return ret;
2418 + }
2419 +
2420 +
2421 +bool nsKDEUtils::commandBlockUi( const nsTArray<nsCString>& command, const GtkWindow* parent, nsTArray<nsCString>* output )
2422 + {
2423 + return self()->internalCommand( command, parent, true, output );
2424 + }
2425 +
2426 +bool nsKDEUtils::internalCommand( const nsTArray<nsCString>& command, const GtkWindow* parent, bool blockUi,
2427 + nsTArray<nsCString>* output )
2428 + {
2429 + if( !startHelper())
2430 + return false;
2431 + feedCommand( command );
2432 + // do not store the data in 'this' but in extra structure, just in case there
2433 + // is reentrancy (can there be? the event loop is re-entered)
2434 + nsKDECommandData data;
2435 + data.file = replyFile;
2436 + data.output = output;
2437 + data.success = false;
2438 + if( blockUi )
2439 + {
2440 + data.loop = g_main_loop_new( NULL, FALSE );
2441 + GtkWidget* window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
2442 + if( parent && parent->group )
2443 + gtk_window_group_add_window( parent->group, GTK_WINDOW( window ));
2444 + gtk_widget_realize( window );
2445 + gtk_widget_set_sensitive( window, TRUE );
2446 + gtk_grab_add( window );
2447 + GIOChannel* channel = g_io_channel_unix_new( fileno( data.file ));
2448 + g_io_add_watch( channel, static_cast< GIOCondition >( G_IO_IN | G_IO_ERR | G_IO_HUP ), kdeReadFunc, &data );
2449 + g_io_channel_unref( channel );
2450 + g_main_loop_run( data.loop );
2451 + g_main_loop_unref( data.loop );
2452 + gtk_grab_remove( window );
2453 + gtk_widget_destroy( window );
2454 + }
2455 + else
2456 + {
2457 + data.loop = NULL;
2458 + while( kdeReadFunc( NULL, static_cast< GIOCondition >( 0 ), &data ))
2459 + ;
2460 + }
2461 + return data.success;
2462 + }
2463 +
2464 +bool nsKDEUtils::startHelper()
2465 + {
2466 + if( helperRunning )
2467 + return true;
2468 + if( helperFailed )
2469 + return false;
2470 + helperFailed = true;
2471 + int fdcommand[ 2 ];
2472 + int fdreply[ 2 ];
2473 + if( pipe( fdcommand ) < 0 )
2474 + return false;
2475 + if( pipe( fdreply ) < 0 )
2476 + {
2477 + close( fdcommand[ 0 ] );
2478 + close( fdcommand[ 1 ] );
2479 + return false;
2480 + }
2481 + char* args[ 2 ] = { const_cast< char* >( KMOZILLAHELPER ), NULL };
2482 + switch( fork())
2483 + {
2484 + case -1:
2485 + {
2486 + close( fdcommand[ 0 ] );
2487 + close( fdcommand[ 1 ] );
2488 + close( fdreply[ 0 ] );
2489 + close( fdreply[ 1 ] );
2490 + return false;
2491 + }
2492 + case 0: // child
2493 + {
2494 + if( dup2( fdcommand[ 0 ], STDIN_FILENO ) < 0 )
2495 + _exit( 1 );
2496 + if( dup2( fdreply[ 1 ], STDOUT_FILENO ) < 0 )
2497 + _exit( 1 );
2498 + int maxfd = 1024; // close all other fds
2499 + struct rlimit rl;
2500 + if( getrlimit( RLIMIT_NOFILE, &rl ) == 0 )
2501 + maxfd = rl.rlim_max;
2502 + for( int i = 3;
2503 + i < maxfd;
2504 + ++i )
2505 + close( i );
2506 +#ifdef DEBUG_KDE
2507 + execvp( KMOZILLAHELPER, args );
2508 +#else
2509 + execv( KMOZILLAHELPER, args );
2510 +#endif
2511 + _exit( 1 ); // failed
2512 + }
2513 + default: // parent
2514 + {
2515 + commandFile = fdopen( fdcommand[ 1 ], "w" );
2516 + replyFile = fdopen( fdreply[ 0 ], "r" );
2517 + close( fdcommand[ 0 ] );
2518 + close( fdreply[ 1 ] );
2519 + if( commandFile == NULL || replyFile == NULL )
2520 + {
2521 + closeHelper();
2522 + return false;
2523 + }
2524 + // ok, helper ready, getKdeRunning() will check if it works
2525 + }
2526 + }
2527 + helperFailed = false;
2528 + helperRunning = true;
2529 + return true;
2530 + }
2531 +
2532 +void nsKDEUtils::closeHelper()
2533 + {
2534 + if( commandFile != NULL )
2535 + fclose( commandFile ); // this will also make the helper quit
2536 + if( replyFile != NULL )
2537 + fclose( replyFile );
2538 + helperRunning = false;
2539 + }
2540 +
2541 +void nsKDEUtils::feedCommand( const nsTArray<nsCString>& command )
2542 + {
2543 + for( int i = 0;
2544 + i < command.Length();
2545 + ++i )
2546 + {
2547 + nsCString line = command[ i ];
2548 + line.ReplaceSubstring( "\\", "\\" "\\" ); // \ -> \\ , i.e. escape
2549 + line.ReplaceSubstring( "\n", "\\n" );
2550 +#ifdef DEBUG_KDE
2551 + fprintf( stderr, "COMM: %s\n", line.get());
2552 +#endif
2553 + fputs( line.get(), commandFile );
2554 + fputs( "\n", commandFile );
2555 + }
2556 + fputs( "\\E\n", commandFile ); // done as \E, so it cannot happen in normal data
2557 + fflush( commandFile );
2558 + }
2559 diff --git a/toolkit/xre/nsKDEUtils.h b/toolkit/xre/nsKDEUtils.h
2560 new file mode 100644
2561 --- /dev/null
2562 +++ b/toolkit/xre/nsKDEUtils.h
2563 @@ -0,0 +1,48 @@
2564 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2565 +/* This Source Code Form is subject to the terms of the Mozilla Public
2566 + * License, v. 2.0. If a copy of the MPL was not distributed with this
2567 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
2568 +
2569 +#ifndef nsKDEUtils_h__
2570 +#define nsKDEUtils_h__
2571 +
2572 +#include "nsStringGlue.h"
2573 +#include "nsTArray.h"
2574 +#include <stdio.h>
2575 +
2576 +typedef struct _GtkWindow GtkWindow;
2577 +
2578 +class nsIArray;
2579 +
2580 +class NS_EXPORT nsKDEUtils
2581 + {
2582 + public:
2583 + /* Returns true if running inside a KDE session (regardless of whether there is KDE
2584 + support available for Firefox). This should be used e.g. when determining
2585 + dialog button order but not for code that requires the KDE support. */
2586 + static bool kdeSession();
2587 + /* Returns true if running inside a KDE session and KDE support is available
2588 + for Firefox. This should be used everywhere where the external helper is needed. */
2589 + static bool kdeSupport();
2590 + /* Executes the given helper command, returns true if helper returned success. */
2591 + static bool command( const nsTArray<nsCString>& command, nsTArray<nsCString>* output = NULL );
2592 + static bool command( nsIArray* command, nsIArray** output = NULL );
2593 + /* Like command(), but additionally blocks the parent widget like if there was
2594 + a modal dialog shown and enters the event loop (i.e. there are still paint updates,
2595 + this is for commands that take long). */
2596 + static bool commandBlockUi( const nsTArray<nsCString>& command, const GtkWindow* parent, nsTArray<nsCString>* output = NULL );
2597 +
2598 + private:
2599 + nsKDEUtils();
2600 + ~nsKDEUtils();
2601 + static nsKDEUtils* self();
2602 + bool startHelper();
2603 + void closeHelper();
2604 + void feedCommand( const nsTArray<nsCString>& command );
2605 + bool internalCommand( const nsTArray<nsCString>& command, const GtkWindow* parent, bool isParent,
2606 + nsTArray<nsCString>* output );
2607 + FILE* commandFile;
2608 + FILE* replyFile;
2609 + };
2610 +
2611 +#endif // nsKDEUtils
2612 diff --git a/uriloader/exthandler/Makefile.in b/uriloader/exthandler/Makefile.in
2613 --- a/uriloader/exthandler/Makefile.in
2614 +++ b/uriloader/exthandler/Makefile.in
2615 @@ -6,9 +6,10 @@
2616 ifdef MOZ_ENABLE_DBUS
2617 OS_INCLUDES += $(TK_CFLAGS) $(MOZ_DBUS_CFLAGS)
2618 endif
2619
2620 include $(topsrcdir)/config/rules.mk
2621
2622 ifneq (,$(filter qt gtk2 gtk3, $(MOZ_WIDGET_TOOLKIT)))
2623 CXXFLAGS += $(TK_CFLAGS) $(MOZ_DBUS_GLIB_CFLAGS)
2624 +LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
2625 endif
2626 diff --git a/uriloader/exthandler/moz.build b/uriloader/exthandler/moz.build
2627 --- a/uriloader/exthandler/moz.build
2628 +++ b/uriloader/exthandler/moz.build
2629 @@ -80,17 +80,19 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
2630 else:
2631 # These files can't be built in unified mode because they force NSPR logging.
2632 SOURCES += [
2633 osdir + '/nsOSHelperAppService.cpp',
2634 ]
2635
2636 if CONFIG['MOZ_ENABLE_GTK']:
2637 UNIFIED_SOURCES += [
2638 + 'unix/nsCommonRegistry.cpp',
2639 'unix/nsGNOMERegistry.cpp',
2640 + 'unix/nsKDERegistry.cpp',
2641 'unix/nsMIMEInfoUnix.cpp',
2642 ]
2643 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
2644 UNIFIED_SOURCES += [
2645 'android/nsAndroidHandlerApp.cpp',
2646 'android/nsExternalSharingAppService.cpp',
2647 'android/nsExternalURLHandlerService.cpp',
2648 'android/nsMIMEInfoAndroid.cpp',
2649 diff --git a/uriloader/exthandler/unix/nsCommonRegistry.cpp b/uriloader/exthandler/unix/nsCommonRegistry.cpp
2650 new file mode 100644
2651 --- /dev/null
2652 +++ b/uriloader/exthandler/unix/nsCommonRegistry.cpp
2653 @@ -0,0 +1,54 @@
2654 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2655 +/* This Source Code Form is subject to the terms of the Mozilla Public
2656 + * License, v. 2.0. If a copy of the MPL was not distributed with this
2657 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
2658 +
2659 +#include "nsCommonRegistry.h"
2660 +
2661 +#include "nsGNOMERegistry.h"
2662 +#include "nsKDERegistry.h"
2663 +#include "nsString.h"
2664 +#include "nsVoidArray.h"
2665 +#include "nsKDEUtils.h"
2666 +
2667 +/* static */ bool
2668 +nsCommonRegistry::HandlerExists(const char *aProtocolScheme)
2669 +{
2670 + if( nsKDEUtils::kdeSupport())
2671 + return nsKDERegistry::HandlerExists( aProtocolScheme );
2672 + return nsGNOMERegistry::HandlerExists( aProtocolScheme );
2673 +}
2674 +
2675 +/* static */ nsresult
2676 +nsCommonRegistry::LoadURL(nsIURI *aURL)
2677 +{
2678 + if( nsKDEUtils::kdeSupport())
2679 + return nsKDERegistry::LoadURL( aURL );
2680 + return nsGNOMERegistry::LoadURL( aURL );
2681 +}
2682 +
2683 +/* static */ void
2684 +nsCommonRegistry::GetAppDescForScheme(const nsACString& aScheme,
2685 + nsAString& aDesc)
2686 +{
2687 + if( nsKDEUtils::kdeSupport())
2688 + return nsKDERegistry::GetAppDescForScheme( aScheme, aDesc );
2689 + return nsGNOMERegistry::GetAppDescForScheme( aScheme, aDesc );
2690 +}
2691 +
2692 +
2693 +/* static */ already_AddRefed<nsMIMEInfoBase>
2694 +nsCommonRegistry::GetFromExtension(const nsACString& aFileExt)
2695 +{
2696 + if( nsKDEUtils::kdeSupport())
2697 + return nsKDERegistry::GetFromExtension( aFileExt );
2698 + return nsGNOMERegistry::GetFromExtension( aFileExt );
2699 +}
2700 +
2701 +/* static */ already_AddRefed<nsMIMEInfoBase>
2702 +nsCommonRegistry::GetFromType(const nsACString& aMIMEType)
2703 +{
2704 + if( nsKDEUtils::kdeSupport())
2705 + return nsKDERegistry::GetFromType( aMIMEType );
2706 + return nsGNOMERegistry::GetFromType( aMIMEType );
2707 +}
2708 diff --git a/uriloader/exthandler/unix/nsCommonRegistry.h b/uriloader/exthandler/unix/nsCommonRegistry.h
2709 new file mode 100644
2710 --- /dev/null
2711 +++ b/uriloader/exthandler/unix/nsCommonRegistry.h
2712 @@ -0,0 +1,23 @@
2713 +/* This Source Code Form is subject to the terms of the Mozilla Public
2714 + * License, v. 2.0. If a copy of the MPL was not distributed with this
2715 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
2716 +
2717 +#include "nsIURI.h"
2718 +#include "nsCOMPtr.h"
2719 +
2720 +class nsMIMEInfoBase;
2721 +
2722 +class nsCommonRegistry
2723 +{
2724 + public:
2725 + static bool HandlerExists(const char *aProtocolScheme);
2726 +
2727 + static nsresult LoadURL(nsIURI *aURL);
2728 +
2729 + static void GetAppDescForScheme(const nsACString& aScheme,
2730 + nsAString& aDesc);
2731 +
2732 + static already_AddRefed<nsMIMEInfoBase> GetFromExtension(const nsACString& aFileExt);
2733 +
2734 + static already_AddRefed<nsMIMEInfoBase> GetFromType(const nsACString& aMIMEType);
2735 +};
2736 diff --git a/uriloader/exthandler/unix/nsKDERegistry.cpp b/uriloader/exthandler/unix/nsKDERegistry.cpp
2737 new file mode 100644
2738 --- /dev/null
2739 +++ b/uriloader/exthandler/unix/nsKDERegistry.cpp
2740 @@ -0,0 +1,88 @@
2741 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2742 +/* This Source Code Form is subject to the terms of the Mozilla Public
2743 + * License, v. 2.0. If a copy of the MPL was not distributed with this
2744 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
2745 +
2746 +#include "nsKDERegistry.h"
2747 +#include "prlink.h"
2748 +#include "prmem.h"
2749 +#include "nsString.h"
2750 +#include "nsILocalFile.h"
2751 +#include "nsMIMEInfoUnix.h"
2752 +#include "nsAutoPtr.h"
2753 +#include "nsKDEUtils.h"
2754 +
2755 +/* static */ bool
2756 +nsKDERegistry::HandlerExists(const char *aProtocolScheme)
2757 +{
2758 + nsTArray<nsCString> command;
2759 + command.AppendElement( NS_LITERAL_CSTRING( "HANDLEREXISTS" ));
2760 + command.AppendElement( nsAutoCString( aProtocolScheme ));
2761 + return nsKDEUtils::command( command );
2762 +}
2763 +
2764 +/* static */ nsresult
2765 +nsKDERegistry::LoadURL(nsIURI *aURL)
2766 +{
2767 + nsTArray<nsCString> command;
2768 + command.AppendElement( NS_LITERAL_CSTRING( "OPEN" ));
2769 + nsCString url;
2770 + aURL->GetSpec( url );
2771 + command.AppendElement( url );
2772 + bool rv = nsKDEUtils::command( command );
2773 + if (!rv)
2774 + return NS_ERROR_FAILURE;
2775 +
2776 + return NS_OK;
2777 +}
2778 +
2779 +/* static */ void
2780 +nsKDERegistry::GetAppDescForScheme(const nsACString& aScheme,
2781 + nsAString& aDesc)
2782 +{
2783 + nsTArray<nsCString> command;
2784 + command.AppendElement( NS_LITERAL_CSTRING( "GETAPPDESCFORSCHEME" ));
2785 + command.AppendElement( aScheme );
2786 + nsTArray<nsCString> output;
2787 + if( nsKDEUtils::command( command, &output ) && output.Length() == 1 )
2788 + CopyUTF8toUTF16( output[ 0 ], aDesc );
2789 +}
2790 +
2791 +
2792 +/* static */ already_AddRefed<nsMIMEInfoBase>
2793 +nsKDERegistry::GetFromExtension(const nsACString& aFileExt)
2794 +{
2795 + NS_ASSERTION(aFileExt[0] != '.', "aFileExt shouldn't start with a dot");
2796 + nsTArray<nsCString> command;
2797 + command.AppendElement( NS_LITERAL_CSTRING( "GETFROMEXTENSION" ));
2798 + command.AppendElement( aFileExt );
2799 + return GetFromHelper( command );
2800 +}
2801 +
2802 +/* static */ already_AddRefed<nsMIMEInfoBase>
2803 +nsKDERegistry::GetFromType(const nsACString& aMIMEType)
2804 +{
2805 + nsTArray<nsCString> command;
2806 + command.AppendElement( NS_LITERAL_CSTRING( "GETFROMTYPE" ));
2807 + command.AppendElement( aMIMEType );
2808 + return GetFromHelper( command );
2809 +}
2810 +
2811 +/* static */ already_AddRefed<nsMIMEInfoBase>
2812 +nsKDERegistry::GetFromHelper(const nsTArray<nsCString>& command)
2813 +{
2814 + nsTArray<nsCString> output;
2815 + if( nsKDEUtils::command( command, &output ) && output.Length() == 3 )
2816 + {
2817 + nsCString mimetype = output[ 0 ];
2818 + nsRefPtr<nsMIMEInfoUnix> mimeInfo = new nsMIMEInfoUnix( mimetype );
2819 + NS_ENSURE_TRUE(mimeInfo, nullptr);
2820 + nsCString description = output[ 1 ];
2821 + mimeInfo->SetDescription(NS_ConvertUTF8toUTF16(description));
2822 + nsCString handlerAppName = output[ 2 ];
2823 + mimeInfo->SetDefaultDescription(NS_ConvertUTF8toUTF16(handlerAppName));
2824 + mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
2825 + return mimeInfo.forget();
2826 + }
2827 + return nullptr;
2828 +}
2829 diff --git a/uriloader/exthandler/unix/nsKDERegistry.h b/uriloader/exthandler/unix/nsKDERegistry.h
2830 new file mode 100644
2831 --- /dev/null
2832 +++ b/uriloader/exthandler/unix/nsKDERegistry.h
2833 @@ -0,0 +1,29 @@
2834 +/* This Source Code Form is subject to the terms of the Mozilla Public
2835 + * License, v. 2.0. If a copy of the MPL was not distributed with this
2836 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
2837 +
2838 +#include "nsIURI.h"
2839 +#include "nsCOMPtr.h"
2840 +#include "nsTArray.h"
2841 +
2842 +class nsMIMEInfoBase;
2843 +class nsAutoCString;
2844 +class nsCString;
2845 +
2846 +class nsKDERegistry
2847 +{
2848 + public:
2849 + static bool HandlerExists(const char *aProtocolScheme);
2850 +
2851 + static nsresult LoadURL(nsIURI *aURL);
2852 +
2853 + static void GetAppDescForScheme(const nsACString& aScheme,
2854 + nsAString& aDesc);
2855 +
2856 + static already_AddRefed<nsMIMEInfoBase> GetFromExtension(const nsACString& aFileExt);
2857 +
2858 + static already_AddRefed<nsMIMEInfoBase> GetFromType(const nsACString& aMIMEType);
2859 + private:
2860 + static already_AddRefed<nsMIMEInfoBase> GetFromHelper(const nsTArray<nsCString>& command);
2861 +
2862 +};
2863 diff --git a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
2864 --- a/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
2865 +++ b/uriloader/exthandler/unix/nsMIMEInfoUnix.cpp
2866 @@ -10,30 +10,33 @@
2867 #include <QString>
2868 #if (MOZ_ENABLE_CONTENTACTION)
2869 #include <contentaction/contentaction.h>
2870 #include "nsContentHandlerApp.h"
2871 #endif
2872 #endif
2873
2874 #include "nsMIMEInfoUnix.h"
2875 -#include "nsGNOMERegistry.h"
2876 +#include "nsCommonRegistry.h"
2877 #include "nsIGIOService.h"
2878 #include "nsNetCID.h"
2879 #include "nsIIOService.h"
2880 #include "nsIGnomeVFSService.h"
2881 #include "nsAutoPtr.h"
2882 #ifdef MOZ_ENABLE_DBUS
2883 #include "nsDBusHandlerApp.h"
2884 #endif
2885 +#if defined(XP_UNIX) && !defined(XP_MACOSX)
2886 +#include "nsKDEUtils.h"
2887 +#endif
2888
2889 nsresult
2890 nsMIMEInfoUnix::LoadUriInternal(nsIURI * aURI)
2891 {
2892 - nsresult rv = nsGNOMERegistry::LoadURL(aURI);
2893 + nsresult rv = nsCommonRegistry::LoadURL(aURI);
2894
2895 #ifdef MOZ_WIDGET_QT
2896 if (NS_FAILED(rv)) {
2897 nsAutoCString spec;
2898 aURI->GetAsciiSpec(spec);
2899 if (QDesktopServices::openUrl(QUrl(spec.get()))) {
2900 rv = NS_OK;
2901 }
2902 @@ -50,24 +53,24 @@ nsMIMEInfoUnix::GetHasDefaultHandler(boo
2903 // either /etc/mailcap or ${HOME}/.mailcap, in which case we don't want to
2904 // give the GNOME answer.
2905 if (mDefaultApplication)
2906 return nsMIMEInfoImpl::GetHasDefaultHandler(_retval);
2907
2908 *_retval = false;
2909
2910 if (mClass == eProtocolInfo) {
2911 - *_retval = nsGNOMERegistry::HandlerExists(mSchemeOrType.get());
2912 + *_retval = nsCommonRegistry::HandlerExists(mSchemeOrType.get());
2913 } else {
2914 - nsRefPtr<nsMIMEInfoBase> mimeInfo = nsGNOMERegistry::GetFromType(mSchemeOrType);
2915 + nsRefPtr<nsMIMEInfoBase> mimeInfo = nsCommonRegistry::GetFromType(mSchemeOrType);
2916 if (!mimeInfo) {
2917 nsAutoCString ext;
2918 nsresult rv = GetPrimaryExtension(ext);
2919 if (NS_SUCCEEDED(rv)) {
2920 - mimeInfo = nsGNOMERegistry::GetFromExtension(ext);
2921 + mimeInfo = nsCommonRegistry::GetFromExtension(ext);
2922 }
2923 }
2924 if (mimeInfo)
2925 *_retval = true;
2926 }
2927
2928 if (*_retval)
2929 return NS_OK;
2930 @@ -102,16 +105,33 @@ nsMIMEInfoUnix::LaunchDefaultWithFile(ns
2931 ContentAction::Action::defaultActionForFile(uri, QString(mSchemeOrType.get()));
2932 if (action.isValid()) {
2933 action.trigger();
2934 return NS_OK;
2935 }
2936 return NS_ERROR_FAILURE;
2937 #endif
2938
2939 + if( nsKDEUtils::kdeSupport()) {
2940 + bool supports;
2941 + if( NS_SUCCEEDED( GetHasDefaultHandler( &supports )) && supports ) {
2942 + nsTArray<nsCString> command;
2943 + command.AppendElement( NS_LITERAL_CSTRING( "OPEN" ));
2944 + command.AppendElement( nativePath );
2945 + command.AppendElement( NS_LITERAL_CSTRING( "MIMETYPE" ));
2946 + command.AppendElement( mSchemeOrType );
2947 + if( nsKDEUtils::command( command ))
2948 + return NS_OK;
2949 + }
2950 + if (!mDefaultApplication)
2951 + return NS_ERROR_FILE_NOT_FOUND;
2952 +
2953 + return LaunchWithIProcess(mDefaultApplication, nativePath);
2954 + }
2955 +
2956 nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
2957 nsAutoCString uriSpec;
2958 if (giovfs) {
2959 // nsGIOMimeApp->Launch wants a URI string instead of local file
2960 nsresult rv;
2961 nsCOMPtr<nsIIOService> ioservice = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
2962 NS_ENSURE_SUCCESS(rv, rv);
2963 nsCOMPtr<nsIURI> uri;
2964 @@ -129,17 +149,17 @@ nsMIMEInfoUnix::LaunchDefaultWithFile(ns
2965 /* Fallback to GnomeVFS */
2966 nsCOMPtr<nsIGnomeVFSMimeApp> app;
2967 if (NS_SUCCEEDED(gnomevfs->GetAppForMimeType(mSchemeOrType, getter_AddRefs(app))) && app)
2968 return app->Launch(nativePath);
2969 }
2970
2971 // If we haven't got an app we try to get a valid one by searching for the
2972 // extension mapped type
2973 - nsRefPtr<nsMIMEInfoBase> mimeInfo = nsGNOMERegistry::GetFromExtension(nativePath);
2974 + nsRefPtr<nsMIMEInfoBase> mimeInfo = nsCommonRegistry::GetFromExtension(nativePath);
2975 if (mimeInfo) {
2976 nsAutoCString type;
2977 mimeInfo->GetType(type);
2978 if (giovfs) {
2979 nsCOMPtr<nsIGIOMimeApp> app;
2980 if (NS_SUCCEEDED(giovfs->GetAppForMimeType(type, getter_AddRefs(app))) && app)
2981 return app->Launch(uriSpec);
2982 } else if (gnomevfs) {
2983 diff --git a/uriloader/exthandler/unix/nsOSHelperAppService.cpp b/uriloader/exthandler/unix/nsOSHelperAppService.cpp
2984 --- a/uriloader/exthandler/unix/nsOSHelperAppService.cpp
2985 +++ b/uriloader/exthandler/unix/nsOSHelperAppService.cpp
2986 @@ -10,17 +10,17 @@
2987 #if defined(MOZ_ENABLE_CONTENTACTION)
2988 #include <contentaction/contentaction.h>
2989 #include <QString>
2990 #endif
2991
2992 #include "nsOSHelperAppService.h"
2993 #include "nsMIMEInfoUnix.h"
2994 #ifdef MOZ_WIDGET_GTK
2995 -#include "nsGNOMERegistry.h"
2996 +#include "nsCommonRegistry.h"
2997 #endif
2998 #include "nsISupports.h"
2999 #include "nsString.h"
3000 #include "nsReadableUtils.h"
3001 #include "nsUnicharUtils.h"
3002 #include "nsXPIDLString.h"
3003 #include "nsIURL.h"
3004 #include "nsIFileStreams.h"
3005 @@ -1146,26 +1146,26 @@ nsresult nsOSHelperAppService::OSProtoco
3006 ContentAction::Action::defaultActionForScheme(QString(aProtocolScheme) + ':');
3007
3008 if (action.isValid())
3009 *aHandlerExists = true;
3010 #endif
3011
3012 #ifdef MOZ_WIDGET_GTK
3013 // Check the GConf registry for a protocol handler
3014 - *aHandlerExists = nsGNOMERegistry::HandlerExists(aProtocolScheme);
3015 + *aHandlerExists = nsCommonRegistry::HandlerExists(aProtocolScheme);
3016 #endif
3017
3018 return NS_OK;
3019 }
3020
3021 NS_IMETHODIMP nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme, nsAString& _retval)
3022 {
3023 #ifdef MOZ_WIDGET_GTK
3024 - nsGNOMERegistry::GetAppDescForScheme(aScheme, _retval);
3025 + nsCommonRegistry::GetAppDescForScheme(aScheme, _retval);
3026 return _retval.IsEmpty() ? NS_ERROR_NOT_AVAILABLE : NS_OK;
3027 #else
3028 return NS_ERROR_NOT_AVAILABLE;
3029 #endif
3030 }
3031
3032 nsresult nsOSHelperAppService::GetFileTokenForPath(const char16_t * platformAppPath, nsIFile ** aFile)
3033 {
3034 @@ -1252,17 +1252,17 @@ nsOSHelperAppService::GetFromExtension(c
3035 mime_types_description,
3036 true);
3037
3038 if (NS_FAILED(rv) || majorType.IsEmpty()) {
3039
3040 #ifdef MOZ_WIDGET_GTK
3041 LOG(("Looking in GNOME registry\n"));
3042 nsRefPtr<nsMIMEInfoBase> gnomeInfo =
3043 - nsGNOMERegistry::GetFromExtension(aFileExt);
3044 + nsCommonRegistry::GetFromExtension(aFileExt);
3045 if (gnomeInfo) {
3046 LOG(("Got MIMEInfo from GNOME registry\n"));
3047 return gnomeInfo.forget();
3048 }
3049 #endif
3050
3051 rv = LookUpTypeAndDescription(NS_ConvertUTF8toUTF16(aFileExt),
3052 majorType,
3053 @@ -1372,17 +1372,17 @@ nsOSHelperAppService::GetFromType(const
3054 #ifdef MOZ_WIDGET_GTK
3055 nsRefPtr<nsMIMEInfoBase> gnomeInfo;
3056 if (handler.IsEmpty()) {
3057 // No useful data yet. Check the GNOME registry. Unfortunately, newer
3058 // GNOME versions no longer have type-to-extension mappings, so we might
3059 // get back a MIMEInfo without any extensions set. In that case we'll have
3060 // to look in our mime.types files for the extensions.
3061 LOG(("Looking in GNOME registry\n"));
3062 - gnomeInfo = nsGNOMERegistry::GetFromType(aMIMEType);
3063 + gnomeInfo = nsCommonRegistry::GetFromType(aMIMEType);
3064 if (gnomeInfo && gnomeInfo->HasExtensions()) {
3065 LOG(("Got MIMEInfo from GNOME registry, and it has extensions set\n"));
3066 return gnomeInfo.forget();
3067 }
3068 }
3069 #endif
3070
3071 // Now look up our extensions
3072 diff --git a/widget/gtk/Makefile.in b/widget/gtk/Makefile.in
3073 --- a/widget/gtk/Makefile.in
3074 +++ b/widget/gtk/Makefile.in
3075 @@ -3,11 +3,13 @@
3076 # License, v. 2.0. If a copy of the MPL was not distributed with this
3077 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
3078
3079 include $(topsrcdir)/config/rules.mk
3080
3081 CFLAGS += $(MOZ_STARTUP_NOTIFICATION_CFLAGS)
3082 CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_STARTUP_NOTIFICATION_CFLAGS)
3083
3084 +LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
3085 +
3086 CFLAGS += $(TK_CFLAGS)
3087 CXXFLAGS += $(TK_CFLAGS)
3088
3089 diff --git a/widget/gtk/nsFilePicker.cpp b/widget/gtk/nsFilePicker.cpp
3090 --- a/widget/gtk/nsFilePicker.cpp
3091 +++ b/widget/gtk/nsFilePicker.cpp
3092 @@ -1,32 +1,34 @@
3093 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3094 /* This Source Code Form is subject to the terms of the Mozilla Public
3095 * License, v. 2.0. If a copy of the MPL was not distributed with this
3096 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
3097
3098 #include "mozilla/Types.h"
3099
3100 #include <gtk/gtk.h>
3101 +#include <gdk/gdkx.h>
3102
3103 #include "nsGtkUtils.h"
3104 #include "nsIFileURL.h"
3105 #include "nsIURI.h"
3106 #include "nsIWidget.h"
3107 #include "nsIFile.h"
3108 #include "nsIStringBundle.h"
3109
3110 #include "nsArrayEnumerator.h"
3111 #include "nsMemory.h"
3112 #include "nsEnumeratorUtils.h"
3113 #include "nsNetUtil.h"
3114 #include "nsReadableUtils.h"
3115 #include "mozcontainer.h"
3116
3117 #include "nsFilePicker.h"
3118 +#include "nsKDEUtils.h"
3119
3120 using namespace mozilla;
3121
3122 #define MAX_PREVIEW_SIZE 180
3123
3124 nsIFile *nsFilePicker::mPrevDisplayDirectory = nullptr;
3125
3126 void
3127 @@ -226,17 +228,19 @@ nsFilePicker::AppendFilters(int32_t aFil
3128 return nsBaseFilePicker::AppendFilters(aFilterMask);
3129 }
3130
3131 NS_IMETHODIMP
3132 nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
3133 {
3134 if (aFilter.EqualsLiteral("..apps")) {
3135 // No platform specific thing we can do here, really....
3136 - return NS_OK;
3137 + // Unless it's KDE.
3138 + if( mMode != modeOpen || !nsKDEUtils::kdeSupport())
3139 + return NS_OK;
3140 }
3141
3142 nsAutoCString filter, name;
3143 CopyUTF16toUTF8(aFilter, filter);
3144 CopyUTF16toUTF8(aTitle, name);
3145
3146 mFilters.AppendElement(filter);
3147 mFilterNames.AppendElement(name);
3148 @@ -351,16 +355,32 @@ nsFilePicker::Show(int16_t *aReturn)
3149
3150 NS_IMETHODIMP
3151 nsFilePicker::Open(nsIFilePickerShownCallback *aCallback)
3152 {
3153 // Can't show two dialogs concurrently with the same filepicker
3154 if (mRunning)
3155 return NS_ERROR_NOT_AVAILABLE;
3156
3157 + // KDE file picker is not handled via callback
3158 + if( nsKDEUtils::kdeSupport()) {
3159 + int16_t result;
3160 + mCallback = aCallback;
3161 + mRunning = true;
3162 + kdeFileDialog(&result);
3163 + if (mCallback) {
3164 + mCallback->Done(result);
3165 + mCallback = nullptr;
3166 + } else {
3167 + mResult = result;
3168 + }
3169 + mRunning = false;
3170 + return NS_OK;
3171 + }
3172 +
3173 nsXPIDLCString title;
3174 title.Adopt(ToNewUTF8String(mTitle));
3175
3176 GtkWindow *parent_widget =
3177 GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
3178
3179 GtkFileChooserAction action = GetGtkFileChooserAction(mMode);
3180 const gchar *accept_button = (action == GTK_FILE_CHOOSER_ACTION_SAVE)
3181 @@ -539,8 +559,235 @@ nsFilePicker::Done(GtkWidget* file_choos
3182 if (mCallback) {
3183 mCallback->Done(result);
3184 mCallback = nullptr;
3185 } else {
3186 mResult = result;
3187 }
3188 NS_RELEASE_THIS();
3189 }
3190 +
3191 +nsCString nsFilePicker::kdeMakeFilter( int index )
3192 + {
3193 + nsCString buf = mFilters[ index ];
3194 + for( PRUint32 i = 0;
3195 + i < buf.Length();
3196 + ++i )
3197 + if( buf[ i ] == ';' ) // KDE separates just using spaces
3198 + buf.SetCharAt( ' ', i );
3199 + if (!mFilterNames[index].IsEmpty())
3200 + {
3201 + buf += "|";
3202 + buf += mFilterNames[index].get();
3203 + }
3204 + return buf;
3205 + }
3206 +
3207 +static PRInt32 windowToXid( nsIWidget* widget )
3208 + {
3209 + GtkWindow *parent_widget = GTK_WINDOW(widget->GetNativeData(NS_NATIVE_SHELLWIDGET));
3210 + GdkWindow* gdk_window = gtk_widget_get_window( gtk_widget_get_toplevel( GTK_WIDGET( parent_widget )));
3211 + return GDK_WINDOW_XID( gdk_window );
3212 + }
3213 +
3214 +NS_IMETHODIMP nsFilePicker::kdeFileDialog(PRInt16 *aReturn)
3215 + {
3216 + NS_ENSURE_ARG_POINTER(aReturn);
3217 +
3218 + if( mMode == modeOpen && mFilters.Length() == 1 && mFilters[ 0 ].EqualsLiteral( "..apps" ))
3219 + return kdeAppsDialog( aReturn );
3220 +
3221 + nsXPIDLCString title;
3222 + title.Adopt(ToNewUTF8String(mTitle));
3223 +
3224 + const char* arg = NULL;
3225 + if( mAllowURLs )
3226 + {
3227 + switch( mMode )
3228 + {
3229 + case nsIFilePicker::modeOpen:
3230 + case nsIFilePicker::modeOpenMultiple:
3231 + arg = "GETOPENURL";
3232 + break;
3233 + case nsIFilePicker::modeSave:
3234 + arg = "GETSAVEURL";
3235 + break;
3236 + case nsIFilePicker::modeGetFolder:
3237 + arg = "GETDIRECTORYURL";
3238 + break;
3239 + }
3240 + }
3241 + else
3242 + {
3243 + switch( mMode )
3244 + {
3245 + case nsIFilePicker::modeOpen:
3246 + case nsIFilePicker::modeOpenMultiple:
3247 + arg = "GETOPENFILENAME";
3248 + break;
3249 + case nsIFilePicker::modeSave:
3250 + arg = "GETSAVEFILENAME";
3251 + break;
3252 + case nsIFilePicker::modeGetFolder:
3253 + arg = "GETDIRECTORYFILENAME";
3254 + break;
3255 + }
3256 + }
3257 +
3258 + nsAutoCString directory;
3259 + if (mDisplayDirectory) {
3260 + mDisplayDirectory->GetNativePath(directory);
3261 + } else if (mPrevDisplayDirectory) {
3262 + mPrevDisplayDirectory->GetNativePath(directory);
3263 + }
3264 +
3265 + nsAutoCString startdir;
3266 + if (!directory.IsEmpty()) {
3267 + startdir = directory;
3268 + }
3269 + if (mMode == nsIFilePicker::modeSave) {
3270 + if( !startdir.IsEmpty())
3271 + {
3272 + startdir += "/";
3273 + startdir += ToNewUTF8String(mDefault);
3274 + }
3275 + else
3276 + startdir = ToNewUTF8String(mDefault);
3277 + }
3278 + if( startdir.IsEmpty())
3279 + startdir = ".";
3280 +
3281 + nsAutoCString filters;
3282 + PRInt32 count = mFilters.Length();
3283 + if( count == 0 ) //just in case
3284 + filters = "*";
3285 + else
3286 + {
3287 + filters = kdeMakeFilter( 0 );
3288 + for (PRInt32 i = 1; i < count; ++i)
3289 + {
3290 + filters += "\n";
3291 + filters += kdeMakeFilter( i );
3292 + }
3293 + }
3294 +
3295 + nsTArray<nsCString> command;
3296 + command.AppendElement( nsAutoCString( arg ));
3297 + command.AppendElement( startdir );
3298 + if( mMode != nsIFilePicker::modeGetFolder )
3299 + {
3300 + command.AppendElement( filters );
3301 + nsAutoCString selected;
3302 + selected.AppendInt( mSelectedType );
3303 + command.AppendElement( selected );
3304 + }
3305 + command.AppendElement( title );
3306 + if( mMode == nsIFilePicker::modeOpenMultiple )
3307 + command.AppendElement( NS_LITERAL_CSTRING( "MULTIPLE" ));
3308 + if( PRInt32 xid = windowToXid( mParentWidget ))
3309 + {
3310 + command.AppendElement( NS_LITERAL_CSTRING( "PARENT" ));
3311 + nsAutoCString parent;
3312 + parent.AppendInt( xid );
3313 + command.AppendElement( parent );
3314 + }
3315 +
3316 + nsTArray<nsCString> output;
3317 + if( nsKDEUtils::commandBlockUi( command, GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)), &output ))
3318 + {
3319 + *aReturn = nsIFilePicker::returnOK;
3320 + mFiles.Clear();
3321 + if( mMode != nsIFilePicker::modeGetFolder )
3322 + {
3323 + mSelectedType = atoi( output[ 0 ].get());
3324 + output.RemoveElementAt( 0 );
3325 + }
3326 + if (mMode == nsIFilePicker::modeOpenMultiple)
3327 + {
3328 + mFileURL.Truncate();
3329 + PRUint32 count = output.Length();
3330 + for( PRUint32 i = 0;
3331 + i < count;
3332 + ++i )
3333 + {
3334 + nsCOMPtr<nsIFile> localfile;
3335 + nsresult rv = NS_NewNativeLocalFile( output[ i ],
3336 + PR_FALSE,
3337 + getter_AddRefs(localfile));
3338 + if (NS_SUCCEEDED(rv))
3339 + mFiles.AppendObject(localfile);
3340 + }
3341 + }
3342 + else
3343 + {
3344 + if( output.Length() == 0 )
3345 + mFileURL = nsCString();
3346 + else if( mAllowURLs )
3347 + mFileURL = output[ 0 ];
3348 + else // GetFile() actually requires it to be url even for local files :-/
3349 + {
3350 + mFileURL = nsCString( "file://" );
3351 + mFileURL.Append( output[ 0 ] );
3352 + }
3353 + }
3354 + // Remember last used directory.
3355 + nsCOMPtr<nsIFile> file;
3356 + GetFile(getter_AddRefs(file));
3357 + if (file) {
3358 + nsCOMPtr<nsIFile> dir;
3359 + file->GetParent(getter_AddRefs(dir));
3360 + nsCOMPtr<nsIFile> localDir(do_QueryInterface(dir));
3361 + if (localDir) {
3362 + localDir.swap(mPrevDisplayDirectory);
3363 + }
3364 + }
3365 + if (mMode == nsIFilePicker::modeSave)
3366 + {
3367 + nsCOMPtr<nsIFile> file;
3368 + GetFile(getter_AddRefs(file));
3369 + if (file)
3370 + {
3371 + bool exists = false;
3372 + file->Exists(&exists);
3373 + if (exists) // TODO do overwrite check in the helper app
3374 + *aReturn = nsIFilePicker::returnReplace;
3375 + }
3376 + }
3377 + }
3378 + else
3379 + {
3380 + *aReturn = nsIFilePicker::returnCancel;
3381 + }
3382 + return NS_OK;
3383 + }
3384 +
3385 +
3386 +NS_IMETHODIMP nsFilePicker::kdeAppsDialog(PRInt16 *aReturn)
3387 + {
3388 + NS_ENSURE_ARG_POINTER(aReturn);
3389 +
3390 + nsXPIDLCString title;
3391 + title.Adopt(ToNewUTF8String(mTitle));
3392 +
3393 + nsTArray<nsCString> command;
3394 + command.AppendElement( NS_LITERAL_CSTRING( "APPSDIALOG" ));
3395 + command.AppendElement( title );
3396 + if( PRInt32 xid = windowToXid( mParentWidget ))
3397 + {
3398 + command.AppendElement( NS_LITERAL_CSTRING( "PARENT" ));
3399 + nsAutoCString parent;
3400 + parent.AppendInt( xid );
3401 + command.AppendElement( parent );
3402 + }
3403 +
3404 + nsTArray<nsCString> output;
3405 + if( nsKDEUtils::commandBlockUi( command, GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)), &output ))
3406 + {
3407 + *aReturn = nsIFilePicker::returnOK;
3408 + mFileURL = output.Length() > 0 ? output[ 0 ] : nsCString();
3409 + }
3410 + else
3411 + {
3412 + *aReturn = nsIFilePicker::returnCancel;
3413 + }
3414 + return NS_OK;
3415 + }
3416 +
3417 diff --git a/widget/gtk/nsFilePicker.h b/widget/gtk/nsFilePicker.h
3418 --- a/widget/gtk/nsFilePicker.h
3419 +++ b/widget/gtk/nsFilePicker.h
3420 @@ -66,11 +66,17 @@ protected:
3421 nsString mDefault;
3422 nsString mDefaultExtension;
3423
3424 nsTArray<nsCString> mFilters;
3425 nsTArray<nsCString> mFilterNames;
3426
3427 private:
3428 static nsIFile *mPrevDisplayDirectory;
3429 +
3430 + bool kdeRunning();
3431 + bool getKdeRunning();
3432 + NS_IMETHODIMP kdeFileDialog(PRInt16 *aReturn);
3433 + NS_IMETHODIMP kdeAppsDialog(PRInt16 *aReturn);
3434 + nsCString kdeMakeFilter( int index );
3435 };
3436
3437 #endif
3438 diff --git a/xpcom/components/Makefile.in b/xpcom/components/Makefile.in
3439 --- a/xpcom/components/Makefile.in
3440 +++ b/xpcom/components/Makefile.in
3441 @@ -2,9 +2,10 @@
3442 # This Source Code Form is subject to the terms of the Mozilla Public
3443 # License, v. 2.0. If a copy of the MPL was not distributed with this
3444 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
3445
3446 include $(topsrcdir)/config/rules.mk
3447
3448 ifdef MOZ_WIDGET_GTK
3449 CXXFLAGS += $(TK_CFLAGS)
3450 +LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
3451 endif
3452 diff --git a/xpcom/components/ManifestParser.cpp b/xpcom/components/ManifestParser.cpp
3453 --- a/xpcom/components/ManifestParser.cpp
3454 +++ b/xpcom/components/ManifestParser.cpp
3455 @@ -31,16 +31,17 @@
3456 #include "nsTextFormatter.h"
3457 #include "nsVersionComparator.h"
3458 #include "nsXPCOMCIDInternal.h"
3459
3460 #include "nsIConsoleService.h"
3461 #include "nsIScriptError.h"
3462 #include "nsIXULAppInfo.h"
3463 #include "nsIXULRuntime.h"
3464 +#include "nsKDEUtils.h"
3465
3466 using namespace mozilla;
3467
3468 struct ManifestDirective
3469 {
3470 const char* directive;
3471 int argc;
3472
3473 @@ -398,16 +399,17 @@ ParseManifest(NSLocationType type, FileL
3474 NS_NAMED_LITERAL_STRING(kPlatform, "platform");
3475 NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
3476 NS_NAMED_LITERAL_STRING(kApplication, "application");
3477 NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
3478 NS_NAMED_LITERAL_STRING(kGeckoVersion, "platformversion");
3479 NS_NAMED_LITERAL_STRING(kOs, "os");
3480 NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
3481 NS_NAMED_LITERAL_STRING(kABI, "abi");
3482 + NS_NAMED_LITERAL_STRING(kDesktop, "desktop");
3483 #if defined(MOZ_WIDGET_ANDROID)
3484 NS_NAMED_LITERAL_STRING(kTablet, "tablet");
3485 #endif
3486
3487 // Obsolete
3488 NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
3489
3490 nsAutoString appID;
3491 @@ -445,42 +447,47 @@ ParseManifest(NSLocationType type, FileL
3492 CopyUTF8toUTF16(s, abi);
3493 abi.Insert(char16_t('_'), 0);
3494 abi.Insert(osTarget, 0);
3495 }
3496 }
3497 }
3498
3499 nsAutoString osVersion;
3500 + nsAutoString desktop;
3501 #if defined(XP_WIN)
3502 #pragma warning(push)
3503 #pragma warning(disable:4996) // VC12+ deprecates GetVersionEx
3504 OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
3505 if (GetVersionEx(&info)) {
3506 nsTextFormatter::ssprintf(osVersion, MOZ_UTF16("%ld.%ld"),
3507 info.dwMajorVersion,
3508 info.dwMinorVersion);
3509 }
3510 + desktop = NS_LITERAL_STRING("win");
3511 #pragma warning(pop)
3512 #elif defined(MOZ_WIDGET_COCOA)
3513 SInt32 majorVersion = nsCocoaFeatures::OSXVersionMajor();
3514 SInt32 minorVersion = nsCocoaFeatures::OSXVersionMinor();
3515 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
3516 majorVersion,
3517 minorVersion);
3518 + desktop = NS_LITERAL_STRING("macosx");
3519 #elif defined(MOZ_WIDGET_GTK)
3520 nsTextFormatter::ssprintf(osVersion, MOZ_UTF16("%ld.%ld"),
3521 gtk_major_version,
3522 gtk_minor_version);
3523 + desktop = nsKDEUtils::kdeSession() ? NS_LITERAL_STRING("kde") : NS_LITERAL_STRING("gnome");
3524 #elif defined(MOZ_WIDGET_ANDROID)
3525 bool isTablet = false;
3526 if (mozilla::AndroidBridge::Bridge()) {
3527 mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION", "RELEASE", osVersion);
3528 isTablet = mozilla::widget::android::GeckoAppShell::IsTablet();
3529 }
3530 + desktop = NS_LITERAL_STRING("android");
3531 #endif
3532
3533 // Because contracts must be registered after CIDs, we save and process them
3534 // at the end.
3535 nsTArray<CachedDirective> contracts;
3536
3537 char *token;
3538 char *newline = buf;
3539 @@ -562,24 +569,26 @@ ParseManifest(NSLocationType type, FileL
3540 TriState stOsVersion = eUnspecified;
3541 TriState stOs = eUnspecified;
3542 TriState stABI = eUnspecified;
3543 #if defined(MOZ_WIDGET_ANDROID)
3544 TriState stTablet = eUnspecified;
3545 #endif
3546 bool platform = false;
3547 bool contentAccessible = false;
3548 + TriState stDesktop = eUnspecified;
3549
3550 while (nullptr != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) && ok) {
3551 ToLowerCase(token);
3552 NS_ConvertASCIItoUTF16 wtoken(token);
3553
3554 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
3555 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
3556 CheckStringFlag(kABI, wtoken, abi, stABI) ||
3557 + CheckStringFlag(kDesktop, wtoken, desktop, stDesktop) ||
3558 CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
3559 CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
3560 CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion))
3561 continue;
3562
3563 #if defined(MOZ_WIDGET_ANDROID)
3564 bool tablet = false;
3565 if (CheckFlag(kTablet, wtoken, tablet)) {
3566 @@ -608,16 +617,17 @@ ParseManifest(NSLocationType type, FileL
3567 }
3568
3569 if (!ok ||
3570 stApp == eBad ||
3571 stAppVersion == eBad ||
3572 stGeckoVersion == eBad ||
3573 stOs == eBad ||
3574 stOsVersion == eBad ||
3575 + stDesktop == eBad ||
3576 #ifdef MOZ_WIDGET_ANDROID
3577 stTablet == eBad ||
3578 #endif
3579 stABI == eBad)
3580 continue;
3581
3582 if (directive->regfunc) {
3583 if (GeckoProcessType_Default != XRE_GetProcessType())
3584 diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp
3585 --- a/xpcom/io/nsLocalFileUnix.cpp
3586 +++ b/xpcom/io/nsLocalFileUnix.cpp
3587 @@ -43,16 +43,17 @@
3588 #include "nsIDirectoryEnumerator.h"
3589 #include "nsISimpleEnumerator.h"
3590 #include "private/pprio.h"
3591 #include "prlink.h"
3592
3593 #ifdef MOZ_WIDGET_GTK
3594 #include "nsIGIOService.h"
3595 #include "nsIGnomeVFSService.h"
3596 +#include "nsKDEUtils.h"
3597 #endif
3598
3599 #ifdef MOZ_WIDGET_COCOA
3600 #include <Carbon/Carbon.h>
3601 #include "CocoaFileUtils.h"
3602 #include "prmem.h"
3603 #include "plbase64.h"
3604
3605 @@ -1816,46 +1817,52 @@ nsLocalFile::SetPersistentDescriptor(con
3606 return InitWithNativePath(aPersistentDescriptor);
3607 #endif
3608 }
3609
3610 NS_IMETHODIMP
3611 nsLocalFile::Reveal()
3612 {
3613 #ifdef MOZ_WIDGET_GTK
3614 - nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
3615 - nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
3616 - if (!giovfs && !gnomevfs)
3617 - return NS_ERROR_FAILURE;
3618 -
3619 + nsAutoCString url;
3620 bool isDirectory;
3621 if (NS_FAILED(IsDirectory(&isDirectory)))
3622 return NS_ERROR_FAILURE;
3623
3624 + nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
3625 if (isDirectory) {
3626 - if (giovfs)
3627 - return giovfs->ShowURIForInput(mPath);
3628 - else
3629 - /* Fallback to GnomeVFS */
3630 - return gnomevfs->ShowURIForInput(mPath);
3631 + url = mPath;
3632 } else if (giovfs && NS_SUCCEEDED(giovfs->OrgFreedesktopFileManager1ShowItems(mPath))) {
3633 return NS_OK;
3634 } else {
3635 nsCOMPtr<nsIFile> parentDir;
3636 nsAutoCString dirPath;
3637 if (NS_FAILED(GetParent(getter_AddRefs(parentDir))))
3638 return NS_ERROR_FAILURE;
3639 if (NS_FAILED(parentDir->GetNativePath(dirPath)))
3640 return NS_ERROR_FAILURE;
3641
3642 - if (giovfs)
3643 - return giovfs->ShowURIForInput(dirPath);
3644 - else
3645 - return gnomevfs->ShowURIForInput(dirPath);
3646 + url = dirPath;
3647 }
3648 +
3649 + if(nsKDEUtils::kdeSupport()) {
3650 + nsTArray<nsCString> command;
3651 + command.AppendElement( NS_LITERAL_CSTRING("REVEAL") );
3652 + command.AppendElement( mPath );
3653 + return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
3654 + }
3655 +
3656 + nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
3657 + if (!giovfs && !gnomevfs)
3658 + return NS_ERROR_FAILURE;
3659 +
3660 + if (giovfs)
3661 + return giovfs->ShowURIForInput(url);
3662 + else
3663 + return gnomevfs->ShowURIForInput(url);
3664 #elif defined(MOZ_WIDGET_COCOA)
3665 CFURLRef url;
3666 if (NS_SUCCEEDED(GetCFURL(&url))) {
3667 nsresult rv = CocoaFileUtils::RevealFileInFinder(url);
3668 ::CFRelease(url);
3669 return rv;
3670 }
3671 return NS_ERROR_FAILURE;
3672 @@ -1863,16 +1870,23 @@ nsLocalFile::Reveal()
3673 return NS_ERROR_FAILURE;
3674 #endif
3675 }
3676
3677 NS_IMETHODIMP
3678 nsLocalFile::Launch()
3679 {
3680 #ifdef MOZ_WIDGET_GTK
3681 + if( nsKDEUtils::kdeSupport()) {
3682 + nsTArray<nsCString> command;
3683 + command.AppendElement( NS_LITERAL_CSTRING("OPEN") );
3684 + command.AppendElement( mPath );
3685 + return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE;
3686 + }
3687 +
3688 nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
3689 nsCOMPtr<nsIGnomeVFSService> gnomevfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID);
3690 if (giovfs) {
3691 return giovfs->ShowURIForInput(mPath);
3692 } else if (gnomevfs) {
3693 /* GnomeVFS fallback */
3694 return gnomevfs->ShowURIForInput(mPath);
3695 }

  ViewVC Help
Powered by ViewVC 1.1.30