shell: Start implementing the popup surface type
This lands the basic behavior of the popup surface type, but there are still a number of details to be worked out. Mainly there's a hardcoded timeout to handle the case of releasing the popup button outside any of the client windows, which triggers popup_end if it happens after the timeout. Maybe we just need to add that as an argument, or we could add a new event that fires in this case to let the client decide whether it ends the popup or not.
This commit is contained in:
parent
dade64968c
commit
b3cca0a411
|
@ -128,19 +128,19 @@ sigchild_handler(int s)
|
|||
}
|
||||
|
||||
static void
|
||||
show_menu(struct panel *panel, struct input *input)
|
||||
show_menu(struct panel *panel, struct input *input, uint32_t time)
|
||||
{
|
||||
int32_t x, y, width = 200, height = 200;
|
||||
struct display *display;
|
||||
int32_t x, y;
|
||||
static const char *entries[] = {
|
||||
"Roy", "Pris", "Leon", "Zhora"
|
||||
};
|
||||
|
||||
input_get_position(input, &x, &y);
|
||||
display = window_get_display(panel->window);
|
||||
panel->menu = window_create_transient(display, panel->window,
|
||||
x - 10, y - 10, width, height);
|
||||
window_set_user_data(panel->menu, panel);
|
||||
panel->menu = window_create_menu(window_get_display(panel->window),
|
||||
input, time, panel->window,
|
||||
x - 10, y - 10, entries, 4);
|
||||
|
||||
window_draw(panel->menu);
|
||||
window_flush(panel->menu);
|
||||
window_schedule_redraw(panel->menu);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -253,9 +253,7 @@ panel_button_handler(struct window *window,
|
|||
panel_activate_item(panel, pi);
|
||||
} else if (button == BTN_RIGHT) {
|
||||
if (state)
|
||||
show_menu(panel, input);
|
||||
else
|
||||
window_destroy(panel->menu);
|
||||
show_menu(panel, input, time);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ key_handler(struct window *window, struct input *input, uint32_t time,
|
|||
}
|
||||
|
||||
static void
|
||||
show_menu(struct resizor *resizor, struct input *input)
|
||||
show_menu(struct resizor *resizor, struct input *input, uint32_t time)
|
||||
{
|
||||
int32_t x, y;
|
||||
static const char *entries[] = {
|
||||
|
@ -176,7 +176,7 @@ show_menu(struct resizor *resizor, struct input *input)
|
|||
|
||||
input_get_position(input, &x, &y);
|
||||
resizor->menu = window_create_menu(resizor->display,
|
||||
resizor->window,
|
||||
input, time, resizor->window,
|
||||
x - 10, y - 10, entries, 4);
|
||||
|
||||
window_schedule_redraw(resizor->menu);
|
||||
|
@ -192,7 +192,7 @@ button_handler(struct window *window,
|
|||
switch (button) {
|
||||
case BTN_RIGHT:
|
||||
if (state)
|
||||
show_menu(resizor, input);
|
||||
show_menu(resizor, input, time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1799,8 +1799,20 @@ handle_configure(void *data, struct wl_shell_surface *shell_surface,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
|
||||
{
|
||||
struct window *window = data;
|
||||
|
||||
/* FIXME: Need more context in this event, at least the input
|
||||
* device. Or just use wl_callback. */
|
||||
|
||||
window_destroy(window);
|
||||
}
|
||||
|
||||
static const struct wl_shell_surface_listener shell_surface_listener = {
|
||||
handle_configure,
|
||||
handle_popup_done
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -2108,6 +2120,7 @@ window_create_transient(struct display *display, struct window *parent,
|
|||
struct menu {
|
||||
struct window *window;
|
||||
const char **entries;
|
||||
uint32_t time;
|
||||
int current;
|
||||
int count;
|
||||
};
|
||||
|
@ -2159,7 +2172,7 @@ menu_button_handler(struct window *window,
|
|||
struct menu *menu = data;
|
||||
|
||||
/* Either relase after press-drag-release or click-motion-click. */
|
||||
if (state == 0 && 0 <= menu->current && menu->current < menu->count)
|
||||
if (state == 0 && time - menu->time > 500)
|
||||
window_destroy(window);
|
||||
}
|
||||
|
||||
|
@ -2209,7 +2222,8 @@ menu_redraw_handler(struct window *window, void *data)
|
|||
}
|
||||
|
||||
struct window *
|
||||
window_create_menu(struct display *display, struct window *parent,
|
||||
window_create_menu(struct display *display,
|
||||
struct input *input, uint32_t time, struct window *parent,
|
||||
int32_t x, int32_t y, const char **entries, int count)
|
||||
{
|
||||
struct window *window;
|
||||
|
@ -2226,14 +2240,16 @@ window_create_menu(struct display *display, struct window *parent,
|
|||
menu->window = window;
|
||||
menu->entries = entries;
|
||||
menu->count = count;
|
||||
menu->time = time;
|
||||
window->decoration = 0;
|
||||
window->type = TYPE_MENU;
|
||||
window->x = x;
|
||||
window->y = y;
|
||||
|
||||
wl_shell_surface_set_transient(window->shell_surface,
|
||||
window->parent->shell_surface,
|
||||
window->x, window->y, 0);
|
||||
wl_shell_surface_set_popup(window->shell_surface,
|
||||
input->input_device, time,
|
||||
window->parent->shell_surface,
|
||||
window->x, window->y, 0);
|
||||
|
||||
window_set_motion_handler(window, menu_motion_handler);
|
||||
window_set_enter_handler(window, menu_enter_handler);
|
||||
|
|
|
@ -203,7 +203,8 @@ struct window *
|
|||
window_create_transient(struct display *display, struct window *parent,
|
||||
int32_t x, int32_t y, int32_t width, int32_t height);
|
||||
struct window *
|
||||
window_create_menu(struct display *display, struct window *parent,
|
||||
window_create_menu(struct display *display,
|
||||
struct input *input, uint32_t time, struct window *parent,
|
||||
int32_t x, int32_t y, const char **entries, int count);
|
||||
|
||||
void
|
||||
|
|
145
src/shell.c
145
src/shell.c
|
@ -76,7 +76,8 @@ enum shell_surface_type {
|
|||
|
||||
SHELL_SURFACE_TOPLEVEL,
|
||||
SHELL_SURFACE_TRANSIENT,
|
||||
SHELL_SURFACE_FULLSCREEN
|
||||
SHELL_SURFACE_FULLSCREEN,
|
||||
SHELL_SURFACE_POPUP
|
||||
};
|
||||
|
||||
struct shell_surface {
|
||||
|
@ -84,10 +85,18 @@ struct shell_surface {
|
|||
|
||||
struct weston_surface *surface;
|
||||
struct wl_listener surface_destroy_listener;
|
||||
struct shell_surface *parent;
|
||||
|
||||
enum shell_surface_type type;
|
||||
int32_t saved_x, saved_y;
|
||||
|
||||
struct {
|
||||
struct wl_grab grab;
|
||||
uint32_t time;
|
||||
int32_t x, y;
|
||||
int32_t initial_up;
|
||||
} popup;
|
||||
|
||||
struct weston_output *output;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
@ -337,6 +346,7 @@ reset_shell_surface_type(struct shell_surface *surface)
|
|||
case SHELL_SURFACE_NONE:
|
||||
case SHELL_SURFACE_TOPLEVEL:
|
||||
case SHELL_SURFACE_TRANSIENT:
|
||||
case SHELL_SURFACE_POPUP:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -415,12 +425,118 @@ shell_surface_set_fullscreen(struct wl_client *client,
|
|||
shsurf->type = SHELL_SURFACE_FULLSCREEN;
|
||||
}
|
||||
|
||||
static void
|
||||
popup_grab_focus(struct wl_grab *grab, uint32_t time,
|
||||
struct wl_surface *surface, int32_t x, int32_t y)
|
||||
{
|
||||
struct wl_input_device *device = grab->input_device;
|
||||
struct shell_surface *priv =
|
||||
container_of(grab, struct shell_surface, popup.grab);
|
||||
struct wl_client *client = priv->surface->surface.resource.client;
|
||||
|
||||
if (surface->resource.client == client) {
|
||||
wl_input_device_set_pointer_focus(device, surface, time,
|
||||
device->x, device->y, x, y);
|
||||
grab->focus = surface;
|
||||
} else {
|
||||
wl_input_device_set_pointer_focus(device, NULL,
|
||||
time, 0, 0, 0, 0);
|
||||
grab->focus = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
popup_grab_motion(struct wl_grab *grab,
|
||||
uint32_t time, int32_t x, int32_t y)
|
||||
{
|
||||
struct wl_input_device *device = grab->input_device;
|
||||
struct wl_resource *resource;
|
||||
|
||||
resource = grab->input_device->pointer_focus_resource;
|
||||
if (resource)
|
||||
wl_resource_post_event(resource, WL_INPUT_DEVICE_MOTION,
|
||||
time, device->x, device->y, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_grab_button(struct wl_grab *grab,
|
||||
uint32_t time, int32_t button, int32_t state)
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
struct shell_surface *shsurf =
|
||||
container_of(grab, struct shell_surface, popup.grab);
|
||||
|
||||
resource = grab->input_device->pointer_focus_resource;
|
||||
if (resource) {
|
||||
wl_resource_post_event(resource, WL_INPUT_DEVICE_BUTTON,
|
||||
time, button, state);
|
||||
} else if (state == 0 &&
|
||||
(shsurf->popup.initial_up ||
|
||||
time - shsurf->popup.time > 500)) {
|
||||
wl_resource_post_event(&shsurf->resource,
|
||||
WL_SHELL_SURFACE_POPUP_DONE);
|
||||
wl_input_device_end_grab(grab->input_device, time);
|
||||
shsurf->popup.grab.input_device = NULL;
|
||||
}
|
||||
|
||||
if (state == 0)
|
||||
shsurf->popup.initial_up = 1;
|
||||
}
|
||||
|
||||
static const struct wl_grab_interface popup_grab_interface = {
|
||||
popup_grab_focus,
|
||||
popup_grab_motion,
|
||||
popup_grab_button,
|
||||
};
|
||||
|
||||
static void
|
||||
shell_map_popup(struct shell_surface *shsurf, uint32_t time)
|
||||
{
|
||||
struct wl_input_device *device;
|
||||
struct weston_surface *es = shsurf->surface;
|
||||
struct weston_surface *parent = shsurf->parent->surface;
|
||||
|
||||
es->output = parent->output;
|
||||
|
||||
shsurf->popup.grab.interface = &popup_grab_interface;
|
||||
device = es->compositor->input_device;
|
||||
|
||||
es->x = shsurf->parent->surface->x + shsurf->popup.x;
|
||||
es->y = shsurf->parent->surface->y + shsurf->popup.y;
|
||||
|
||||
shsurf->popup.grab.input_device = device;
|
||||
shsurf->popup.time = device->grab_time;
|
||||
shsurf->popup.initial_up = 0;
|
||||
|
||||
wl_input_device_start_grab(shsurf->popup.grab.input_device,
|
||||
&shsurf->popup.grab, shsurf->popup.time);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_surface_set_popup(struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
struct wl_resource *input_device_resource,
|
||||
uint32_t time,
|
||||
struct wl_resource *parent_resource,
|
||||
int32_t x, int32_t y, uint32_t flags)
|
||||
{
|
||||
struct shell_surface *shsurf = resource->data;
|
||||
struct weston_surface *es = shsurf->surface;
|
||||
|
||||
weston_surface_damage(es);
|
||||
shsurf->type = SHELL_SURFACE_POPUP;
|
||||
shsurf->parent = parent_resource->data;
|
||||
shsurf->popup.x = x;
|
||||
shsurf->popup.y = y;
|
||||
}
|
||||
|
||||
static const struct wl_shell_surface_interface shell_surface_implementation = {
|
||||
shell_surface_move,
|
||||
shell_surface_resize,
|
||||
shell_surface_set_toplevel,
|
||||
shell_surface_set_transient,
|
||||
shell_surface_set_fullscreen
|
||||
shell_surface_set_fullscreen,
|
||||
shell_surface_set_popup
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -428,6 +544,9 @@ destroy_shell_surface(struct wl_resource *resource)
|
|||
{
|
||||
struct shell_surface *shsurf = resource->data;
|
||||
|
||||
if (shsurf->popup.grab.input_device)
|
||||
wl_input_device_end_grab(shsurf->popup.grab.input_device, 0);
|
||||
|
||||
/* in case cleaning up a dead client destroys shell_surface first */
|
||||
if (shsurf->surface)
|
||||
wl_list_remove(&shsurf->surface_destroy_listener.link);
|
||||
|
@ -1066,9 +1185,25 @@ map(struct weston_shell *base,
|
|||
}
|
||||
}
|
||||
|
||||
if (do_configure)
|
||||
weston_surface_configure(surface,
|
||||
surface->x, surface->y, width, height);
|
||||
switch (surface_type) {
|
||||
case SHELL_SURFACE_TOPLEVEL:
|
||||
surface->x = 10 + random() % 400;
|
||||
surface->y = 10 + random() % 400;
|
||||
break;
|
||||
case SHELL_SURFACE_POPUP:
|
||||
shell_map_popup(shsurf, shsurf->popup.time);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
if (do_configure) {
|
||||
weston_surface_configure(surface, surface->x, surface->y,
|
||||
width, height);
|
||||
weston_compositor_repick(compositor);
|
||||
}
|
||||
|
||||
switch (surface_type) {
|
||||
case SHELL_SURFACE_TOPLEVEL:
|
||||
|
|
Loading…
Reference in New Issue