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