#include <xdg-shell-unstable-v6-server-protocol.h>
#include <libds/output.h>
#include <libds/xdg_shell_v6.h>
+#include <libds/seat.h>
+#include <libds/surface.h>
#include <libds/util/box.h>
enum ds_xdg_surface_v6_role
bool sent_initial_configure;
};
-struct ds_xdg_popup
+struct ds_xdg_popup_v6
{
+ struct wl_resource *resource;
+ struct ds_xdg_surface_v6 *base;
+
+ struct ds_surface *parent;
+ struct ds_seat *seat;
+
+ struct ds_box geometry;
+
+ struct wl_list link; // ds_xdg_surface_v6::popups
+ bool committed;
};
struct ds_xdg_surface_v6_state
union {
struct ds_xdg_toplevel_v6 *toplevel;
- struct ds_xdg_popup *popup;
+ struct ds_xdg_popup_v6 *popup;
};
struct wl_resource *resource;
struct wl_event_source *configure_idle;
uint32_t scheduled_serial;
struct wl_list configure_list;
+ struct wl_list popups; // ds_xdg_popup_v6.link
struct ds_xdg_surface_v6_state current, pending;
'xdg_shell_v6.c',
'xdg_surface_v6.c',
'xdg_toplevel_v6.c',
+ 'xdg_popup_v6.c',
'xdg_positioner_v6.c',
]
--- /dev/null
+#include <stdlib.h>
+
+#include "libds/log.h"
+#include "libds/util/box.h"
+#include "xdg_shell_v6.h"
+
+static void
+xdg_popup_v6_handle_resource_destroy(struct wl_resource *resource)
+{
+ struct ds_xdg_popup_v6 *popup;
+
+ popup = wl_resource_get_user_data(resource);
+ if (!popup)
+ return;
+
+ zxdg_popup_v6_send_popup_done(popup->resource);
+ destroy_xdg_surface_v6_role(popup->base);
+}
+
+static void
+xdg_popup_v6_handle_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+xdg_popup_v6_handle_grab(struct wl_client *wl_client,
+ struct wl_resource *resource, struct wl_resource *seat_resource,
+ uint32_t serial)
+{
+ struct ds_xdg_popup_v6 *popup;
+
+ popup = wl_resource_get_user_data(resource);
+ if (!popup)
+ return;
+
+ if (popup->committed) {
+ wl_resource_post_error(popup->resource,
+ ZXDG_POPUP_V6_ERROR_INVALID_GRAB,
+ "xdg_popup already is mapped");
+ return;
+ }
+
+ // TODO handle grab
+}
+
+static const struct zxdg_popup_v6_interface xdg_popup_v6_impl = {
+ .destroy = xdg_popup_v6_handle_destroy,
+ .grab = xdg_popup_v6_handle_grab,
+};
+
+const struct ds_surface_role xdg_popup_v6_surface_role = {
+ .name = "xdg_popup_v6",
+};
+
+struct ds_xdg_popup_v6 *
+create_xdg_popup_v6(struct ds_xdg_surface_v6 *surface,
+ struct ds_xdg_surface_v6 *parent,
+ struct ds_xdg_positioner_v6 *positioner, uint32_t id)
+{
+ struct ds_xdg_popup_v6 *popup;
+
+ if (!ds_surface_set_role(surface->ds_surface, &xdg_popup_v6_surface_role,
+ NULL, surface->client->resource, ZXDG_SHELL_V6_ERROR_ROLE)) {
+ return NULL;
+ }
+
+ popup = calloc(1, sizeof(struct ds_xdg_popup_v6));
+ if (!popup) {
+ wl_resource_post_no_memory(surface->resource);
+ return NULL;
+ }
+
+ popup->base = surface;
+ popup->parent = parent->ds_surface;
+ popup->resource = wl_resource_create(surface->client->wl_client,
+ &zxdg_popup_v6_interface,
+ wl_resource_get_version(surface->resource), id);
+ if (!popup->resource) {
+ free(popup);
+ wl_resource_post_no_memory(surface->resource);
+ return NULL;
+ }
+ wl_resource_set_implementation(popup->resource,
+ &xdg_popup_v6_impl, popup, xdg_popup_v6_handle_resource_destroy);
+
+ // TODO get geometry from positioner
+
+ ds_inf("Created ds_xdg_popup_v6(%p) with surface(%p), parent(%p)",
+ popup, surface->ds_surface, parent->ds_surface);
+
+ return popup;
+}
+
+void
+destroy_xdg_popup_v6(struct ds_xdg_popup_v6 *popup)
+{
+ struct ds_xdg_popup_v6 *child, *child_tmp;
+
+ ds_inf("Destroy ds_xdg_popup_v6(%p)", popup);
+
+ wl_list_for_each_safe(child, child_tmp, &popup->base->popups, link) {
+ zxdg_popup_v6_send_popup_done(child->resource);
+ destroy_xdg_surface_v6_role(child->base);
+ }
+
+ wl_resource_set_user_data(popup->resource, NULL);
+
+ ds_surface_reset_role_data(popup->base->ds_surface);
+ wl_list_remove(&popup->link);
+ free(popup);
+}
+
+void
+reset_xdg_popup_v6(struct ds_xdg_popup_v6 *popup)
+{
+ ds_inf("Reset ds_xdg_popup_v6(%p)", popup);
+
+ // TODO handle grab
+
+ popup->committed = false;
+}
+
+void
+handle_xdg_popup_v6_committed(struct ds_xdg_popup_v6 *popup)
+{
+ if (!popup->committed) {
+ ds_xdg_surface_v6_schedule_configure(popup->base);
+ popup->committed = true;
+ }
+
+ // TODO commit state
+}
+
+void
+send_xdg_popup_v6_configure(struct ds_xdg_surface_v6 *surface)
+{
+ struct ds_xdg_popup_v6 *popup = surface->popup;
+
+ zxdg_popup_v6_send_configure(popup->resource,
+ popup->geometry.x, popup->geometry.y,
+ popup->geometry.width, popup->geometry.height);
+}
struct ds_xdg_positioner_v6 *positioner;
if (((anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) &&
- (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) ||
- ((anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) &&
- (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT))) {
+ (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) ||
+ ((anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) &&
+ (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT))) {
wl_resource_post_error(resource,
ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
"same-axis values are not allowed (%d)", anchor);
struct ds_xdg_positioner_v6 *positioner;
if (((gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) &&
- (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) ||
- ((gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) &&
- (gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT))) {
+ (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) ||
+ ((gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) &&
+ (gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT))) {
wl_resource_post_error(resource,
ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
"same-axis values are not allowed (%d)", gravity);
void create_xdg_positioner_v6(struct ds_xdg_client_v6 *client, uint32_t id);
+struct ds_xdg_popup_v6 *create_xdg_popup_v6(struct ds_xdg_surface_v6 *surface,
+ struct ds_xdg_surface_v6 *parent,
+ struct ds_xdg_positioner_v6 *positioner, uint32_t id);
+
+void destroy_xdg_popup_v6(struct ds_xdg_popup_v6 *popup);
+
+void reset_xdg_popup_v6(struct ds_xdg_popup_v6 *popup);
+
+void handle_xdg_popup_v6_committed(struct ds_xdg_popup_v6 *popup);
+
+void send_xdg_popup_v6_configure(struct ds_xdg_surface_v6 *surface);
+
#endif
+#include <assert.h>
#include <stdlib.h>
#include "libds/log.h"
}
wl_list_init(&surface->configure_list);
+ wl_list_init(&surface->popups);
wl_signal_init(&surface->events.destroy);
wl_signal_init(&surface->events.ping_timeout);
reset_xdg_surface_v6(struct ds_xdg_surface_v6 *surface)
{
struct ds_xdg_surface_v6_configure *configure, *tmp;
+ struct ds_xdg_popup_v6 *popup, *popup_tmp;
surface->configured = false;
+ wl_list_for_each_safe(popup, popup_tmp, &surface->popups, link) {
+ destroy_xdg_popup_v6(popup);
+ }
+
switch (surface->role) {
case DS_XDG_SURFACE_V6_ROLE_TOPLEVEL:
reset_xdg_toplevel_v6(surface->toplevel);
break;
case DS_XDG_SURFACE_V6_ROLE_POPUP:
- // TODO
+ reset_xdg_popup_v6(surface->popup);
break;
case DS_XDG_SURFACE_V6_ROLE_NONE:
break;
surface->toplevel = NULL;
break;
case DS_XDG_SURFACE_V6_ROLE_POPUP:
- // TODO
+ destroy_xdg_popup_v6(surface->popup);
+ surface->popup = NULL;
break;
default:
break;
switch (surface->role) {
case DS_XDG_SURFACE_V6_ROLE_NONE:
- // inert toplevel or popup
+ wl_resource_post_error(surface->resource,
+ ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
+ "xdg_surface must have a role before commit");
break;
case DS_XDG_SURFACE_V6_ROLE_TOPLEVEL:
handle_xdg_toplevel_v6_committed(surface->toplevel);
- // TODO
break;
case DS_XDG_SURFACE_V6_ROLE_POPUP:
- // TODO
+ handle_xdg_popup_v6_committed(surface->popup);
break;
}
struct wl_resource *parent_resource,
struct wl_resource *positioner_resource)
{
- struct ds_xdg_surface_v6 *surface;
+ struct ds_xdg_surface_v6 *surface, *parent;
+ struct ds_xdg_positioner_v6 *positioner;
surface = wl_resource_get_user_data(resource);
+ if (surface->role != DS_XDG_SURFACE_V6_ROLE_NONE) {
+ wl_resource_post_error(surface->resource,
+ ZXDG_SURFACE_V6_ERROR_ALREADY_CONSTRUCTED,
+ "xdg-surface has already been constructed");
+ return;
+ }
+
+ positioner = wl_resource_get_user_data(positioner_resource);
+ if (positioner->size.width == 0 || positioner->anchor_rect.width == 0) {
+ wl_resource_post_error(surface->client->resource,
+ ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER,
+ "positioner object is not complete");
+ return;
+ }
+
+ assert(surface->popup == NULL);
+
+ parent = wl_resource_get_user_data(parent_resource);
+ surface->popup = create_xdg_popup_v6(surface, parent, positioner, id);
+ surface->role = DS_XDG_SURFACE_V6_ROLE_POPUP;
+ wl_list_insert(&surface->popups, &surface->popup->link);
- // TODO
- (void)surface;
+ wl_signal_emit_mutable(&surface->events.new_popup, surface->popup);
}
static void
send_xdg_toplevel_v6_configure(surface, configure);
break;
case DS_XDG_SURFACE_V6_ROLE_POPUP:
+ send_xdg_popup_v6_configure(surface);
break;
}