diff --git a/src/meson.build b/src/meson.build index 8bca3dd8e8cd1b19146cf3b6669c55782726835d..2757c4118dbe6789e7fa70265f5d5ce08b67a0b2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -22,6 +22,7 @@ phosh_resources = gnome.compile_resources( wl_protos = [ '/'.join([wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml']), + '../protocol/gamma-control.xml', '../protocol/idle.xml', '../protocol/phosh-private.xml', '../protocol/wlr-input-inhibitor-unstable-v1.xml', diff --git a/src/monitor-manager.c b/src/monitor-manager.c index f47afb7cee4f0915376bb8f23dd40b452c1ee82d..2b54cfdb2da8250220e0c905320e83cb3806db9e 100644 --- a/src/monitor-manager.c +++ b/src/monitor-manager.c @@ -10,8 +10,13 @@ #include "monitor-manager.h" #include "monitor/monitor.h" + +#include "gamma-control-client-protocol.h" +#include "phosh.h" + #include <gdk/gdkwayland.h> + static void phosh_monitor_manager_display_config_init ( PhoshDisplayDbusOrgGnomeMutterDisplayConfigIface *iface); @@ -135,6 +140,7 @@ phosh_monitor_manager_handle_get_resources ( return TRUE; } + static gboolean phosh_monitor_manager_handle_change_backlight ( PhoshDisplayDbusOrgGnomeMutterDisplayConfig *skeleton, @@ -148,6 +154,52 @@ phosh_monitor_manager_handle_change_backlight ( } +struct get_wl_gamma_callback_data { + PhoshDisplayDbusOrgGnomeMutterDisplayConfig *skeleton; + GDBusMethodInvocation *invocation; +}; + + +static void handle_wl_gamma_size(void *data, struct gamma_control *gamma_control, + uint32_t size) { + struct get_wl_gamma_callback_data *gamma_callback_data = data; + GBytes *red_bytes, *green_bytes, *blue_bytes; + GVariant *red_v, *green_v, *blue_v; + /* All known clients using libgnome-desktop's + gnome_rr_crtc_get_gamma only do so to get the size of the gamma + table. So don't bother getting the real table since this is not + supported by wlroots: https://github.com/swaywm/wlroots/pull/1059. + Return an empty table instead. + */ + size *= sizeof(unsigned short); + red_bytes = g_bytes_new_take (g_malloc0 (size), size); + green_bytes = g_bytes_new_take (g_malloc0 (size), size); + blue_bytes = g_bytes_new_take (g_malloc0 (size), size); + + red_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), red_bytes, TRUE); + green_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), green_bytes, TRUE); + blue_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), blue_bytes, TRUE); + + phosh_display_dbus_org_gnome_mutter_display_config_complete_get_crtc_gamma ( + gamma_callback_data->skeleton, + gamma_callback_data->invocation, + red_v, green_v, blue_v); + + g_bytes_unref (red_bytes); + g_bytes_unref (green_bytes); + g_bytes_unref (blue_bytes); + + g_free (gamma_callback_data); + gamma_control_destroy (gamma_control); +} + + +static const struct +gamma_control_listener gamma_control_listener = { + .gamma_size = handle_wl_gamma_size, +}; + + static gboolean phosh_monitor_manager_handle_get_crtc_gamma ( PhoshDisplayDbusOrgGnomeMutterDisplayConfig *skeleton, @@ -155,8 +207,47 @@ phosh_monitor_manager_handle_get_crtc_gamma ( guint serial, guint crtc_id) { - g_debug ("Unimplemented DBus call %s\n", __func__); - return FALSE; + PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (skeleton); + PhoshMonitor *monitor; + struct gamma_control *gamma_control; + struct gamma_control_manager *gamma_control_manager; + struct get_wl_gamma_callback_data *data;; + + g_debug ("DBus call %s for crtc %d, serial %d\n", __func__, crtc_id, serial); + + if (serial != self->serial) { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + "The requested configuration is based on stale information"); + return TRUE; + } + + if (crtc_id >= self->monitors->len) { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Invalid crtc id %d", crtc_id); + return TRUE; + } + + gamma_control_manager = phosh_shell_get_wl_gamma_control_manager (); + if (gamma_control_manager == NULL) { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_NOT_SUPPORTED, + "gamma control not supported"); + return TRUE; + } + + data = g_new0 (struct get_wl_gamma_callback_data, 1); + data->skeleton = skeleton; + data->invocation = invocation; + + monitor = g_ptr_array_index (self->monitors, crtc_id); + gamma_control = gamma_control_manager_get_gamma_control ( + gamma_control_manager, + monitor->wl_output); + gamma_control_add_listener (gamma_control, &gamma_control_listener, data); + + return TRUE; } @@ -170,8 +261,87 @@ phosh_monitor_manager_handle_set_crtc_gamma ( GVariant *green_v, GVariant *blue_v) { - g_debug ("Unimplemented DBus call %s\n", __func__); - return FALSE; + PhoshMonitorManager *self = PHOSH_MONITOR_MANAGER (skeleton); + PhoshMonitor *monitor; + unsigned short *red, *green, *blue; + GBytes *red_bytes, *green_bytes, *blue_bytes; + gsize size, dummy; + struct gamma_control_manager *gamma_control_manager; + struct gamma_control *gamma_control; + struct wl_array wl_red, wl_green, wl_blue; + + g_debug ("DBus call %s for crtc %d, serial %d\n", __func__, crtc_id, serial); + if (serial != self->serial) { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + "The requested configuration is based on stale information"); + return TRUE; + } + + if (crtc_id >= self->monitors->len) { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Invalid crtc id"); + return TRUE; + } + + gamma_control_manager = phosh_shell_get_wl_gamma_control_manager (); + if (!gamma_control_manager) { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_NOT_SUPPORTED, + "gamma control not supported"); + return TRUE; + } + + monitor = g_ptr_array_index (self->monitors, crtc_id); + + red_bytes = g_variant_get_data_as_bytes (red_v); + green_bytes = g_variant_get_data_as_bytes (green_v); + blue_bytes = g_variant_get_data_as_bytes (blue_v); + + size = g_bytes_get_size (red_bytes); + if (size != g_bytes_get_size (blue_bytes) || size != g_bytes_get_size (green_bytes)) { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_NOT_SUPPORTED, + "gamma for each color must have same size"); + goto err; + } + + red = (unsigned short*) g_bytes_get_data (red_bytes, &dummy); + green = (unsigned short*) g_bytes_get_data (green_bytes, &dummy); + blue = (unsigned short*) g_bytes_get_data (blue_bytes, &dummy); + + wl_array_init (&wl_red); + wl_array_init (&wl_green); + wl_array_init (&wl_blue); + + wl_array_add (&wl_red, size); + wl_array_add (&wl_green, size); + wl_array_add (&wl_blue, size); + + memcpy(wl_red.data, red, size); + memcpy(wl_green.data, green, size); + memcpy(wl_blue.data, blue, size); + + gamma_control = gamma_control_manager_get_gamma_control ( + gamma_control_manager, + monitor->wl_output); + gamma_control_set_gamma(gamma_control, &wl_red, &wl_green, &wl_blue); + gamma_control_destroy (gamma_control); + + phosh_display_dbus_org_gnome_mutter_display_config_complete_set_crtc_gamma ( + skeleton, + invocation); + + wl_array_release (&wl_red); + wl_array_release (&wl_green); + wl_array_release (&wl_blue); + + err: + g_bytes_unref (red_bytes); + g_bytes_unref (green_bytes); + g_bytes_unref (blue_bytes); + return TRUE; } #define MODE_FORMAT "(siiddada{sv})" diff --git a/src/monitor-manager.h b/src/monitor-manager.h index f882d4ade0906930f9fdc7c40851e47eb66384b0..1f8e3c5538229bbc64912170636d46568e58f07c 100644 --- a/src/monitor-manager.h +++ b/src/monitor-manager.h @@ -13,9 +13,11 @@ G_DECLARE_FINAL_TYPE (PhoshMonitorManager, phosh_monitor_manager, PHOSH, MONITOR_MANAGER, PhoshDisplayDbusOrgGnomeMutterDisplayConfigSkeleton) -PhoshMonitorManager * phosh_monitor_manager_new (void); -void phosh_monitor_manager_add_monitor (PhoshMonitorManager *self, - PhoshMonitor *monitor); -PhoshMonitor * phosh_monitor_manager_get_monitor (PhoshMonitorManager *self, - guint monitor); -guint phosh_monitor_manager_get_num_monitors (PhoshMonitorManager *self); +PhoshMonitorManager * phosh_monitor_manager_new (void); +void phosh_monitor_manager_add_monitor (PhoshMonitorManager *self, + PhoshMonitor *monitor); +PhoshMonitor * phosh_monitor_manager_get_monitor (PhoshMonitorManager *self, + guint monitor); +guint phosh_monitor_manager_get_num_monitors (PhoshMonitorManager *self); +void phosh_monitor_manager_set_gamma_control_manager (PhoshMonitorManager *self, + gpointer *gamma); diff --git a/src/phosh.c b/src/phosh.c index dda382f003dbaa7def2695ca5eb0b58f4423a486..3aa853f3133fc363a30e62873c5197fc3e0902b7 100644 --- a/src/phosh.c +++ b/src/phosh.c @@ -26,7 +26,7 @@ #include "wlr-input-inhibitor-unstable-v1-client-protocol.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "xdg-shell-client-protocol.h" - +#include "gamma-control-client-protocol.h" #include "phosh.h" #include "monitor/monitor.h" /* FIXME: move upwards? */ @@ -70,6 +70,7 @@ typedef struct struct org_kde_kwin_idle *idle_manager; struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager; struct zwlr_input_inhibitor_v1 *input_inhibitor; + struct gamma_control_manager *gamma_control_manager; struct wl_seat *wl_seat; struct xdg_wm_base *xdg_wm_base; @@ -653,24 +654,36 @@ registry_handle_global (void *data, PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); struct wl_output *output; - if (!strcmp (interface, "phosh_private")) { - priv->mshell = wl_registry_bind (registry, name, - &phosh_private_interface, 1); + priv->mshell = wl_registry_bind ( + registry, + name, + &phosh_private_interface, + 1); } else if (!strcmp (interface, zwlr_layer_shell_v1_interface.name)) { - priv->layer_shell = wl_registry_bind (registry, name, - &zwlr_layer_shell_v1_interface, 1); + priv->layer_shell = wl_registry_bind ( + registry, + name, + &zwlr_layer_shell_v1_interface, + 1); } else if (!strcmp (interface, "wl_output")) { - output = wl_registry_bind (registry, name, - &wl_output_interface, 1); - phosh_monitor_manager_add_monitor (priv->monitor_manager, - phosh_monitor_new_from_wl_output(output)); + output = wl_registry_bind ( + registry, + name, + &wl_output_interface, 1); + phosh_monitor_manager_add_monitor ( + priv->monitor_manager, + phosh_monitor_new_from_wl_output(output)); } else if (!strcmp (interface, "org_kde_kwin_idle")) { - priv->idle_manager = wl_registry_bind (registry, - name, - &org_kde_kwin_idle_interface, 1); + priv->idle_manager = wl_registry_bind ( + registry, + name, + &org_kde_kwin_idle_interface, + 1); } else if (!strcmp(interface, "wl_seat")) { - priv->wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 1); + priv->wl_seat = wl_registry_bind( + registry, name, &wl_seat_interface, + 1); } else if (!strcmp(interface, zwlr_input_inhibit_manager_v1_interface.name)) { priv->input_inhibit_manager = wl_registry_bind( registry, @@ -678,7 +691,17 @@ registry_handle_global (void *data, &zwlr_input_inhibit_manager_v1_interface, 1); } else if (!strcmp(interface, xdg_wm_base_interface.name)) { - priv->xdg_wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); + priv->xdg_wm_base = wl_registry_bind( + registry, + name, + &xdg_wm_base_interface, + 1); + } else if (!strcmp(interface, gamma_control_manager_interface.name)) { + priv->gamma_control_manager = wl_registry_bind( + registry, + name, + &gamma_control_manager_interface, + 1); } } @@ -768,7 +791,7 @@ phosh_shell_constructed (GObject *object) { PhoshShell *self = PHOSH_SHELL (object); PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); - guint num_mon;; + guint num_mon; G_OBJECT_CLASS (phosh_shell_parent_class)->constructed (object); @@ -788,26 +811,34 @@ phosh_shell_constructed (GObject *object) /* Wait until we have been notified about the compositor, * shell, and shell helper objects */ num_mon = phosh_monitor_manager_get_num_monitors (priv->monitor_manager); - if (!num_mon || !priv->layer_shell || !priv->idle_manager || - !priv->input_inhibit_manager || !priv->mshell || !priv->xdg_wm_base) + if (!num_mon || + !priv->layer_shell || + !priv->idle_manager || + !priv->input_inhibit_manager || + !priv->mshell || + !priv->xdg_wm_base || + !priv->gamma_control_manager) wl_display_roundtrip (priv->display); num_mon = phosh_monitor_manager_get_num_monitors (priv->monitor_manager); - if (!num_mon || !priv->layer_shell || !priv->idle_manager || - !priv->input_inhibit_manager || !priv->xdg_wm_base) { + if (!num_mon || + !priv->layer_shell || + !priv->idle_manager || + !priv->input_inhibit_manager || + !priv->xdg_wm_base || + !priv->gamma_control_manager) { g_error ("Could not find needed globals\n" "outputs: %d, layer_shell: %p, seat: %p, " - "inhibit: %p, xdg_wm: %p\n", + "inhibit: %p, xdg_wm: %p, gamma %p\n", num_mon, priv->layer_shell, priv->idle_manager, - priv->input_inhibit_manager, priv->xdg_wm_base); + priv->input_inhibit_manager, priv->xdg_wm_base, + priv->gamma_control_manager); } if (!priv->mshell) { g_info ("Could not find phosh global, disabling some features\n"); } - gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (), "/sm/puri/phosh/icons"); - env_setup (); css_setup (self); panel_create (self); @@ -884,6 +915,14 @@ phosh_shell_get_wl_layer_shell () } +gpointer +phosh_shell_get_wl_gamma_control_manager () +{ + PhoshShellPrivate *priv = phosh_shell_get_instance_private (_phosh); + return priv->gamma_control_manager; +} + + PhoshMonitor * phosh_shell_get_primary_monitor () { diff --git a/src/phosh.h b/src/phosh.h index 74bfbe55ffdd62e31bd0c1d35a93831c07b01f6e..e17adb368b4bf4cad2dba9e995553a6073faaff8 100644 --- a/src/phosh.h +++ b/src/phosh.h @@ -31,4 +31,5 @@ PhoshMonitor *phosh_shell_get_primary_monitor (); /* Phosh keeps track of the wayland globals */ gpointer phosh_shell_get_wl_layer_shell (); +gpointer phosh_shell_get_wl_gamma_control_manager (); #endif /* PHOSH_H */