Coverage Report

Created: 2018-09-25 14:53

/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
}