Implement GNOME Settings Daemon MediaKeys handling.

Clean up some warnings.
This commit is contained in:
Joshua Strobl 2021-04-06 15:35:01 +03:00
parent 43ebe6d041
commit e18b8ca100
5 changed files with 210 additions and 10 deletions

View file

@ -88,10 +88,6 @@ static void koto_playerbar_constructed(GObject *obj) {
gtk_range_set_increments(GTK_RANGE(self->progress_bar), 1, 1); gtk_range_set_increments(GTK_RANGE(self->progress_bar), 1, 1);
gtk_range_set_round_digits(GTK_RANGE(self->progress_bar), 1); gtk_range_set_round_digits(GTK_RANGE(self->progress_bar), 1);
GtkEventController *scroll_controller = gtk_event_controller_scroll_new(GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL);
g_signal_connect(scroll_controller, "scroll-begin", G_CALLBACK(koto_playerbar_handle_progressbar_scroll_begin), self);
gtk_widget_add_controller(GTK_WIDGET(self->progress_bar), scroll_controller);
GtkGesture *press_controller = gtk_gesture_click_new(); // Create a new GtkGestureLongPress GtkGesture *press_controller = gtk_gesture_click_new(); // Create a new GtkGestureLongPress
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(press_controller), 1); // Set to left click gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(press_controller), 1); // Set to left click
@ -241,7 +237,6 @@ void koto_playerbar_create_secondary_controls(KotoPlayerBar* bar) {
if (GTK_IS_VOLUME_BUTTON(bar->volume_button)) { if (GTK_IS_VOLUME_BUTTON(bar->volume_button)) {
GtkAdjustment *granular_volume_change = gtk_adjustment_new(0.5, 0, 1.0, 0.02, 0.02, 0.02); GtkAdjustment *granular_volume_change = gtk_adjustment_new(0.5, 0, 1.0, 0.02, 0.02, 0.02);
g_object_set(bar->volume_button, "use-symbolic", TRUE, NULL); g_object_set(bar->volume_button, "use-symbolic", TRUE, NULL);
gtk_range_set_round_digits(GTK_RANGE(bar->volume_button), FALSE);
gtk_scale_button_set_adjustment(GTK_SCALE_BUTTON(bar->volume_button), granular_volume_change); // Set our adjustment gtk_scale_button_set_adjustment(GTK_SCALE_BUTTON(bar->volume_button), granular_volume_change); // Set our adjustment
gtk_box_append(GTK_BOX(bar->secondary_controls_section), bar->volume_button); gtk_box_append(GTK_BOX(bar->secondary_controls_section), bar->volume_button);
@ -290,10 +285,6 @@ void koto_playerbar_handle_is_paused(KotoPlaybackEngine *engine, gpointer user_d
koto_button_show_image(bar->play_pause_button, FALSE); // Set to FALSE to show play as the next action koto_button_show_image(bar->play_pause_button, FALSE); // Set to FALSE to show play as the next action
} }
void koto_playerbar_handle_progressbar_scroll_begin(GtkEventControllerScroll *controller, gpointer data){
(void) controller;
}
void koto_playerbar_handle_progressbar_gesture_begin(GtkGesture *gesture, GdkEventSequence *seq, gpointer data) { void koto_playerbar_handle_progressbar_gesture_begin(GtkGesture *gesture, GdkEventSequence *seq, gpointer data) {
(void) gesture; (void) seq; (void) gesture; (void) seq;
KotoPlayerBar *bar = data; KotoPlayerBar *bar = data;

View file

@ -19,6 +19,7 @@
#include <gstreamer-1.0/gst/gst.h> #include <gstreamer-1.0/gst/gst.h>
#include "db/cartographer.h" #include "db/cartographer.h"
#include "db/db.h" #include "db/db.h"
#include "playback/media-keys.h"
#include "playback/mimes.h" #include "playback/mimes.h"
#include "playback/mpris.h" #include "playback/mpris.h"
@ -43,6 +44,8 @@ static void on_activate (GtkApplication *app) {
main_window = gtk_application_get_active_window (app); main_window = gtk_application_get_active_window (app);
if (main_window == NULL) { if (main_window == NULL) {
main_window = g_object_new(KOTO_TYPE_WINDOW, "application", app, "default-width", 1200, "default-height", 675, NULL); main_window = g_object_new(KOTO_TYPE_WINDOW, "application", app, "default-width", 1200, "default-height", 675, NULL);
setup_mpris_interfaces(); // Set up our MPRIS interfaces
setup_mediakeys_interface(); // Set up our media key support
} }
gtk_window_present(main_window); gtk_window_present(main_window);
@ -72,7 +75,6 @@ int main (int argc, char *argv[]) {
koto_maps = koto_cartographer_new(); // Create our new cartographer and their collection of maps koto_maps = koto_cartographer_new(); // Create our new cartographer and their collection of maps
open_db(); // Open our database open_db(); // Open our database
setup_mpris_interfaces(); // Set up our MPRIS interfaces
app = gtk_application_new ("com.github.joshstrobl.koto", G_APPLICATION_FLAGS_NONE); app = gtk_application_new ("com.github.joshstrobl.koto", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);

View file

@ -12,6 +12,7 @@ koto_sources = [
'pages/music/disc-view.c', 'pages/music/disc-view.c',
'pages/music/music-local.c', 'pages/music/music-local.c',
'playback/engine.c', 'playback/engine.c',
'playback/media-keys.c',
'playback/mimes.c', 'playback/mimes.c',
'playback/mpris.c', 'playback/mpris.c',
'playlist/current.c', 'playlist/current.c',

174
src/playback/media-keys.c Normal file
View file

@ -0,0 +1,174 @@
/* media-keys.c
*
* Copyright 2021 Joshua Strobl
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <glib-2.0/glib.h>
#include <glib-2.0/gio/gio.h>
#include <gtk-4.0/gtk/gtk.h>
#include "engine.h"
#include "media-keys.h"
extern GtkWindow *main_window;
extern KotoPlaybackEngine *playback_engine;
GDBusConnection *media_keys_dbus_conn = NULL;
GDBusProxy *media_keys_proxy = NULL;
GDBusNodeInfo *media_keys_introspection_data = NULL;
static const gchar introspection_xml[] =
"<node name='/org/gnome/SettingsDaemon/MediaKeys'>"
" <interface name='org.gnome.SettingsDaemon.MediaKeys'>"
" <annotation name='org.freedesktop.DBus.GLib.CSymbol' value='gsd_media_keys_manager'/>"
" <method name='GrabMediaPlayerKeys'>"
" <arg name='application' direction='in' type='s'/>"
" <arg name='time' direction='in' type='u'/>"
" </method>"
" <method name='ReleaseMediaPlayerKeys'>"
" <arg name='application' direction='in' type='s'/>"
" </method>"
" <signal name='MediaPlayerKeyPressed'>"
" <arg name='application' type='s'/>"
" <arg name='key' type='s'/>"
" </signal>"
" </interface>"
"</node>";
void grab_media_keys() {
if (media_keys_proxy == NULL) { // No connection
return;
}
g_dbus_proxy_call(
media_keys_proxy,
"GrabMediaPlayerKeys",
g_variant_new("(su)", "com.github.joshstrobl.koto", 0),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
handle_media_keys_async_done,
NULL
);
}
void handle_media_keys_async_done(GObject *source_object, GAsyncResult *res, gpointer user_data) {
(void) user_data;
g_dbus_proxy_call_finish(G_DBUS_PROXY(source_object), res, NULL); // Ensure we finish our call
}
void handle_media_keys_signal(GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) {
(void) proxy; (void) sender_name; (void) user_data;
if (g_strcmp0(signal_name, "MediaPlayerKeyPressed") != 0) { // Not MediaPlayerKeyPressed
return;
}
gchar *application_name = NULL;
gchar *key = NULL;
g_variant_get(parameters, "(ss)", &application_name, &key);
if (g_strcmp0(application_name, "com.github.joshstrobl.koto") != 0) { // Not for Koto
return;
}
if (g_strcmp0(key, "Play") == 0) {
koto_playback_engine_play(playback_engine);
} else if (g_strcmp0(key, "Pause") == 0) {
koto_playback_engine_pause(playback_engine);
} else if (g_strcmp0(key, "Stop") == 0) {
koto_playback_engine_stop(playback_engine);
} else if (g_strcmp0(key, "Previous") == 0) {
koto_playback_engine_backwards(playback_engine);
} else if (g_strcmp0(key, "Next") == 0) {
koto_playback_engine_forwards(playback_engine);
} else if (g_strcmp0(key, "Repeat") == 0) {
koto_playback_engine_toggle_track_repeat(playback_engine);
} else if (g_strcmp0(key, "Shuffle") == 0) {
koto_playback_engine_toggle_track_shuffle(playback_engine);
}
}
void handle_window_enter(GtkEventControllerFocus *controller, gpointer user_data) {
grab_media_keys(); // Grab our media keys
}
void handle_window_leave(GtkEventControllerFocus *controller, gpointer user_data) {
release_media_keys(); // Release our media keys
}
void release_media_keys() {
if (media_keys_dbus_conn == NULL) { // No connection
return;
}
GVariant *params = g_variant_new_string(g_strdup("com.github.joshstrobl.koto"));
g_dbus_proxy_call(
media_keys_proxy,
"ReleaseMediaPlayerKeys",
params,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
handle_media_keys_async_done,
NULL
);
}
void setup_mediakeys_interface() {
media_keys_introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
g_assert(media_keys_introspection_data != NULL);
GDBusConnection *bus;
GError *error = NULL;
bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
if (bus == NULL) { // Failed to get session bus
g_printerr("Failed to get our session bus: %s\n", error->message);
g_error_free(error);
return;
}
media_keys_proxy = g_dbus_proxy_new_sync(
bus,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"org.gnome.SettingsDaemon.MediaKeys",
"/org/gnome/SettingsDaemon/MediaKeys",
"org.gnome.SettingsDaemon.MediaKeys",
NULL,
&error
);
if (media_keys_proxy == NULL) {
g_printerr("Failed to get a proxy to GNOME Settings Daemon Media-Keys: %s\n", error->message);
g_error_free(error);
return;
}
g_signal_connect_object(
media_keys_proxy,
"g-signal",
G_CALLBACK(handle_media_keys_signal),
NULL,
0
);
GtkEventController *focus_controller = gtk_event_controller_focus_new(); // Create a new focus controller
g_signal_connect(focus_controller, "enter", G_CALLBACK(handle_window_enter), NULL);
g_signal_connect(focus_controller, "leave", G_CALLBACK(handle_window_leave), NULL);
gtk_widget_add_controller(GTK_WIDGET(main_window), focus_controller);
}

32
src/playback/media-keys.h Normal file
View file

@ -0,0 +1,32 @@
/* media-keys.h
*
* Copyright 2021 Joshua Strobl
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <glib-2.0/glib.h>
#include <glib-2.0/gio/gio.h>
#include <gtk-4.0/gtk/gtk.h>
G_BEGIN_DECLS
void grab_media_keys();
void handle_media_keys_async_done(GObject *source_object, GAsyncResult *res, gpointer user_data);
void handle_media_keys_signal(GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data);
void handle_window_enter(GtkEventControllerFocus *controller, gpointer user_data);
void handle_window_leave(GtkEventControllerFocus *controller, gpointer user_data);
void release_media_keys();
void setup_mediakeys_interface();
G_END_DECLS