shell_surface_t *shsurf =
pepper_container_of(listener, shell_surface_t, surface_commit_listener);
- if (!shsurf->mapped && shsurf->shell_surface_map)
+ if (!shsurf->mapped && shsurf->ack_configure && shsurf->shell_surface_map)
shsurf->shell_surface_map(shsurf);
}
}
static void
-handle_client_destroy(struct wl_listener *listener, void *data)
-{
- shell_surface_t *shsurf =
- pepper_container_of(listener, shell_surface_t, client_destroy_listener);
-
- if (!wl_list_empty(&shsurf->client_destroy_listener.link))
- wl_list_remove(&shsurf->client_destroy_listener.link);
- wl_list_init(&shsurf->client_destroy_listener.link);
-}
-
-static void
handle_surface_destroy(struct wl_listener *listener, void *data)
{
shell_surface_t *child, *tmp;
shell_surface_t *shsurf =
pepper_container_of(listener, shell_surface_t, surface_destroy_listener);
- if (!wl_list_empty(&shsurf->client_destroy_listener.link))
- wl_list_remove(&shsurf->client_destroy_listener.link);
-
wl_list_remove(&shsurf->surface_destroy_listener.link);
shsurf_stop_listen_commit_event(shsurf);
shell_surface_set_parent(child, NULL);
wl_list_remove(&shsurf->link);
+
+ if (shsurf->fullscreen.background_surface)
+ /* TODO: pepper_surface_destroy(shsurf->fullscreen.background_surface); */;
+
+ if (shsurf->fullscreen.background_view)
+ pepper_view_destroy(shsurf->fullscreen.background_view);
+
free(shsurf);
}
shsurf->resource = NULL;
}
+static void
+shsurf_wl_shell_surface_send_configure(shell_surface_t *shsurf, int32_t width, int32_t height)
+{
+ uint32_t edges = 0; /* FIXME */
+
+ wl_shell_surface_send_configure(shsurf->resource,
+ edges,
+ width,
+ height);
+
+ /* wl_shell_surface dont need this */
+ shsurf->ack_configure = PEPPER_TRUE;
+}
+
+static void
+shsurf_xdg_surface_send_configure(shell_surface_t *shsurf, int32_t width, int32_t height)
+{
+ struct wl_display *display;
+ struct wl_array states;
+ uint32_t *state;
+ uint32_t serial;
+
+ wl_array_init(&states);
+
+ if (shsurf->next_type == SHELL_SURFACE_TYPE_MAXIMIZED)
+ {
+ state = wl_array_add(&states, sizeof(uint32_t));
+ *state = XDG_SURFACE_STATE_MAXIMIZED;
+ }
+ else if (shsurf->next_type == SHELL_SURFACE_TYPE_FULLSCREEN)
+ {
+ state = wl_array_add(&states, sizeof(uint32_t));
+ *state = XDG_SURFACE_STATE_FULLSCREEN;
+ }
+
+ /* TODO: XDG_SURFACE_STATE_RESIZING, XDG_SURFACE_STATE_ACTIVATED */
+
+ /* Send configure event */
+ display = pepper_compositor_get_display(shsurf->shell->compositor);
+ serial = wl_display_next_serial(display);
+
+ xdg_surface_send_configure(shsurf->resource,
+ width,
+ height,
+ &states,
+ serial);
+
+ wl_array_release(&states);
+
+ shsurf->ack_configure = PEPPER_FALSE;
+}
+
+static void
+shsurf_xdg_popup_send_configure(shell_surface_t *shsurf, int32_t width, int32_t height)
+{
+ /* Do nothing */
+}
+
+static pepper_bool_t
+shsurf_is_wl_shell_surface(shell_surface_t *shsurf)
+{
+ return (shsurf->send_configure == shsurf_wl_shell_surface_send_configure);
+}
+
+static pepper_bool_t
+shsurf_is_xdg_surface(shell_surface_t *shsurf)
+{
+ return (shsurf->send_configure == shsurf_xdg_surface_send_configure);
+}
+
+static pepper_bool_t
+shsurf_is_xdg_popup(shell_surface_t *shsurf)
+{
+ return (shsurf->send_configure == shsurf_xdg_popup_send_configure);
+}
+
shell_surface_t *
shell_surface_create(shell_client_t *shell_client, pepper_surface_t *surface,
struct wl_client *client, const struct wl_interface *interface,
const void *implementation, uint32_t version, uint32_t id)
{
shell_surface_t *shsurf = NULL;
+ const char *role = NULL;
shsurf = calloc(1, sizeof(shell_surface_t));
if (!shsurf)
wl_resource_set_implementation(shsurf->resource, implementation, shsurf, handle_resource_destroy);
- shsurf->client_destroy_listener.notify = handle_client_destroy;
- wl_client_add_destroy_listener(client, &shsurf->client_destroy_listener);
-
shsurf->surface_destroy_listener.notify = handle_surface_destroy;
pepper_object_add_destroy_listener((pepper_object_t *)surface, &shsurf->surface_destroy_listener);
wl_list_init(&shsurf->link);
wl_list_insert(&shsurf->shell->shell_surface_list, &shsurf->link);
+ role = pepper_surface_get_role(shsurf->surface);
+
+ if (!strcmp(role, "wl_shell_surface"))
+ shsurf->send_configure = shsurf_wl_shell_surface_send_configure;
+ else if (!strcmp(role, "xdg_surface"))
+ shsurf->send_configure = shsurf_xdg_surface_send_configure;
+ else if (!strcmp(role, "xdg_popup"))
+ shsurf->send_configure = shsurf_xdg_popup_send_configure;
+
return shsurf;
error:
{
shell_client_t *shell_client = shsurf->shell_client;
struct wl_display *display;
- const char *role;
/* Already stucked, do not send another ping */
if (shell_client->irresponsive)
shell_client->ping_serial = wl_display_next_serial(display);
shell_client->need_pong = PEPPER_TRUE;
- role = pepper_surface_get_role(shsurf->surface);
-
- if (!strcmp(role, "wl_shell_surface"))
+ if (shsurf_is_wl_shell_surface(shsurf))
wl_shell_surface_send_ping(shsurf->resource, shell_client->ping_serial);
- else if (!strcmp(role, "xdg_surface") || !strcmp(role, "xdg_popup"))
+ else if (shsurf_is_xdg_surface(shsurf) || shsurf_is_xdg_popup(shsurf))
xdg_shell_send_ping(shell_client->resource, shell_client->ping_serial);
- else
- PEPPER_ASSERT(0);
}
void
shell_client_handle_pong(shsurf->shell_client, serial);
}
+/* XXX: Temporary code for test, to be deleted */
+static void
+shell_surface_map_toplevel(shell_surface_t *shsurf);
+
void
shell_surface_set_toplevel(shell_surface_t *shsurf)
{
shell_surface_set_type(shsurf, SHELL_SURFACE_TYPE_TOPLEVEL);
/* Need to map in later */
- shsurf->mapped = PEPPER_FALSE;
+ /* XXX: Temporary code for test, to be deleted */
+ shell_surface_map_toplevel(shsurf);
}
void
shell_surface_set_type(shsurf, SHELL_SURFACE_TYPE_TRANSIENT);
}
-static void
-shell_surface_set_position(shell_surface_t *shsurf, int32_t x, int32_t y)
+static pepper_output_t *
+shell_surface_get_output(shell_surface_t *shsurf)
{
- pepper_view_set_position(shsurf->view, x, y);
-}
+ pepper_output_t *output = NULL;
-static void
-shell_surface_map_toplevel(shell_surface_t *shsurf)
-{
- int32_t x = 0, y = 0;
+ /* TODO: Find the output on which the surface has the biggest surface area */
- /**
- * TODO: To placing view, need to get output's size, position and seat->pointer's position
- * or, read from config file
- */
+ return output;
+}
- shell_surface_set_position(shsurf, x, y);
+void
+shell_surface_get_geometry(shell_surface_t *shsurf, pixman_rectangle32_t *geometry)
+{
+ double x, y;
+ int w, h;
- pepper_view_map(shsurf->view);
+ pepper_view_get_position(shsurf->view, &x, &y);
+ pepper_view_get_size(shsurf->view, &w, &h);
- shsurf->mapped = PEPPER_TRUE;
+ geometry->x = (int32_t)x;
+ geometry->y = (int32_t)y;
+ geometry->width = (uint32_t)w;
+ geometry->height = (uint32_t)h;
}
-static void
-shell_surface_map_popup(shell_surface_t *shsurf)
+void
+shell_surface_set_maximized(shell_surface_t *shsurf,
+ pepper_output_t *output)
{
- shell_surface_t *parent = get_shsurf_from_surface(shsurf->parent, shsurf->shell);
+ pixman_rectangle32_t area;
- /* Set position as relatively */
- pepper_view_set_parent(shsurf->view, parent->view);
- shell_surface_set_position(shsurf, shsurf->popup.x, shsurf->popup.y);
+ /* XXX: If the given shell_surface has a parent, what's the corrent behavior? */
+ shell_surface_set_parent(shsurf, NULL);
- pepper_view_map(shsurf->view);
+ /* If the client does not specify the output then the compositor will apply its policy */
+ if (!output)
+ output = shell_surface_get_output(shsurf);
- pepper_view_stack_top(shsurf->view, PEPPER_TRUE);
+ shsurf->maximized.output = output;
- /* TODO: add_popup_grab(), but how? */
+ /* Save current position and size for unset_maximized */
+ shell_surface_get_geometry(shsurf, &area);
+ shsurf->saved.x = area.x;
+ shsurf->saved.y = area.y;
+ shsurf->saved.w = area.width;
+ shsurf->saved.h = area.height;
+
+ shell_get_output_workarea(shsurf->shell, output, &area);
+
+ shell_surface_set_type(shsurf, SHELL_SURFACE_TYPE_MAXIMIZED);
+
+ /* Send configure */
+ shsurf->send_configure(shsurf, area.width, area.height);
}
-static void
-shell_surface_map_transient(shell_surface_t *shsurf)
+void
+shell_surface_unset_maximized(shell_surface_t *shsurf)
{
- shell_surface_t *parent = get_shsurf_from_surface(shsurf->parent, shsurf->shell);
- double x, y;
+ /* TODO */
+ shell_surface_set_toplevel(shsurf);
+}
- pepper_view_get_position(parent->view, &x, &y);
+void
+shell_surface_set_fullscreen(shell_surface_t *shsurf,
+ pepper_output_t *output,
+ uint32_t method,
+ uint32_t framerate)
+{
+ const pepper_output_geometry_t *geom;
+ pixman_rectangle32_t area;
- pepper_view_set_parent(shsurf->view, parent->view);
+ /* XXX: If the given shell_surface has a parent, what's the corrent behavior? */
+ shell_surface_set_parent(shsurf, NULL);
- shell_surface_set_position(shsurf,
- x + shsurf->transient.x,
- y + shsurf->transient.y);
+ /* If the client does not specify the output then the compositor will apply its policy */
+ if (!output)
+ output = shell_surface_get_output(shsurf);
- if (shsurf->transient.flags != WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
- {
- /* TODO: set keyboard focus to view */
- }
+ shsurf->fullscreen.output = output;
+ shsurf->fullscreen.method = method;
+ shsurf->fullscreen.framerate = framerate;
- pepper_view_map(shsurf->view);
+ shell_surface_set_type(shsurf, SHELL_SURFACE_TYPE_FULLSCREEN);
+
+ /* Save current position and size for unset_fullscreen */
+ shell_surface_get_geometry(shsurf, &area);
+ shsurf->saved.x = area.x;
+ shsurf->saved.y = area.y;
+ shsurf->saved.w = area.width;
+ shsurf->saved.h = area.height;
+
+ geom = pepper_output_get_geometry(output);
+
+ /* Send configure */
+ shsurf->send_configure(shsurf, geom->w, geom->h);
}
void
-shell_surface_set_type(shell_surface_t *shsurf, shell_surface_type_t type)
+shell_surface_unset_fullscreen(shell_surface_t *shsurf)
{
- shsurf->type = type;
+ shell_surface_set_toplevel(shsurf);
+}
- switch (type)
- {
- case SHELL_SURFACE_TYPE_NONE:
- shsurf->shell_surface_map = NULL;
- break;
- case SHELL_SURFACE_TYPE_TOPLEVEL:
- shsurf->shell_surface_map = shell_surface_map_toplevel;
- break;
- case SHELL_SURFACE_TYPE_POPUP:
- shsurf->shell_surface_map = shell_surface_map_popup;
- break;
- case SHELL_SURFACE_TYPE_TRANSIENT:
- shsurf->shell_surface_map = shell_surface_map_transient;
- break;
- default :
- /* XXX: Maybe some logs be needed */
- break;
- }
+void
+shell_surface_set_minimized(shell_surface_t *shsurf)
+{
+ shell_surface_set_type(shsurf, SHELL_SURFACE_TYPE_MINIMIZED);
+}
+
+void
+shell_surface_ack_configure(shell_surface_t *shsurf, uint32_t serial)
+{
+ shsurf->ack_configure = PEPPER_TRUE;
+}
+
+static void
+shell_surface_set_position(shell_surface_t *shsurf, int32_t x, int32_t y)
+{
+ pepper_view_set_position(shsurf->view, x, y);
}
shell_surface_t *
{
parent_shsurf = get_shsurf_from_surface(parent, shsurf->shell);
if (parent_shsurf)
+ {
wl_list_insert(&parent_shsurf->child_list, &shsurf->parent_link);
+ pepper_view_set_parent(shsurf->view, parent_shsurf->view);
+ }
+ }
+ else
+ {
+ pepper_view_set_parent(shsurf->view, NULL);
}
}
+void
+shell_surface_set_geometry(shell_surface_t *shsurf, int32_t x, int32_t y, int32_t w, int32_t h)
+{
+ pepper_view_set_position(shsurf->view, (double)x, (double)y);
+ pepper_view_resize(shsurf->view, w, h);
+}
+
pepper_bool_t
shell_surface_set_title(shell_surface_t *shsurf, const char* title)
{
return PEPPER_TRUE;
}
+
+static void
+shell_surface_map_toplevel(shell_surface_t *shsurf)
+{
+ int32_t x = 0, y = 0, w = 0, h = 0;
+
+ /* Restore original geometry */
+ if (shsurf->type == SHELL_SURFACE_TYPE_FULLSCREEN ||
+ shsurf->type == SHELL_SURFACE_TYPE_MAXIMIZED ||
+ shsurf->type == SHELL_SURFACE_TYPE_MINIMIZED)
+ {
+ x = shsurf->saved.x;
+ y = shsurf->saved.y;
+
+ pepper_view_resize(shsurf->view, shsurf->saved.w, shsurf->saved.h);
+
+ if (shsurf->type == SHELL_SURFACE_TYPE_FULLSCREEN)
+ {
+ /* TODO: pepper_surface_destroy(shsurf->fullscreen.background_surface); */
+ pepper_view_destroy(shsurf->fullscreen.background_view);
+
+ shsurf->fullscreen.background_surface = NULL;
+ shsurf->fullscreen.background_view = NULL;
+ }
+ }
+ else
+ {
+ /**
+ * TODO: To get view's initial position, need to know output's size, position
+ * seat->pointer's position, or read from config file
+ */
+ }
+
+ shell_surface_set_position(shsurf, x, y);
+
+ pepper_view_map(shsurf->view);
+
+ shsurf->mapped = PEPPER_TRUE;
+ shsurf->type = SHELL_SURFACE_TYPE_TOPLEVEL;
+ shsurf->next_type = SHELL_SURFACE_TYPE_NONE;
+}
+
+static void
+shell_surface_map_popup(shell_surface_t *shsurf)
+{
+ shell_surface_t *parent = get_shsurf_from_surface(shsurf->parent, shsurf->shell);
+
+ /* Set position as relatively */
+ pepper_view_set_parent(shsurf->view, parent->view);
+ shell_surface_set_position(shsurf, shsurf->popup.x, shsurf->popup.y);
+
+ pepper_view_map(shsurf->view);
+
+ pepper_view_stack_top(shsurf->view, PEPPER_TRUE);
+
+ /* TODO: add_popup_grab(), but how? */
+
+ shsurf->mapped = PEPPER_TRUE;
+ shsurf->type = SHELL_SURFACE_TYPE_POPUP;
+ shsurf->next_type = SHELL_SURFACE_TYPE_NONE;
+}
+
+static void
+shell_surface_map_transient(shell_surface_t *shsurf)
+{
+ shell_surface_t *parent = get_shsurf_from_surface(shsurf->parent, shsurf->shell);
+ double x, y;
+
+ pepper_view_get_position(parent->view, &x, &y);
+
+ pepper_view_set_parent(shsurf->view, parent->view);
+
+ shell_surface_set_position(shsurf,
+ x + shsurf->transient.x,
+ y + shsurf->transient.y);
+
+ if (shsurf->transient.flags != WL_SHELL_SURFACE_TRANSIENT_INACTIVE)
+ {
+ /* TODO: set keyboard focus to view */
+ }
+
+ pepper_view_map(shsurf->view);
+
+ shsurf->mapped = PEPPER_TRUE;
+ shsurf->type = SHELL_SURFACE_TYPE_TRANSIENT;
+ shsurf->next_type = SHELL_SURFACE_TYPE_NONE;
+}
+
+static void
+shell_surface_map_maximized(shell_surface_t *shsurf)
+{
+ pixman_rectangle32_t area;
+
+ shell_get_output_workarea(shsurf->shell, shsurf->maximized.output, &area);
+
+ shell_surface_set_position(shsurf, area.x, area.y);
+
+ pepper_view_map(shsurf->view);
+
+ /* Set top of z-order */
+ pepper_view_stack_top(shsurf->view, PEPPER_TRUE /*FIXME:*/);
+}
+
+static void
+shell_surface_map_minimized(shell_surface_t *shsurf)
+{
+ /* TODO */
+ pepper_view_unmap(shsurf->view);
+
+ shsurf->mapped = PEPPER_TRUE;
+ shsurf->type = SHELL_SURFACE_TYPE_MINIMIZED;
+ shsurf->next_type = SHELL_SURFACE_TYPE_NONE;
+}
+
+static float
+get_scale(float output_w, float output_h, float view_w, float view_h)
+{
+ float scale, output_aspect, view_aspect;
+
+ output_aspect = output_w / output_h;
+
+ view_aspect = view_w / view_h;
+
+ if (output_aspect < view_aspect)
+ scale = output_w / view_w;
+ else
+ scale = output_h / view_h;
+
+ return scale;
+}
+
+static void
+shell_surface_center_on_output_by_scale(shell_surface_t *shsurf,
+ const pepper_output_geometry_t *output,
+ pixman_rectangle32_t *surface_geom,
+ float scale)
+{
+ float x, y;
+
+ x = output->x + (output->w - surface_geom->width * scale) / 2 - surface_geom->x;
+ y = output->y + (output->h - surface_geom->height * scale) / 2 - surface_geom->y;
+
+ shell_surface_set_position(shsurf, x, y);
+}
+
+static void
+switch_output_mode(pepper_output_t *output, pepper_output_mode_t *mode)
+{
+ pepper_output_mode_t *new_mode;
+
+ /* TODO: Find the output mode to the smallest mode that can fit */
+
+ pepper_output_set_mode(output, new_mode);
+}
+
+static void
+shell_surface_map_fullscreen(shell_surface_t *shsurf)
+{
+ pepper_output_t *output;
+ const pepper_output_geometry_t *output_geom;
+ pixman_rectangle32_t shsurf_geom;
+ float scale = 0.f;
+
+ output = shsurf->fullscreen.output;
+ output_geom = pepper_output_get_geometry(output);
+
+ /* Get current geometry */
+ shell_surface_get_geometry(shsurf, &shsurf_geom);
+
+ switch (shsurf->fullscreen.method)
+ {
+ case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
+ {
+ scale = get_scale(output_geom->w, output_geom->h, shsurf_geom.width, shsurf_geom.height);
+ }
+ break;
+ case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
+ {
+ pepper_output_mode_t mode;
+ int32_t buffer_scale;
+
+ buffer_scale = pepper_surface_get_buffer_scale(shsurf->surface);
+
+ mode.w = shsurf_geom.width * buffer_scale;
+ mode.h = shsurf_geom.height * buffer_scale;
+ mode.refresh = shsurf->fullscreen.framerate;
+
+ switch_output_mode(output, &mode);
+
+ /* Recalculate output geometry */
+ output_geom = pepper_output_get_geometry(output);
+
+ scale = 1.f;
+ }
+ break;
+ case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
+ case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
+ {
+ scale = 1.f;
+ }
+ break;
+ default:
+ PEPPER_ERROR("invalid method type = 0x%x\n", shsurf->fullscreen.method);
+ break;
+ }
+
+ /* TODO: Create background black view */
+ {
+ pepper_surface_t *surface;
+
+ /**
+ * surface->x = output_geom->w;
+ * surface->y = output_geom->y;
+ */
+
+ shsurf->fullscreen.background_surface = surface;
+ shsurf->fullscreen.background_view =
+ pepper_compositor_add_surface_view(shsurf->shell->compositor, surface);
+ }
+
+ /* Place background black view */
+ pepper_view_set_position(shsurf->fullscreen.background_view, output_geom->x, output_geom->y);
+ pepper_view_map(shsurf->fullscreen.background_view);
+ pepper_view_stack_top(shsurf->fullscreen.background_view, PEPPER_TRUE /*FIXME*/ );
+
+ /* Place target view */
+ shell_surface_center_on_output_by_scale(shsurf, output_geom, &shsurf_geom, scale);
+ pepper_view_map(shsurf->view);
+ pepper_view_stack_top(shsurf->view, PEPPER_TRUE /*FIXME*/ );
+}
+
+void
+shell_surface_set_type(shell_surface_t *shsurf, shell_surface_type_t type)
+{
+ if (shsurf->type == type )
+ return;
+
+ if (shsurf->next_type == type)
+ return ;
+
+ switch (type)
+ {
+ case SHELL_SURFACE_TYPE_NONE:
+ shsurf->shell_surface_map = NULL;
+ break;
+ case SHELL_SURFACE_TYPE_TOPLEVEL:
+ shsurf->shell_surface_map = shell_surface_map_toplevel;
+ break;
+ case SHELL_SURFACE_TYPE_POPUP:
+ shsurf->shell_surface_map = shell_surface_map_popup;
+ break;
+ case SHELL_SURFACE_TYPE_TRANSIENT:
+ shsurf->shell_surface_map = shell_surface_map_transient;
+ break;
+ case SHELL_SURFACE_TYPE_MAXIMIZED:
+ shsurf->shell_surface_map = shell_surface_map_maximized;
+ break;
+ case SHELL_SURFACE_TYPE_FULLSCREEN:
+ shsurf->shell_surface_map = shell_surface_map_fullscreen;
+ break;
+ case SHELL_SURFACE_TYPE_MINIMIZED:
+ shsurf->shell_surface_map = shell_surface_map_minimized;
+ break;
+ default :
+ PEPPER_ERROR("invalid surface type = 0x%x\n", type);
+ return ;
+ }
+
+ shsurf->next_type = type;
+ shsurf->mapped = PEPPER_FALSE;
+}