/src/mozilla-central/browser/components/shell/nsGNOMEShellService.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #include "mozilla/ArrayUtils.h" |
7 | | |
8 | | #include "nsCOMPtr.h" |
9 | | #include "nsGNOMEShellService.h" |
10 | | #include "nsShellService.h" |
11 | | #include "nsIServiceManager.h" |
12 | | #include "nsIFile.h" |
13 | | #include "nsIProperties.h" |
14 | | #include "nsDirectoryServiceDefs.h" |
15 | | #include "nsIPrefService.h" |
16 | | #include "prenv.h" |
17 | | #include "nsString.h" |
18 | | #include "nsIGConfService.h" |
19 | | #include "nsIGIOService.h" |
20 | | #include "nsIGSettingsService.h" |
21 | | #include "nsIStringBundle.h" |
22 | | #include "nsIOutputStream.h" |
23 | | #include "nsIProcess.h" |
24 | | #include "nsServiceManagerUtils.h" |
25 | | #include "nsComponentManagerUtils.h" |
26 | | #include "nsIImageLoadingContent.h" |
27 | | #include "imgIRequest.h" |
28 | | #include "imgIContainer.h" |
29 | | #include "mozilla/Sprintf.h" |
30 | | #include "mozilla/dom/Element.h" |
31 | | #if defined(MOZ_WIDGET_GTK) |
32 | | #include "nsIImageToPixbuf.h" |
33 | | #endif |
34 | | #include "nsXULAppAPI.h" |
35 | | #include "gfxPlatform.h" |
36 | | |
37 | | #include <glib.h> |
38 | | #include <glib-object.h> |
39 | | #include <gtk/gtk.h> |
40 | | #include <gdk/gdk.h> |
41 | | #include <gdk-pixbuf/gdk-pixbuf.h> |
42 | | #include <limits.h> |
43 | | #include <stdlib.h> |
44 | | |
45 | | using namespace mozilla; |
46 | | |
47 | | struct ProtocolAssociation |
48 | | { |
49 | | const char *name; |
50 | | bool essential; |
51 | | }; |
52 | | |
53 | | struct MimeTypeAssociation |
54 | | { |
55 | | const char *mimeType; |
56 | | const char *extensions; |
57 | | }; |
58 | | |
59 | | static const ProtocolAssociation appProtocols[] = { |
60 | | { "http", true }, |
61 | | { "https", true }, |
62 | | { "ftp", false }, |
63 | | { "chrome", false } |
64 | | }; |
65 | | |
66 | | static const MimeTypeAssociation appTypes[] = { |
67 | | { "text/html", "htm html shtml" }, |
68 | | { "application/xhtml+xml", "xhtml xht" } |
69 | | }; |
70 | | |
71 | | // GConf registry key constants |
72 | | #define DG_BACKGROUND "/desktop/gnome/background" |
73 | | |
74 | | #define kDesktopImageKey DG_BACKGROUND "/picture_filename" |
75 | | #define kDesktopOptionsKey DG_BACKGROUND "/picture_options" |
76 | | #define kDesktopDrawBGKey DG_BACKGROUND "/draw_background" |
77 | | #define kDesktopColorKey DG_BACKGROUND "/primary_color" |
78 | | |
79 | | #define kDesktopBGSchema "org.gnome.desktop.background" |
80 | | #define kDesktopImageGSKey "picture-uri" |
81 | | #define kDesktopOptionGSKey "picture-options" |
82 | | #define kDesktopDrawBGGSKey "draw-background" |
83 | | #define kDesktopColorGSKey "primary-color" |
84 | | |
85 | | static bool |
86 | | IsRunningAsASnap() |
87 | 0 | { |
88 | 0 | return (PR_GetEnv("SNAP") != nullptr); |
89 | 0 | } |
90 | | |
91 | | nsresult |
92 | | nsGNOMEShellService::Init() |
93 | 0 | { |
94 | 0 | nsresult rv; |
95 | 0 |
|
96 | 0 | if (gfxPlatform::IsHeadless()) { |
97 | 0 | return NS_ERROR_NOT_AVAILABLE; |
98 | 0 | } |
99 | 0 | |
100 | 0 | // GConf, GSettings or GIO _must_ be available, or we do not allow |
101 | 0 | // CreateInstance to succeed. |
102 | 0 | |
103 | 0 | nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); |
104 | 0 | nsCOMPtr<nsIGIOService> giovfs = |
105 | 0 | do_GetService(NS_GIOSERVICE_CONTRACTID); |
106 | 0 | nsCOMPtr<nsIGSettingsService> gsettings = |
107 | 0 | do_GetService(NS_GSETTINGSSERVICE_CONTRACTID); |
108 | 0 |
|
109 | 0 | if (!gconf && !giovfs && !gsettings) |
110 | 0 | return NS_ERROR_NOT_AVAILABLE; |
111 | 0 | |
112 | 0 | // Check G_BROKEN_FILENAMES. If it's set, then filenames in glib use |
113 | 0 | // the locale encoding. If it's not set, they use UTF-8. |
114 | 0 | mUseLocaleFilenames = PR_GetEnv("G_BROKEN_FILENAMES") != nullptr; |
115 | 0 |
|
116 | 0 | if (GetAppPathFromLauncher()) |
117 | 0 | return NS_OK; |
118 | 0 | |
119 | 0 | nsCOMPtr<nsIProperties> dirSvc |
120 | 0 | (do_GetService("@mozilla.org/file/directory_service;1")); |
121 | 0 | NS_ENSURE_TRUE(dirSvc, NS_ERROR_NOT_AVAILABLE); |
122 | 0 |
|
123 | 0 | nsCOMPtr<nsIFile> appPath; |
124 | 0 | rv = dirSvc->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile), |
125 | 0 | getter_AddRefs(appPath)); |
126 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
127 | 0 |
|
128 | 0 | return appPath->GetNativePath(mAppPath); |
129 | 0 | } |
130 | | |
131 | | NS_IMPL_ISUPPORTS(nsGNOMEShellService, nsIGNOMEShellService, nsIShellService) |
132 | | |
133 | | bool |
134 | | nsGNOMEShellService::GetAppPathFromLauncher() |
135 | 0 | { |
136 | 0 | gchar *tmp; |
137 | 0 |
|
138 | 0 | const char *launcher = PR_GetEnv("MOZ_APP_LAUNCHER"); |
139 | 0 | if (!launcher) |
140 | 0 | return false; |
141 | 0 | |
142 | 0 | if (g_path_is_absolute(launcher)) { |
143 | 0 | mAppPath = launcher; |
144 | 0 | tmp = g_path_get_basename(launcher); |
145 | 0 | gchar *fullpath = g_find_program_in_path(tmp); |
146 | 0 | if (fullpath && mAppPath.Equals(fullpath)) |
147 | 0 | mAppIsInPath = true; |
148 | 0 | g_free(fullpath); |
149 | 0 | } else { |
150 | 0 | tmp = g_find_program_in_path(launcher); |
151 | 0 | if (!tmp) |
152 | 0 | return false; |
153 | 0 | mAppPath = tmp; |
154 | 0 | mAppIsInPath = true; |
155 | 0 | } |
156 | 0 |
|
157 | 0 | g_free(tmp); |
158 | 0 | return true; |
159 | 0 | } |
160 | | |
161 | | bool |
162 | | nsGNOMEShellService::KeyMatchesAppName(const char *aKeyValue) const |
163 | 0 | { |
164 | 0 |
|
165 | 0 | gchar *commandPath; |
166 | 0 | if (mUseLocaleFilenames) { |
167 | 0 | gchar *nativePath = g_filename_from_utf8(aKeyValue, -1, |
168 | 0 | nullptr, nullptr, nullptr); |
169 | 0 | if (!nativePath) { |
170 | 0 | NS_ERROR("Error converting path to filesystem encoding"); |
171 | 0 | return false; |
172 | 0 | } |
173 | 0 |
|
174 | 0 | commandPath = g_find_program_in_path(nativePath); |
175 | 0 | g_free(nativePath); |
176 | 0 | } else { |
177 | 0 | commandPath = g_find_program_in_path(aKeyValue); |
178 | 0 | } |
179 | 0 |
|
180 | 0 | if (!commandPath) |
181 | 0 | return false; |
182 | 0 | |
183 | 0 | bool matches = mAppPath.Equals(commandPath); |
184 | 0 | g_free(commandPath); |
185 | 0 | return matches; |
186 | 0 | } |
187 | | |
188 | | bool |
189 | | nsGNOMEShellService::CheckHandlerMatchesAppName(const nsACString &handler) const |
190 | 0 | { |
191 | 0 | gint argc; |
192 | 0 | gchar **argv; |
193 | 0 | nsAutoCString command(handler); |
194 | 0 |
|
195 | 0 | // The string will be something of the form: [/path/to/]browser "%s" |
196 | 0 | // We want to remove all of the parameters and get just the binary name. |
197 | 0 |
|
198 | 0 | if (g_shell_parse_argv(command.get(), &argc, &argv, nullptr) && argc > 0) { |
199 | 0 | command.Assign(argv[0]); |
200 | 0 | g_strfreev(argv); |
201 | 0 | } |
202 | 0 |
|
203 | 0 | if (!KeyMatchesAppName(command.get())) |
204 | 0 | return false; // the handler is set to another app |
205 | 0 | |
206 | 0 | return true; |
207 | 0 | } |
208 | | |
209 | | NS_IMETHODIMP |
210 | | nsGNOMEShellService::IsDefaultBrowser(bool aStartupCheck, |
211 | | bool aForAllTypes, |
212 | | bool* aIsDefaultBrowser) |
213 | 0 | { |
214 | 0 | *aIsDefaultBrowser = false; |
215 | 0 |
|
216 | 0 | if (IsRunningAsASnap()) { |
217 | 0 | const gchar *argv[] = { "xdg-settings", "check", "default-web-browser", |
218 | 0 | "firefox.desktop", nullptr }; |
219 | 0 | GSpawnFlags flags = static_cast<GSpawnFlags>(G_SPAWN_SEARCH_PATH | |
220 | 0 | G_SPAWN_STDERR_TO_DEV_NULL); |
221 | 0 | gchar *output = nullptr; |
222 | 0 | gint exit_status = 0; |
223 | 0 | if (!g_spawn_sync(nullptr, (gchar **) argv, nullptr, flags, nullptr, |
224 | 0 | nullptr, &output, nullptr, &exit_status, nullptr)) { |
225 | 0 | return NS_OK; |
226 | 0 | } |
227 | 0 | if (exit_status != 0) { |
228 | 0 | g_free(output); |
229 | 0 | return NS_OK; |
230 | 0 | } |
231 | 0 | if (strcmp(output, "yes\n") == 0) { |
232 | 0 | *aIsDefaultBrowser = true; |
233 | 0 | } |
234 | 0 | g_free(output); |
235 | 0 | return NS_OK; |
236 | 0 | } |
237 | 0 |
|
238 | 0 | nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); |
239 | 0 | nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); |
240 | 0 |
|
241 | 0 | bool enabled; |
242 | 0 | nsAutoCString handler; |
243 | 0 | nsCOMPtr<nsIGIOMimeApp> gioApp; |
244 | 0 |
|
245 | 0 | for (unsigned int i = 0; i < ArrayLength(appProtocols); ++i) { |
246 | 0 | if (!appProtocols[i].essential) |
247 | 0 | continue; |
248 | 0 | |
249 | 0 | if (gconf) { |
250 | 0 | handler.Truncate(); |
251 | 0 | gconf->GetAppForProtocol(nsDependentCString(appProtocols[i].name), |
252 | 0 | &enabled, handler); |
253 | 0 |
|
254 | 0 | if (!CheckHandlerMatchesAppName(handler) || !enabled) |
255 | 0 | return NS_OK; // the handler is disabled or set to another app |
256 | 0 | } |
257 | 0 | |
258 | 0 | if (giovfs) { |
259 | 0 | handler.Truncate(); |
260 | 0 | nsCOMPtr<nsIHandlerApp> handlerApp; |
261 | 0 | giovfs->GetAppForURIScheme(nsDependentCString(appProtocols[i].name), |
262 | 0 | getter_AddRefs(handlerApp)); |
263 | 0 | gioApp = do_QueryInterface(handlerApp); |
264 | 0 | if (!gioApp) |
265 | 0 | return NS_OK; |
266 | 0 | |
267 | 0 | gioApp->GetCommand(handler); |
268 | 0 |
|
269 | 0 | if (!CheckHandlerMatchesAppName(handler)) |
270 | 0 | return NS_OK; // the handler is set to another app |
271 | 0 | } |
272 | 0 | } |
273 | 0 |
|
274 | 0 | *aIsDefaultBrowser = true; |
275 | 0 |
|
276 | 0 | return NS_OK; |
277 | 0 | } |
278 | | |
279 | | NS_IMETHODIMP |
280 | | nsGNOMEShellService::SetDefaultBrowser(bool aClaimAllTypes, |
281 | | bool aForAllUsers) |
282 | 0 | { |
283 | | #ifdef DEBUG |
284 | | if (aForAllUsers) |
285 | | NS_WARNING("Setting the default browser for all users is not yet supported"); |
286 | | #endif |
287 | |
|
288 | 0 | if (IsRunningAsASnap()) { |
289 | 0 | const gchar *argv[] = { "xdg-settings", "set", "default-web-browser", |
290 | 0 | "firefox.desktop", nullptr }; |
291 | 0 | GSpawnFlags flags = static_cast<GSpawnFlags>(G_SPAWN_SEARCH_PATH | |
292 | 0 | G_SPAWN_STDOUT_TO_DEV_NULL | |
293 | 0 | G_SPAWN_STDERR_TO_DEV_NULL); |
294 | 0 | g_spawn_sync(nullptr, (gchar **) argv, nullptr, flags, nullptr, nullptr, |
295 | 0 | nullptr, nullptr, nullptr, nullptr); |
296 | 0 | return NS_OK; |
297 | 0 | } |
298 | 0 | |
299 | 0 | nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); |
300 | 0 | nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); |
301 | 0 | if (gconf) { |
302 | 0 | nsAutoCString appKeyValue; |
303 | 0 | if (mAppIsInPath) { |
304 | 0 | // mAppPath is in the users path, so use only the basename as the launcher |
305 | 0 | gchar *tmp = g_path_get_basename(mAppPath.get()); |
306 | 0 | appKeyValue = tmp; |
307 | 0 | g_free(tmp); |
308 | 0 | } else { |
309 | 0 | appKeyValue = mAppPath; |
310 | 0 | } |
311 | 0 |
|
312 | 0 | appKeyValue.AppendLiteral(" %s"); |
313 | 0 |
|
314 | 0 | for (unsigned int i = 0; i < ArrayLength(appProtocols); ++i) { |
315 | 0 | if (appProtocols[i].essential || aClaimAllTypes) { |
316 | 0 | gconf->SetAppForProtocol(nsDependentCString(appProtocols[i].name), |
317 | 0 | appKeyValue); |
318 | 0 | } |
319 | 0 | } |
320 | 0 | } |
321 | 0 |
|
322 | 0 | if (giovfs) { |
323 | 0 | nsresult rv; |
324 | 0 | nsCOMPtr<nsIStringBundleService> bundleService = |
325 | 0 | do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); |
326 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
327 | 0 |
|
328 | 0 | nsCOMPtr<nsIStringBundle> brandBundle; |
329 | 0 | rv = bundleService->CreateBundle(BRAND_PROPERTIES, getter_AddRefs(brandBundle)); |
330 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
331 | 0 |
|
332 | 0 | nsAutoString brandShortName; |
333 | 0 | brandBundle->GetStringFromName("brandShortName", brandShortName); |
334 | 0 |
|
335 | 0 | // use brandShortName as the application id. |
336 | 0 | NS_ConvertUTF16toUTF8 id(brandShortName); |
337 | 0 | nsCOMPtr<nsIGIOMimeApp> appInfo; |
338 | 0 | rv = giovfs->FindAppFromCommand(mAppPath, getter_AddRefs(appInfo)); |
339 | 0 | if (NS_FAILED(rv)) { |
340 | 0 | // Application was not found in the list of installed applications provided |
341 | 0 | // by OS. Fallback to create appInfo from command and name. |
342 | 0 | rv = giovfs->CreateAppFromCommand(mAppPath, |
343 | 0 | id, |
344 | 0 | getter_AddRefs(appInfo)); |
345 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
346 | 0 | } |
347 | 0 |
|
348 | 0 | // set handler for the protocols |
349 | 0 | for (unsigned int i = 0; i < ArrayLength(appProtocols); ++i) { |
350 | 0 | if (appProtocols[i].essential || aClaimAllTypes) { |
351 | 0 | appInfo->SetAsDefaultForURIScheme(nsDependentCString(appProtocols[i].name)); |
352 | 0 | } |
353 | 0 | } |
354 | 0 |
|
355 | 0 | // set handler for .html and xhtml files and MIME types: |
356 | 0 | if (aClaimAllTypes) { |
357 | 0 | // Add mime types for html, xhtml extension and set app to just created appinfo. |
358 | 0 | for (unsigned int i = 0; i < ArrayLength(appTypes); ++i) { |
359 | 0 | appInfo->SetAsDefaultForMimeType(nsDependentCString(appTypes[i].mimeType)); |
360 | 0 | appInfo->SetAsDefaultForFileExtensions(nsDependentCString(appTypes[i].extensions)); |
361 | 0 | } |
362 | 0 | } |
363 | 0 | } |
364 | 0 |
|
365 | 0 | nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID)); |
366 | 0 | if (prefs) { |
367 | 0 | (void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true); |
368 | 0 | // Reset the number of times the dialog should be shown |
369 | 0 | // before it is silenced. |
370 | 0 | (void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0); |
371 | 0 | } |
372 | 0 |
|
373 | 0 | return NS_OK; |
374 | 0 | } |
375 | | |
376 | | NS_IMETHODIMP |
377 | | nsGNOMEShellService::GetCanSetDesktopBackground(bool* aResult) |
378 | 0 | { |
379 | 0 | // setting desktop background is currently only supported |
380 | 0 | // for Gnome or desktops using the same GSettings and GConf keys |
381 | 0 | const char* gnomeSession = getenv("GNOME_DESKTOP_SESSION_ID"); |
382 | 0 | if (gnomeSession) { |
383 | 0 | *aResult = true; |
384 | 0 | } else { |
385 | 0 | *aResult = false; |
386 | 0 | } |
387 | 0 |
|
388 | 0 | return NS_OK; |
389 | 0 | } |
390 | | |
391 | | static nsresult |
392 | | WriteImage(const nsCString& aPath, imgIContainer* aImage) |
393 | 0 | { |
394 | | #if !defined(MOZ_WIDGET_GTK) |
395 | | return NS_ERROR_NOT_AVAILABLE; |
396 | | #else |
397 | | nsCOMPtr<nsIImageToPixbuf> imgToPixbuf = |
398 | 0 | do_GetService("@mozilla.org/widget/image-to-gdk-pixbuf;1"); |
399 | 0 | if (!imgToPixbuf) |
400 | 0 | return NS_ERROR_NOT_AVAILABLE; |
401 | 0 | |
402 | 0 | GdkPixbuf* pixbuf = imgToPixbuf->ConvertImageToPixbuf(aImage); |
403 | 0 | if (!pixbuf) |
404 | 0 | return NS_ERROR_NOT_AVAILABLE; |
405 | 0 | |
406 | 0 | gboolean res = gdk_pixbuf_save(pixbuf, aPath.get(), "png", nullptr, nullptr); |
407 | 0 |
|
408 | 0 | g_object_unref(pixbuf); |
409 | 0 | return res ? NS_OK : NS_ERROR_FAILURE; |
410 | 0 | #endif |
411 | 0 | } |
412 | | |
413 | | NS_IMETHODIMP |
414 | | nsGNOMEShellService::SetDesktopBackground(dom::Element* aElement, |
415 | | int32_t aPosition, |
416 | | const nsACString& aImageName) |
417 | 0 | { |
418 | 0 | nsresult rv; |
419 | 0 | nsCOMPtr<nsIImageLoadingContent> imageContent = do_QueryInterface(aElement, &rv); |
420 | 0 | if (!imageContent) return rv; |
421 | 0 | |
422 | 0 | // get the image container |
423 | 0 | nsCOMPtr<imgIRequest> request; |
424 | 0 | rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, |
425 | 0 | getter_AddRefs(request)); |
426 | 0 | if (!request) return rv; |
427 | 0 | nsCOMPtr<imgIContainer> container; |
428 | 0 | rv = request->GetImage(getter_AddRefs(container)); |
429 | 0 | if (!container) return rv; |
430 | 0 | |
431 | 0 | // Set desktop wallpaper filling style |
432 | 0 | nsAutoCString options; |
433 | 0 | if (aPosition == BACKGROUND_TILE) |
434 | 0 | options.AssignLiteral("wallpaper"); |
435 | 0 | else if (aPosition == BACKGROUND_STRETCH) |
436 | 0 | options.AssignLiteral("stretched"); |
437 | 0 | else if (aPosition == BACKGROUND_FILL) |
438 | 0 | options.AssignLiteral("zoom"); |
439 | 0 | else if (aPosition == BACKGROUND_FIT) |
440 | 0 | options.AssignLiteral("scaled"); |
441 | 0 | else |
442 | 0 | options.AssignLiteral("centered"); |
443 | 0 |
|
444 | 0 | // Write the background file to the home directory. |
445 | 0 | nsAutoCString filePath(PR_GetEnv("HOME")); |
446 | 0 |
|
447 | 0 | // get the product brand name from localized strings |
448 | 0 | nsAutoString brandName; |
449 | 0 | nsCID bundleCID = NS_STRINGBUNDLESERVICE_CID; |
450 | 0 | nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(bundleCID)); |
451 | 0 | if (bundleService) { |
452 | 0 | nsCOMPtr<nsIStringBundle> brandBundle; |
453 | 0 | rv = bundleService->CreateBundle(BRAND_PROPERTIES, |
454 | 0 | getter_AddRefs(brandBundle)); |
455 | 0 | if (NS_SUCCEEDED(rv) && brandBundle) { |
456 | 0 | rv = brandBundle->GetStringFromName("brandShortName", brandName); |
457 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
458 | 0 | } |
459 | 0 | } |
460 | 0 |
|
461 | 0 | // build the file name |
462 | 0 | filePath.Append('/'); |
463 | 0 | filePath.Append(NS_ConvertUTF16toUTF8(brandName)); |
464 | 0 | filePath.AppendLiteral("_wallpaper.png"); |
465 | 0 |
|
466 | 0 | // write the image to a file in the home dir |
467 | 0 | rv = WriteImage(filePath, container); |
468 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
469 | 0 |
|
470 | 0 | // Try GSettings first. If we don't have GSettings or the right schema, fall back |
471 | 0 | // to using GConf instead. Note that if GSettings works ok, the changes get |
472 | 0 | // mirrored to GConf by the gsettings->gconf bridge in gnome-settings-daemon |
473 | 0 | nsCOMPtr<nsIGSettingsService> gsettings = |
474 | 0 | do_GetService(NS_GSETTINGSSERVICE_CONTRACTID); |
475 | 0 | if (gsettings) { |
476 | 0 | nsCOMPtr<nsIGSettingsCollection> background_settings; |
477 | 0 | gsettings->GetCollectionForSchema( |
478 | 0 | NS_LITERAL_CSTRING(kDesktopBGSchema), getter_AddRefs(background_settings)); |
479 | 0 | if (background_settings) { |
480 | 0 | gchar *file_uri = g_filename_to_uri(filePath.get(), nullptr, nullptr); |
481 | 0 | if (!file_uri) |
482 | 0 | return NS_ERROR_FAILURE; |
483 | 0 | |
484 | 0 | background_settings->SetString(NS_LITERAL_CSTRING(kDesktopOptionGSKey), |
485 | 0 | options); |
486 | 0 |
|
487 | 0 | background_settings->SetString(NS_LITERAL_CSTRING(kDesktopImageGSKey), |
488 | 0 | nsDependentCString(file_uri)); |
489 | 0 | g_free(file_uri); |
490 | 0 | background_settings->SetBoolean(NS_LITERAL_CSTRING(kDesktopDrawBGGSKey), |
491 | 0 | true); |
492 | 0 | return rv; |
493 | 0 | } |
494 | 0 | } |
495 | 0 |
|
496 | 0 | // if the file was written successfully, set it as the system wallpaper |
497 | 0 | nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); |
498 | 0 |
|
499 | 0 | if (gconf) { |
500 | 0 | gconf->SetString(NS_LITERAL_CSTRING(kDesktopOptionsKey), options); |
501 | 0 |
|
502 | 0 | // Set the image to an empty string first to force a refresh |
503 | 0 | // (since we could be writing a new image on top of an existing |
504 | 0 | // Firefox_wallpaper.png and nautilus doesn't monitor the file for changes) |
505 | 0 | gconf->SetString(NS_LITERAL_CSTRING(kDesktopImageKey), |
506 | 0 | EmptyCString()); |
507 | 0 |
|
508 | 0 | gconf->SetString(NS_LITERAL_CSTRING(kDesktopImageKey), filePath); |
509 | 0 | gconf->SetBool(NS_LITERAL_CSTRING(kDesktopDrawBGKey), true); |
510 | 0 | } |
511 | 0 |
|
512 | 0 | return rv; |
513 | 0 | } |
514 | | |
515 | 0 | #define COLOR_16_TO_8_BIT(_c) ((_c) >> 8) |
516 | 0 | #define COLOR_8_TO_16_BIT(_c) ((_c) << 8 | (_c)) |
517 | | |
518 | | NS_IMETHODIMP |
519 | | nsGNOMEShellService::GetDesktopBackgroundColor(uint32_t *aColor) |
520 | 0 | { |
521 | 0 | nsCOMPtr<nsIGSettingsService> gsettings = |
522 | 0 | do_GetService(NS_GSETTINGSSERVICE_CONTRACTID); |
523 | 0 | nsCOMPtr<nsIGSettingsCollection> background_settings; |
524 | 0 | nsAutoCString background; |
525 | 0 |
|
526 | 0 | if (gsettings) { |
527 | 0 | gsettings->GetCollectionForSchema( |
528 | 0 | NS_LITERAL_CSTRING(kDesktopBGSchema), getter_AddRefs(background_settings)); |
529 | 0 | if (background_settings) { |
530 | 0 | background_settings->GetString(NS_LITERAL_CSTRING(kDesktopColorGSKey), |
531 | 0 | background); |
532 | 0 | } |
533 | 0 | } |
534 | 0 |
|
535 | 0 | if (!background_settings) { |
536 | 0 | nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); |
537 | 0 | if (gconf) |
538 | 0 | gconf->GetString(NS_LITERAL_CSTRING(kDesktopColorKey), background); |
539 | 0 | } |
540 | 0 |
|
541 | 0 | if (background.IsEmpty()) { |
542 | 0 | *aColor = 0; |
543 | 0 | return NS_OK; |
544 | 0 | } |
545 | 0 | |
546 | 0 | GdkColor color; |
547 | 0 | gboolean success = gdk_color_parse(background.get(), &color); |
548 | 0 |
|
549 | 0 | NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); |
550 | 0 |
|
551 | 0 | *aColor = COLOR_16_TO_8_BIT(color.red) << 16 | |
552 | 0 | COLOR_16_TO_8_BIT(color.green) << 8 | |
553 | 0 | COLOR_16_TO_8_BIT(color.blue); |
554 | 0 | return NS_OK; |
555 | 0 | } |
556 | | |
557 | | static void |
558 | | ColorToCString(uint32_t aColor, nsCString& aResult) |
559 | 0 | { |
560 | 0 | // The #rrrrggggbbbb format is used to match gdk_color_to_string() |
561 | 0 | aResult.SetLength(13); |
562 | 0 | char *buf = aResult.BeginWriting(); |
563 | 0 | if (!buf) |
564 | 0 | return; |
565 | 0 | |
566 | 0 | uint16_t red = COLOR_8_TO_16_BIT((aColor >> 16) & 0xff); |
567 | 0 | uint16_t green = COLOR_8_TO_16_BIT((aColor >> 8) & 0xff); |
568 | 0 | uint16_t blue = COLOR_8_TO_16_BIT(aColor & 0xff); |
569 | 0 |
|
570 | 0 | snprintf(buf, 14, "#%04x%04x%04x", red, green, blue); |
571 | 0 | } |
572 | | |
573 | | NS_IMETHODIMP |
574 | | nsGNOMEShellService::SetDesktopBackgroundColor(uint32_t aColor) |
575 | 0 | { |
576 | 0 | NS_ASSERTION(aColor <= 0xffffff, "aColor has extra bits"); |
577 | 0 | nsAutoCString colorString; |
578 | 0 | ColorToCString(aColor, colorString); |
579 | 0 |
|
580 | 0 | nsCOMPtr<nsIGSettingsService> gsettings = |
581 | 0 | do_GetService(NS_GSETTINGSSERVICE_CONTRACTID); |
582 | 0 | if (gsettings) { |
583 | 0 | nsCOMPtr<nsIGSettingsCollection> background_settings; |
584 | 0 | gsettings->GetCollectionForSchema( |
585 | 0 | NS_LITERAL_CSTRING(kDesktopBGSchema), getter_AddRefs(background_settings)); |
586 | 0 | if (background_settings) { |
587 | 0 | background_settings->SetString(NS_LITERAL_CSTRING(kDesktopColorGSKey), |
588 | 0 | colorString); |
589 | 0 | return NS_OK; |
590 | 0 | } |
591 | 0 | } |
592 | 0 |
|
593 | 0 | nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); |
594 | 0 |
|
595 | 0 | if (gconf) { |
596 | 0 | gconf->SetString(NS_LITERAL_CSTRING(kDesktopColorKey), colorString); |
597 | 0 | } |
598 | 0 |
|
599 | 0 | return NS_OK; |
600 | 0 | } |
601 | | |
602 | | NS_IMETHODIMP |
603 | | nsGNOMEShellService::OpenApplication(int32_t aApplication) |
604 | 0 | { |
605 | 0 | nsAutoCString scheme; |
606 | 0 | if (aApplication == APPLICATION_MAIL) |
607 | 0 | scheme.AssignLiteral("mailto"); |
608 | 0 | else if (aApplication == APPLICATION_NEWS) |
609 | 0 | scheme.AssignLiteral("news"); |
610 | 0 | else |
611 | 0 | return NS_ERROR_NOT_AVAILABLE; |
612 | 0 | |
613 | 0 | nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID); |
614 | 0 | if (giovfs) { |
615 | 0 | nsCOMPtr<nsIHandlerApp> handlerApp; |
616 | 0 | giovfs->GetAppForURIScheme(scheme, getter_AddRefs(handlerApp)); |
617 | 0 | if (handlerApp) |
618 | 0 | return handlerApp->LaunchWithURI(nullptr, nullptr); |
619 | 0 | } |
620 | 0 | |
621 | 0 | nsCOMPtr<nsIGConfService> gconf = do_GetService(NS_GCONFSERVICE_CONTRACTID); |
622 | 0 | if (!gconf) |
623 | 0 | return NS_ERROR_FAILURE; |
624 | 0 | |
625 | 0 | bool enabled; |
626 | 0 | nsAutoCString appCommand; |
627 | 0 | gconf->GetAppForProtocol(scheme, &enabled, appCommand); |
628 | 0 |
|
629 | 0 | if (!enabled) |
630 | 0 | return NS_ERROR_FAILURE; |
631 | 0 | |
632 | 0 | // XXX we don't currently handle launching a terminal window. |
633 | 0 | // If the handler requires a terminal, bail. |
634 | 0 | bool requiresTerminal; |
635 | 0 | gconf->HandlerRequiresTerminal(scheme, &requiresTerminal); |
636 | 0 | if (requiresTerminal) |
637 | 0 | return NS_ERROR_FAILURE; |
638 | 0 | |
639 | 0 | // Perform shell argument expansion |
640 | 0 | int argc; |
641 | 0 | char **argv; |
642 | 0 | if (!g_shell_parse_argv(appCommand.get(), &argc, &argv, nullptr)) |
643 | 0 | return NS_ERROR_FAILURE; |
644 | 0 | |
645 | 0 | char **newArgv = new char*[argc + 1]; |
646 | 0 | int newArgc = 0; |
647 | 0 |
|
648 | 0 | // Run through the list of arguments. Copy all of them to the new |
649 | 0 | // argv except for %s, which we skip. |
650 | 0 | for (int i = 0; i < argc; ++i) { |
651 | 0 | if (strcmp(argv[i], "%s") != 0) |
652 | 0 | newArgv[newArgc++] = argv[i]; |
653 | 0 | } |
654 | 0 |
|
655 | 0 | newArgv[newArgc] = nullptr; |
656 | 0 |
|
657 | 0 | gboolean err = g_spawn_async(nullptr, newArgv, nullptr, G_SPAWN_SEARCH_PATH, |
658 | 0 | nullptr, nullptr, nullptr, nullptr); |
659 | 0 |
|
660 | 0 | g_strfreev(argv); |
661 | 0 | delete[] newArgv; |
662 | 0 |
|
663 | 0 | return err ? NS_OK : NS_ERROR_FAILURE; |
664 | 0 | } |
665 | | |
666 | | NS_IMETHODIMP |
667 | | nsGNOMEShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACString& aURI) |
668 | 0 | { |
669 | 0 | nsresult rv; |
670 | 0 | nsCOMPtr<nsIProcess> process = |
671 | 0 | do_CreateInstance("@mozilla.org/process/util;1", &rv); |
672 | 0 | if (NS_FAILED(rv)) |
673 | 0 | return rv; |
674 | 0 | |
675 | 0 | rv = process->Init(aApplication); |
676 | 0 | if (NS_FAILED(rv)) |
677 | 0 | return rv; |
678 | 0 | |
679 | 0 | const nsCString spec(aURI); |
680 | 0 | const char* specStr = spec.get(); |
681 | 0 | return process->Run(false, &specStr, 1); |
682 | 0 | } |
683 | | |
684 | | NS_IMETHODIMP |
685 | | nsGNOMEShellService::GetDefaultFeedReader(nsIFile** _retval) |
686 | 0 | { |
687 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
688 | 0 | } |