xdg_shell_v6: Add zxdg_popup_v6 implementation 77/297877/1 accepted/tizen/unified/20230828.145929
authorSeunghun Lee <shiin.lee@samsung.com>
Wed, 23 Aug 2023 02:09:12 +0000 (11:09 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Mon, 28 Aug 2023 04:49:18 +0000 (13:49 +0900)
Change-Id: Ia5594fc42744b3d707837140bd82b2ee346f3d6d

include/libds/types/ds_xdg_shell_v6.h
src/xdg_shell_v6/meson.build
src/xdg_shell_v6/xdg_popup_v6.c [new file with mode: 0644]
src/xdg_shell_v6/xdg_positioner_v6.c
src/xdg_shell_v6/xdg_shell_v6.h
src/xdg_shell_v6/xdg_surface_v6.c

index fc34553..b846c0c 100644 (file)
@@ -5,6 +5,8 @@
 #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
@@ -96,9 +98,19 @@ struct ds_xdg_toplevel_v6
     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
@@ -119,7 +131,7 @@ struct ds_xdg_surface_v6
 
     union {
         struct ds_xdg_toplevel_v6 *toplevel;
-        struct ds_xdg_popup *popup;
+        struct ds_xdg_popup_v6 *popup;
     };
 
     struct wl_resource *resource;
@@ -127,6 +139,7 @@ struct ds_xdg_surface_v6
     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;
 
index 1370be4..bfac814 100644 (file)
@@ -2,6 +2,7 @@ libds_xdg_shell_v6_files = [
   'xdg_shell_v6.c',
   'xdg_surface_v6.c',
   'xdg_toplevel_v6.c',
+  'xdg_popup_v6.c',
   'xdg_positioner_v6.c',
 ]
 
diff --git a/src/xdg_shell_v6/xdg_popup_v6.c b/src/xdg_shell_v6/xdg_popup_v6.c
new file mode 100644 (file)
index 0000000..2444fd0
--- /dev/null
@@ -0,0 +1,144 @@
+#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);
+}
index 5eecf1a..d2f6877 100644 (file)
@@ -69,9 +69,9 @@ xdg_positioner_v6_handle_set_anchor(struct wl_client *wl_client,
     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);
@@ -90,9 +90,9 @@ xdg_positioner_v6_handle_set_gravity(struct wl_client *wl_client,
     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);
index c4059a6..51a0fe1 100644 (file)
@@ -60,4 +60,16 @@ void destroy_xdg_toplevel_v6(struct ds_xdg_toplevel_v6 *toplevel);
 
 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
index fe7e2b4..13c699a 100644 (file)
@@ -1,3 +1,4 @@
+#include <assert.h>
 #include <stdlib.h>
 
 #include "libds/log.h"
@@ -77,6 +78,7 @@ create_xdg_surface_v6(struct ds_xdg_client_v6 *client, struct ds_surface *ds_sur
     }
 
     wl_list_init(&surface->configure_list);
+    wl_list_init(&surface->popups);
 
     wl_signal_init(&surface->events.destroy);
     wl_signal_init(&surface->events.ping_timeout);
@@ -118,15 +120,20 @@ void
 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;
@@ -174,7 +181,8 @@ destroy_xdg_surface_v6_role(struct ds_xdg_surface_v6 *surface)
             surface->toplevel = NULL;
             break;
         case DS_XDG_SURFACE_V6_ROLE_POPUP:
-            // TODO
+            destroy_xdg_popup_v6(surface->popup);
+            surface->popup = NULL;
             break;
         default:
             break;
@@ -234,14 +242,15 @@ xdg_surface_v6_handle_surface_commit(struct wl_listener *listener, void *data)
 
     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;
     }
 
@@ -308,12 +317,33 @@ xdg_surface_v6_handle_get_popup(struct wl_client *client,
         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
@@ -438,6 +468,7 @@ surface_send_configure(void *user_data)
             send_xdg_toplevel_v6_configure(surface, configure);
             break;
         case DS_XDG_SURFACE_V6_ROLE_POPUP:
+            send_xdg_popup_v6_configure(surface);
             break;
     }