mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
Compare commits
11 commits
72c481b549
...
bbf0ff2aca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbf0ff2aca | ||
|
|
879243e370 | ||
|
|
989cffe70d | ||
|
|
3e08e3be4a | ||
|
|
91f4890ec2 | ||
|
|
74ce6c22a5 | ||
|
|
0b58bddf13 | ||
|
|
3d36ab9211 | ||
|
|
d786e07899 | ||
|
|
6d63871f05 | ||
|
|
1495db3e16 |
20 changed files with 994 additions and 52 deletions
|
|
@ -519,8 +519,6 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
break;
|
||||
}
|
||||
|
||||
bool is_boot_vga = false;
|
||||
|
||||
const char *path = udev_list_entry_get_name(entry);
|
||||
struct udev_device *dev = udev_device_new_from_syspath(session->udev, path);
|
||||
if (!dev) {
|
||||
|
|
@ -536,14 +534,20 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
continue;
|
||||
}
|
||||
|
||||
// This is owned by 'dev', so we don't need to free it
|
||||
struct udev_device *pci =
|
||||
udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
|
||||
bool is_primary = false;
|
||||
const char *boot_display = udev_device_get_sysattr_value(dev, "boot_display");
|
||||
if (boot_display && strcmp(boot_display, "1") == 0) {
|
||||
is_primary = true;
|
||||
} else {
|
||||
// This is owned by 'dev', so we don't need to free it
|
||||
struct udev_device *pci =
|
||||
udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
|
||||
|
||||
if (pci) {
|
||||
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
|
||||
if (id && strcmp(id, "1") == 0) {
|
||||
is_boot_vga = true;
|
||||
if (pci) {
|
||||
const char *id = udev_device_get_sysattr_value(pci, "boot_vga");
|
||||
if (id && strcmp(id, "1") == 0) {
|
||||
is_primary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +561,7 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
|||
udev_device_unref(dev);
|
||||
|
||||
ret[i] = wlr_dev;
|
||||
if (is_boot_vga) {
|
||||
if (is_primary) {
|
||||
struct wlr_device *tmp = ret[0];
|
||||
ret[0] = ret[i];
|
||||
ret[i] = tmp;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ enum wlr_color_transform_type {
|
|||
COLOR_TRANSFORM_INVERSE_EOTF,
|
||||
COLOR_TRANSFORM_LCMS2,
|
||||
COLOR_TRANSFORM_LUT_3X1D,
|
||||
COLOR_TRANSFORM_PIPELINE,
|
||||
};
|
||||
|
||||
struct wlr_color_transform {
|
||||
|
|
@ -39,6 +40,13 @@ struct wlr_color_transform_lut_3x1d {
|
|||
size_t dim;
|
||||
};
|
||||
|
||||
struct wlr_color_transform_pipeline {
|
||||
struct wlr_color_transform base;
|
||||
|
||||
struct wlr_color_transform **transforms;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
void wlr_color_transform_init(struct wlr_color_transform *tr,
|
||||
enum wlr_color_transform_type type);
|
||||
|
||||
|
|
@ -72,12 +80,6 @@ struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_b
|
|||
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
||||
struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
* Evaluate a 3x1D LUT color transform for a given RGB triplet.
|
||||
*/
|
||||
void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
||||
float out[static 3], const float in[static 3]);
|
||||
|
||||
/**
|
||||
* Obtain primaries values from a well-known primaries name.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -141,6 +141,13 @@ struct wlr_color_transform *wlr_color_transform_init_linear_to_inverse_eotf(
|
|||
struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
|
||||
const uint16_t *r, const uint16_t *g, const uint16_t *b);
|
||||
|
||||
/**
|
||||
* Initialize a color transformation to apply a sequence of color transforms
|
||||
* one after another.
|
||||
*/
|
||||
struct wlr_color_transform *wlr_color_transform_init_pipeline(
|
||||
struct wlr_color_transform **transforms, size_t len);
|
||||
|
||||
/**
|
||||
* Increase the reference count of the color transform by 1.
|
||||
*/
|
||||
|
|
@ -152,4 +159,10 @@ struct wlr_color_transform *wlr_color_transform_ref(struct wlr_color_transform *
|
|||
*/
|
||||
void wlr_color_transform_unref(struct wlr_color_transform *tr);
|
||||
|
||||
/**
|
||||
* Evaluate a color transform for a given RGB triplet.
|
||||
*/
|
||||
void wlr_color_transform_eval(struct wlr_color_transform *tr,
|
||||
float out[static 3], const float in[static 3]);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
82
include/wlr/types/wlr_action_binder_v1.h
Normal file
82
include/wlr/types/wlr_action_binder_v1.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||
* future consistency of this API.
|
||||
*/
|
||||
#ifndef WLR_USE_UNSTABLE
|
||||
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||
#endif
|
||||
|
||||
#ifndef WLR_TYPES_WLR_ACTION_BINDER_V1_H
|
||||
#define WLR_TYPES_WLR_ACTION_BINDER_V1_H
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include "ext-action-binder-v1-protocol.h"
|
||||
|
||||
struct wlr_action_binder_v1 {
|
||||
struct wl_global *global;
|
||||
struct wl_list states; // wlr_action_binder_v1_state.link
|
||||
struct wl_listener display_destroy;
|
||||
|
||||
struct {
|
||||
struct wl_signal bind;
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct wlr_action_binder_v1_state {
|
||||
struct wl_list binds; // wlr_action_binding_v1.link
|
||||
struct wl_list bind_queue; // wlr_action_binding_v1.link
|
||||
struct wlr_action_binder_v1 *binder;
|
||||
struct wl_resource *resource;
|
||||
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct wlr_action_binding_hint_v1 {
|
||||
enum {
|
||||
WLR_ACTION_BINDING_HINT_V1_NONE,
|
||||
WLR_ACTION_BINDING_HINT_V1_KEYBOARD,
|
||||
WLR_ACTION_BINDING_HINT_V1_MOUSE,
|
||||
WLR_ACTION_BINDING_HINT_V1_GESTURE,
|
||||
} type;
|
||||
|
||||
union {
|
||||
char *keycombo; // WLR_ACTION_BINDING_HINT_V1_KEYBOARD
|
||||
uint32_t mouse_button; // WLR_ACTION_BINDING_HINT_V1_MOUSE
|
||||
struct {
|
||||
enum ext_action_binding_v1_gesture_type type;
|
||||
enum ext_action_binding_v1_gesture_direction direction;
|
||||
uint32_t fingers;
|
||||
} gesture; // WLR_ACTION_BINDING_HINT_V1_GESTURE
|
||||
};
|
||||
};
|
||||
|
||||
struct wlr_action_binding_v1 {
|
||||
struct wl_resource *resource;
|
||||
struct wlr_action_binder_v1_state *state;
|
||||
|
||||
char *category, *name;
|
||||
char *description; // may be NULL when the client doesn't set a description
|
||||
|
||||
struct wlr_action_binding_hint_v1 hint;
|
||||
char *app_id; // may be NULL when the client doesn't set an app_id
|
||||
struct wlr_seat *seat; // may be NULL when the client doesn't set a seat
|
||||
struct wl_listener seat_destroy;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
} events;
|
||||
|
||||
bool bound;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct wlr_action_binder_v1 *wlr_action_binder_v1_create(struct wl_display *display);
|
||||
void wlr_action_binding_v1_bind(struct wlr_action_binding_v1 *bind, const char *trigger);
|
||||
void wlr_action_binding_v1_reject(struct wlr_action_binding_v1 *bind);
|
||||
void wlr_action_binding_v1_trigger(struct wlr_action_binding_v1 *binding, uint32_t trigger_type, uint32_t time_msec);
|
||||
|
||||
#endif
|
||||
|
|
@ -10,6 +10,11 @@ struct wlr_gamma_control_manager_v1 {
|
|||
struct wl_global *global;
|
||||
struct wl_list controls; // wlr_gamma_control_v1.link
|
||||
|
||||
// Fallback to use when an struct wlr_output doesn't support gamma LUTs.
|
||||
// Can be used to apply gamma LUTs via a struct wlr_renderer. Leave zero to
|
||||
// indicate that the fallback is unsupported.
|
||||
size_t fallback_gamma_size;
|
||||
|
||||
struct {
|
||||
struct wl_signal destroy;
|
||||
struct wl_signal set_gamma; // struct wlr_gamma_control_manager_v1_set_gamma_event
|
||||
|
|
@ -49,6 +54,8 @@ struct wlr_gamma_control_v1 *wlr_gamma_control_manager_v1_get_control(
|
|||
struct wlr_gamma_control_manager_v1 *manager, struct wlr_output *output);
|
||||
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
|
||||
struct wlr_output_state *output_state);
|
||||
struct wlr_color_transform *wlr_gamma_control_v1_get_color_transform(
|
||||
struct wlr_gamma_control_v1 *gamma_control);
|
||||
void wlr_gamma_control_v1_send_failed_and_destroy(struct wlr_gamma_control_v1 *gamma_control);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@ struct wlr_output {
|
|||
struct {
|
||||
struct wl_listener display_destroy;
|
||||
struct wlr_output_image_description image_description_value;
|
||||
struct wlr_color_transform *color_transform;
|
||||
} WLR_PRIVATE;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -252,6 +252,11 @@ struct wlr_scene_output {
|
|||
|
||||
bool gamma_lut_changed;
|
||||
struct wlr_gamma_control_v1 *gamma_lut;
|
||||
struct wlr_color_transform *gamma_lut_color_transform;
|
||||
|
||||
struct wlr_color_transform *prev_gamma_lut_color_transform;
|
||||
struct wlr_color_transform *prev_supplied_color_transform;
|
||||
struct wlr_color_transform *prev_combined_color_transform;
|
||||
|
||||
struct wl_listener output_commit;
|
||||
struct wl_listener output_damage;
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ struct wlr_xwm {
|
|||
struct wl_listener drop_focus_destroy;
|
||||
};
|
||||
|
||||
// xwm_create takes ownership of wm_fd and will close it under all circumstances.
|
||||
struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland, int wm_fd);
|
||||
|
||||
void xwm_destroy(struct wlr_xwm *xwm);
|
||||
|
|
|
|||
266
protocol/ext-action-binder-v1.xml
Normal file
266
protocol/ext-action-binder-v1.xml
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="ext_action_binder_v1">
|
||||
<copyright>
|
||||
Copyright © 2023-2024 Anna "navi" Figueiredo Gomes
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that copyright notice and this permission
|
||||
notice appear in supporting documentation, and that the name of
|
||||
the copyright holders not be used in advertising or publicity
|
||||
pertaining to distribution of the software without specific,
|
||||
written prior permission. The copyright holders make no
|
||||
representations about the suitability of this software for any
|
||||
purpose. It is provided "as is" without express or implied
|
||||
warranty.
|
||||
|
||||
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<description summary="binds actions">
|
||||
This protocol allows clients to register "actions" as a set of triggers
|
||||
and metadata, and get notified when those actions are triggered by the user.
|
||||
|
||||
Warning! The protocol described in this file is currently in the testing
|
||||
phase. Backward compatible changes may be added together with the
|
||||
corresponding interface version bump. Backward incompatible changes can
|
||||
only be done by creating a new major version of the extension.
|
||||
|
||||
The key words "must", "must not", "required", "shall", "shall not", "should",
|
||||
"should not", "recommended", "may", and "optional" in this document are to
|
||||
be interpreted as described in IETF RFC 2119.
|
||||
</description>
|
||||
|
||||
<interface name="ext_action_binder_v1" version="1">
|
||||
<description summary="action binder">
|
||||
This interface is designed to allow any application to bind an action.
|
||||
|
||||
It is left to the compositor to determine which client will get events.
|
||||
The choice can be based on policy, heuristic, user configuration, or any
|
||||
other mechanism that may be relevant.
|
||||
Here are some examples of dispatching choice: all applications, last
|
||||
focused, user-defined preference order, latest fullscreened application.
|
||||
|
||||
This interface is exposed as global.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="unbind the actions">
|
||||
The client no longer wants to receive events for any action.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="create_binding">
|
||||
<description summary="create a binding">
|
||||
Creates a binding.
|
||||
|
||||
After setting the metadata on all bindings created, the client must
|
||||
call ext_action_binder_v1.commit for the binding to take effect.
|
||||
</description>
|
||||
<arg name="binding" type="new_id" interface="ext_action_binding_v1" summary="the new binding" />
|
||||
</request>
|
||||
|
||||
<request name="commit">
|
||||
<description summary="commits all created bindings">
|
||||
Commits all bindings created from this interface.
|
||||
This request may be called again if new bindings are created,
|
||||
already bound bindings are unaffected.
|
||||
|
||||
After calling bind, either the "bound" or "rejected" event shall
|
||||
be sent for each binding created.
|
||||
|
||||
If no action has been set for any binding, the error "invalid_binding" is raised.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="invalid_binding" value="0" summary="the binding has no action set"/>
|
||||
</enum>
|
||||
</interface>
|
||||
|
||||
<interface name="ext_action_binding_v1" version="1">
|
||||
<description summary="a binding for an action">
|
||||
This interface defines an individual binding, allowing the client to register metadata about
|
||||
the action and receive triggered events.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="unbind the actions">
|
||||
The client no longer wants to receive events for this binding.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="set_name">
|
||||
<description summary="sets the category and name of a binding">
|
||||
Sets an arbitrary couple of a category and a name describing the
|
||||
wanted behaviour. Some categories are well-known and shared by
|
||||
applications while each application can have its own category
|
||||
for internal actions.
|
||||
|
||||
This name may be used by the compositor to render a ui for bindings.
|
||||
|
||||
A name must be set before attempting to commit a binding.
|
||||
|
||||
Attempting to send this request twice or after the binding was bound raises an already set error.
|
||||
</description>
|
||||
<arg name="category" type="string" summary="the action category" />
|
||||
<arg name="name" type="string" summary="the action name" />
|
||||
</request>
|
||||
|
||||
<request name="set_description">
|
||||
<description summary="set the human-readable description of a binding">
|
||||
This setting is optional.
|
||||
|
||||
This description may be used by the compositor to render a ui for bindings.
|
||||
|
||||
Attempting to send this request twice or after the binding was bound raises an already_set error.
|
||||
</description>
|
||||
<arg name="description" type="string" summary="a human-readable description of what the binding does" />
|
||||
</request>
|
||||
|
||||
<request name="set_app_id">
|
||||
<description summary="set the application ID">
|
||||
This setting is optional.
|
||||
|
||||
The app ID identifies the general class of applications to which
|
||||
the binding belongs. The compositor may use this to select which
|
||||
client will receive an event.
|
||||
|
||||
Attempting to send this request twice or after the binding was bound raises an already_set error.
|
||||
</description>
|
||||
<arg name="app_id" type="string" summary="app_id of the application requesting this bind"/>
|
||||
</request>
|
||||
|
||||
<request name="set_seat">
|
||||
<description summary="sets a target seat">
|
||||
This setting is optional.
|
||||
|
||||
If set, the actions shall only be triggered by the specific seat.
|
||||
|
||||
Attempting to send this request twice or after the binding was bound raises an already_set error.
|
||||
</description>
|
||||
<arg name="seat" type="object" interface="wl_seat" summary="target seat"/>
|
||||
</request>
|
||||
|
||||
<request name="set_keyboard_hint">
|
||||
<description summary="Sets a keycombo as a trigger hint.">
|
||||
This setting is optional.
|
||||
|
||||
This hint is a suggestion to the compositor, and the action must not rely
|
||||
on being set to this specific trigger.
|
||||
|
||||
The keycombo must follow the XDG Shortcut standard.
|
||||
|
||||
Only a maximum of one hint shall be set per action.
|
||||
</description>
|
||||
<arg name="keycombo" type="string" summary="the keycombo that the client would like to trigger the action"/>
|
||||
</request>
|
||||
|
||||
<request name="set_mouse_hint">
|
||||
<description summary="Sets a mouse button as a trigger hint.">
|
||||
This setting is optional.
|
||||
|
||||
This hint is a suggestion to the compositor, and the action must not rely
|
||||
on being set to this specific trigger.
|
||||
|
||||
Button is a value mapped to their x11 values (1=left, 2=middle, 3=right,
|
||||
4=scroll up, 5=scroll down, 6=scroll left, 7=scroll right, 8=back, 9=forward).
|
||||
|
||||
Only a maximum of one hint shall be set per action.
|
||||
</description>
|
||||
<arg name="button" type="uint" summary="the mouse button that the client would like to trigger the action"/>
|
||||
</request>
|
||||
|
||||
<enum name="gesture_type">
|
||||
<description summary="Type of the hint gesture.">
|
||||
</description>
|
||||
<entry name="hold" value="0"/>
|
||||
<entry name="swipe" value="1"/>
|
||||
<entry name="pinch" value="2"/>
|
||||
</enum>
|
||||
|
||||
<enum name="gesture_direction">
|
||||
<description summary="Direction of the hint gesture.">
|
||||
</description>
|
||||
<entry name="none" value="0"/>
|
||||
<entry name="up" value="1"/>
|
||||
<entry name="down" value="2"/>
|
||||
<entry name="left" value="3"/>
|
||||
<entry name="right" value="4"/>
|
||||
<entry name="inward" value="5"/>
|
||||
<entry name="outward" value="6"/>
|
||||
<entry name="clockwise" value="7"/>
|
||||
<entry name="counterclockwise" value="8"/>
|
||||
</enum>
|
||||
|
||||
<request name="set_gesture_hint">
|
||||
<description summary="sets a touchpad gesture as a trigger hint">
|
||||
This setting is optional.
|
||||
|
||||
This hint is a suggestion to the compositor, and the action must not rely
|
||||
on being set to this specific trigger.
|
||||
|
||||
Only a maximum of one trigger hint may be set per action.
|
||||
</description>
|
||||
<arg name="type" type="uint" enum="gesture_type" summary="the type of trigger that was sent"/>
|
||||
<arg name="direction" type="uint" enum="gesture_direction" summary="the type of trigger that was sent"/>
|
||||
<arg name="fingers" type="uint" summary="the number of fingers on the gesture"/>
|
||||
</request>
|
||||
|
||||
<event name="bound">
|
||||
<description summary="the compositor bound the binding to an action">
|
||||
Sent after the event was processed, and was bound to one or more of the actions set.
|
||||
</description>
|
||||
<arg name="trigger" type="string" summary="human-readable string describing the trigger for the action" />
|
||||
</event>
|
||||
|
||||
<event name="rejected">
|
||||
<description summary="the compositor rejected the binding">
|
||||
Sent after the event was processed and got rejected,
|
||||
or at any time should the compositor want to remove the binding.
|
||||
The compositor must not send further events after this event.
|
||||
The client should destroy the object at this point.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<enum name="trigger_type">
|
||||
<description summary="type of binding triggered">
|
||||
Depending on the user configuration, an action can be either one_shot or
|
||||
sustained. The client must handle all the three event types and either make
|
||||
sense of them or ignore them properly.
|
||||
|
||||
one_shot actions are for events that don't have a defined "end", like a laptop
|
||||
lid closing, or a gesture. The client should not expect to recieve a released or
|
||||
ending event for that action.
|
||||
|
||||
sustained actions have a start and an end. after a 'pressed' event is sent, a
|
||||
'released' event should eventually be sent as well.
|
||||
</description>
|
||||
<entry name="one_shot" value="0"
|
||||
summary="a one shot action was triggered" />
|
||||
<entry name="pressed" value="1"
|
||||
summary="a sustained action was started" />
|
||||
<entry name="released" value="2"
|
||||
summary="a sustained action ended" />
|
||||
</enum>
|
||||
|
||||
<event name="triggered">
|
||||
<description summary="the action triggered">
|
||||
This event is sent when actions are triggered.
|
||||
</description>
|
||||
<arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
|
||||
<arg name="type" type="uint" enum="trigger_type" summary="the type of trigger that was sent"/>
|
||||
</event>
|
||||
<enum name="error">
|
||||
<entry name="already_set" value="0" summary="property was already set"/>
|
||||
</enum>
|
||||
</interface>
|
||||
</protocol>
|
||||
|
|
@ -66,6 +66,7 @@ protocols = {
|
|||
'drm': 'drm.xml',
|
||||
'input-method-unstable-v2': 'input-method-unstable-v2.xml',
|
||||
'kde-server-decoration': 'server-decoration.xml',
|
||||
'ext-action-binder-v1': 'ext-action-binder-v1.xml',
|
||||
'virtual-keyboard-unstable-v1': 'virtual-keyboard-unstable-v1.xml',
|
||||
'wlr-data-control-unstable-v1': 'wlr-data-control-unstable-v1.xml',
|
||||
'wlr-export-dmabuf-unstable-v1': 'wlr-export-dmabuf-unstable-v1.xml',
|
||||
|
|
|
|||
121
render/color.c
121
render/color.c
|
|
@ -62,6 +62,33 @@ struct wlr_color_transform *wlr_color_transform_init_lut_3x1d(size_t dim,
|
|||
return &tx->base;
|
||||
}
|
||||
|
||||
struct wlr_color_transform *wlr_color_transform_init_pipeline(
|
||||
struct wlr_color_transform **transforms, size_t len) {
|
||||
assert(len > 0);
|
||||
|
||||
struct wlr_color_transform **copy = calloc(len, sizeof(copy[0]));
|
||||
if (copy == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_color_transform_pipeline *tx = calloc(1, sizeof(*tx));
|
||||
if (!tx) {
|
||||
free(copy);
|
||||
return NULL;
|
||||
}
|
||||
wlr_color_transform_init(&tx->base, COLOR_TRANSFORM_PIPELINE);
|
||||
|
||||
// TODO: flatten nested pipeline transforms
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
copy[i] = wlr_color_transform_ref(transforms[i]);
|
||||
}
|
||||
|
||||
tx->transforms = copy;
|
||||
tx->len = len;
|
||||
|
||||
return &tx->base;
|
||||
}
|
||||
|
||||
static void color_transform_destroy(struct wlr_color_transform *tr) {
|
||||
switch (tr->type) {
|
||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||
|
|
@ -73,6 +100,14 @@ static void color_transform_destroy(struct wlr_color_transform *tr) {
|
|||
struct wlr_color_transform_lut_3x1d *lut_3x1d = color_transform_lut_3x1d_from_base(tr);
|
||||
free(lut_3x1d->lut_3x1d);
|
||||
break;
|
||||
case COLOR_TRANSFORM_PIPELINE:;
|
||||
struct wlr_color_transform_pipeline *pipeline =
|
||||
wl_container_of(tr, pipeline, base);
|
||||
for (size_t i = 0; i < pipeline->len; i++) {
|
||||
wlr_color_transform_unref(pipeline->transforms[i]);
|
||||
}
|
||||
free(pipeline->transforms);
|
||||
break;
|
||||
}
|
||||
wlr_addon_set_finish(&tr->addons);
|
||||
free(tr);
|
||||
|
|
@ -108,6 +143,65 @@ struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
|||
return lut_3x1d;
|
||||
}
|
||||
|
||||
static float srgb_eval_inverse_eotf(float x) {
|
||||
// See https://www.w3.org/Graphics/Color/srgb
|
||||
if (x <= 0.0031308) {
|
||||
return 12.92 * x;
|
||||
} else {
|
||||
return 1.055 * powf(x, 1.0 / 2.4) - 0.055;
|
||||
}
|
||||
}
|
||||
|
||||
static float st2084_pq_eval_inverse_eotf(float x) {
|
||||
// H.273 TransferCharacteristics code point 16
|
||||
float c1 = 0.8359375;
|
||||
float c2 = 18.8515625;
|
||||
float c3 = 18.6875;
|
||||
float m = 78.84375;
|
||||
float n = 0.1593017578125;
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
}
|
||||
if (x > 1) {
|
||||
x = 1;
|
||||
}
|
||||
float pow_n = powf(x, n);
|
||||
return powf((c1 + c2 * pow_n) / (1 + c3 * pow_n), m);
|
||||
}
|
||||
|
||||
static float bt1886_eval_inverse_eotf(float x) {
|
||||
float lb = powf(0.0001, 1.0 / 2.4);
|
||||
float lw = powf(1.0, 1.0 / 2.4);
|
||||
float a = powf(lw - lb, 2.4);
|
||||
float b = lb / (lw - lb);
|
||||
return powf(x / a, 1.0 / 2.4) - b;
|
||||
}
|
||||
|
||||
static float transfer_function_eval_inverse_eotf(
|
||||
enum wlr_color_transfer_function tf, float x) {
|
||||
switch (tf) {
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||
return srgb_eval_inverse_eotf(x);
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||
return st2084_pq_eval_inverse_eotf(x);
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||
return x;
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||
return powf(x, 1.0 / 2.2);
|
||||
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||
return bt1886_eval_inverse_eotf(x);
|
||||
}
|
||||
abort(); // unreachable
|
||||
}
|
||||
|
||||
static void color_transform_inverse_eotf_eval(
|
||||
struct wlr_color_transform_inverse_eotf *tr,
|
||||
float out[static 3], const float in[static 3]) {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
out[i] = transfer_function_eval_inverse_eotf(tr->tf, in[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static float lut_1d_get(const uint16_t *lut, size_t len, size_t i) {
|
||||
if (i >= len) {
|
||||
i = len - 1;
|
||||
|
|
@ -125,13 +219,38 @@ static float lut_1d_eval(const uint16_t *lut, size_t len, float x) {
|
|||
return a * (1 - frac_part) + b * frac_part;
|
||||
}
|
||||
|
||||
void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
||||
static void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
||||
float out[static 3], const float in[static 3]) {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
out[i] = lut_1d_eval(&tr->lut_3x1d[tr->dim * i], tr->dim, in[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void wlr_color_transform_eval(struct wlr_color_transform *tr,
|
||||
float out[static 3], const float in[static 3]) {
|
||||
switch (tr->type) {
|
||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||
color_transform_inverse_eotf_eval(wlr_color_transform_inverse_eotf_from_base(tr), out, in);
|
||||
break;
|
||||
case COLOR_TRANSFORM_LCMS2:
|
||||
color_transform_lcms2_eval(color_transform_lcms2_from_base(tr), out, in);
|
||||
break;
|
||||
case COLOR_TRANSFORM_LUT_3X1D:
|
||||
color_transform_lut_3x1d_eval(color_transform_lut_3x1d_from_base(tr), out, in);
|
||||
break;
|
||||
case COLOR_TRANSFORM_PIPELINE:;
|
||||
struct wlr_color_transform_pipeline *pipeline =
|
||||
wl_container_of(tr, pipeline, base);
|
||||
float color[3];
|
||||
memcpy(color, in, sizeof(color));
|
||||
for (size_t i = 0; i < pipeline->len; i++) {
|
||||
wlr_color_transform_eval(pipeline->transforms[i], color, color);
|
||||
}
|
||||
memcpy(out, color, sizeof(color));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void wlr_color_primaries_from_named(struct wlr_color_primaries *out,
|
||||
enum wlr_color_named_primaries named) {
|
||||
switch (named) {
|
||||
|
|
|
|||
|
|
@ -964,19 +964,6 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
|||
*ds = VK_NULL_HANDLE;
|
||||
*ds_pool = NULL;
|
||||
|
||||
struct wlr_color_transform_lcms2 *tr_lcms2 = NULL;
|
||||
struct wlr_color_transform_lut_3x1d *tr_lut_3x1d = NULL;
|
||||
switch (tr->type) {
|
||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||
abort(); // unreachable
|
||||
case COLOR_TRANSFORM_LCMS2:
|
||||
tr_lcms2 = color_transform_lcms2_from_base(tr);
|
||||
break;
|
||||
case COLOR_TRANSFORM_LUT_3X1D:
|
||||
tr_lut_3x1d = color_transform_lut_3x1d_from_base(tr);
|
||||
break;
|
||||
}
|
||||
|
||||
// R32G32B32 is not a required Vulkan format
|
||||
// TODO: use it when available
|
||||
VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
|
|
@ -1074,11 +1061,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
|||
b_index * sample_range,
|
||||
};
|
||||
float rgb_out[3];
|
||||
if (tr_lcms2 != NULL) {
|
||||
color_transform_lcms2_eval(tr_lcms2, rgb_out, rgb_in);
|
||||
} else {
|
||||
color_transform_lut_3x1d_eval(tr_lut_3x1d, rgb_out, rgb_in);
|
||||
}
|
||||
wlr_color_transform_eval(tr, rgb_out, rgb_in);
|
||||
|
||||
dst[dst_offset] = rgb_out[0];
|
||||
dst[dst_offset + 1] = rgb_out[1];
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ wlr_files += files(
|
|||
'buffer/dmabuf.c',
|
||||
'buffer/readonly_data.c',
|
||||
'buffer/resource.c',
|
||||
'wlr_action_binder_v1.c',
|
||||
'wlr_alpha_modifier_v1.c',
|
||||
'wlr_color_management_v1.c',
|
||||
'wlr_color_representation_v1.c',
|
||||
|
|
|
|||
|
|
@ -242,6 +242,15 @@ static void output_apply_state(struct wlr_output *output,
|
|||
}
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) {
|
||||
wlr_color_transform_unref(output->color_transform);
|
||||
if (state->color_transform != NULL) {
|
||||
output->color_transform = wlr_color_transform_ref(state->color_transform);
|
||||
} else {
|
||||
output->color_transform = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool geometry_updated = state->committed &
|
||||
(WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM |
|
||||
WLR_OUTPUT_STATE_SUBPIXEL);
|
||||
|
|
@ -407,6 +416,7 @@ void wlr_output_finish(struct wlr_output *output) {
|
|||
|
||||
wlr_swapchain_destroy(output->cursor_swapchain);
|
||||
wlr_buffer_unlock(output->cursor_front_buffer);
|
||||
wlr_color_transform_unref(output->color_transform);
|
||||
|
||||
wlr_swapchain_destroy(output->swapchain);
|
||||
|
||||
|
|
@ -515,8 +525,7 @@ const struct wlr_output_image_description *output_pending_image_description(
|
|||
* Returns a bitfield of the unchanged fields.
|
||||
*
|
||||
* Some fields are not checked: damage always changes in-between frames, the
|
||||
* gamma LUT is too expensive to check, the contents of the buffer might have
|
||||
* changed, etc.
|
||||
* contents of the buffer might have changed, etc.
|
||||
*/
|
||||
static uint32_t output_compare_state(struct wlr_output *output,
|
||||
const struct wlr_output_state *state) {
|
||||
|
|
@ -562,6 +571,10 @@ static uint32_t output_compare_state(struct wlr_output *output,
|
|||
output->subpixel == state->subpixel) {
|
||||
fields |= WLR_OUTPUT_STATE_SUBPIXEL;
|
||||
}
|
||||
if ((state->committed & WLR_OUTPUT_STATE_COLOR_TRANSFORM) &&
|
||||
output->color_transform == state->color_transform) {
|
||||
fields |= WLR_OUTPUT_STATE_COLOR_TRANSFORM;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1530,6 +1530,8 @@ static void scene_handle_gamma_control_manager_v1_set_gamma(struct wl_listener *
|
|||
|
||||
output->gamma_lut_changed = true;
|
||||
output->gamma_lut = event->control;
|
||||
wlr_color_transform_unref(output->gamma_lut_color_transform);
|
||||
output->gamma_lut_color_transform = wlr_gamma_control_v1_get_color_transform(event->control);
|
||||
wlr_output_schedule_frame(output->output);
|
||||
}
|
||||
|
||||
|
|
@ -1547,6 +1549,8 @@ static void scene_handle_gamma_control_manager_v1_destroy(struct wl_listener *li
|
|||
wl_list_for_each(output, &scene->outputs, link) {
|
||||
output->gamma_lut_changed = false;
|
||||
output->gamma_lut = NULL;
|
||||
wlr_color_transform_unref(output->gamma_lut_color_transform);
|
||||
output->gamma_lut_color_transform = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1766,6 +1770,10 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) {
|
|||
wl_list_remove(&scene_output->output_damage.link);
|
||||
wl_list_remove(&scene_output->output_needs_frame.link);
|
||||
wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
|
||||
wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
|
||||
wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
|
||||
wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
|
||||
wlr_color_transform_unref(scene_output->prev_combined_color_transform);
|
||||
wl_array_release(&scene_output->render_list);
|
||||
free(scene_output);
|
||||
}
|
||||
|
|
@ -2104,16 +2112,15 @@ static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_outp
|
|||
return;
|
||||
}
|
||||
|
||||
if (!wlr_gamma_control_v1_apply(scene_output->gamma_lut, &gamma_pending)) {
|
||||
wlr_output_state_finish(&gamma_pending);
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_output_state_set_color_transform(&gamma_pending, scene_output->gamma_lut_color_transform);
|
||||
scene_output->gamma_lut_changed = false;
|
||||
|
||||
if (!wlr_output_test_state(scene_output->output, &gamma_pending)) {
|
||||
wlr_gamma_control_v1_send_failed_and_destroy(scene_output->gamma_lut);
|
||||
|
||||
scene_output->gamma_lut = NULL;
|
||||
wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
|
||||
scene_output->gamma_lut_color_transform = NULL;
|
||||
wlr_output_state_finish(&gamma_pending);
|
||||
return;
|
||||
}
|
||||
|
|
@ -2122,6 +2129,41 @@ static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_outp
|
|||
wlr_output_state_finish(&gamma_pending);
|
||||
}
|
||||
|
||||
static struct wlr_color_transform *scene_output_combine_color_transforms(
|
||||
struct wlr_scene_output *scene_output, struct wlr_color_transform *supplied) {
|
||||
struct wlr_color_transform *gamma_lut = scene_output->gamma_lut_color_transform;
|
||||
assert(gamma_lut != NULL);
|
||||
|
||||
if (gamma_lut == scene_output->prev_gamma_lut_color_transform &&
|
||||
supplied == scene_output->prev_supplied_color_transform) {
|
||||
return wlr_color_transform_ref(scene_output->prev_combined_color_transform);
|
||||
}
|
||||
|
||||
struct wlr_color_transform *combined;
|
||||
if (supplied == NULL) {
|
||||
combined = wlr_color_transform_ref(gamma_lut);
|
||||
} else {
|
||||
struct wlr_color_transform *transforms[] = {
|
||||
gamma_lut,
|
||||
supplied,
|
||||
};
|
||||
size_t transforms_len = sizeof(transforms) / sizeof(transforms[0]);
|
||||
combined = wlr_color_transform_init_pipeline(transforms, transforms_len);
|
||||
if (combined == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
|
||||
scene_output->prev_gamma_lut_color_transform = wlr_color_transform_ref(gamma_lut);
|
||||
wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
|
||||
scene_output->prev_supplied_color_transform = supplied ? wlr_color_transform_ref(supplied) : NULL;
|
||||
wlr_color_transform_unref(scene_output->prev_combined_color_transform);
|
||||
scene_output->prev_combined_color_transform = wlr_color_transform_ref(combined);
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
||||
struct wlr_output_state *state, const struct wlr_scene_output_state_options *options) {
|
||||
struct wlr_scene_output_state_options default_options = {0};
|
||||
|
|
@ -2145,6 +2187,16 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
enum wlr_scene_debug_damage_option debug_damage =
|
||||
scene_output->scene->debug_damage_option;
|
||||
|
||||
bool render_gamma_lut = false;
|
||||
if (wlr_output_get_gamma_size(output) == 0 && output->renderer->features.output_color_transform) {
|
||||
if (scene_output->gamma_lut_color_transform != scene_output->prev_gamma_lut_color_transform) {
|
||||
scene_output_damage_whole(scene_output);
|
||||
}
|
||||
if (scene_output->gamma_lut_color_transform != NULL) {
|
||||
render_gamma_lut = true;
|
||||
}
|
||||
}
|
||||
|
||||
struct render_data render_data = {
|
||||
.transform = output->transform,
|
||||
.scale = output->scale,
|
||||
|
|
@ -2245,7 +2297,7 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
// - There are no color transforms that need to be applied
|
||||
// - Damage highlight debugging is not enabled
|
||||
enum scene_direct_scanout_result scanout_result = SCANOUT_INELIGIBLE;
|
||||
if (options->color_transform == NULL && list_len == 1
|
||||
if (options->color_transform == NULL && !render_gamma_lut && list_len == 1
|
||||
&& debug_damage != WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
|
||||
scanout_result = scene_entry_try_direct_scanout(&list_data[0], state, &render_data);
|
||||
}
|
||||
|
|
@ -2319,6 +2371,17 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
color_transform = wlr_color_transform_ref(options->color_transform);
|
||||
}
|
||||
|
||||
if (render_gamma_lut) {
|
||||
struct wlr_color_transform *combined =
|
||||
scene_output_combine_color_transforms(scene_output, color_transform);
|
||||
wlr_color_transform_unref(color_transform);
|
||||
if (combined == NULL) {
|
||||
wlr_buffer_unlock(buffer);
|
||||
return false;
|
||||
}
|
||||
color_transform = combined;
|
||||
}
|
||||
|
||||
scene_output->in_point++;
|
||||
struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(output->renderer, buffer,
|
||||
&(struct wlr_buffer_pass_options){
|
||||
|
|
@ -2441,7 +2504,9 @@ bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
|
|||
scene_output->in_point);
|
||||
}
|
||||
|
||||
scene_output_state_attempt_gamma(scene_output, state);
|
||||
if (!render_gamma_lut) {
|
||||
scene_output_state_attempt_gamma(scene_output, state);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
361
types/wlr_action_binder_v1.c
Normal file
361
types/wlr_action_binder_v1.c
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_action_binder_v1.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <util/time.h>
|
||||
#include "ext-action-binder-v1-protocol.h"
|
||||
|
||||
static void resource_handle_destroy(struct wl_client *client, struct wl_resource *resource) {
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static const struct ext_action_binder_v1_interface ext_action_binder_v1_implementation;
|
||||
static struct wlr_action_binder_v1_state *wlr_action_binder_v1_state_from_resource(struct wl_resource *resource) {
|
||||
assert(wl_resource_instance_of(resource, &ext_action_binder_v1_interface, &ext_action_binder_v1_implementation));
|
||||
return wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
static const struct ext_action_binding_v1_interface ext_action_binding_v1_implementation;
|
||||
static struct wlr_action_binding_v1 *wlr_action_binding_v1_from_resource(struct wl_resource *resource) {
|
||||
assert(wl_resource_instance_of(resource, &ext_action_binding_v1_interface, &ext_action_binding_v1_implementation));
|
||||
return wl_resource_get_user_data(resource);
|
||||
}
|
||||
|
||||
static void destroy_binding(struct wlr_action_binding_v1 *binding) {
|
||||
if (!binding) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(binding->category);
|
||||
free(binding->name);
|
||||
|
||||
if (binding->hint.type == WLR_ACTION_BINDING_HINT_V1_KEYBOARD) {
|
||||
free(binding->hint.keycombo);
|
||||
}
|
||||
|
||||
free(binding->description);
|
||||
|
||||
free(binding->app_id);
|
||||
|
||||
wl_list_remove(&binding->link);
|
||||
wl_list_remove(&binding->seat_destroy.link);
|
||||
|
||||
wl_resource_set_user_data(binding->resource, NULL); // make resource inert
|
||||
|
||||
free(binding);
|
||||
}
|
||||
|
||||
static void handle_seat_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_action_binding_v1 *binding = wl_container_of(listener, binding, seat_destroy);
|
||||
wl_list_remove(&binding->seat_destroy.link);
|
||||
binding->seat = NULL;
|
||||
wlr_action_binding_v1_reject(binding);
|
||||
}
|
||||
|
||||
static void action_binding_destroy(struct wl_resource *resource) {
|
||||
struct wlr_action_binding_v1 *binding = wlr_action_binding_v1_from_resource(resource);
|
||||
destroy_binding(binding);
|
||||
}
|
||||
|
||||
static void action_binding_set_name(struct wl_client *client,
|
||||
struct wl_resource *resource, const char *category, const char *name) {
|
||||
struct wlr_action_binding_v1 *binding = wlr_action_binding_v1_from_resource(resource);
|
||||
if (!binding) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (binding->bound || binding->name || binding->category) {
|
||||
wl_resource_post_error(binding->resource,
|
||||
EXT_ACTION_BINDING_V1_ERROR_ALREADY_SET,
|
||||
"attempted to set a binding property twice");
|
||||
return;
|
||||
}
|
||||
|
||||
binding->name = strdup(name);
|
||||
if (binding->name == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
}
|
||||
|
||||
binding->category = strdup(category);
|
||||
if (binding->category == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
}
|
||||
}
|
||||
|
||||
static struct wlr_action_binding_hint_v1 *action_binding_hint_from_resource(struct wl_resource *resource) {
|
||||
struct wlr_action_binding_v1 *binding = wlr_action_binding_v1_from_resource(resource);
|
||||
if (!binding) {
|
||||
return NULL;
|
||||
}
|
||||
if (binding->bound || binding->hint.type != WLR_ACTION_BINDING_HINT_V1_NONE) {
|
||||
wl_resource_post_error(binding->resource,
|
||||
EXT_ACTION_BINDING_V1_ERROR_ALREADY_SET, "attempted to set a hint twice");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &binding->hint;
|
||||
}
|
||||
|
||||
static void action_binding_set_mouse_hint(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t button) {
|
||||
struct wlr_action_binding_hint_v1 *hint = action_binding_hint_from_resource(resource);
|
||||
if (!hint) {
|
||||
return;
|
||||
}
|
||||
|
||||
hint->type = WLR_ACTION_BINDING_HINT_V1_MOUSE;
|
||||
hint->mouse_button = button;
|
||||
}
|
||||
|
||||
static void action_binding_set_keyboard_hint(struct wl_client *client,
|
||||
struct wl_resource *resource, const char *keycombo) {
|
||||
struct wlr_action_binding_hint_v1 *hint = action_binding_hint_from_resource(resource);
|
||||
if (!hint) {
|
||||
return;
|
||||
}
|
||||
|
||||
hint->type = WLR_ACTION_BINDING_HINT_V1_KEYBOARD;
|
||||
hint->keycombo = strdup(keycombo);
|
||||
}
|
||||
|
||||
static void action_binding_set_gesture_hint(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t type, uint32_t direction, uint32_t fingers) {
|
||||
struct wlr_action_binding_hint_v1 *hint = action_binding_hint_from_resource(resource);
|
||||
if (!hint) {
|
||||
return;
|
||||
}
|
||||
|
||||
hint->type = WLR_ACTION_BINDING_HINT_V1_GESTURE;
|
||||
hint->gesture.type = type;
|
||||
hint->gesture.direction = direction;
|
||||
hint->gesture.fingers = fingers;
|
||||
}
|
||||
|
||||
static void action_binding_set_desc(struct wl_client *client,
|
||||
struct wl_resource *resource, const char *description) {
|
||||
struct wlr_action_binding_v1 *binding = wlr_action_binding_v1_from_resource(resource);
|
||||
if (!binding) {
|
||||
return;
|
||||
}
|
||||
if (binding->bound || binding->description) {
|
||||
wl_resource_post_error(binding->resource,
|
||||
EXT_ACTION_BINDING_V1_ERROR_ALREADY_SET,
|
||||
"attempted to set a binding property twice");
|
||||
return;
|
||||
}
|
||||
|
||||
binding->description = strdup(description);
|
||||
if (binding->description == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
}
|
||||
}
|
||||
|
||||
static void action_binding_set_app_id(struct wl_client *client,
|
||||
struct wl_resource *resource, const char *app_id) {
|
||||
struct wlr_action_binding_v1 *binding = wlr_action_binding_v1_from_resource(resource);
|
||||
if (!binding) {
|
||||
return;
|
||||
}
|
||||
if (binding->bound || binding->app_id) {
|
||||
wl_resource_post_error(binding->resource,
|
||||
EXT_ACTION_BINDING_V1_ERROR_ALREADY_SET,
|
||||
"attempted to set a binding property twice");
|
||||
return;
|
||||
}
|
||||
|
||||
binding->app_id = strdup(app_id);
|
||||
if (binding->app_id == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
}
|
||||
}
|
||||
|
||||
static void action_binding_set_seat(struct wl_client *client,
|
||||
struct wl_resource *resource, struct wl_resource *seat_resource) {
|
||||
struct wlr_action_binding_v1 *binding = wlr_action_binding_v1_from_resource(resource);
|
||||
if (!binding) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (binding->bound || binding->seat) {
|
||||
wl_resource_post_error(binding->resource,
|
||||
EXT_ACTION_BINDING_V1_ERROR_ALREADY_SET,
|
||||
"attempted to set a binding property twice");
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource);
|
||||
binding->seat = seat_client ? seat_client->seat : NULL;
|
||||
if (binding->seat) {
|
||||
wl_signal_add(&binding->seat->events.destroy, &binding->seat_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct ext_action_binding_v1_interface ext_action_binding_v1_implementation = {
|
||||
.destroy = resource_handle_destroy,
|
||||
.set_mouse_hint = action_binding_set_mouse_hint,
|
||||
.set_keyboard_hint = action_binding_set_keyboard_hint,
|
||||
.set_gesture_hint = action_binding_set_gesture_hint,
|
||||
.set_description = action_binding_set_desc,
|
||||
.set_name = action_binding_set_name,
|
||||
.set_app_id = action_binding_set_app_id,
|
||||
.set_seat = action_binding_set_seat,
|
||||
};
|
||||
|
||||
static void action_binder_create_binding(struct wl_client *client,
|
||||
struct wl_resource *resource, uint32_t binding) {
|
||||
struct wlr_action_binder_v1_state *state = wlr_action_binder_v1_state_from_resource(resource);
|
||||
|
||||
struct wl_resource *bind_resource = wl_resource_create(client,
|
||||
&ext_action_binding_v1_interface, ext_action_binding_v1_interface.version, binding);
|
||||
if (bind_resource == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_action_binding_v1 *bind = calloc(1, sizeof(*bind));
|
||||
if (bind == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
wl_resource_destroy(bind_resource);
|
||||
return;
|
||||
}
|
||||
bind->resource = bind_resource;
|
||||
bind->state = state;
|
||||
bind->bound = false;
|
||||
|
||||
wl_list_init(&bind->link);
|
||||
wl_signal_init(&bind->events.destroy);
|
||||
wl_list_insert(&state->bind_queue, &bind->link);
|
||||
|
||||
wl_list_init(&bind->seat_destroy.link);
|
||||
bind->seat_destroy.notify = handle_seat_destroy;
|
||||
|
||||
wl_resource_set_implementation(bind_resource,
|
||||
&ext_action_binding_v1_implementation, bind, action_binding_destroy);
|
||||
}
|
||||
|
||||
static void action_binder_commit(struct wl_client *client, struct wl_resource *resource) {
|
||||
struct wlr_action_binder_v1_state *state = wlr_action_binder_v1_state_from_resource(resource);
|
||||
struct wlr_action_binding_v1 *binding = NULL;
|
||||
|
||||
wl_list_for_each(binding, &state->bind_queue, link) {
|
||||
if (!binding->category || !binding->name) {
|
||||
wl_resource_post_error(binding->resource,
|
||||
EXT_ACTION_BINDER_V1_ERROR_INVALID_BINDING,
|
||||
"attempted to bind a unactionable binding");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wl_signal_emit_mutable(&state->binder->events.bind, state);
|
||||
}
|
||||
|
||||
static const struct ext_action_binder_v1_interface ext_action_binder_v1_implementation = {
|
||||
.create_binding = action_binder_create_binding,
|
||||
.commit = action_binder_commit,
|
||||
.destroy = resource_handle_destroy,
|
||||
};
|
||||
|
||||
static void action_binder_destroy(struct wl_resource *resource) {
|
||||
struct wlr_action_binder_v1_state *state = wlr_action_binder_v1_state_from_resource(resource);
|
||||
struct wlr_action_binding_v1 *binding = NULL, *tmp = NULL;
|
||||
|
||||
wl_list_for_each_safe(binding, tmp, &state->binds, link) {
|
||||
wl_signal_emit(&binding->events.destroy, NULL);
|
||||
destroy_binding(binding);
|
||||
}
|
||||
|
||||
wl_list_for_each_safe(binding, tmp, &state->bind_queue, link) {
|
||||
destroy_binding(binding);
|
||||
}
|
||||
|
||||
wl_list_remove(&state->link);
|
||||
|
||||
free(state);
|
||||
}
|
||||
|
||||
static void action_binder_bind(struct wl_client *wl_client,
|
||||
void *data, uint32_t version, uint32_t id) {
|
||||
struct wlr_action_binder_v1 *binder = data;
|
||||
|
||||
struct wl_resource *resource = wl_resource_create(wl_client,
|
||||
&ext_action_binder_v1_interface, version, id);
|
||||
if (resource == NULL) {
|
||||
wl_client_post_no_memory(wl_client);
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_action_binder_v1_state *state = calloc(1, sizeof(*state));
|
||||
if (state == NULL) {
|
||||
wl_client_post_no_memory(wl_client);
|
||||
wl_resource_destroy(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_list_init(&state->binds);
|
||||
wl_list_init(&state->bind_queue);
|
||||
state->binder = binder;
|
||||
state->resource = resource;
|
||||
|
||||
wl_list_insert(&binder->states, &state->link);
|
||||
|
||||
wl_resource_set_implementation(resource,
|
||||
&ext_action_binder_v1_implementation, state, action_binder_destroy);
|
||||
}
|
||||
|
||||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_action_binder_v1 *binder = wl_container_of(listener, binder, display_destroy);
|
||||
wl_signal_emit(&binder->events.destroy, NULL);
|
||||
wl_list_remove(&binder->display_destroy.link);
|
||||
wl_global_destroy(binder->global);
|
||||
free(binder);
|
||||
}
|
||||
|
||||
struct wlr_action_binder_v1 *wlr_action_binder_v1_create(struct wl_display *display) {
|
||||
struct wlr_action_binder_v1 *action_binder = calloc(1, sizeof(*action_binder));
|
||||
if (!action_binder) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wl_global *global = wl_global_create(display,
|
||||
&ext_action_binder_v1_interface, 1, action_binder, action_binder_bind);
|
||||
if (!global) {
|
||||
free(action_binder);
|
||||
return NULL;
|
||||
}
|
||||
action_binder->global = global;
|
||||
|
||||
wl_signal_init(&action_binder->events.bind);
|
||||
wl_signal_init(&action_binder->events.destroy);
|
||||
wl_list_init(&action_binder->states);
|
||||
|
||||
action_binder->display_destroy.notify = handle_display_destroy;
|
||||
wl_display_add_destroy_listener(display, &action_binder->display_destroy);
|
||||
|
||||
return action_binder;
|
||||
}
|
||||
|
||||
void wlr_action_binding_v1_bind(struct wlr_action_binding_v1 *binding, const char *trigger) {
|
||||
assert(!binding->bound);
|
||||
binding->bound = true;
|
||||
wl_list_remove(&binding->link);
|
||||
wl_list_insert(&binding->state->binds, &binding->link);
|
||||
|
||||
ext_action_binding_v1_send_bound(binding->resource, trigger);
|
||||
}
|
||||
|
||||
void wlr_action_binding_v1_reject(struct wlr_action_binding_v1 *binding) {
|
||||
ext_action_binding_v1_send_rejected(binding->resource);
|
||||
wl_signal_emit(&binding->events.destroy, NULL);
|
||||
destroy_binding(binding);
|
||||
}
|
||||
|
||||
void wlr_action_binding_v1_trigger(struct wlr_action_binding_v1 *binding, uint32_t trigger_type, uint32_t time_msec) {
|
||||
ext_action_binding_v1_send_triggered(binding->resource, time_msec, trigger_type);
|
||||
}
|
||||
|
|
@ -157,6 +157,9 @@ static void gamma_control_manager_get_gamma_control(struct wl_client *client,
|
|||
}
|
||||
|
||||
size_t gamma_size = wlr_output_get_gamma_size(output);
|
||||
if (gamma_size == 0) {
|
||||
gamma_size = manager->fallback_gamma_size;
|
||||
}
|
||||
if (gamma_size == 0) {
|
||||
zwlr_gamma_control_v1_send_failed(resource);
|
||||
return;
|
||||
|
|
@ -262,15 +265,24 @@ struct wlr_gamma_control_v1 *wlr_gamma_control_manager_v1_get_control(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_color_transform *wlr_gamma_control_v1_get_color_transform(
|
||||
struct wlr_gamma_control_v1 *gamma_control) {
|
||||
if (gamma_control == NULL || gamma_control->table == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint16_t *r = gamma_control->table;
|
||||
const uint16_t *g = gamma_control->table + gamma_control->ramp_size;
|
||||
const uint16_t *b = gamma_control->table + 2 * gamma_control->ramp_size;
|
||||
|
||||
return wlr_color_transform_init_lut_3x1d(gamma_control->ramp_size, r, g, b);
|
||||
}
|
||||
|
||||
bool wlr_gamma_control_v1_apply(struct wlr_gamma_control_v1 *gamma_control,
|
||||
struct wlr_output_state *output_state) {
|
||||
struct wlr_color_transform *tr = NULL;
|
||||
if (gamma_control != NULL && gamma_control->table != NULL) {
|
||||
const uint16_t *r = gamma_control->table;
|
||||
const uint16_t *g = gamma_control->table + gamma_control->ramp_size;
|
||||
const uint16_t *b = gamma_control->table + 2 * gamma_control->ramp_size;
|
||||
|
||||
tr = wlr_color_transform_init_lut_3x1d(gamma_control->ramp_size, r, g, b);
|
||||
tr = wlr_gamma_control_v1_get_color_transform(gamma_control);
|
||||
if (tr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ struct wlr_linux_drm_syncobj_surface_v1 {
|
|||
};
|
||||
|
||||
struct wlr_linux_drm_syncobj_surface_v1_commit {
|
||||
struct wlr_linux_drm_syncobj_surface_v1 *surface;
|
||||
struct wlr_surface *surface;
|
||||
struct wlr_drm_syncobj_timeline_waiter waiter;
|
||||
uint32_t cached_seq;
|
||||
|
||||
|
|
@ -192,7 +192,7 @@ static struct wlr_linux_drm_syncobj_surface_v1 *surface_from_wlr_surface(
|
|||
}
|
||||
|
||||
static void surface_commit_destroy(struct wlr_linux_drm_syncobj_surface_v1_commit *commit) {
|
||||
wlr_surface_unlock_cached(commit->surface->surface, commit->cached_seq);
|
||||
wlr_surface_unlock_cached(commit->surface, commit->cached_seq);
|
||||
wl_list_remove(&commit->surface_destroy.link);
|
||||
wlr_drm_syncobj_timeline_waiter_finish(&commit->waiter);
|
||||
free(commit);
|
||||
|
|
@ -237,7 +237,7 @@ static bool lock_surface_commit(struct wlr_linux_drm_syncobj_surface_v1 *surface
|
|||
return false;
|
||||
}
|
||||
|
||||
commit->surface = surface;
|
||||
commit->surface = surface->surface;
|
||||
commit->cached_seq = wlr_surface_lock_pending(surface->surface);
|
||||
|
||||
commit->surface_destroy.notify = surface_commit_handle_surface_destroy;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ static void handle_server_start(struct wl_listener *listener, void *data) {
|
|||
static void xwayland_mark_ready(struct wlr_xwayland *xwayland) {
|
||||
assert(xwayland->server->wm_fd[0] >= 0);
|
||||
xwayland->xwm = xwm_create(xwayland, xwayland->server->wm_fd[0]);
|
||||
// xwm_create takes ownership of wm_fd[0] under all circumstances
|
||||
xwayland->server->wm_fd[0] = -1;
|
||||
|
||||
if (!xwayland->xwm) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2530,6 +2530,7 @@ void xwm_set_cursor(struct wlr_xwm *xwm, const uint8_t *pixels, uint32_t stride,
|
|||
struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
|
||||
struct wlr_xwm *xwm = calloc(1, sizeof(*xwm));
|
||||
if (xwm == NULL) {
|
||||
close(wm_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -2544,11 +2545,13 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *xwayland, int wm_fd) {
|
|||
|
||||
xwm->ping_timeout = 10000;
|
||||
|
||||
// xcb_connect_to_fd takes ownership of the FD regardless of success/failure
|
||||
xwm->xcb_conn = xcb_connect_to_fd(wm_fd, NULL);
|
||||
|
||||
int rc = xcb_connection_has_error(xwm->xcb_conn);
|
||||
if (rc) {
|
||||
wlr_log(WLR_ERROR, "xcb connect failed: %d", rc);
|
||||
xcb_disconnect(xwm->xcb_conn);
|
||||
free(xwm);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue