157 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| This file is part of Telegram Desktop,
 | |
| the official desktop application for the Telegram messaging service.
 | |
| 
 | |
| For license and copyright information please follow this link:
 | |
| https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | |
| */
 | |
| #include "platform/linux/linux_gsd_media_keys.h"
 | |
| 
 | |
| #include "core/sandbox.h"
 | |
| #include "media/player/media_player_instance.h"
 | |
| #include "base/platform/linux/base_linux_glibmm_helper.h"
 | |
| #include "base/platform/linux/base_linux_dbus_utilities.h"
 | |
| 
 | |
| #include <glibmm.h>
 | |
| #include <giomm.h>
 | |
| 
 | |
| namespace Platform {
 | |
| namespace internal {
 | |
| namespace {
 | |
| 
 | |
| constexpr auto kService = "org.gnome.SettingsDaemon.MediaKeys"_cs;
 | |
| constexpr auto kOldService = "org.gnome.SettingsDaemon"_cs;
 | |
| constexpr auto kMATEService = "org.mate.SettingsDaemon"_cs;
 | |
| constexpr auto kObjectPath = "/org/gnome/SettingsDaemon/MediaKeys"_cs;
 | |
| constexpr auto kMATEObjectPath = "/org/mate/SettingsDaemon/MediaKeys"_cs;
 | |
| constexpr auto kInterface = kService;
 | |
| constexpr auto kMATEInterface = "org.mate.SettingsDaemon.MediaKeys"_cs;
 | |
| 
 | |
| void KeyPressed(
 | |
| 		const Glib::RefPtr<Gio::DBus::Connection> &connection,
 | |
| 		const Glib::ustring &sender_name,
 | |
| 		const Glib::ustring &object_path,
 | |
| 		const Glib::ustring &interface_name,
 | |
| 		const Glib::ustring &signal_name,
 | |
| 		const Glib::VariantContainerBase ¶meters) {
 | |
| 	try {
 | |
| 		auto parametersCopy = parameters;
 | |
| 
 | |
| 		const auto app = base::Platform::GlibVariantCast<Glib::ustring>(
 | |
| 			parametersCopy.get_child(0));
 | |
| 
 | |
| 		const auto key = base::Platform::GlibVariantCast<Glib::ustring>(
 | |
| 			parametersCopy.get_child(1));
 | |
| 
 | |
| 		if (app != QCoreApplication::applicationName().toStdString()) {
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		Core::Sandbox::Instance().customEnterFromEventLoop([&] {
 | |
| 			if (key == "Play") {
 | |
| 				Media::Player::instance()->playPause();
 | |
| 			} else if (key == "Stop") {
 | |
| 				Media::Player::instance()->stop();
 | |
| 			} else if (key == "Next") {
 | |
| 				Media::Player::instance()->next();
 | |
| 			} else if (key == "Previous") {
 | |
| 				Media::Player::instance()->previous();
 | |
| 			}
 | |
| 		});
 | |
| 	} catch (...) {
 | |
| 	}
 | |
| }
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| class GSDMediaKeys::Private {
 | |
| public:
 | |
| 	Glib::RefPtr<Gio::DBus::Connection> dbusConnection;
 | |
| 
 | |
| 	Glib::ustring service;
 | |
| 	Glib::ustring objectPath;
 | |
| 	Glib::ustring interface;
 | |
| 	uint signalId = 0;
 | |
| 	bool grabbed = false;
 | |
| };
 | |
| 
 | |
| GSDMediaKeys::GSDMediaKeys()
 | |
| : _private(std::make_unique<Private>()) {
 | |
| 	try {
 | |
| 		_private->dbusConnection = Gio::DBus::Connection::get_sync(
 | |
| 			Gio::DBus::BusType::BUS_TYPE_SESSION);
 | |
| 
 | |
| 		if (base::Platform::DBus::NameHasOwner(
 | |
| 			_private->dbusConnection,
 | |
| 			std::string(kService))) {
 | |
| 			_private->service = std::string(kService);
 | |
| 			_private->objectPath = std::string(kObjectPath);
 | |
| 			_private->interface = std::string(kInterface);
 | |
| 		} else if (base::Platform::DBus::NameHasOwner(
 | |
| 			_private->dbusConnection,
 | |
| 			std::string(kOldService))) {
 | |
| 			_private->service = std::string(kOldService);
 | |
| 			_private->objectPath = std::string(kObjectPath);
 | |
| 			_private->interface = std::string(kInterface);
 | |
| 		} else if (base::Platform::DBus::NameHasOwner(
 | |
| 			_private->dbusConnection,
 | |
| 			std::string(kMATEService))) {
 | |
| 			_private->service = std::string(kMATEService);
 | |
| 			_private->objectPath = std::string(kMATEObjectPath);
 | |
| 			_private->interface = std::string(kMATEInterface);
 | |
| 		} else {
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		_private->dbusConnection->call_sync(
 | |
| 			_private->objectPath,
 | |
| 			_private->interface,
 | |
| 			"GrabMediaPlayerKeys",
 | |
| 			base::Platform::MakeGlibVariant(std::tuple{
 | |
| 				Glib::ustring(
 | |
| 					QCoreApplication::applicationName()
 | |
| 						.toStdString()),
 | |
| 				uint(0),
 | |
| 			}),
 | |
| 			_private->service);
 | |
| 
 | |
| 		_private->grabbed = true;
 | |
| 
 | |
| 		_private->signalId = _private->dbusConnection->signal_subscribe(
 | |
| 			sigc::ptr_fun(KeyPressed),
 | |
| 			_private->service,
 | |
| 			_private->interface,
 | |
| 			"MediaPlayerKeyPressed",
 | |
| 			_private->objectPath);
 | |
| 	} catch (...) {
 | |
| 	}
 | |
| }
 | |
| 
 | |
| GSDMediaKeys::~GSDMediaKeys() {
 | |
| 	if (_private->dbusConnection) {
 | |
| 		if (_private->signalId != 0) {
 | |
| 			_private->dbusConnection->signal_unsubscribe(_private->signalId);
 | |
| 		}
 | |
| 
 | |
| 		if (_private->grabbed) {
 | |
| 			try {
 | |
| 				_private->dbusConnection->call_sync(
 | |
| 					_private->objectPath,
 | |
| 					_private->interface,
 | |
| 					"ReleaseMediaPlayerKeys",
 | |
| 					base::Platform::MakeGlibVariant(std::tuple{
 | |
| 						Glib::ustring(
 | |
| 							QCoreApplication::applicationName()
 | |
| 								.toStdString())
 | |
| 					}),
 | |
| 					_private->service);
 | |
| 
 | |
| 				_private->grabbed = false;
 | |
| 			} catch (...) {
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| } // namespace internal
 | |
| } // namespace Platform
 | 
