Bug 1760839 - Use more automatic memory management in GTK code. r=stransky

This fixes a couple potential leaks (e.g., see the UPowerClient changes,
we weren't freeing all the devices properly).

Differential Revision: https://phabricator.services.mozilla.com/D141775
This commit is contained in:
Emilio Cobos Álvarez
2022-03-23 16:14:34 +00:00
parent 1218c5a06f
commit 0a450d3a7b
16 changed files with 301 additions and 335 deletions

View File

@@ -22,6 +22,7 @@
#include "nsIImageLoadingContent.h"
#include "imgIRequest.h"
#include "imgIContainer.h"
#include "mozilla/GRefPtr.h"
#include "mozilla/Sprintf.h"
#include "mozilla/WidgetUtils.h"
#include "mozilla/WidgetUtilsGtk.h"
@@ -357,14 +358,12 @@ nsGNOMEShellService::GetCanSetDesktopBackground(bool* aResult) {
}
static nsresult WriteImage(const nsCString& aPath, imgIContainer* aImage) {
GdkPixbuf* pixbuf = nsImageToPixbuf::ImageToPixbuf(aImage);
RefPtr<GdkPixbuf> pixbuf = nsImageToPixbuf::ImageToPixbuf(aImage);
if (!pixbuf) {
return NS_ERROR_NOT_AVAILABLE;
}
gboolean res = gdk_pixbuf_save(pixbuf, aPath.get(), "png", nullptr, nullptr);
g_object_unref(pixbuf);
return res ? NS_OK : NS_ERROR_FAILURE;
}

View File

@@ -9,26 +9,13 @@
#include <dbus/dbus-glib-lowlevel.h>
#include <mozilla/Attributes.h>
#include <mozilla/dom/battery/Constants.h>
#include "nsAutoRef.h"
#include "mozilla/GRefPtr.h"
#include "mozilla/GUniquePtr.h"
#include <cmath>
/*
* Helper that manages the destruction of glib objects as soon as they leave
* the current scope.
*
* We are specializing nsAutoRef class.
*/
template <>
class nsAutoRefTraits<GHashTable> : public nsPointerRefTraits<GHashTable> {
public:
static void Release(GHashTable* ptr) { g_hash_table_unref(ptr); }
};
using namespace mozilla::dom::battery;
namespace mozilla {
namespace hal_impl {
namespace mozilla::hal_impl {
/**
* This is the declaration of UPowerClient class. This class is listening and
@@ -69,9 +56,8 @@ class UPowerClient {
/**
* Returns a hash table with the properties of aDevice.
* Note: the caller has to unref the hash table.
*/
GHashTable* GetDevicePropertiesSync(DBusGProxy* aProxy);
already_AddRefed<GHashTable> GetDevicePropertiesSync(DBusGProxy* aProxy);
void GetDevicePropertiesAsync(DBusGProxy* aProxy);
static void GetDevicePropertiesCallback(DBusGProxy* aProxy,
DBusGProxyCall* aCall, void* aData);
@@ -104,16 +90,16 @@ class UPowerClient {
void* aData);
// The DBus connection object.
DBusGConnection* mDBusConnection;
RefPtr<DBusGConnection> mDBusConnection;
// The DBus proxy object to upower.
DBusGProxy* mUPowerProxy;
RefPtr<DBusGProxy> mUPowerProxy;
// The path of the tracked device.
gchar* mTrackedDevice;
GUniquePtr<gchar> mTrackedDevice;
// The DBusGProxy for the tracked device.
DBusGProxy* mTrackedDeviceProxy;
RefPtr<DBusGProxy> mTrackedDeviceProxy;
double mLevel;
bool mCharging;
@@ -163,11 +149,7 @@ UPowerClient* UPowerClient::GetInstance() {
}
UPowerClient::UPowerClient()
: mDBusConnection(nullptr),
mUPowerProxy(nullptr),
mTrackedDevice(nullptr),
mTrackedDeviceProxy(nullptr),
mLevel(kDefaultLevel),
: mLevel(kDefaultLevel),
mCharging(kDefaultCharging),
mRemainingTime(kDefaultRemainingTime) {}
@@ -179,12 +161,12 @@ UPowerClient::~UPowerClient() {
}
void UPowerClient::BeginListening() {
GError* error = nullptr;
mDBusConnection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
GUniquePtr<GError> error;
mDBusConnection =
dont_AddRef(dbus_g_bus_get(DBUS_BUS_SYSTEM, getter_Transfers(error)));
if (!mDBusConnection) {
HAL_LOG("Failed to open connection to bus: %s\n", error->message);
g_error_free(error);
return;
}
@@ -199,9 +181,9 @@ void UPowerClient::BeginListening() {
dbus_connection_add_filter(dbusConnection, ConnectionSignalFilter, this,
nullptr);
mUPowerProxy = dbus_g_proxy_new_for_name(
mUPowerProxy = dont_AddRef(dbus_g_proxy_new_for_name(
mDBusConnection, "org.freedesktop.UPower", "/org/freedesktop/UPower",
"org.freedesktop.UPower");
"org.freedesktop.UPower"));
UpdateTrackedDeviceSync();
@@ -231,21 +213,15 @@ void UPowerClient::StopListening() {
dbus_g_proxy_disconnect_signal(mUPowerProxy, "DeviceChanged",
G_CALLBACK(DeviceChanged), this);
g_free(mTrackedDevice);
mTrackedDevice = nullptr;
if (mTrackedDeviceProxy) {
dbus_g_proxy_disconnect_signal(mTrackedDeviceProxy, "PropertiesChanged",
G_CALLBACK(PropertiesChanged), this);
g_object_unref(mTrackedDeviceProxy);
mTrackedDeviceProxy = nullptr;
}
g_object_unref(mUPowerProxy);
mUPowerProxy = nullptr;
dbus_g_connection_unref(mDBusConnection);
mDBusConnection = nullptr;
// We should now show the default values, not the latest we got.
@@ -258,27 +234,23 @@ void UPowerClient::UpdateTrackedDeviceSync() {
GType typeGPtrArray =
dbus_g_type_get_collection("GPtrArray", DBUS_TYPE_G_OBJECT_PATH);
GPtrArray* devices = nullptr;
GError* error = nullptr;
// Reset the current tracked device:
g_free(mTrackedDevice);
mTrackedDevice = nullptr;
// Reset the current tracked device proxy:
if (mTrackedDeviceProxy) {
dbus_g_proxy_disconnect_signal(mTrackedDeviceProxy, "PropertiesChanged",
G_CALLBACK(PropertiesChanged), this);
g_object_unref(mTrackedDeviceProxy);
mTrackedDeviceProxy = nullptr;
}
GUniquePtr<GError> error;
// If that fails, that likely means upower isn't installed.
if (!dbus_g_proxy_call(mUPowerProxy, "EnumerateDevices", &error,
G_TYPE_INVALID, typeGPtrArray, &devices,
G_TYPE_INVALID)) {
if (!dbus_g_proxy_call(mUPowerProxy, "EnumerateDevices",
getter_Transfers(error), G_TYPE_INVALID, typeGPtrArray,
&devices, G_TYPE_INVALID)) {
HAL_LOG("Error: %s\n", error->message);
g_error_free(error);
return;
}
@@ -287,23 +259,25 @@ void UPowerClient::UpdateTrackedDeviceSync() {
* TODO: we could try to combine more than one battery.
*/
for (guint i = 0; i < devices->len; ++i) {
gchar* devicePath = static_cast<gchar*>(g_ptr_array_index(devices, i));
GUniquePtr<gchar> devicePath(
static_cast<gchar*>(g_ptr_array_index(devices, i)));
if (mTrackedDevice) {
continue;
}
DBusGProxy* proxy = dbus_g_proxy_new_from_proxy(
mUPowerProxy, "org.freedesktop.DBus.Properties", devicePath);
RefPtr<DBusGProxy> proxy = dont_AddRef(dbus_g_proxy_new_from_proxy(
mUPowerProxy, "org.freedesktop.DBus.Properties", devicePath.get()));
nsAutoRef<GHashTable> hashTable(GetDevicePropertiesSync(proxy));
RefPtr<GHashTable> hashTable(GetDevicePropertiesSync(proxy));
if (g_value_get_uint(static_cast<const GValue*>(
g_hash_table_lookup(hashTable, "Type"))) == sDeviceTypeBattery) {
UpdateSavedInfo(hashTable);
mTrackedDevice = devicePath;
mTrackedDeviceProxy = proxy;
break;
mTrackedDevice = std::move(devicePath);
mTrackedDeviceProxy = std::move(proxy);
// Can't break here because we still need to iterate over all other
// devices to free them.
}
g_object_unref(proxy);
g_free(devicePath);
}
if (mTrackedDeviceProxy) {
@@ -326,9 +300,9 @@ void UPowerClient::DeviceChanged(DBusGProxy* aProxy, const gchar* aObjectPath,
}
#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 16
if (g_strcmp0(aObjectPath, aListener->mTrackedDevice)) {
if (g_strcmp0(aObjectPath, aListener->mTrackedDevice.get())) {
#else
if (g_ascii_strcasecmp(aObjectPath, aListener->mTrackedDevice)) {
if (g_ascii_strcasecmp(aObjectPath, aListener->mTrackedDevice.get())) {
#endif
return;
}
@@ -355,34 +329,35 @@ DBusHandlerResult UPowerClient::ConnectionSignalFilter(
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
GHashTable* UPowerClient::GetDevicePropertiesSync(DBusGProxy* aProxy) {
GError* error = nullptr;
GHashTable* hashTable = nullptr;
already_AddRefed<GHashTable> UPowerClient::GetDevicePropertiesSync(
DBusGProxy* aProxy) {
GUniquePtr<GError> error;
RefPtr<GHashTable> hashTable;
GType typeGHashTable =
dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
if (!dbus_g_proxy_call(aProxy, "GetAll", &error, G_TYPE_STRING,
"org.freedesktop.UPower.Device", G_TYPE_INVALID,
typeGHashTable, &hashTable, G_TYPE_INVALID)) {
if (!dbus_g_proxy_call(aProxy, "GetAll", getter_Transfers(error),
G_TYPE_STRING, "org.freedesktop.UPower.Device",
G_TYPE_INVALID, typeGHashTable,
hashTable.StartAssignment(), G_TYPE_INVALID)) {
HAL_LOG("Error: %s\n", error->message);
g_error_free(error);
return nullptr;
}
return hashTable;
return hashTable.forget();
}
/* static */
void UPowerClient::GetDevicePropertiesCallback(DBusGProxy* aProxy,
DBusGProxyCall* aCall,
void* aData) {
GError* error = nullptr;
GHashTable* hashTable = nullptr;
GUniquePtr<GError> error;
RefPtr<GHashTable> hashTable;
GType typeGHashTable =
dbus_g_type_get_map("GHashTable", G_TYPE_STRING, G_TYPE_VALUE);
if (!dbus_g_proxy_end_call(aProxy, aCall, &error, typeGHashTable, &hashTable,
if (!dbus_g_proxy_end_call(aProxy, aCall, getter_Transfers(error),
typeGHashTable, hashTable.StartAssignment(),
G_TYPE_INVALID)) {
HAL_LOG("Error: %s\n", error->message);
g_error_free(error);
} else {
sInstance->UpdateSavedInfo(hashTable);
hal::NotifyBatteryChange(hal::BatteryInformation(
@@ -470,5 +445,4 @@ bool UPowerClient::IsCharging() { return mCharging; }
double UPowerClient::GetRemainingTime() { return mRemainingTime; }
} // namespace hal_impl
} // namespace mozilla
} // namespace mozilla::hal_impl

View File

@@ -45,6 +45,7 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
"android/AndroidHal.cpp",
]
elif CONFIG["OS_TARGET"] == "Linux":
UNIFIED_SOURCES += [
"fallback/FallbackProcessPriority.cpp",
"fallback/FallbackScreenConfiguration.cpp",
@@ -127,6 +128,8 @@ LOCAL_INCLUDES += [
]
CFLAGS += CONFIG["GLIB_CFLAGS"]
CFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
CFLAGS += CONFIG["MOZ_DBUS_GLIB_CFLAGS"]
CXXFLAGS += CONFIG["GLIB_CFLAGS"]
CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
CXXFLAGS += CONFIG["MOZ_DBUS_GLIB_CFLAGS"]

View File

@@ -16,11 +16,15 @@
#include "nsIObserverService.h"
#include "nsCRT.h"
#include "mozilla/XREAppData.h"
#include "mozilla/GRefPtr.h"
#include "mozilla/GUniquePtr.h"
#include "mozilla/UniquePtrExtensions.h"
#include <dlfcn.h>
#include <gdk/gdk.h>
extern const mozilla::StaticXREAppData* gAppData;
using namespace mozilla;
extern const StaticXREAppData* gAppData;
static bool gHasActions = false;
static bool gHasCaps = false;
@@ -64,7 +68,8 @@ static void notify_closed_marshal(GClosure* closure, GValue* return_value,
NS_RELEASE(alert);
}
static GdkPixbuf* GetPixbufFromImgRequest(imgIRequest* aRequest) {
static already_AddRefed<GdkPixbuf> GetPixbufFromImgRequest(
imgIRequest* aRequest) {
nsCOMPtr<imgIContainer> image;
nsresult rv = aRequest->GetImage(getter_AddRefs(image));
if (NS_FAILED(rv)) {
@@ -145,14 +150,8 @@ nsAlertsIconListener::OnImageMissing(nsISupports*) {
NS_IMETHODIMP
nsAlertsIconListener::OnImageReady(nsISupports*, imgIRequest* aRequest) {
GdkPixbuf* imagePixbuf = GetPixbufFromImgRequest(aRequest);
if (!imagePixbuf) {
ShowAlert(nullptr);
} else {
RefPtr<GdkPixbuf> imagePixbuf = GetPixbufFromImgRequest(aRequest);
ShowAlert(imagePixbuf);
g_object_unref(imagePixbuf);
}
return NS_OK;
}
@@ -202,10 +201,9 @@ nsresult nsAlertsIconListener::ShowAlert(GdkPixbuf* aPixbuf) {
g_closure_set_marshal(closure, notify_closed_marshal);
mClosureHandler =
g_signal_connect_closure(mNotification, "closed", closure, FALSE);
GError* error = nullptr;
if (!notify_notification_show(mNotification, &error)) {
GUniquePtr<GError> error;
if (!notify_notification_show(mNotification, getter_Transfers(error))) {
NS_WARNING(error->message);
g_error_free(error);
return NS_ERROR_FAILURE;
}
@@ -253,10 +251,9 @@ nsresult nsAlertsIconListener::Close() {
return NS_OK;
}
GError* error = nullptr;
if (!notify_notification_close(mNotification, &error)) {
GUniquePtr<GError> error;
if (!notify_notification_close(mNotification, getter_Transfers(error))) {
NS_WARNING(error->message);
g_error_free(error);
return NS_ERROR_FAILURE;
}

View File

@@ -73,7 +73,7 @@ nsFlatpakHandlerApp::LaunchWithURI(
nsIURI* aUri, mozilla::dom::BrowsingContext* aBrowsingContext) {
nsCString spec;
aUri->GetSpec(spec);
GError* error = nullptr;
GUniquePtr<GError> error;
// The TMPDIR where files are downloaded when user choose to open them
// needs to be accessible from sandbox and host. The default settings
@@ -81,12 +81,11 @@ nsFlatpakHandlerApp::LaunchWithURI(
// why the gtk_show_uri fails there.
// The workaround is to set TMPDIR environment variable in sandbox to
// $XDG_CACHE_HOME/tmp before executing Firefox.
gtk_show_uri(nullptr, spec.get(), GDK_CURRENT_TIME, &error);
gtk_show_uri(nullptr, spec.get(), GDK_CURRENT_TIME, getter_Transfers(error));
if (error) {
NS_WARNING(
nsPrintfCString("Cannot launch flatpak handler: %s", error->message)
.get());
g_error_free(error);
return NS_ERROR_FAILURE;
}
return NS_OK;
@@ -100,13 +99,12 @@ nsFlatpakHandlerApp::LaunchWithURI(
*/
static nsresult GetCommandFromCommandline(
nsACString const& aCommandWithArguments, nsACString& aCommand) {
GError* error = nullptr;
GUniquePtr<GError> error;
gchar** argv = nullptr;
if (!g_shell_parse_argv(aCommandWithArguments.BeginReading(), nullptr, &argv,
&error) ||
getter_Transfers(error)) ||
!argv[0]) {
g_warning("Cannot parse command with arguments: %s", error->message);
g_error_free(error);
g_strfreev(argv);
return NS_ERROR_FAILURE;
}
@@ -121,12 +119,12 @@ class nsGIOMimeApp final : public nsIGIOMimeApp {
NS_DECL_NSIHANDLERAPP
NS_DECL_NSIGIOMIMEAPP
explicit nsGIOMimeApp(GAppInfo* aApp) : mApp(aApp) {}
explicit nsGIOMimeApp(already_AddRefed<GAppInfo> aApp) : mApp(aApp) {}
private:
~nsGIOMimeApp() { g_object_unref(mApp); }
~nsGIOMimeApp() = default;
GAppInfo* mApp;
RefPtr<GAppInfo> mApp;
};
NS_IMPL_ISUPPORTS(nsGIOMimeApp, nsIGIOMimeApp, nsIHandlerApp)
@@ -224,12 +222,12 @@ nsGIOMimeApp::LaunchWithURI(nsIURI* aUri,
// nsPromiseFlatCString flatUri(aUri);
uris.data = const_cast<char*>(spec.get());
GError* error = nullptr;
gboolean result = g_app_info_launch_uris(mApp, &uris, nullptr, &error);
GUniquePtr<GError> error;
gboolean result =
g_app_info_launch_uris(mApp, &uris, nullptr, getter_Transfers(error));
if (!result) {
g_warning("Cannot launch application: %s", error->message);
g_error_free(error);
return NS_ERROR_FAILURE;
}
@@ -297,20 +295,17 @@ nsGIOMimeApp::GetSupportedURISchemes(nsIUTF8StringEnumerator** aSchemes) {
NS_IMETHODIMP
nsGIOMimeApp::SetAsDefaultForMimeType(nsACString const& aMimeType) {
char* content_type =
g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
GUniquePtr<char> content_type(
g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get()));
if (!content_type) return NS_ERROR_FAILURE;
GError* error = nullptr;
g_app_info_set_as_default_for_type(mApp, content_type, &error);
GUniquePtr<GError> error;
g_app_info_set_as_default_for_type(mApp, content_type.get(),
getter_Transfers(error));
if (error) {
g_warning("Cannot set application as default for MIME type (%s): %s",
PromiseFlatCString(aMimeType).get(), error->message);
g_error_free(error);
g_free(content_type);
return NS_ERROR_FAILURE;
}
g_free(content_type);
return NS_OK;
}
/**
@@ -321,21 +316,20 @@ nsGIOMimeApp::SetAsDefaultForMimeType(nsACString const& aMimeType) {
*/
NS_IMETHODIMP
nsGIOMimeApp::SetAsDefaultForFileExtensions(nsACString const& fileExts) {
GError* error = nullptr;
char* extensions = g_strdup(PromiseFlatCString(fileExts).get());
char* ext_pos = extensions;
GUniquePtr<GError> error;
GUniquePtr<char> extensions(g_strdup(PromiseFlatCString(fileExts).get()));
char* ext_pos = extensions.get();
char* space_pos;
while ((space_pos = strchr(ext_pos, ' ')) || (*ext_pos != '\0')) {
if (space_pos) {
*space_pos = '\0';
}
g_app_info_set_as_default_for_extension(mApp, ext_pos, &error);
g_app_info_set_as_default_for_extension(mApp, ext_pos,
getter_Transfers(error));
if (error) {
g_warning("Cannot set application as default for extension (%s): %s",
ext_pos, error->message);
g_error_free(error);
g_free(extensions);
return NS_ERROR_FAILURE;
}
if (space_pos) {
@@ -344,7 +338,6 @@ nsGIOMimeApp::SetAsDefaultForFileExtensions(nsACString const& fileExts) {
*ext_pos = '\0';
}
}
g_free(extensions);
return NS_OK;
}
@@ -356,15 +349,15 @@ nsGIOMimeApp::SetAsDefaultForFileExtensions(nsACString const& fileExts) {
*/
NS_IMETHODIMP
nsGIOMimeApp::SetAsDefaultForURIScheme(nsACString const& aURIScheme) {
GError* error = nullptr;
GUniquePtr<GError> error;
nsAutoCString contentType("x-scheme-handler/");
contentType.Append(aURIScheme);
g_app_info_set_as_default_for_type(mApp, contentType.get(), &error);
g_app_info_set_as_default_for_type(mApp, contentType.get(),
getter_Transfers(error));
if (error) {
g_warning("Cannot set application as default for URI scheme (%s): %s",
PromiseFlatCString(aURIScheme).get(), error->message);
g_error_free(error);
return NS_ERROR_FAILURE;
}
@@ -380,21 +373,18 @@ nsGIOService::GetMimeTypeFromExtension(const nsACString& aExtension,
fileExtToUse.Append(aExtension);
gboolean result_uncertain;
char* content_type =
g_content_type_guess(fileExtToUse.get(), nullptr, 0, &result_uncertain);
if (!content_type) return NS_ERROR_FAILURE;
char* mime_type = g_content_type_get_mime_type(content_type);
if (!mime_type) {
g_free(content_type);
GUniquePtr<char> content_type(
g_content_type_guess(fileExtToUse.get(), nullptr, 0, &result_uncertain));
if (!content_type) {
return NS_ERROR_FAILURE;
}
aMimeType.Assign(mime_type);
g_free(mime_type);
g_free(content_type);
GUniquePtr<char> mime_type(g_content_type_get_mime_type(content_type.get()));
if (!mime_type) {
return NS_ERROR_FAILURE;
}
aMimeType.Assign(mime_type.get());
return NS_OK;
}
// used in nsGNOMERegistry
@@ -416,19 +406,18 @@ nsGIOService::GetAppForURIScheme(const nsACString& aURIScheme,
// apps, and we're much better off returning an error here instead.
return NS_ERROR_FAILURE;
}
nsFlatpakHandlerApp* mozApp = new nsFlatpakHandlerApp();
NS_ADDREF(*aApp = mozApp);
RefPtr<nsFlatpakHandlerApp> mozApp = new nsFlatpakHandlerApp();
mozApp.forget(aApp);
return NS_OK;
}
GAppInfo* app_info = g_app_info_get_default_for_uri_scheme(
PromiseFlatCString(aURIScheme).get());
if (app_info) {
nsGIOMimeApp* mozApp = new nsGIOMimeApp(app_info);
NS_ADDREF(*aApp = mozApp);
} else {
RefPtr<GAppInfo> app_info = dont_AddRef(g_app_info_get_default_for_uri_scheme(
PromiseFlatCString(aURIScheme).get()));
if (!app_info) {
return NS_ERROR_FAILURE;
}
RefPtr<nsGIOMimeApp> mozApp = new nsGIOMimeApp(app_info.forget());
mozApp.forget(aApp);
return NS_OK;
}
@@ -456,13 +445,13 @@ nsGIOService::GetAppsForURIScheme(const nsACString& aURIScheme,
GList* appInfo = appInfoList;
while (appInfo) {
nsCOMPtr<nsIGIOMimeApp> mimeApp =
new nsGIOMimeApp(G_APP_INFO(appInfo->data));
new nsGIOMimeApp(dont_AddRef(G_APP_INFO(appInfo->data)));
handlersArray->AppendElement(mimeApp);
appInfo = appInfo->next;
}
g_list_free(appInfoList);
}
NS_ADDREF(*aResult = handlersArray);
handlersArray.forget(aResult);
return NS_OK;
}
@@ -474,19 +463,21 @@ nsGIOService::GetAppForMimeType(const nsACString& aMimeType,
// Flatpak does not reveal installed application to the sandbox,
// we need to create generic system handler.
if (widget::ShouldUsePortal(widget::PortalKind::MimeHandler)) {
nsFlatpakHandlerApp* mozApp = new nsFlatpakHandlerApp();
NS_ADDREF(*aApp = mozApp);
RefPtr<nsFlatpakHandlerApp> mozApp = new nsFlatpakHandlerApp();
mozApp.forget(aApp);
return NS_OK;
}
char* content_type =
g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
if (!content_type) return NS_ERROR_FAILURE;
GUniquePtr<char> content_type(
g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get()));
if (!content_type) {
return NS_ERROR_FAILURE;
}
// GIO returns "unknown" appinfo for the application/octet-stream, which is
// useless. It's better to fallback to create appinfo from file extension
// later.
if (g_content_type_is_unknown(content_type)) {
if (g_content_type_is_unknown(content_type.get())) {
return NS_ERROR_NOT_AVAILABLE;
}
@@ -496,40 +487,37 @@ nsGIOService::GetAppForMimeType(const nsACString& aMimeType,
// registered as defaults for this type. Fake it up by just executing
// xdg-open via gio-launch-desktop (which we do have access to) and letting
// it figure out which program to execute for this MIME type
GAppInfo* app_info = g_app_info_create_from_commandline(
RefPtr<GAppInfo> app_info = dont_AddRef(g_app_info_create_from_commandline(
"/usr/local/bin/xdg-open",
nsPrintfCString("System default for %s", content_type).get(),
G_APP_INFO_CREATE_NONE, NULL);
nsPrintfCString("System default for %s", content_type.get()).get(),
G_APP_INFO_CREATE_NONE, NULL));
#else
GAppInfo* app_info = g_app_info_get_default_for_type(content_type, false);
RefPtr<GAppInfo> app_info =
dont_AddRef(g_app_info_get_default_for_type(content_type.get(), false));
#endif
if (app_info) {
nsGIOMimeApp* mozApp = new nsGIOMimeApp(app_info);
NS_ADDREF(*aApp = mozApp);
} else {
g_free(content_type);
if (!app_info) {
return NS_ERROR_FAILURE;
}
g_free(content_type);
RefPtr<nsGIOMimeApp> mozApp = new nsGIOMimeApp(app_info.forget());
mozApp.forget(aApp);
return NS_OK;
}
NS_IMETHODIMP
nsGIOService::GetDescriptionForMimeType(const nsACString& aMimeType,
nsACString& aDescription) {
char* content_type =
g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
if (!content_type) return NS_ERROR_FAILURE;
char* desc = g_content_type_get_description(content_type);
if (!desc) {
g_free(content_type);
GUniquePtr<char> content_type(
g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get()));
if (!content_type) {
return NS_ERROR_FAILURE;
}
aDescription.Assign(desc);
g_free(content_type);
g_free(desc);
GUniquePtr<char> desc(g_content_type_get_description(content_type.get()));
if (!desc) {
return NS_ERROR_FAILURE;
}
aDescription.Assign(desc.get());
return NS_OK;
}
@@ -538,11 +526,11 @@ nsGIOService::ShowURI(nsIURI* aURI) {
nsAutoCString spec;
nsresult rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
GError* error = nullptr;
if (!g_app_info_launch_default_for_uri(spec.get(), nullptr, &error)) {
GUniquePtr<GError> error;
if (!g_app_info_launch_default_for_uri(spec.get(), nullptr,
getter_Transfers(error))) {
g_warning("Could not launch default application for URI: %s",
error->message);
g_error_free(error);
return NS_ERROR_FAILURE;
}
return NS_OK;
@@ -550,22 +538,17 @@ nsGIOService::ShowURI(nsIURI* aURI) {
NS_IMETHODIMP
nsGIOService::ShowURIForInput(const nsACString& aUri) {
GFile* file = g_file_new_for_commandline_arg(PromiseFlatCString(aUri).get());
char* spec = g_file_get_uri(file);
nsresult rv = NS_ERROR_FAILURE;
GError* error = nullptr;
g_app_info_launch_default_for_uri(spec, nullptr, &error);
RefPtr<GFile> file = dont_AddRef(
g_file_new_for_commandline_arg(PromiseFlatCString(aUri).get()));
GUniquePtr<char> spec(g_file_get_uri(file));
GUniquePtr<GError> error;
g_app_info_launch_default_for_uri(spec.get(), nullptr,
getter_Transfers(error));
if (error) {
g_warning("Cannot launch default application: %s", error->message);
g_error_free(error);
} else {
rv = NS_OK;
return NS_ERROR_FAILURE;
}
g_object_unref(file);
g_free(spec);
return rv;
return NS_OK;
}
NS_IMETHODIMP
@@ -625,39 +608,37 @@ nsGIOService::OrgFreedesktopFileManager1ShowItems(const nsACString& aPath) {
NS_IMETHODIMP
nsGIOService::FindAppFromCommand(nsACString const& aCmd,
nsIGIOMimeApp** aAppInfo) {
GAppInfo *app_info = nullptr, *app_info_from_list = nullptr;
RefPtr<GAppInfo> app_info;
GList* apps = g_app_info_get_all();
GList* apps_p = apps;
// Try to find relevant and existing GAppInfo in all installed application
// We do this by comparing each GAppInfo's executable with out own
while (apps_p) {
app_info_from_list = (GAppInfo*)apps_p->data;
for (GList* node = apps; node; node = node->next) {
RefPtr<GAppInfo> app_info_from_list = dont_AddRef((GAppInfo*)node->data);
node->data = nullptr;
if (!app_info) {
// If the executable is not absolute, get it's full path
char* executable =
g_find_program_in_path(g_app_info_get_executable(app_info_from_list));
GUniquePtr<char> executable(g_find_program_in_path(
g_app_info_get_executable(app_info_from_list)));
if (executable &&
strcmp(executable, PromiseFlatCString(aCmd).get()) == 0) {
g_object_ref(app_info_from_list);
app_info = app_info_from_list;
strcmp(executable.get(), PromiseFlatCString(aCmd).get()) == 0) {
app_info = std::move(app_info_from_list);
// Can't break here because we need to keep iterating to unref the other
// nodes.
}
}
g_free(executable);
}
g_object_unref(app_info_from_list);
apps_p = apps_p->next;
}
g_list_free(apps);
if (app_info) {
nsGIOMimeApp* app = new nsGIOMimeApp(app_info);
NS_ADDREF(*aAppInfo = app);
return NS_OK;
}
if (!app_info) {
*aAppInfo = nullptr;
return NS_ERROR_NOT_AVAILABLE;
}
RefPtr<nsGIOMimeApp> app = new nsGIOMimeApp(app_info.forget());
app.forget(aAppInfo);
return NS_OK;
}
/**
@@ -673,7 +654,6 @@ NS_IMETHODIMP
nsGIOService::CreateAppFromCommand(nsACString const& cmd,
nsACString const& appName,
nsIGIOMimeApp** appInfo) {
GError* error = nullptr;
*appInfo = nullptr;
// Using G_APP_INFO_CREATE_SUPPORTS_URIS calling
@@ -683,25 +663,24 @@ nsGIOService::CreateAppFromCommand(nsACString const& cmd,
nsAutoCString commandWithoutArgs;
nsresult rv = GetCommandFromCommandline(cmd, commandWithoutArgs);
NS_ENSURE_SUCCESS(rv, rv);
GAppInfo* app_info = g_app_info_create_from_commandline(
GUniquePtr<GError> error;
RefPtr<GAppInfo> app_info = dont_AddRef(g_app_info_create_from_commandline(
commandWithoutArgs.BeginReading(), PromiseFlatCString(appName).get(),
G_APP_INFO_CREATE_SUPPORTS_URIS, &error);
G_APP_INFO_CREATE_SUPPORTS_URIS, getter_Transfers(error)));
if (!app_info) {
g_warning("Cannot create application info from command: %s",
error->message);
g_error_free(error);
return NS_ERROR_FAILURE;
}
// Check if executable exist in path
gchar* executableWithFullPath =
g_find_program_in_path(commandWithoutArgs.BeginReading());
GUniquePtr<gchar> executableWithFullPath(
g_find_program_in_path(commandWithoutArgs.BeginReading()));
if (!executableWithFullPath) {
return NS_ERROR_FILE_NOT_FOUND;
}
g_free(executableWithFullPath);
nsGIOMimeApp* mozApp = new nsGIOMimeApp(app_info);
NS_ADDREF(*appInfo = mozApp);
RefPtr<nsGIOMimeApp> mozApp = new nsGIOMimeApp(app_info.forget());
mozApp.forget(appInfo);
return NS_OK;
}

View File

@@ -12,6 +12,9 @@
#include <gtk/gtk.h>
#include "mozilla/RefPtr.h"
// TODO: Remove this (we should use GDBus instead, which is not deprecated).
#include <dbus/dbus-glib.h>
namespace mozilla {
template <typename T>
@@ -25,12 +28,17 @@ struct GObjectRefPtrTraits {
struct RefPtrTraits<type_> : public GObjectRefPtrTraits<type_> {};
GOBJECT_TRAITS(GtkWidget)
GOBJECT_TRAITS(GFile)
GOBJECT_TRAITS(GMenu)
GOBJECT_TRAITS(GMenuItem)
GOBJECT_TRAITS(GSimpleAction)
GOBJECT_TRAITS(GSimpleActionGroup)
GOBJECT_TRAITS(GDBusProxy)
GOBJECT_TRAITS(GAppInfo)
GOBJECT_TRAITS(GdkDragContext)
GOBJECT_TRAITS(GdkPixbuf)
GOBJECT_TRAITS(DBusGProxy)
#undef GOBJECT_TRAITS
@@ -40,6 +48,30 @@ struct RefPtrTraits<GVariant> {
static void Release(GVariant* aVariant) { g_variant_unref(aVariant); }
};
template <>
struct RefPtrTraits<GHashTable> {
static void AddRef(GHashTable* aObject) { g_hash_table_ref(aObject); }
static void Release(GHashTable* aObject) { g_hash_table_unref(aObject); }
};
template <>
struct RefPtrTraits<GDBusNodeInfo> {
static void AddRef(GDBusNodeInfo* aObject) { g_dbus_node_info_ref(aObject); }
static void Release(GDBusNodeInfo* aObject) {
g_dbus_node_info_unref(aObject);
}
};
template <>
struct RefPtrTraits<DBusGConnection> {
static void AddRef(DBusGConnection* aObject) {
dbus_g_connection_ref(aObject);
}
static void Release(DBusGConnection* aObject) {
dbus_g_connection_unref(aObject);
}
};
} // namespace mozilla
#endif

View File

@@ -12,14 +12,18 @@
#include "MPRISInterfaceDescription.h"
#include "mozilla/dom/MediaControlUtils.h"
#include "mozilla/GUniquePtr.h"
#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/Maybe.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Sprintf.h"
#include "nsXULAppAPI.h"
#include "nsIXULAppInfo.h"
#include "nsIOutputStream.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "WidgetUtilsGtk.h"
#include "prio.h"
#define LOGMPRIS(msg, ...) \
MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
@@ -32,19 +36,19 @@ namespace widget {
// used to form a unique image file name.
static uint32_t gImageNumber = 0;
static inline Maybe<mozilla::dom::MediaControlKey> GetMediaControlKey(
static inline Maybe<dom::MediaControlKey> GetMediaControlKey(
const gchar* aMethodName) {
const std::unordered_map<std::string, mozilla::dom::MediaControlKey> map = {
{"Raise", mozilla::dom::MediaControlKey::Focus},
{"Next", mozilla::dom::MediaControlKey::Nexttrack},
{"Previous", mozilla::dom::MediaControlKey::Previoustrack},
{"Pause", mozilla::dom::MediaControlKey::Pause},
{"PlayPause", mozilla::dom::MediaControlKey::Playpause},
{"Stop", mozilla::dom::MediaControlKey::Stop},
{"Play", mozilla::dom::MediaControlKey::Play}};
const std::unordered_map<std::string, dom::MediaControlKey> map = {
{"Raise", dom::MediaControlKey::Focus},
{"Next", dom::MediaControlKey::Nexttrack},
{"Previous", dom::MediaControlKey::Previoustrack},
{"Pause", dom::MediaControlKey::Pause},
{"PlayPause", dom::MediaControlKey::Playpause},
{"Stop", dom::MediaControlKey::Stop},
{"Play", dom::MediaControlKey::Play}};
auto it = map.find(aMethodName);
return (it == map.end() ? Nothing() : Some(it->second));
return it == map.end() ? Nothing() : Some(it->second);
}
static void HandleMethodCall(GDBusConnection* aConnection, const gchar* aSender,
@@ -56,7 +60,7 @@ static void HandleMethodCall(GDBusConnection* aConnection, const gchar* aSender,
MOZ_ASSERT(aUserData);
MOZ_ASSERT(NS_IsMainThread());
Maybe<mozilla::dom::MediaControlKey> key = GetMediaControlKey(aMethodName);
Maybe<dom::MediaControlKey> key = GetMediaControlKey(aMethodName);
if (key.isNothing()) {
g_dbus_method_invocation_return_error(
aInvocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED,
@@ -94,19 +98,18 @@ enum class Property : uint8_t {
eGetMetadata,
};
static inline Maybe<mozilla::dom::MediaControlKey> GetPairedKey(
Property aProperty) {
static inline Maybe<dom::MediaControlKey> GetPairedKey(Property aProperty) {
switch (aProperty) {
case Property::eCanRaise:
return Some(mozilla::dom::MediaControlKey::Focus);
return Some(dom::MediaControlKey::Focus);
case Property::eCanGoNext:
return Some(mozilla::dom::MediaControlKey::Nexttrack);
return Some(dom::MediaControlKey::Nexttrack);
case Property::eCanGoPrevious:
return Some(mozilla::dom::MediaControlKey::Previoustrack);
return Some(dom::MediaControlKey::Previoustrack);
case Property::eCanPlay:
return Some(mozilla::dom::MediaControlKey::Play);
return Some(dom::MediaControlKey::Play);
case Property::eCanPause:
return Some(mozilla::dom::MediaControlKey::Pause);
return Some(dom::MediaControlKey::Pause);
default:
return Nothing();
}
@@ -179,7 +182,7 @@ static GVariant* HandleGetProperty(GDBusConnection* aConnection,
case Property::eCanGoPrevious:
case Property::eCanPlay:
case Property::eCanPause:
Maybe<mozilla::dom::MediaControlKey> key = GetPairedKey(property.value());
Maybe<dom::MediaControlKey> key = GetPairedKey(property.value());
MOZ_ASSERT(key.isSome());
return g_variant_new_boolean(handler->IsMediaKeySupported(key.value()));
}
@@ -266,21 +269,18 @@ void MPRISServiceHandler::OnNameLost(GDBusConnection* aConnection,
void MPRISServiceHandler::OnBusAcquired(GDBusConnection* aConnection,
const gchar* aName) {
GError* error = nullptr;
GUniquePtr<GError> error;
LOGMPRIS("OnBusAcquired: %s", aName);
mRootRegistrationId = g_dbus_connection_register_object(
aConnection, DBUS_MPRIS_OBJECT_PATH, mIntrospectionData->interfaces[0],
&gInterfaceVTable, this, /* user_data */
nullptr, /* user_data_free_func */
&error); /* GError** */
getter_Transfers(error)); /* GError** */
if (mRootRegistrationId == 0) {
LOGMPRIS("Failed at root registration: %s",
error ? error->message : "Unknown Error");
if (error) {
g_error_free(error);
}
return;
}
@@ -288,21 +288,18 @@ void MPRISServiceHandler::OnBusAcquired(GDBusConnection* aConnection,
aConnection, DBUS_MPRIS_OBJECT_PATH, mIntrospectionData->interfaces[1],
&gInterfaceVTable, this, /* user_data */
nullptr, /* user_data_free_func */
&error); /* GError** */
getter_Transfers(error)); /* GError** */
if (mPlayerRegistrationId == 0) {
LOGMPRIS("Failed at object registration: %s",
error ? error->message : "Unknown Error");
if (error) {
g_error_free(error);
}
}
}
bool MPRISServiceHandler::Open() {
MOZ_ASSERT(!mInitialized);
MOZ_ASSERT(NS_IsMainThread());
GError* error = nullptr;
GUniquePtr<GError> error;
gchar serviceName[256];
InitIdentity();
@@ -315,14 +312,12 @@ bool MPRISServiceHandler::Open() {
OnNameAcquiredStatic, OnNameLostStatic, this, nullptr);
/* parse introspection data */
mIntrospectionData = g_dbus_node_info_new_for_xml(introspection_xml, &error);
mIntrospectionData = dont_AddRef(
g_dbus_node_info_new_for_xml(introspection_xml, getter_Transfers(error)));
if (!mIntrospectionData) {
LOGMPRIS("Failed at parsing XML Interface definition: %s",
error ? error->message : "Unknown Error");
if (error) {
g_error_free(error);
}
return false;
}
@@ -330,8 +325,9 @@ bool MPRISServiceHandler::Open() {
return true;
}
MPRISServiceHandler::MPRISServiceHandler() = default;
MPRISServiceHandler::~MPRISServiceHandler() {
MOZ_ASSERT(!mInitialized); // Close hasn't been called!
MOZ_ASSERT(!mInitialized, "Close hasn't been called!");
}
void MPRISServiceHandler::Close() {
@@ -347,9 +343,8 @@ void MPRISServiceHandler::Close() {
if (mOwnerId != 0) {
g_bus_unown_name(mOwnerId);
}
if (mIntrospectionData) {
g_dbus_node_info_unref(mIntrospectionData);
}
mIntrospectionData = nullptr;
mInitialized = false;
MediaControlKeySource::Close();
@@ -385,7 +380,7 @@ const char* MPRISServiceHandler::DesktopEntry() const {
return mDesktopEntry.get();
}
bool MPRISServiceHandler::PressKey(mozilla::dom::MediaControlKey aKey) const {
bool MPRISServiceHandler::PressKey(dom::MediaControlKey aKey) const {
MOZ_ASSERT(mInitialized);
if (!IsMediaKeySupported(aKey)) {
LOGMPRIS("%s is not supported", ToMediaControlKeyStr(aKey));
@@ -444,7 +439,7 @@ void MPRISServiceHandler::SetMediaMetadata(
// 1) MPRIS image is being fetched, and the one in fetching is in the artwork
// 2) MPRIS image is not being fetched, and the one in use is in the artwork
if (!mFetchingUrl.IsEmpty()) {
if (mozilla::dom::IsImageIn(aMetadata.mArtwork, mFetchingUrl)) {
if (dom::IsImageIn(aMetadata.mArtwork, mFetchingUrl)) {
LOGMPRIS(
"No need to load MPRIS image. The one being processed is in the "
"artwork");
@@ -454,7 +449,7 @@ void MPRISServiceHandler::SetMediaMetadata(
return;
}
} else if (!mCurrentImageUrl.IsEmpty()) {
if (mozilla::dom::IsImageIn(aMetadata.mArtwork, mCurrentImageUrl)) {
if (dom::IsImageIn(aMetadata.mArtwork, mCurrentImageUrl)) {
LOGMPRIS("No need to load MPRIS image. The one in use is in the artwork");
SetMediaMetadataInternal(aMetadata, false);
return;
@@ -508,9 +503,9 @@ void MPRISServiceHandler::LoadImageAtIndex(const size_t aIndex) {
return;
}
const mozilla::dom::MediaImage& image = mMPRISMetadata.mArtwork[aIndex];
const dom::MediaImage& image = mMPRISMetadata.mArtwork[aIndex];
if (!mozilla::dom::IsValidImageUrl(image.mSrc)) {
if (!dom::IsValidImageUrl(image.mSrc)) {
LOGMPRIS("Skip the image with invalid URL. Try next image");
LoadImageAtIndex(mNextImageIndex++);
return;
@@ -519,7 +514,7 @@ void MPRISServiceHandler::LoadImageAtIndex(const size_t aIndex) {
mImageFetchRequest.DisconnectIfExists();
mFetchingUrl = image.mSrc;
mImageFetcher = mozilla::MakeUnique<mozilla::dom::FetchImageHelper>(image);
mImageFetcher = MakeUnique<dom::FetchImageHelper>(image);
RefPtr<MPRISServiceHandler> self = this;
mImageFetcher->FetchImage()
->Then(
@@ -532,7 +527,7 @@ void MPRISServiceHandler::LoadImageAtIndex(const size_t aIndex) {
char* data = nullptr;
// Only used to hold the image data
nsCOMPtr<nsIInputStream> inputStream;
nsresult rv = mozilla::dom::GetEncodedImageBuffer(
nsresult rv = dom::GetEncodedImageBuffer(
aImage, mMimeType, getter_AddRefs(inputStream), &size, &data);
if (NS_FAILED(rv) || !inputStream || size == 0 || !data) {
LOGMPRIS("Failed to get the image buffer info. Try next image");
@@ -754,9 +749,9 @@ GVariant* MPRISServiceHandler::GetMetadataAsGVariant() const {
return g_variant_builder_end(&builder);
}
void MPRISServiceHandler::EmitEvent(mozilla::dom::MediaControlKey aKey) const {
void MPRISServiceHandler::EmitEvent(dom::MediaControlKey aKey) const {
for (const auto& listener : mListeners) {
listener->OnActionPerformed(mozilla::dom::MediaControlAction(aKey));
listener->OnActionPerformed(dom::MediaControlAction(aKey));
}
}
@@ -764,23 +759,21 @@ struct InterfaceProperty {
const char* interface;
const char* property;
};
static const std::unordered_map<mozilla::dom::MediaControlKey,
InterfaceProperty>
gKeyProperty = {{mozilla::dom::MediaControlKey::Focus,
{DBUS_MPRIS_INTERFACE, "CanRaise"}},
{mozilla::dom::MediaControlKey::Nexttrack,
static const std::unordered_map<dom::MediaControlKey, InterfaceProperty>
gKeyProperty = {
{dom::MediaControlKey::Focus, {DBUS_MPRIS_INTERFACE, "CanRaise"}},
{dom::MediaControlKey::Nexttrack,
{DBUS_MPRIS_PLAYER_INTERFACE, "CanGoNext"}},
{mozilla::dom::MediaControlKey::Previoustrack,
{dom::MediaControlKey::Previoustrack,
{DBUS_MPRIS_PLAYER_INTERFACE, "CanGoPrevious"}},
{mozilla::dom::MediaControlKey::Play,
{DBUS_MPRIS_PLAYER_INTERFACE, "CanPlay"}},
{mozilla::dom::MediaControlKey::Pause,
{dom::MediaControlKey::Play, {DBUS_MPRIS_PLAYER_INTERFACE, "CanPlay"}},
{dom::MediaControlKey::Pause,
{DBUS_MPRIS_PLAYER_INTERFACE, "CanPause"}}};
void MPRISServiceHandler::SetSupportedMediaKeys(
const MediaKeysArray& aSupportedKeys) {
uint32_t supportedKeys = 0;
for (const mozilla::dom::MediaControlKey& key : aSupportedKeys) {
for (const dom::MediaControlKey& key : aSupportedKeys) {
supportedKeys |= GetMediaKeyMask(key);
}
@@ -804,13 +797,12 @@ void MPRISServiceHandler::SetSupportedMediaKeys(
}
}
bool MPRISServiceHandler::IsMediaKeySupported(
mozilla::dom::MediaControlKey aKey) const {
bool MPRISServiceHandler::IsMediaKeySupported(dom::MediaControlKey aKey) const {
return mSupportedKeys & GetMediaKeyMask(aKey);
}
bool MPRISServiceHandler::EmitSupportedKeyChanged(
mozilla::dom::MediaControlKey aKey, bool aSupported) const {
bool MPRISServiceHandler::EmitSupportedKeyChanged(dom::MediaControlKey aKey,
bool aSupported) const {
auto it = gKeyProperty.find(aKey);
if (it == gKeyProperty.end()) {
LOGMPRIS("No property for %s", ToMediaControlKeyStr(aKey));

View File

@@ -58,11 +58,7 @@ class MPRISServiceHandler final : public dom::MediaControlKeySource {
// Note that this constructor does NOT initialize the MPRIS Service but only
// this class. The method Open() is responsible for registering and MAY FAIL.
// The image format used in MPRIS is based on the mMimeType here. Although
// IMAGE_JPEG or IMAGE_BMP are valid types as well but a png image with
// transparent background will be converted into a jpeg/bmp file with a
// colored background IMAGE_PNG format seems to be the best choice for now.
MPRISServiceHandler() : mMimeType(IMAGE_PNG){};
MPRISServiceHandler();
bool Open() override;
void Close() override;
bool IsOpened() const override;
@@ -97,13 +93,17 @@ class MPRISServiceHandler final : public dom::MediaControlKeySource {
guint mRootRegistrationId = 0;
// This is for the interface org.mpris.MediaPlayer2.Player
guint mPlayerRegistrationId = 0;
GDBusNodeInfo* mIntrospectionData = nullptr;
RefPtr<GDBusNodeInfo> mIntrospectionData;
GDBusConnection* mConnection = nullptr;
bool mInitialized = false;
nsAutoCString mIdentity;
nsAutoCString mDesktopEntry;
nsCString mMimeType;
// The image format used in MPRIS is based on the mMimeType here. Although
// IMAGE_JPEG or IMAGE_BMP are valid types as well but a png image with
// transparent background will be converted into a jpeg/bmp file with a
// colored background IMAGE_PNG format seems to be the best choice for now.
nsCString mMimeType{IMAGE_PNG};
// A bitmask indicating what keys are enabled
uint32_t mSupportedKeys = 0;
@@ -132,9 +132,8 @@ class MPRISServiceHandler final : public dom::MediaControlKeySource {
nsCOMPtr<nsIFile> mLocalImageFile;
nsCOMPtr<nsIFile> mLocalImageFolder;
mozilla::UniquePtr<mozilla::dom::FetchImageHelper> mImageFetcher;
mozilla::MozPromiseRequestHolder<mozilla::dom::ImagePromise>
mImageFetchRequest;
UniquePtr<dom::FetchImageHelper> mImageFetcher;
MozPromiseRequestHolder<dom::ImagePromise> mImageFetchRequest;
nsString mFetchingUrl;
nsString mCurrentImageUrl;
@@ -174,7 +173,7 @@ class MPRISServiceHandler final : public dom::MediaControlKeySource {
void SetMediaMetadataInternal(const dom::MediaMetadataBase& aMetadata,
bool aClearArtUrl = true);
bool EmitSupportedKeyChanged(mozilla::dom::MediaControlKey aKey,
bool EmitSupportedKeyChanged(dom::MediaControlKey aKey,
bool aSupported) const;
bool EmitPropertiesChangedSignal(GVariant* aParameters) const;

View File

@@ -19,6 +19,7 @@
#include "mozilla/ProfilerLabels.h"
#include "mozilla/ProfilerThreadSleep.h"
#include "mozilla/Unused.h"
#include "mozilla/GUniquePtr.h"
#include "mozilla/WidgetUtils.h"
#include "nsIPowerManagerService.h"
#ifdef MOZ_ENABLE_DBUS
@@ -37,8 +38,7 @@
# include "nsWaylandDisplay.h"
#endif
using mozilla::LazyLogModule;
using mozilla::Unused;
using namespace mozilla;
using mozilla::widget::HeadlessScreenHelper;
using mozilla::widget::ScreenHelperGTK;
using mozilla::widget::ScreenManager;
@@ -195,13 +195,12 @@ static DBusHandlerResult ConnectionSignalFilter(DBusConnection* aConnection,
// https://github.com/lcp/NetworkManager/blob/240f47c892b4e935a3e92fc09eb15163d1fa28d8/src/nm-sleep-monitor-systemd.c
// Use login1 to signal sleep and wake notifications.
void nsAppShell::StartDBusListening() {
GError* error = nullptr;
mDBusConnection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
GUniquePtr<GError> error;
mDBusConnection = dbus_g_bus_get(DBUS_BUS_SYSTEM, getter_Transfers(error));
if (!mDBusConnection) {
NS_WARNING(nsPrintfCString("gds: Failed to open connection to bus %s\n",
error->message)
.get());
g_error_free(error);
return;
}

View File

@@ -833,7 +833,7 @@ void nsClipboard::SelectionGetEvent(GtkClipboard* aClipboard,
return;
}
GdkPixbuf* pixbuf = nsImageToPixbuf::ImageToPixbuf(image);
RefPtr<GdkPixbuf> pixbuf = nsImageToPixbuf::ImageToPixbuf(image);
if (!pixbuf) {
LOGCLIP(" nsImageToPixbuf::ImageToPixbuf() failed!\n");
return;
@@ -842,7 +842,6 @@ void nsClipboard::SelectionGetEvent(GtkClipboard* aClipboard,
LOGCLIP(" Setting pixbuf image data as %s\n",
GUniquePtr<gchar>(gdk_atom_name(selectionTarget)).get());
gtk_selection_data_set_pixbuf(aSelectionData, pixbuf);
g_object_unref(pixbuf);
return;
}

View File

@@ -1820,14 +1820,13 @@ void nsDragService::SourceDataGet(GtkWidget* aWidget, GdkDragContext* aContext,
LOGDRAGSERVICE((" do_QueryInterface failed\n"));
return;
}
GdkPixbuf* pixbuf = nsImageToPixbuf::ImageToPixbuf(image);
RefPtr<GdkPixbuf> pixbuf = nsImageToPixbuf::ImageToPixbuf(image);
if (!pixbuf) {
LOGDRAGSERVICE((" ImageToPixbuf failed\n"));
return;
}
gtk_selection_data_set_pixbuf(aSelectionData, pixbuf);
LOGDRAGSERVICE((" image data set\n"));
g_object_unref(pixbuf);
} else {
void* tmpData = nullptr;
uint32_t tmpDataLen = 0;
@@ -1955,12 +1954,11 @@ void nsDragService::SetDragIcon(GdkDragContext* aContext) {
}
} else if (surface) {
if (!SetAlphaPixmap(surface, aContext, offsetX, offsetY, dragRect)) {
GdkPixbuf* dragPixbuf = nsImageToPixbuf::SourceSurfaceToPixbuf(
RefPtr<GdkPixbuf> dragPixbuf = nsImageToPixbuf::SourceSurfaceToPixbuf(
surface, dragRect.width, dragRect.height);
if (dragPixbuf) {
LOGDRAGSERVICE((" set drag pixbuf"));
gtk_drag_set_icon_pixbuf(aContext, dragPixbuf, offsetX, offsetY);
g_object_unref(dragPixbuf);
}
}
}

View File

@@ -10,6 +10,8 @@
#include "imgIContainer.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/RefPtr.h"
#include "GRefPtr.h"
#include "nsCOMPtr.h"
using mozilla::gfx::DataSourceSurface;
using mozilla::gfx::SurfaceFormat;
@@ -20,7 +22,7 @@ inline unsigned char unpremultiply(unsigned char color, unsigned char alpha) {
return (color * 255 + alpha / 2) / alpha;
}
GdkPixbuf* nsImageToPixbuf::ImageToPixbuf(
already_AddRefed<GdkPixbuf> nsImageToPixbuf::ImageToPixbuf(
imgIContainer* aImage, const mozilla::Maybe<nsIntSize>& aOverrideSize) {
RefPtr<SourceSurface> surface;
@@ -55,15 +57,14 @@ GdkPixbuf* nsImageToPixbuf::ImageToPixbuf(
surface->GetSize().height);
}
GdkPixbuf* nsImageToPixbuf::SourceSurfaceToPixbuf(SourceSurface* aSurface,
int32_t aWidth,
int32_t aHeight) {
already_AddRefed<GdkPixbuf> nsImageToPixbuf::SourceSurfaceToPixbuf(
SourceSurface* aSurface, int32_t aWidth, int32_t aHeight) {
MOZ_ASSERT(aWidth <= aSurface->GetSize().width &&
aHeight <= aSurface->GetSize().height,
"Requested rect is bigger than the supplied surface");
GdkPixbuf* pixbuf =
gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, aWidth, aHeight);
RefPtr<GdkPixbuf> pixbuf =
dont_AddRef(gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, aWidth, aHeight));
if (!pixbuf) {
return nullptr;
}
@@ -116,5 +117,5 @@ GdkPixbuf* nsImageToPixbuf::SourceSurfaceToPixbuf(SourceSurface* aSurface,
dataSurface->Unmap();
return pixbuf;
return pixbuf.forget();
}

View File

@@ -8,6 +8,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "nsSize.h"
class imgIContainer;
@@ -23,15 +24,11 @@ class nsImageToPixbuf final {
public:
// Friendlier version of ConvertImageToPixbuf for callers inside of
// widget
/**
* The return value of all these, if not null, should be
* released as needed by the caller using g_object_unref.
*/
static GdkPixbuf* ImageToPixbuf(
static already_AddRefed<GdkPixbuf> ImageToPixbuf(
imgIContainer* aImage,
const mozilla::Maybe<nsIntSize>& aOverrideSize = mozilla::Nothing());
static GdkPixbuf* SourceSurfaceToPixbuf(SourceSurface* aSurface,
int32_t aWidth, int32_t aHeight);
static already_AddRefed<GdkPixbuf> SourceSurfaceToPixbuf(
SourceSurface* aSurface, int32_t aWidth, int32_t aHeight);
private:
~nsImageToPixbuf() = default;

View File

@@ -176,17 +176,16 @@ nsLookAndFeel::nsLookAndFeel() {
nsWindow::GetSystemGtkWindowDecoration() != nsWindow::GTK_DECORATION_NONE;
if (ShouldUsePortal(PortalKind::Settings)) {
GError* error = nullptr;
mDBusSettingsProxy = g_dbus_proxy_new_for_bus_sync(
GUniquePtr<GError> error;
mDBusSettingsProxy = dont_AddRef(g_dbus_proxy_new_for_bus_sync(
G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, nullptr,
"org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Settings", nullptr, &error);
"org.freedesktop.portal.Settings", nullptr, getter_Transfers(error)));
if (mDBusSettingsProxy) {
g_signal_connect(mDBusSettingsProxy, "g-signal",
G_CALLBACK(settings_changed_signal_cb), nullptr);
} else {
LOGLNF("Can't create DBus proxy for settings: %s\n", error->message);
g_error_free(error);
}
}
}
@@ -196,7 +195,7 @@ nsLookAndFeel::~nsLookAndFeel() {
g_signal_handlers_disconnect_by_func(
mDBusSettingsProxy, FuncToGpointer(settings_changed_signal_cb),
nullptr);
g_object_unref(mDBusSettingsProxy);
mDBusSettingsProxy = nullptr;
}
g_signal_handlers_disconnect_by_func(
gtk_settings_get_default(), FuncToGpointer(settings_changed_cb), nullptr);
@@ -1316,15 +1315,15 @@ Maybe<ColorScheme> nsLookAndFeel::ComputeColorSchemeSetting() {
if (!mDBusSettingsProxy) {
return Nothing();
}
GError* error = nullptr;
GUniquePtr<GError> error;
RefPtr<GVariant> variant = dont_AddRef(g_dbus_proxy_call_sync(
mDBusSettingsProxy, "Read",
g_variant_new("(ss)", "org.freedesktop.appearance", "color-scheme"),
G_DBUS_CALL_FLAGS_NONE,
StaticPrefs::widget_gtk_settings_portal_timeout_ms(), nullptr, &error));
StaticPrefs::widget_gtk_settings_portal_timeout_ms(), nullptr,
getter_Transfers(error)));
if (!variant) {
LOGLNF("color-scheme query error: %s\n", error->message);
g_error_free(error);
return Nothing();
}
LOGLNF("color-scheme query result: %s\n", GVariantToString(variant).get());

View File

@@ -150,7 +150,7 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
return mSystemThemeOverridden ? mAltTheme : mSystemTheme;
}
GDBusProxy* mDBusSettingsProxy = nullptr;
RefPtr<GDBusProxy> mDBusSettingsProxy;
mozilla::Maybe<ColorScheme> mColorSchemePreference;
int32_t mCaretBlinkTime = 0;
int32_t mCaretBlinkCount = -1;

View File

@@ -27,6 +27,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Components.h"
#include "mozilla/GRefPtr.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/WheelEventBinding.h"
#include "mozilla/gfx/2D.h"
@@ -3064,7 +3065,7 @@ static GdkCursor* GetCursorForImage(const nsIWidget::Cursor& aCursor,
}
nsIntSize rasterSize = size * gtkScale;
GdkPixbuf* pixbuf =
RefPtr<GdkPixbuf> pixbuf =
nsImageToPixbuf::ImageToPixbuf(aCursor.mContainer, Some(rasterSize));
if (!pixbuf) {
return nullptr;
@@ -3074,17 +3075,14 @@ static GdkCursor* GetCursorForImage(const nsIWidget::Cursor& aCursor,
// is of course not documented anywhere...
// So add one if there isn't one yet
if (!gdk_pixbuf_get_has_alpha(pixbuf)) {
GdkPixbuf* alphaBuf = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0);
g_object_unref(pixbuf);
pixbuf = alphaBuf;
if (!alphaBuf) {
RefPtr<GdkPixbuf> alphaBuf =
dont_AddRef(gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0));
pixbuf = std::move(alphaBuf);
if (!pixbuf) {
return nullptr;
}
}
auto CleanupPixBuf =
mozilla::MakeScopeExit([&]() { g_object_unref(pixbuf); });
cairo_surface_t* surface =
gdk_cairo_surface_create_from_pixbuf(pixbuf, gtkScale, nullptr);
if (!surface) {
@@ -3092,7 +3090,7 @@ static GdkCursor* GetCursorForImage(const nsIWidget::Cursor& aCursor,
}
auto CleanupSurface =
mozilla::MakeScopeExit([&]() { cairo_surface_destroy(surface); });
MakeScopeExit([&]() { cairo_surface_destroy(surface); });
return gdk_cursor_new_from_surface(gdk_display_get_default(), surface,
aCursor.mHotspotX, aCursor.mHotspotY);