diff --git a/drw.c b/drw.c index 94e9983..5dde3d1 100644 --- a/drw.c +++ b/drw.c @@ -6,7 +6,7 @@ #include "shm_open.h" void -drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, uint32_t s) { +drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, double s) { if (ds->buf) { munmap(ds->pool_data, ds->size); wl_buffer_destroy(ds->buf); @@ -131,7 +131,5 @@ setup_buffer(struct drwsurf *drwsurf) { pango_layout_set_auto_dir(drwsurf->layout, false); cairo_save(drwsurf->cairo); - wl_surface_set_buffer_scale(drwsurf->surf, drwsurf->scale); - return 0; } diff --git a/drw.h b/drw.h index 3fb6ce0..2e5c919 100644 --- a/drw.h +++ b/drw.h @@ -9,7 +9,8 @@ struct drw { PangoFontDescription *font_description; }; struct drwsurf { - uint32_t width, height, scale, size; + uint32_t width, height, size; + double scale; struct drw *ctx; struct wl_surface *surf; @@ -22,7 +23,7 @@ struct drwsurf { }; struct kbd; -void drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, uint32_t s); +void drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, double s); void drwsurf_flip(struct drwsurf *ds); typedef union { diff --git a/keyboard.c b/keyboard.c index 5ee5981..356caea 100644 --- a/keyboard.c +++ b/keyboard.c @@ -580,7 +580,7 @@ kbd_draw_layout(struct kbd *kb) { void kbd_resize(struct kbd *kb, struct layout *layouts, uint8_t layoutcount) { - fprintf(stderr, "Resize %dx%d %d, %d layouts\n", kb->w, kb->h, kb->scale, + fprintf(stderr, "Resize %dx%d %f, %d layouts\n", kb->w, kb->h, kb->scale, layoutcount); drwsurf_resize(kb->surf, kb->w, kb->h, kb->scale); diff --git a/keyboard.h b/keyboard.h index e45444d..2c3bffc 100644 --- a/keyboard.h +++ b/keyboard.h @@ -95,7 +95,8 @@ struct kbd { bool print; bool print_intersect; - uint32_t w, h, scale; + uint32_t w, h; + double scale; bool landscape; uint8_t mods; uint8_t compose; diff --git a/main.c b/main.c index 82ec700..549e665 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,8 @@ #include "proto/virtual-keyboard-unstable-v1-client-protocol.h" #include "proto/wlr-layer-shell-unstable-v1-client-protocol.h" #include "proto/xdg-shell-client-protocol.h" +#include "proto/fractional-scale-v1-client-protocol.h" +#include "proto/viewporter-client-protocol.h" #include #include #include @@ -36,6 +38,10 @@ static struct xdg_surface *popup_xdg_surface; static struct xdg_popup *popup_xdg_popup; static struct xdg_positioner *popup_xdg_positioner; static struct zwp_virtual_keyboard_manager_v1 *vkbd_mgr; +static struct wp_fractional_scale_v1 *wfs_draw_surf; +static struct wp_fractional_scale_manager_v1 *wfs_mgr; +static struct wp_viewport *draw_surf_viewport, *popup_draw_surf_viewport; +static struct wp_viewporter *viewporter; struct Output { uint32_t name; @@ -355,7 +361,11 @@ display_handle_done(void *data, struct wl_output *wl_output) {} static void display_handle_scale(void *data, struct wl_output *wl_output, int32_t scale) { ((struct Output*)data)->scale = scale; + if (wfs_mgr && viewporter) { + return; + } keyboard.scale = scale; + wl_surface_set_buffer_scale(draw_surf.surf, scale); } static void @@ -404,6 +414,12 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); xdg_wm_base_add_listener(wm_base, &xdg_wm_base_listener, NULL); + } else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0) { + wfs_mgr = + wl_registry_bind(registry, name, &wp_fractional_scale_manager_v1_interface, 1); + } else if (strcmp(interface, wp_viewporter_interface.name) == 0) { + viewporter = + wl_registry_bind(registry, name, &wp_viewporter_interface, 1); } else if (strcmp(interface, zwp_virtual_keyboard_manager_v1_interface.name) == 0) { vkbd_mgr = wl_registry_bind(registry, name, @@ -458,6 +474,18 @@ static const struct xdg_popup_listener xdg_popup_listener = { .popup_done = xdg_popup_done, }; +static void +wp_fractional_scale_prefered_scale(void *data, + struct wp_fractional_scale_v1 *wp_fractional_scale_v1, + uint32_t scale) +{ + keyboard.scale = (double)scale / 120; +} + +static const struct wp_fractional_scale_v1_listener wp_fractional_scale_listener = { + .preferred_scale = wp_fractional_scale_prefered_scale, +}; + void layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t w, uint32_t h) { @@ -465,20 +493,48 @@ layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface, keyboard.w = w; keyboard.h = h; - xdg_positioner_set_size(popup_xdg_positioner, w, h*2); - xdg_positioner_set_anchor_rect(popup_xdg_positioner, 0, -h, w, h*2); + if (wfs_mgr && viewporter) { + if (!wfs_draw_surf) { + wfs_draw_surf = wp_fractional_scale_manager_v1_get_fractional_scale(wfs_mgr, draw_surf.surf); + wp_fractional_scale_v1_add_listener(wfs_draw_surf, &wp_fractional_scale_listener, NULL); + } + if (!draw_surf_viewport) { + draw_surf_viewport = wp_viewporter_get_viewport(viewporter, draw_surf.surf); + } + wp_viewport_set_destination(draw_surf_viewport, keyboard.w, keyboard.h); + } else { + wl_surface_set_buffer_scale(draw_surf.surf, keyboard.scale); + } if (popup_xdg_popup) { xdg_popup_destroy(popup_xdg_popup); } + if (popup_xdg_surface) { + xdg_surface_destroy(popup_xdg_surface); + } + if (popup_draw_surf.surf) { + wl_surface_destroy(popup_draw_surf.surf); + } popup_draw_surf.surf = wl_compositor_create_surface(compositor); + + xdg_positioner_set_size(popup_xdg_positioner, w, h*2); + xdg_positioner_set_anchor_rect(popup_xdg_positioner, 0, -h, w, h*2); + wl_surface_set_input_region(popup_draw_surf.surf, empty_region); popup_xdg_surface = xdg_wm_base_get_xdg_surface(wm_base, popup_draw_surf.surf); xdg_surface_add_listener(popup_xdg_surface, &xdg_popup_surface_listener, NULL); popup_xdg_popup = xdg_surface_get_popup(popup_xdg_surface, NULL, popup_xdg_positioner); xdg_popup_add_listener(popup_xdg_popup, &xdg_popup_listener, NULL); zwlr_layer_surface_v1_get_popup(layer_surface, popup_xdg_popup); + + if (wfs_mgr && viewporter) { + popup_draw_surf_viewport = wp_viewporter_get_viewport(viewporter, popup_draw_surf.surf); + wp_viewport_set_destination(popup_draw_surf_viewport, keyboard.w, keyboard.h * 2); + } else { + wl_surface_set_buffer_scale(popup_draw_surf.surf, keyboard.scale); + } + wl_surface_commit(popup_draw_surf.surf); } diff --git a/proto/fractional-scale-v1.xml b/proto/fractional-scale-v1.xml new file mode 100644 index 0000000..350bfc0 --- /dev/null +++ b/proto/fractional-scale-v1.xml @@ -0,0 +1,102 @@ + + + + Copyright © 2022 Kenny Levinsen + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol allows a compositor to suggest for surfaces to render at + fractional scales. + + A client can submit scaled content by utilizing wp_viewport. This is done by + creating a wp_viewport object for the surface and setting the destination + rectangle to the surface size before the scale factor is applied. + + The buffer size is calculated by multiplying the surface size by the + intended scale. + + The wl_surface buffer scale should remain set to 1. + + If a surface has a surface-local size of 100 px by 50 px and wishes to + submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should + be used and the wp_viewport destination rectangle should be 100 px by 50 px. + + For toplevel surfaces, the size is rounded halfway away from zero. The + rounding algorithm for subsurface position and size is not defined. + + + + + A global interface for requesting surfaces to use fractional scales. + + + + + Informs the server that the client will not be using this protocol + object anymore. This does not affect any other objects, + wp_fractional_scale_v1 objects included. + + + + + + + + + + Create an add-on object for the the wl_surface to let the compositor + request fractional scales. If the given wl_surface already has a + wp_fractional_scale_v1 object associated, the fractional_scale_exists + protocol error is raised. + + + + + + + + + An additional interface to a wl_surface object which allows the compositor + to inform the client of the preferred scale. + + + + + Destroy the fractional scale object. When this object is destroyed, + preferred_scale events will no longer be sent. + + + + + + Notification of a new preferred scale for this surface that the + compositor suggests that the client should use. + + The sent scale is the numerator of a fraction with a denominator of 120. + + + + + diff --git a/proto/viewporter.xml b/proto/viewporter.xml new file mode 100644 index 0000000..d1048d1 --- /dev/null +++ b/proto/viewporter.xml @@ -0,0 +1,180 @@ + + + + + Copyright © 2013-2016 Collabora, Ltd. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + The global interface exposing surface cropping and scaling + capabilities is used to instantiate an interface extension for a + wl_surface object. This extended interface will then allow + cropping and scaling the surface contents, effectively + disconnecting the direct relationship between the buffer and the + surface size. + + + + + Informs the server that the client will not be using this + protocol object anymore. This does not affect any other objects, + wp_viewport objects included. + + + + + + + + + + Instantiate an interface extension for the given wl_surface to + crop and scale its content. If the given wl_surface already has + a wp_viewport object associated, the viewport_exists + protocol error is raised. + + + + + + + + + An additional interface to a wl_surface object, which allows the + client to specify the cropping and scaling of the surface + contents. + + This interface works with two concepts: the source rectangle (src_x, + src_y, src_width, src_height), and the destination size (dst_width, + dst_height). The contents of the source rectangle are scaled to the + destination size, and content outside the source rectangle is ignored. + This state is double-buffered, and is applied on the next + wl_surface.commit. + + The two parts of crop and scale state are independent: the source + rectangle, and the destination size. Initially both are unset, that + is, no scaling is applied. The whole of the current wl_buffer is + used as the source, and the surface size is as defined in + wl_surface.attach. + + If the destination size is set, it causes the surface size to become + dst_width, dst_height. The source (rectangle) is scaled to exactly + this size. This overrides whatever the attached wl_buffer size is, + unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + has no content and therefore no size. Otherwise, the size is always + at least 1x1 in surface local coordinates. + + If the source rectangle is set, it defines what area of the wl_buffer is + taken as the source. If the source rectangle is set and the destination + size is not set, then src_width and src_height must be integers, and the + surface size becomes the source rectangle size. This results in cropping + without scaling. If src_width or src_height are not integers and + destination size is not set, the bad_size protocol error is raised when + the surface state is applied. + + The coordinate transformations from buffer pixel coordinates up to + the surface-local coordinates happen in the following order: + 1. buffer_transform (wl_surface.set_buffer_transform) + 2. buffer_scale (wl_surface.set_buffer_scale) + 3. crop and scale (wp_viewport.set*) + This means, that the source rectangle coordinates of crop and scale + are given in the coordinates after the buffer transform and scale, + i.e. in the coordinates that would be the surface-local coordinates + if the crop and scale was not applied. + + If src_x or src_y are negative, the bad_value protocol error is raised. + Otherwise, if the source rectangle is partially or completely outside of + the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + when the surface state is applied. A NULL wl_buffer does not raise the + out_of_buffer error. + + If the wl_surface associated with the wp_viewport is destroyed, + all wp_viewport requests except 'destroy' raise the protocol error + no_surface. + + If the wp_viewport object is destroyed, the crop and scale + state is removed from the wl_surface. The change will be applied + on the next wl_surface.commit. + + + + + The associated wl_surface's crop and scale state is removed. + The change is applied on the next wl_surface.commit. + + + + + + + + + + + + + Set the source rectangle of the associated wl_surface. See + wp_viewport for the description, and relation to the wl_buffer + size. + + If all of x, y, width and height are -1.0, the source rectangle is + unset instead. Any other set of values where width or height are zero + or negative, or x or y are negative, raise the bad_value protocol + error. + + The crop and scale state is double-buffered state, and will be + applied on the next wl_surface.commit. + + + + + + + + + + Set the destination size of the associated wl_surface. See + wp_viewport for the description, and relation to the wl_buffer + size. + + If width is -1 and height is -1, the destination size is unset + instead. Any other pair of values for width and height that + contains zero or negative values raises the bad_value protocol + error. + + The crop and scale state is double-buffered state, and will be + applied on the next wl_surface.commit. + + + + + + +