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.
dev
Kristian Høgsberg 13 years ago
parent dade64968c
commit b3cca0a411
  1. 22
      clients/desktop-shell.c
  2. 6
      clients/resizor.c
  3. 22
      clients/window.c
  4. 3
      clients/window.h
  5. 145
      src/shell.c

@ -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,12 +2240,14 @@ 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,
wl_shell_surface_set_popup(window->shell_surface,
input->input_device, time,
window->parent->shell_surface,
window->x, window->y, 0);

@ -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

@ -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…
Cancel
Save