summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@bitplanet.net>2011-12-05 09:40:43 -0500
committerKristian Høgsberg <krh@bitplanet.net>2011-12-07 10:13:05 -0500
commit9ed7635ed78218771e71f1a12da7487243639d73 (patch)
tree39a7d46c0350033ab29be3f22f083baff5492e2d
parent7172d9e22d49507db158994129672772f4a60a46 (diff)
menumenu
-rw-r--r--clients/resizor.c11
-rw-r--r--clients/window.c152
-rw-r--r--clients/window.h3
-rw-r--r--compositor/compositor.c215
-rw-r--r--compositor/compositor.h14
-rw-r--r--compositor/data-device.c88
-rw-r--r--compositor/shell.c219
7 files changed, 565 insertions, 137 deletions
diff --git a/clients/resizor.c b/clients/resizor.c
index c3d0327a..fa55f97c 100644
--- a/clients/resizor.c
+++ b/clients/resizor.c
@@ -159,12 +159,11 @@ show_menu(struct resizor *resizor, struct input *input)
int32_t x, y, width = 200, height = 200;
input_get_position(input, &x, &y);
- resizor->menu = window_create_transient(resizor->display,
- resizor->window,
- x - 10, y - 10, width, height);
+ resizor->menu = window_create_menu(resizor->display,
+ resizor->window,
+ x - 10, y - 10, width, height);
- window_draw(resizor->menu);
- window_flush(resizor->menu);
+ window_schedule_redraw(resizor->menu);
}
static void
@@ -178,8 +177,6 @@ button_handler(struct window *window,
case 274:
if (state)
show_menu(resizor, input);
- else
- window_destroy(resizor->menu);
break;
}
}
diff --git a/clients/window.c b/clients/window.c
index e0693da1..be62d1f4 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -96,6 +96,7 @@ enum {
TYPE_TOPLEVEL,
TYPE_FULLSCREEN,
TYPE_TRANSIENT,
+ TYPE_MENU,
TYPE_CUSTOM
};
@@ -765,6 +766,8 @@ window_set_type(struct window *window)
window->parent->shell_surface,
window->x, window->y, 0);
break;
+ case TYPE_MENU:
+ break;
case TYPE_CUSTOM:
break;
}
@@ -923,28 +926,6 @@ window_create_surface(struct window *window)
}
static void
-window_draw_menu(struct window *window)
-{
- cairo_t *cr;
- int width, height, r = 5;
-
- window_create_surface(window);
-
- cr = cairo_create(window->cairo_surface);
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
- cairo_paint(cr);
-
- width = window->allocation.width;
- height = window->allocation.height;
- rounded_rect(cr, r, r, width - r, height - r, r);
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source_rgba(cr, 1.0, 1.0, 0.0, 0.5);
- cairo_fill(cr);
- cairo_destroy(cr);
-}
-
-static void
window_draw_decorations(struct window *window)
{
cairo_t *cr;
@@ -1088,9 +1069,7 @@ item_get_user_data(struct item *item)
void
window_draw(struct window *window)
{
- if (window->parent)
- window_draw_menu(window);
- else if (!window->decoration)
+ if (!window->decoration)
window_create_surface(window);
else
window_draw_decorations(window);
@@ -1738,8 +1717,17 @@ handle_configure(void *data, struct wl_shell_surface *shell_surface,
}
}
+static void
+handle_menu_done(void *data, struct wl_shell_surface *shell_surface)
+{
+ struct window *window = data;
+
+ window_destroy(window);
+}
+
static const struct wl_shell_surface_listener shell_surface_listener = {
handle_configure,
+ handle_menu_done
};
void
@@ -2044,6 +2032,120 @@ window_create_transient(struct display *display, struct window *parent,
return window;
}
+struct menu {
+ int current;
+ int count;
+};
+
+static int
+menu_motion_handler(struct window *window,
+ struct input *input, uint32_t time,
+ int32_t x, int32_t y,
+ int32_t sx, int32_t sy, void *data)
+{
+ struct menu *menu = data;
+ int next;
+
+ next = (sy - 8) / 20;
+ if (menu->current != next) {
+ menu->current = next;
+ window_schedule_redraw(window);
+ }
+
+ return POINTER_LEFT_PTR;
+}
+
+static void
+menu_button_handler(struct window *window,
+ struct input *input, uint32_t time,
+ int button, int state, void *data)
+
+{
+ struct menu *menu = data;
+
+ fprintf(stderr, "menu_redraw_handler\n");
+
+ /* Either relase after press-drag-release or click-motion-click. */
+ if (state == 0 && 0 <= menu->current && menu->current < menu->count)
+ window_destroy(window);
+}
+
+static void
+menu_redraw_handler(struct window *window, void *data)
+{
+ cairo_t *cr;
+ int width, height, r = 5, i;
+ struct menu *menu = data;
+ static const char *entries[] = {
+ "Roy", "Pris", "Leon", "Zhora"
+ };
+
+ window_create_surface(window);
+
+ cr = cairo_create(window->cairo_surface);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
+ cairo_paint(cr);
+
+ width = window->allocation.width;
+ height = window->allocation.height;
+ rounded_rect(cr, r, r, width - r, height - r, r);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgba(cr, 1.0, 1.0, 0.0, 0.5);
+ cairo_fill(cr);
+
+ for (i = 0; i < ARRAY_LENGTH(entries); i++) {
+ if (i == menu->current) {
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_rectangle(cr, 0, i * 20 + 8, width, 20);
+ cairo_fill(cr);
+ cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
+ cairo_move_to(cr, 10, i * 20 + 20);
+ cairo_show_text(cr, entries[i]);
+ } else {
+ cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
+ cairo_move_to(cr, 10, i * 20 + 20);
+ cairo_show_text(cr, entries[i]);
+ }
+ }
+
+ cairo_destroy(cr);
+ window_flush(window);
+}
+
+struct window *
+window_create_menu(struct display *display, struct window *parent,
+ int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ struct window *window;
+ struct menu *menu;
+
+ window = window_create_internal(parent->display,
+ parent, width, height);
+ if (!window)
+ return NULL;
+ menu = malloc(sizeof *menu);
+ if (!menu)
+ return NULL;
+
+ menu->count = 4;
+ window->decoration = 0;
+ window->type = TYPE_MENU;
+ window->x = x;
+ window->y = y;
+
+ wl_shell_surface_set_menu(window->shell_surface,
+ window->parent->shell_surface,
+ window->x, window->y, 0);
+
+ window_set_motion_handler(window, menu_motion_handler);
+ window_set_button_handler(window, menu_button_handler);
+ window_set_redraw_handler(window, menu_redraw_handler);
+ window_set_user_data(window, menu);
+
+ return window;
+}
+
void
window_set_buffer_type(struct window *window, enum window_buffer_type type)
{
diff --git a/clients/window.h b/clients/window.h
index 8d17340f..63b16e5d 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -177,6 +177,9 @@ window_create(struct display *display, int32_t width, int32_t height);
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,
+ int32_t x, int32_t y, int32_t width, int32_t height);
void
window_destroy(struct window *window);
diff --git a/compositor/compositor.c b/compositor/compositor.c
index 2c04c3b4..33b896a6 100644
--- a/compositor/compositor.c
+++ b/compositor/compositor.c
@@ -242,28 +242,41 @@ wlsc_compositor_get_time(void)
}
WL_EXPORT void
+wlsc_device_repick(struct wl_input_device *device, uint32_t time)
+{
+ const struct wl_grab_interface *interface;
+ struct wlsc_surface *surface;
+ int32_t x, y;
+
+ surface = pick_surface(device, &x, &y);
+ if (&surface->surface == device->grab->focus)
+ return;
+
+ interface = device->grab->interface;
+ if (device->grab->focus) {
+ interface->leave(device->grab, time, device->grab->focus);
+ device->grab->focus = NULL;
+ }
+
+ interface = device->grab->interface;
+ if (surface) {
+ interface->enter(device->grab, time, &surface->surface, x, y);
+ device->grab->focus = &surface->surface;
+ }
+}
+
+WL_EXPORT void
wlsc_compositor_repick(struct wlsc_compositor *compositor)
{
struct wlsc_input_device *device;
- struct wlsc_surface *surface;
- int32_t sx, sy;
uint32_t time;
if (!compositor->focus)
return;
time = wlsc_compositor_get_time();
- wl_list_for_each(device, &compositor->input_device_list, link) {
- if (device->input_device.grab)
- continue;
- surface = pick_surface(&device->input_device, &sx, &sy);
- wl_input_device_set_pointer_focus(&device->input_device,
- &surface->surface,
- time,
- device->input_device.x,
- device->input_device.y,
- sx, sy);
- }
+ wl_list_for_each(device, &compositor->input_device_list, link)
+ wlsc_device_repick(&device->input_device, time);
}
static void
@@ -1146,7 +1159,7 @@ const static struct wl_compositor_interface compositor_interface = {
compositor_create_surface,
};
-static void
+WL_EXPORT void
wlsc_surface_transform(struct wlsc_surface *surface,
int32_t x, int32_t y, int32_t *sx, int32_t *sy)
{
@@ -1173,10 +1186,56 @@ pick_surface(struct wl_input_device *device, int32_t *sx, int32_t *sy)
return NULL;
}
+static void
+default_grab_enter(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 wl_resource *resource;
+
+ wl_list_for_each(resource, &device->resource_list, link) {
+ if (resource->client == surface->resource.client)
+ break;
+ }
+
+ if (&resource->link != &device->resource_list) {
+ wl_resource_post_event(resource,
+ WL_INPUT_DEVICE_POINTER_FOCUS,
+ time, surface,
+ device->x, device->y, x, y);
+ wl_list_insert(resource->destroy_listener_list.prev,
+ &device->pointer_focus_listener.link);
+
+ device->pointer_focus_resource = resource;
+ } else {
+ device->pointer_focus_resource = NULL;
+ }
+
+ device->pointer_focus = surface;
+ device->pointer_focus_time = time;
+}
+
+static void
+default_grab_leave(struct wl_grab *grab,
+ uint32_t time, struct wl_surface *surface)
+{
+ struct wl_input_device *device = grab->input_device;
+
+ if (device->pointer_focus_resource) {
+ wl_resource_post_event(device->pointer_focus_resource,
+ WL_INPUT_DEVICE_POINTER_FOCUS,
+ time, NULL, 0, 0, 0, 0);
+ wl_list_remove(&device->pointer_focus_listener.link);
+ }
+
+ device->pointer_focus_resource = NULL;
+ device->pointer_focus = NULL;
+}
static void
-implicit_grab_motion(struct wl_grab *grab,
- uint32_t time, int32_t x, int32_t y)
+default_grab_motion(struct wl_grab *grab,
+ uint32_t time, int32_t x, int32_t y)
{
struct wlsc_input_device *device =
(struct wlsc_input_device *) grab->input_device;
@@ -1194,8 +1253,8 @@ implicit_grab_motion(struct wl_grab *grab,
}
static void
-implicit_grab_button(struct wl_grab *grab,
- uint32_t time, int32_t button, int32_t state)
+default_grab_button(struct wl_grab *grab,
+ uint32_t time, int32_t button, int32_t state)
{
struct wl_resource *resource;
@@ -1206,16 +1265,90 @@ implicit_grab_button(struct wl_grab *grab,
}
static void
-implicit_grab_end(struct wl_grab *grab, uint32_t time)
+default_grab_end(struct wl_grab *grab, uint32_t time)
+{
+}
+
+static const struct wl_grab_interface default_grab_interface = {
+ default_grab_enter,
+ default_grab_leave,
+ default_grab_motion,
+ default_grab_button,
+ default_grab_end
+};
+
+static void
+implicit_grab_enter(struct wl_grab *grab,
+ uint32_t time, struct wl_surface *surface,
+ int32_t x, int32_t y)
+{
+}
+
+static void
+implicit_grab_leave(struct wl_grab *grab,
+ uint32_t time, struct wl_surface *surface)
{
}
static const struct wl_grab_interface implicit_grab_interface = {
- implicit_grab_motion,
- implicit_grab_button,
- implicit_grab_end
+ implicit_grab_enter,
+ implicit_grab_leave,
+ default_grab_motion,
+ default_grab_button,
+ default_grab_end
};
+WL_EXPORT int
+wlsc_input_device_update_grab(struct wl_input_device *device,
+ struct wl_grab *grab,
+ struct wl_surface *surface, uint32_t time)
+{
+ const struct wl_grab_interface *interface;
+ int32_t x, y;
+
+#if 0
+ if (device->grab != &device->implicit_grab ||
+ device->grab_time != time ||
+ device->pointer_focus != surface)
+ return -1;
+#endif
+
+ interface = device->grab->interface;
+ if (device->default_grab.focus)
+ default_grab_leave(device->grab, time,
+ device->default_grab.focus);
+
+ device->grab = grab;
+ interface = device->grab->interface;
+ grab->input_device = device;
+ grab->focus = (struct wl_surface *) pick_surface(device, &x, &y);
+ if (grab->focus)
+ interface->enter(device->grab, time, grab->focus, x, y);
+
+ return 0;
+}
+
+WL_EXPORT void
+wlsc_input_device_end_grab(struct wl_input_device *device, uint32_t time)
+{
+ const struct wl_grab_interface *interface;
+ int32_t x, y;
+
+ interface = device->grab->interface;
+ if (device->grab->focus)
+ interface->leave(device->grab, time, device->grab->focus);
+ interface->end(device->grab, time);
+
+ device->grab = &device->default_grab;
+ device->grab->focus =
+ (struct wl_surface *) pick_surface(device, &x, &y);
+ if (device->grab->focus)
+ default_grab_enter(device->grab,
+ time, device->grab->focus, x, y);
+
+ wl_list_remove(&device->grab_listener.link);
+}
+
WL_EXPORT void
wlsc_compositor_wake(struct wlsc_compositor *compositor)
{
@@ -1266,12 +1399,10 @@ idle_handler(void *data)
WL_EXPORT void
notify_motion(struct wl_input_device *device, uint32_t time, int x, int y)
{
- struct wlsc_surface *es;
struct wlsc_output *output;
const struct wl_grab_interface *interface;
struct wlsc_input_device *wd = (struct wlsc_input_device *) device;
struct wlsc_compositor *ec = wd->compositor;
- int32_t sx, sy;
int x_valid = 0, y_valid = 0;
int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN;
@@ -1312,19 +1443,9 @@ notify_motion(struct wl_input_device *device, uint32_t time, int x, int y)
device->x = x;
device->y = y;
- if (device->grab) {
- interface = device->grab->interface;
- interface->motion(device->grab, time, x, y);
- } else {
- es = pick_surface(device, &sx, &sy);
- wl_input_device_set_pointer_focus(device,
- &es->surface,
- time, x, y, sx, sy);
- if (device->pointer_focus_resource)
- wl_resource_post_event(device->pointer_focus_resource,
- WL_INPUT_DEVICE_MOTION,
- time, x, y, sx, sy);
- }
+ wlsc_device_repick(device, time);
+ interface = device->grab->interface;
+ interface->motion(device->grab, time, x, y);
wlsc_surface_damage_below(wd->sprite);
@@ -1362,14 +1483,13 @@ notify_button(struct wl_input_device *device,
struct wlsc_binding *b;
struct wlsc_surface *surface =
(struct wlsc_surface *) device->pointer_focus;
- int32_t sx, sy;
if (state)
wlsc_compositor_idle_inhibit(compositor);
else
wlsc_compositor_idle_release(compositor);
- if (state && surface && device->grab == NULL) {
+ if (state && surface && device->grab == &device->default_grab) {
compositor->shell->activate(compositor->shell,
surface, wd, time);
wl_input_device_start_grab(device,
@@ -1386,17 +1506,10 @@ notify_button(struct wl_input_device *device,
}
}
- if (device->grab)
- device->grab->interface->button(device->grab, time,
- button, state);
+ device->grab->interface->button(device->grab, time, button, state);
- if (!state && device->grab && device->grab_button == button) {
- wl_input_device_end_grab(device, time);
- surface = pick_surface(device, &sx, &sy);
- wl_input_device_set_pointer_focus(device, &surface->surface,
- time, device->x, device->y,
- sx, sy);
- }
+ if (!state && device->grab && device->grab_button == button)
+ wlsc_input_device_end_grab(device, time);
}
static void
@@ -1653,7 +1766,11 @@ wlsc_input_device_init(struct wlsc_input_device *device,
device->hotspot_y = 16;
device->modifier_state = 0;
+ device->input_device.default_grab.interface = &default_grab_interface;
+ device->input_device.default_grab.input_device = &device->input_device;
device->input_device.implicit_grab.interface = &implicit_grab_interface;
+ device->input_device.grab = &device->input_device.default_grab;
+
wl_list_insert(ec->input_device_list.prev, &device->link);
diff --git a/compositor/compositor.h b/compositor/compositor.h
index 1d551584..62c93cf0 100644
--- a/compositor/compositor.h
+++ b/compositor/compositor.h
@@ -124,10 +124,10 @@ struct wlsc_input_device {
struct wl_surface *drag_focus;
struct wl_resource *drag_focus_resource;
struct wl_listener drag_focus_listener;
+ struct wl_grab drag_grab;
struct wlsc_data_source *selection_data_source;
struct wl_listener selection_data_source_listener;
- struct wl_grab grab;
};
enum wlsc_visual {
@@ -292,6 +292,9 @@ wlsc_surface_activate(struct wlsc_surface *surface,
struct wlsc_input_device *device, uint32_t time);
void
+wlsc_surface_transform(struct wlsc_surface *surface,
+ int32_t x, int32_t y, int32_t *sx, int32_t *sy);
+void
notify_motion(struct wl_input_device *device,
uint32_t time, int x, int y);
void
@@ -368,6 +371,15 @@ wlsc_surface_damage_rectangle(struct wlsc_surface *surface,
void
wlsc_input_device_set_pointer_image(struct wlsc_input_device *device,
enum wlsc_pointer_type type);
+void
+wlsc_device_repick(struct wl_input_device *device, uint32_t time);
+
+int
+wlsc_input_device_update_grab(struct wl_input_device *device,
+ struct wl_grab *grab,
+ struct wl_surface *surface, uint32_t time);
+void
+wlsc_input_device_end_grab(struct wl_input_device *device, uint32_t time);
struct wlsc_surface *
pick_surface(struct wl_input_device *device, int32_t *sx, int32_t *sy);
diff --git a/compositor/data-device.c b/compositor/data-device.c
index c39465f0..f42441f7 100644
--- a/compositor/data-device.c
+++ b/compositor/data-device.c
@@ -167,27 +167,20 @@ destroy_drag_focus(struct wl_listener *listener,
}
static void
-drag_set_focus(struct wlsc_input_device *device,
- struct wl_surface *surface, uint32_t time,
- int32_t x, int32_t y)
+drag_grab_enter(struct wl_grab *grab,
+ uint32_t time, struct wl_surface *surface,
+ int32_t x, int32_t y)
{
+ struct wlsc_input_device *device =
+ container_of(grab, struct wlsc_input_device, drag_grab);
struct wl_resource *resource, *offer;
- if (device->drag_focus == surface)
- return;
-
- if (device->drag_focus_resource) {
- wl_resource_post_event(device->drag_focus_resource,
- WL_DATA_DEVICE_LEAVE);
- wl_list_remove(&device->drag_focus_listener.link);
- device->drag_focus_resource = NULL;
- device->drag_focus = NULL;
- }
+ resource = find_resource(&device->drag_resource_list,
+ surface->resource.client);
+ fprintf(stderr, "drag enter, resource %p, id %d\n",
+ resource, resource ? resource->object.id : 0);
- if (surface)
- resource = find_resource(&device->drag_resource_list,
- surface->resource.client);
- if (surface && resource) {
+ if (resource) {
offer = wlsc_data_source_send_offer(device->drag_data_source,
resource);
@@ -204,43 +197,65 @@ drag_set_focus(struct wlsc_input_device *device,
}
static void
+drag_grab_leave(struct wl_grab *grab,
+ uint32_t time, struct wl_surface *surface)
+{
+ struct wlsc_input_device *device =
+ container_of(grab, struct wlsc_input_device, drag_grab);
+
+ if (device->drag_focus_resource) {
+ wl_resource_post_event(device->drag_focus_resource,
+ WL_DATA_DEVICE_LEAVE);
+ wl_list_remove(&device->drag_focus_listener.link);
+ device->drag_focus_resource = NULL;
+ device->drag_focus = NULL;
+ }
+}
+
+static void
drag_grab_motion(struct wl_grab *grab,
uint32_t time, int32_t x, int32_t y)
{
struct wlsc_input_device *device =
- container_of(grab, struct wlsc_input_device, grab);
+ container_of(grab, struct wlsc_input_device, drag_grab);
struct wlsc_surface *es;
+ int32_t sx, sy;
- es = pick_surface(&device->input_device, &x, &y);
- drag_set_focus(device, &es->surface, time, x, y);
+ if (device->drag_focus_resource) {
+ es = (struct wlsc_surface *) grab->focus;
+ wlsc_surface_transform(es, x, y, &sx, &sy);
- if (es && device->drag_focus_resource)
wl_resource_post_event(device->drag_focus_resource,
- WL_DATA_DEVICE_MOTION, time, x, y);
+ WL_DATA_DEVICE_MOTION, time, sx, sy);
+ }
}
static void
drag_grab_button(struct wl_grab *grab,
uint32_t time, int32_t button, int32_t state)
{
+ struct wlsc_input_device *device =
+ container_of(grab, struct wlsc_input_device, drag_grab);
+
+ if (device->drag_focus_resource &&
+ device->input_device.grab_button == button && state == 0)
+ wl_resource_post_event(device->drag_focus_resource,
+ WL_DATA_DEVICE_DROP);
}
static void
drag_grab_end(struct wl_grab *grab, uint32_t time)
{
struct wlsc_input_device *device =
- container_of(grab, struct wlsc_input_device, grab);
+ container_of(grab, struct wlsc_input_device, drag_grab);
- if (device->drag_focus_resource)
- wl_resource_post_event(device->drag_focus_resource,
- WL_DATA_DEVICE_DROP);
-
- drag_set_focus(device, NULL, time, 0, 0);
wlsc_data_source_unref(device->drag_data_source);
device->drag_data_source = NULL;
}
static const struct wl_grab_interface drag_grab_interface = {
+ drag_grab_enter,
+ drag_grab_leave,
drag_grab_motion,
drag_grab_button,
drag_grab_end
@@ -253,26 +268,21 @@ data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
{
struct wlsc_input_device *device = resource->data;
struct wlsc_surface *surface = surface_resource->data;
- struct wlsc_surface *target;
- int32_t sx, sy;
/* FIXME: Check that client has implicit grab on the surface
* that matches the given time. */
/* FIXME: Check that the data source type array isn't empty. */
- if (wl_input_device_update_grab(&device->input_device, &device->grab,
- &surface->surface, time) < 0)
- return;
-
- device->grab.interface = &drag_grab_interface;
+ device->drag_grab.interface = &drag_grab_interface;
device->drag_data_source = source_resource->data;
device->drag_data_source->refcount++;
- target = pick_surface(&device->input_device, &sx, &sy);
- wl_input_device_set_pointer_focus(&device->input_device,
- NULL, time, 0, 0, 0, 0);
- drag_set_focus(device, &target->surface, time, sx, sy);
+ if (wlsc_input_device_update_grab(&device->input_device,
+ &device->drag_grab,
+ &surface->surface, time) < 0)
+ return;
+
}
static void
diff --git a/compositor/shell.c b/compositor/shell.c
index b7cfdd33..0bf26f96 100644
--- a/compositor/shell.c
+++ b/compositor/shell.c
@@ -68,7 +68,8 @@ enum shell_surface_type {
SHELL_SURFACE_TOPLEVEL,
SHELL_SURFACE_TRANSIENT,
- SHELL_SURFACE_FULLSCREEN
+ SHELL_SURFACE_FULLSCREEN,
+ SHELL_SURFACE_MENU
};
struct shell_surface {
@@ -76,10 +77,17 @@ struct shell_surface {
struct wlsc_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;
+ } menu;
+
struct wlsc_output *output;
struct wl_list link;
};
@@ -91,6 +99,19 @@ struct wlsc_move_grab {
};
static void
+noop_grab_enter(struct wl_grab *grab,
+ uint32_t time, struct wl_surface *surface,
+ int32_t x, int32_t y)
+{
+}
+
+static void
+noop_grab_leave(struct wl_grab *grab,
+ uint32_t time, struct wl_surface *surface)
+{
+}
+
+static void
move_grab_motion(struct wl_grab *grab,
uint32_t time, int32_t x, int32_t y)
{
@@ -114,6 +135,8 @@ move_grab_end(struct wl_grab *grab, uint32_t time)
}
static const struct wl_grab_interface move_grab_interface = {
+ noop_grab_enter,
+ noop_grab_leave,
move_grab_motion,
move_grab_button,
move_grab_end
@@ -134,13 +157,11 @@ wlsc_surface_move(struct wlsc_surface *es,
move->dy = es->y - wd->input_device.grab_y;
move->surface = es;
- if (wl_input_device_update_grab(&wd->input_device,
- &move->grab, &es->surface, time) < 0)
+ if (wlsc_input_device_update_grab(&wd->input_device,
+ &move->grab, &es->surface, time) < 0)
return 0;
wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
- wl_input_device_set_pointer_focus(&wd->input_device,
- NULL, time, 0, 0, 0, 0);
return 0;
}
@@ -205,6 +226,8 @@ resize_grab_end(struct wl_grab *grab, uint32_t time)
}
static const struct wl_grab_interface resize_grab_interface = {
+ noop_grab_enter,
+ noop_grab_leave,
resize_grab_motion,
resize_grab_button,
resize_grab_end
@@ -264,13 +287,11 @@ wlsc_surface_resize(struct shell_surface *shsurf,
break;
}
- if (wl_input_device_update_grab(&wd->input_device,
- &resize->grab, &es->surface, time) < 0)
+ if (wlsc_input_device_update_grab(&wd->input_device,
+ &resize->grab, &es->surface, time) < 0)
return 0;
wlsc_input_device_set_pointer_image(wd, pointer);
- wl_input_device_set_pointer_focus(&wd->input_device,
- NULL, time, 0, 0, 0, 0);
return 0;
}
@@ -351,12 +372,161 @@ shell_surface_set_fullscreen(struct wl_client *client,
shsurf->type = SHELL_SURFACE_FULLSCREEN;
}
+
+static void
+menu_grab_enter(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 wl_resource *resource;
+ struct shell_surface *priv =
+ container_of(grab, struct shell_surface, menu.grab);
+
+ wl_list_for_each(resource, &device->resource_list, link) {
+ if (resource->client == surface->resource.client)
+ break;
+ }
+
+ if (&resource->link != &device->resource_list &&
+ resource->client == priv->surface->surface.resource.client) {
+ wl_resource_post_event(resource,
+ WL_INPUT_DEVICE_POINTER_FOCUS,
+ time, surface,
+ device->x, device->y, x, y);
+ wl_list_insert(resource->destroy_listener_list.prev,
+ &device->pointer_focus_listener.link);
+
+ device->pointer_focus_resource = resource;
+ } else {
+ device->pointer_focus_resource = NULL;
+ }
+
+ device->pointer_focus = surface;
+ device->pointer_focus_time = time;
+}
+
+static void
+menu_grab_leave(struct wl_grab *grab,
+ uint32_t time, struct wl_surface *surface)
+{
+ struct wl_input_device *device = grab->input_device;
+
+ if (device->pointer_focus_resource) {
+ wl_resource_post_event(device->pointer_focus_resource,
+ WL_INPUT_DEVICE_POINTER_FOCUS,
+ time, NULL, 0, 0, 0, 0);
+ wl_list_remove(&device->pointer_focus_listener.link);
+ }
+
+ device->pointer_focus_resource = NULL;
+ device->pointer_focus = NULL;
+}
+
+static void
+menu_grab_motion(struct wl_grab *grab,
+ uint32_t time, int32_t x, int32_t y)
+{
+ struct wlsc_input_device *device =
+ (struct wlsc_input_device *) grab->input_device;
+ struct wlsc_surface *es =
+ (struct wlsc_surface *) device->input_device.pointer_focus;
+ int32_t sx, sy;
+ struct wl_resource *resource;
+
+ resource = grab->input_device->pointer_focus_resource;
+ if (resource) {
+ wlsc_surface_transform(es, x, y, &sx, &sy);
+ wl_resource_post_event(resource, WL_INPUT_DEVICE_MOTION,
+ time, x, y, sx, sy);
+ }
+}
+
+static void
+menu_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, menu.grab);
+
+ resource = grab->input_device->pointer_focus_resource;
+ if (resource) {
+ wl_resource_post_event(resource, WL_INPUT_DEVICE_BUTTON,
+ time, button, state);
+ } else {
+ wl_resource_post_event(&shsurf->resource,
+ WL_SHELL_SURFACE_MENU_DONE);
+ wlsc_input_device_end_grab(grab->input_device, time);
+ shsurf->menu.grab.input_device = NULL;
+ }
+}
+
+static void
+menu_grab_end(struct wl_grab *grab, uint32_t time)
+{
+}
+
+static const struct wl_grab_interface menu_grab_interface = {
+ menu_grab_enter,
+ menu_grab_leave,
+ menu_grab_motion,
+ menu_grab_button,
+ menu_grab_end
+};
+
+static void
+shell_map_menu(struct shell_surface *shsurf, uint32_t time)
+{
+ struct wl_input_device *device;
+ struct wlsc_surface *es = shsurf->surface;
+ struct wlsc_surface *parent = shsurf->parent->surface;
+
+ es->output = parent->output;
+
+ shsurf->menu.grab.interface = &menu_grab_interface;
+ device = es->compositor->input_device;
+
+ es->x = shsurf->parent->surface->x + shsurf->menu.x;
+ es->y = shsurf->parent->surface->y + shsurf->menu.y;
+
+ shsurf->menu.grab.input_device = device;
+ shsurf->menu.time = device->grab_time;
+
+ if (wlsc_input_device_update_grab(shsurf->menu.grab.input_device,
+ &shsurf->menu.grab,
+ &shsurf->parent->surface->surface,
+ shsurf->menu.time)) {
+ fprintf(stderr, "update grab failed\n");
+ }
+
+ /* FIXME: Hack to prevent button release from ending the grab */
+ device->grab_button = 0;
+}
+
+static void
+shell_surface_set_menu(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *parent_resource,
+ int32_t x, int32_t y, uint32_t flags)
+{
+ struct shell_surface *shsurf = resource->data;
+ struct wlsc_surface *es = shsurf->surface;
+
+ wlsc_surface_damage(es);
+ shsurf->type = SHELL_SURFACE_MENU;
+ shsurf->parent = parent_resource->data;
+ shsurf->menu.x = x;
+ shsurf->menu.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_menu
};
static void
@@ -364,6 +534,9 @@ destroy_shell_surface(struct wl_resource *resource)
{
struct shell_surface *shsurf = resource->data;
+ if (shsurf->menu.grab.input_device)
+ wlsc_input_device_end_grab(shsurf->menu.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);
@@ -376,9 +549,9 @@ static void
shell_handle_surface_destroy(struct wl_listener *listener,
struct wl_resource *resource, uint32_t time)
{
- struct shell_surface *shsurf = container_of(listener,
- struct shell_surface,
- surface_destroy_listener);
+ struct shell_surface *shsurf =
+ container_of(listener,
+ struct shell_surface, surface_destroy_listener);
shsurf->surface = NULL;
wl_resource_destroy(&shsurf->resource, time);
@@ -795,8 +968,13 @@ map(struct wlsc_shell *base,
struct wlsc_compositor *compositor = shell->compositor;
struct wl_list *list;
enum shell_surface_type surface_type;
+ struct shell_surface *shsurf;
- surface_type = get_shell_surface_type(surface);
+ shsurf = get_shell_surface(surface);
+ if (shsurf)
+ surface_type = shsurf->type;
+ else
+ surface_type = SHELL_SURFACE_NORMAL;
if (shell->locked)
list = &shell->hidden_surface_list;
@@ -832,16 +1010,25 @@ map(struct wlsc_shell *base,
}
}
- if (surface_type == SHELL_SURFACE_TOPLEVEL) {
+ switch (surface_type) {
+ case SHELL_SURFACE_TOPLEVEL:
surface->x = 10 + random() % 400;
surface->y = 10 + random() % 400;
+ break;
+ case SHELL_SURFACE_MENU:
+ shell_map_menu(shsurf, shsurf->menu.time);
+ break;
+ default:
+ break;
}
surface->width = width;
surface->height = height;
- if (!shell->locked || surface_type == SHELL_SURFACE_LOCK)
+ if (!shell->locked || surface_type == SHELL_SURFACE_LOCK) {
wlsc_surface_configure(surface,
surface->x, surface->y, width, height);
+ wlsc_compositor_repick(compositor);
+ }
if (surface_type == SHELL_SURFACE_TOPLEVEL)
wlsc_zoom_run(surface, 0.8, 1.0, NULL, NULL);