summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@bitplanet.net>2012-01-04 22:19:14 -0500
committerKristian Høgsberg <krh@bitplanet.net>2012-01-04 22:19:14 -0500
commita59e4f9e8686b5e91a6addb25bc319fccce78d5c (patch)
tree274857bf35817a76b1b86fe4a25b6e6838bf56ba
parent8662907a825a95e945d121145cd5e7ca0ec9aa21 (diff)
popup wippopup
-rw-r--r--clients/desktop-shell.c22
-rw-r--r--clients/resizor.c6
-rw-r--r--clients/window.c26
-rw-r--r--clients/window.h3
-rw-r--r--src/shell.c145
5 files changed, 176 insertions, 26 deletions
diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index f20e19a7..25fcee60 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-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);
}
}
diff --git a/clients/resizor.c b/clients/resizor.c
index 2f32ad5b..867ceb90 100644
--- a/clients/resizor.c
+++ b/clients/resizor.c
@@ -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;
}
}
diff --git a/clients/window.c b/clients/window.c
index aa5f48b2..3be93b9c 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -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);
diff --git a/clients/window.h b/clients/window.h
index 75bafc13..f1bad3fd 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -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
diff --git a/src/shell.c b/src/shell.c
index 2bc2c09a..5e3f1f67 100644
--- a/src/shell.c
+++ b/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;
};
@@ -333,6 +342,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;
}
@@ -411,12 +421,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
@@ -424,6 +540,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);
@@ -1062,9 +1181,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: