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

Contents of /updates/5/firefox/current/SOURCES/mozilla-kde.patch

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.30