kiss-nihal

personal KISS Linux package repo
git clone git://git.nihaljere.xyz/kiss-nihal
Log | Files | Refs | Submodules

popup.patch (10928B)


      1 From 86be336e59c9adc3771fb15bd590d39469d52d05 Mon Sep 17 00:00:00 2001
      2 From: ian <42294085+ianbeyst@users.noreply.github.com>
      3 Date: Tue, 14 Apr 2020 00:59:42 +0200
      4 Subject: [PATCH] Implement xdg shell popup support
      5 
      6 Menu bars and other popups in graphical applications should now work
      7 properly. The implementation is very rough and still requires a lot of
      8 polishing, but it works for now.
      9 ---
     10  libswc/xdg_shell.c | 245 ++++++++++++++++++++++++++++++++++++++++++++-
     11  1 file changed, 240 insertions(+), 5 deletions(-)
     12 
     13 diff --git a/libswc/xdg_shell.c b/libswc/xdg_shell.c
     14 index 6ee4f73..9236b48 100644
     15 --- a/libswc/xdg_shell.c
     16 +++ b/libswc/xdg_shell.c
     17 @@ -22,8 +22,10 @@
     18   */
     19  
     20  #include "xdg_shell.h"
     21 +#include "compositor.h"
     22  #include "internal.h"
     23  #include "seat.h"
     24 +#include "keyboard.h"
     25  #include "surface.h"
     26  #include "util.h"
     27  #include "window.h"
     28 @@ -33,15 +35,43 @@
     29  #include <wayland-server.h>
     30  #include "xdg-shell-server-protocol.h"
     31  
     32 +enum xdg_surface_role {
     33 +    XDG_SURFACE_ROLE_NONE,
     34 +    XDG_SURFACE_ROLE_TOPLEVEL,
     35 +    XDG_SURFACE_ROLE_POPUP,
     36 +};
     37 +
     38  struct xdg_surface {
     39  	struct wl_resource *resource, *role;
     40  	struct surface *surface;
     41  	struct wl_listener surface_destroy_listener, role_destroy_listener;
     42  	uint32_t configure_serial;
     43 +    enum xdg_surface_role surface_role;
     44  };
     45  
     46  struct xdg_positioner {
     47  	struct wl_resource *resource;
     48 +
     49 +	struct {
     50 +        uint32_t width;
     51 +        uint32_t height;
     52 +	} size;
     53 +
     54 +	struct {
     55 +        int32_t x;
     56 +        int32_t y;
     57 +        uint32_t width;
     58 +        uint32_t height;
     59 +	} anchor_rect;
     60 +
     61 +	uint32_t anchor;
     62 +	uint32_t gravity;
     63 +	uint32_t constraint_adjustment;
     64 +
     65 +	struct {
     66 +        int32_t x;
     67 +        int32_t y;
     68 +	} offset;
     69  };
     70  
     71  struct xdg_toplevel {
     72 @@ -51,7 +81,87 @@ struct xdg_toplevel {
     73  	struct xdg_surface *xdg_surface;
     74  };
     75  
     76 +struct xdg_popup {
     77 +    struct compositor_view* view;
     78 +	struct wl_resource *resource;
     79 +	struct xdg_surface *xdg_surface;
     80 +	struct xdg_surface *parent;
     81 +};
     82 +
     83  /* xdg_positioner */
     84 +static struct swc_rectangle
     85 +xdg_positioner_get_geometry(struct xdg_positioner *positioner)
     86 +{
     87 +	struct swc_rectangle geometry = {
     88 +		.x = positioner->offset.x,
     89 +		.y = positioner->offset.y,
     90 +		.width = positioner->size.width,
     91 +		.height = positioner->size.height,
     92 +	};
     93 +
     94 +	switch (positioner->anchor) {
     95 +		case XDG_POSITIONER_ANCHOR_TOP:
     96 +		case XDG_POSITIONER_ANCHOR_TOP_LEFT:
     97 +		case XDG_POSITIONER_ANCHOR_TOP_RIGHT:
     98 +			geometry.y += positioner->anchor_rect.y;
     99 +			break;
    100 +		case XDG_POSITIONER_ANCHOR_BOTTOM:
    101 +		case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:
    102 +		case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
    103 +			geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height;
    104 +			break;
    105 +		default:
    106 +			geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height / 2;
    107 +	}
    108 +
    109 +	switch (positioner->anchor) {
    110 +		case XDG_POSITIONER_ANCHOR_LEFT:
    111 +		case XDG_POSITIONER_ANCHOR_TOP_LEFT:
    112 +		case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:
    113 +			geometry.x += positioner->anchor_rect.x;
    114 +			break;
    115 +		case XDG_POSITIONER_ANCHOR_RIGHT:
    116 +		case XDG_POSITIONER_ANCHOR_TOP_RIGHT:
    117 +		case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
    118 +			geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width;
    119 +			break;
    120 +		default:
    121 +			geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width / 2;
    122 +	}
    123 +
    124 +	switch (positioner->gravity) {
    125 +		case XDG_POSITIONER_GRAVITY_TOP:
    126 +		case XDG_POSITIONER_GRAVITY_TOP_LEFT:
    127 +		case XDG_POSITIONER_GRAVITY_TOP_RIGHT:
    128 +			geometry.y -= geometry.height;
    129 +			break;
    130 +		case XDG_POSITIONER_GRAVITY_BOTTOM:
    131 +		case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT:
    132 +		case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT:
    133 +			geometry.y = geometry.y;
    134 +			break;
    135 +		default:
    136 +			geometry.y -= geometry.height / 2;
    137 +	}
    138 +
    139 +	switch (positioner->gravity) {
    140 +		case XDG_POSITIONER_GRAVITY_LEFT:
    141 +		case XDG_POSITIONER_GRAVITY_TOP_LEFT:
    142 +		case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT:
    143 +			geometry.x -= geometry.width;
    144 +			break;
    145 +		case XDG_POSITIONER_GRAVITY_RIGHT:
    146 +		case XDG_POSITIONER_GRAVITY_TOP_RIGHT:
    147 +		case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT:
    148 +			geometry.x = geometry.x;
    149 +			break;
    150 +		default:
    151 +			geometry.x -= geometry.width / 2;
    152 +	}
    153 +
    154 +	return geometry;
    155 +}
    156 +
    157  static void
    158  destroy_positioner(struct wl_resource *resource)
    159  {
    160 @@ -63,31 +173,65 @@ destroy_positioner(struct wl_resource *resource)
    161  static void
    162  set_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height)
    163  {
    164 +	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
    165 +
    166 +	if (width < 1 || height < 1) {
    167 +		wl_resource_post_error(resource,
    168 +				       XDG_POSITIONER_ERROR_INVALID_INPUT,
    169 +				       "width and height must be positives and non-zero");
    170 +		return;
    171 +	}
    172 +
    173 +	positioner->size.width = width;
    174 +	positioner->size.height = height;
    175  }
    176  
    177  static void
    178  set_anchor_rect(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
    179  {
    180 +	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
    181 +
    182 +	if (width < 0 || height < 0) {
    183 +		wl_resource_post_error(resource,
    184 +				       XDG_POSITIONER_ERROR_INVALID_INPUT,
    185 +				       "width and height must be non-negative");
    186 +		return;
    187 +	}
    188 +
    189 +	positioner->anchor_rect.x = x;
    190 +	positioner->anchor_rect.y = y;
    191 +	positioner->anchor_rect.width = width;
    192 +	positioner->anchor_rect.height = height;
    193  }
    194  
    195  static void
    196  set_anchor(struct wl_client *client, struct wl_resource *resource, uint32_t anchor)
    197  {
    198 +	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
    199 +	positioner->anchor = anchor;
    200  }
    201  
    202  static void
    203  set_gravity(struct wl_client *client, struct wl_resource *resource, uint32_t gravity)
    204  {
    205 +	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
    206 +	positioner->gravity = gravity;
    207  }
    208  
    209  static void
    210  set_constraint_adjustment(struct wl_client *client, struct wl_resource *resource, uint32_t adjustment)
    211  {
    212 +	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
    213 +	positioner->constraint_adjustment = adjustment;
    214  }
    215  
    216  static void
    217  set_offset(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y)
    218  {
    219 +	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
    220 +
    221 +	positioner->offset.x = x;
    222 +	positioner->offset.y = y;
    223  }
    224  
    225  static const struct xdg_positioner_interface positioner_impl = {
    226 @@ -100,6 +244,42 @@ static const struct xdg_positioner_interface positioner_impl = {
    227  	.set_offset = set_offset,
    228  };
    229  
    230 +/* xdg_popup */
    231 +static void
    232 +destroy_popup(struct wl_resource *resource)
    233 +{
    234 +	struct xdg_popup *popup = wl_resource_get_user_data(resource);
    235 +
    236 +    compositor_view_destroy(popup->view);
    237 +	free(popup);
    238 +}
    239 +
    240 +static uint32_t
    241 +popup_send_configure(struct xdg_popup *popup, int32_t x, int32_t y, int32_t width, int32_t height) {
    242 +	uint32_t serial = wl_display_next_serial(swc.display);
    243 +
    244 +	xdg_popup_send_configure(popup->resource, x, y, width, height);
    245 +	xdg_surface_send_configure(popup->xdg_surface->resource, serial);
    246 +
    247 +	return serial;
    248 +}
    249 +
    250 +static void
    251 +grab(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial)
    252 +{
    253 +}
    254 +
    255 +static void
    256 +reposition(struct wl_client *client, struct wl_resource *resource, struct wl_resource *positioner, uint32_t token)
    257 +{
    258 +}
    259 +
    260 +static const struct xdg_popup_interface popup_impl = {
    261 +	.destroy = destroy_resource,
    262 +	.grab = grab,
    263 +	.reposition = reposition,
    264 +};
    265 +
    266  /* xdg_toplevel */
    267  static void
    268  destroy_toplevel(struct wl_resource *resource)
    269 @@ -356,6 +536,31 @@ xdg_toplevel_new(struct wl_client *client, uint32_t version, uint32_t id, struct
    270  	return NULL;
    271  }
    272  
    273 +static struct xdg_popup *
    274 +xdg_popup_new(struct wl_client *client, uint32_t version, uint32_t id, struct xdg_surface *xdg_surface, struct xdg_surface *parent)
    275 +{
    276 +	struct xdg_popup *popup;
    277 +
    278 +	popup = malloc(sizeof(*popup));
    279 +	if (!popup)
    280 +		goto error0;
    281 +	popup->xdg_surface = xdg_surface;
    282 +	popup->parent = parent;
    283 +	popup->resource = wl_resource_create(client, &xdg_popup_interface, version, id);
    284 +	if (!popup->resource)
    285 +		goto error1;
    286 +
    287 +    popup->view = compositor_create_view(popup->xdg_surface->surface);
    288 +    wl_resource_set_implementation(popup->resource, &popup_impl, popup, &destroy_popup);
    289 +
    290 +	return popup;
    291 +
    292 +error1:
    293 +	free(popup);
    294 +error0:
    295 +	return NULL;
    296 +}
    297 +
    298  /* xdg_surface */
    299  static void
    300  get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id)
    301 @@ -373,25 +578,55 @@ get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id
    302  		return;
    303  	}
    304  	xdg_surface->role = toplevel->resource;
    305 +    xdg_surface->surface_role = XDG_SURFACE_ROLE_TOPLEVEL;
    306  	wl_resource_add_destroy_listener(xdg_surface->role, &xdg_surface->role_destroy_listener);
    307  }
    308  
    309  static void
    310 -get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent, struct wl_resource *positioner)
    311 +get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent, struct wl_resource *positioner_resource)
    312  {
    313 +
    314 +    struct xdg_surface *popup_surface = wl_resource_get_user_data(resource);
    315 +    struct xdg_surface *parent_surface = wl_resource_get_user_data(parent);
    316 +    struct xdg_popup *popup;
    317 +
    318 +    popup = xdg_popup_new(client, wl_resource_get_version(resource), id, popup_surface, parent_surface);
    319 +    if (!popup) {
    320 +        wl_client_post_no_memory(client);
    321 +        return;
    322 +    }
    323 +
    324 +    popup_surface->role = popup->resource;
    325 +    popup_surface->surface_role = XDG_SURFACE_ROLE_POPUP;
    326 +	wl_resource_add_destroy_listener(popup_surface->role, &popup_surface->role_destroy_listener);
    327 +
    328 +    struct compositor_view *parent_view = compositor_view(parent_surface->surface->view);
    329 +	compositor_view_set_parent(popup->view, parent_view);
    330 +
    331 +    struct xdg_positioner *positioner = wl_resource_get_user_data(positioner_resource);
    332 +    struct swc_rectangle geometry = xdg_positioner_get_geometry(positioner);
    333 +	view_set_size(&popup->view->base, geometry.width, geometry.height);
    334 +    view_move(&popup->view->base, parent_view->base.geometry.x + geometry.x, parent_view->base.geometry.y + geometry.y);
    335 +
    336 +    popup->xdg_surface->configure_serial = popup_send_configure(popup, parent_view->base.geometry.x + geometry.x, parent_view->base.geometry.y + geometry.y, geometry.width, geometry.height);
    337  }
    338  
    339  static void
    340  ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial)
    341  {
    342  	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
    343 -	struct window *window;
    344  
    345 -	if (!xdg_surface->role)
    346 -		return;
    347 +    switch (xdg_surface->surface_role) {
    348 +        case XDG_SURFACE_ROLE_NONE:
    349 +            return;
    350 +        case XDG_SURFACE_ROLE_POPUP:
    351 +            return;
    352 +    }
    353 +
    354 +	struct window *window;
    355  	window = wl_resource_get_user_data(xdg_surface->role);
    356  	if (window && serial == xdg_surface->configure_serial)
    357 -		window->configure.acknowledged = true;
    358 +	 	window->configure.acknowledged = true;
    359  }
    360  
    361  static void