X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=clients%2Fwindow.c;h=e44d65c9249ffe325b33df258b7bf190c6477631;hb=b2c18647775732da740946eb199b1f2b46ba950b;hp=96b49a4c8d4a1fc1674aded1d62b503ebd76912e;hpb=e818d59e8827933511a0611aff0e9605ecacfeeb;p=profile%2Fivi%2Fweston-ivi-shell.git diff --git a/clients/window.c b/clients/window.c index 96b49a4..e44d65c 100644 --- a/clients/window.c +++ b/clients/window.c @@ -217,8 +217,8 @@ struct window { struct rectangle saved_allocation; struct rectangle min_allocation; struct rectangle pending_allocation; + struct rectangle last_geometry; int x, y; - int resize_edges; int redraw_needed; int redraw_task_scheduled; struct task redraw_task; @@ -240,12 +240,14 @@ struct window { window_close_handler_t close_handler; window_fullscreen_handler_t fullscreen_handler; window_output_handler_t output_handler; + window_state_changed_handler_t state_changed_handler; struct surface *main_surface; struct xdg_surface *xdg_surface; struct xdg_popup *xdg_popup; - struct window *transient_for; + struct window *parent; + struct wl_surface *last_parent_surface; struct window_frame *frame; @@ -334,6 +336,11 @@ struct input { xkb_mod_mask_t shift_mask; } xkb; + int32_t repeat_rate_sec; + int32_t repeat_rate_nsec; + int32_t repeat_delay_sec; + int32_t repeat_delay_nsec; + struct task repeat_task; int repeat_timer_fd; uint32_t repeat_sym; @@ -349,6 +356,8 @@ struct output { struct wl_list link; int transform; int scale; + char *make; + char *model; display_output_handler_t destroy_handler; void *user_data; @@ -358,11 +367,14 @@ struct window_frame { struct widget *widget; struct widget *child; struct frame *frame; + + uint32_t last_time; + uint32_t did_double, double_click; }; struct menu { + void *user_data; struct window *window; - struct window *parent; struct widget *widget; struct input *input; struct frame *frame; @@ -395,22 +407,6 @@ enum { CURSOR_UNSET }; -enum window_location { - WINDOW_INTERIOR = 0, - WINDOW_RESIZING_TOP = 1, - WINDOW_RESIZING_BOTTOM = 2, - WINDOW_RESIZING_LEFT = 4, - WINDOW_RESIZING_TOP_LEFT = 5, - WINDOW_RESIZING_BOTTOM_LEFT = 6, - WINDOW_RESIZING_RIGHT = 8, - WINDOW_RESIZING_TOP_RIGHT = 9, - WINDOW_RESIZING_BOTTOM_RIGHT = 10, - WINDOW_RESIZING_MASK = 15, - WINDOW_EXTERIOR = 16, - WINDOW_TITLEBAR = 17, - WINDOW_CLIENT_AREA = 18, -}; - static const cairo_user_data_key_t shm_surface_data_key; /* #define DEBUG */ @@ -585,8 +581,8 @@ egl_window_surface_release(struct toysurface *base) if (!device) return; - if (!eglMakeCurrent(surface->display->dpy, NULL, NULL, - surface->display->argb_ctx)) + if (!eglMakeCurrent(surface->display->dpy, + EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) fprintf(stderr, "failed to make context current\n"); cairo_device_release(device); @@ -1296,6 +1292,10 @@ create_cursors(struct display *display) weston_config_destroy(config); display->cursor_theme = wl_cursor_theme_load(theme, size, display->shm); + if (!display->cursor_theme) { + fprintf(stderr, "could not load theme '%s'\n", theme); + return; + } free(theme); display->cursors = xmalloc(ARRAY_LENGTH(cursors) * sizeof display->cursors[0]); @@ -1379,7 +1379,7 @@ window_get_display(struct window *window) } static void -surface_create_surface(struct surface *surface, int dx, int dy, uint32_t flags) +surface_create_surface(struct surface *surface, uint32_t flags) { struct display *display = surface->window->display; struct rectangle allocation = surface->allocation; @@ -1399,7 +1399,7 @@ surface_create_surface(struct surface *surface, int dx, int dy, uint32_t flags) flags, &allocation); surface->cairo_surface = surface->toysurface->prepare( - surface->toysurface, dx, dy, + surface->toysurface, 0, 0, allocation.width, allocation.height, flags, surface->buffer_transform, surface->buffer_scale); } @@ -1409,8 +1409,6 @@ window_create_main_surface(struct window *window) { struct surface *surface = window->main_surface; uint32_t flags = 0; - int dx = 0; - int dy = 0; if (window->resizing) flags |= SURFACE_HINT_RESIZE; @@ -1418,17 +1416,7 @@ window_create_main_surface(struct window *window) if (window->preferred_format == WINDOW_PREFERRED_FORMAT_RGB565) flags |= SURFACE_HINT_RGB565; - if (window->resize_edges & WINDOW_RESIZING_LEFT) - dx = surface->server_allocation.width - - surface->allocation.width; - - if (window->resize_edges & WINDOW_RESIZING_TOP) - dy = surface->server_allocation.height - - surface->allocation.height; - - window->resize_edges = 0; - - surface_create_surface(surface, dx, dy, flags); + surface_create_surface(surface, flags); } int @@ -1700,7 +1688,7 @@ widget_get_cairo_surface(struct widget *widget) if (surface == window->main_surface) window_create_main_surface(window); else - surface_create_surface(surface, 0, 0, 0); + surface_create_surface(surface, 0); } return surface->cairo_surface; @@ -2143,12 +2131,6 @@ frame_resize_handler(struct widget *widget, interior.width = width; interior.height = height; } else { - if (widget->window->maximized) { - frame_set_flag(frame->frame, FRAME_FLAG_MAXIMIZED); - } else { - frame_unset_flag(frame->frame, FRAME_FLAG_MAXIMIZED); - } - frame_resize(frame->frame, width, height); frame_interior(frame->frame, &interior.x, &interior.y, &interior.width, &interior.height); @@ -2216,12 +2198,6 @@ frame_redraw_handler(struct widget *widget, void *data) if (window->fullscreen) return; - if (window->focused) { - frame_set_flag(frame->frame, FRAME_FLAG_ACTIVE); - } else { - frame_unset_flag(frame->frame, FRAME_FLAG_ACTIVE); - } - cr = widget_cairo_create(widget); frame_repaint(frame->frame, cr); @@ -2263,9 +2239,9 @@ frame_get_pointer_image_for_location(struct window_frame *frame, } static void -frame_menu_func(struct window *window, - struct input *input, int index, void *data) +frame_menu_func(void *data, struct input *input, int index) { + struct window *window = data; struct display *display; switch (index) { @@ -2370,8 +2346,10 @@ frame_handle_status(struct window_frame *frame, struct input *input, if (status & FRAME_STATUS_REPAINT) widget_schedule_redraw(frame->widget); - if (status & FRAME_STATUS_MINIMIZE) - fprintf(stderr,"Minimize stub\n"); + if (status & FRAME_STATUS_MINIMIZE) { + window_set_minimized(window); + frame_status_clear(frame->frame, FRAME_STATUS_MINIMIZE); + } if (status & FRAME_STATUS_MENU) { window_show_frame_menu(window, input, time); @@ -2400,7 +2378,6 @@ frame_handle_status(struct window_frame *frame, struct input *input, if ((status & FRAME_STATUS_RESIZE) && window->xdg_surface) { input_ungrab(input); - window->resizing = 1; xdg_surface_resize(window->xdg_surface, input_get_seat(input), window->display->serial, @@ -2410,6 +2387,7 @@ frame_handle_status(struct window_frame *frame, struct input *input, } } +#define DOUBLE_CLICK_PERIOD 250 static void frame_button_handler(struct widget *widget, struct input *input, uint32_t time, @@ -2420,7 +2398,27 @@ frame_button_handler(struct widget *widget, struct window_frame *frame = data; enum theme_location location; - location = frame_pointer_button(frame->frame, input, button, state); + frame->double_click = 0; + if (state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (time - frame->last_time <= DOUBLE_CLICK_PERIOD) { + frame->double_click = 1; + frame->did_double = 1; + } else + frame->did_double = 0; + + frame->last_time = time; + } else if (frame->did_double == 1) { + frame->double_click = 1; + frame->did_double = 0; + } + + if (frame->double_click) + location = frame_double_click(frame->frame, input, + button, state); + else + location = frame_pointer_button(frame->frame, input, + button, state); + frame_handle_status(frame, input, time, location); } @@ -2579,6 +2577,8 @@ input_grab(struct input *input, struct widget *widget, uint32_t button) { input->grab = widget; input->grab_button = button; + + input_set_focus_widget(input, widget, input->sx, input->sy); } void @@ -2624,16 +2624,15 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer, return; } + window = wl_surface_get_user_data(surface); + if (surface != window->main_surface->surface) { + DBG("Ignoring input event from subsurface %p\n", surface); + return; + } + input->display->serial = serial; input->pointer_enter_serial = serial; - input->pointer_focus = wl_surface_get_user_data(surface); - window = input->pointer_focus; - - if (window->resizing) { - window->resizing = 0; - /* Schedule a redraw to free the pool */ - window_schedule_redraw(window); - } + input->pointer_focus = window; input->sx = sx; input->sy = sy; @@ -2663,12 +2662,12 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer, float sx = wl_fixed_to_double(sx_w); float sy = wl_fixed_to_double(sy_w); - input->sx = sx; - input->sy = sy; - if (!window) return; + input->sx = sx; + input->sy = sy; + /* when making the window smaller - e.g. after a unmaximise we might * still have a pending motion event that the compositor has picked * based on the old surface dimensions @@ -2818,10 +2817,10 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, return; } - keymap = xkb_map_new_from_string(input->display->xkb_context, - map_str, - XKB_KEYMAP_FORMAT_TEXT_V1, - 0); + keymap = xkb_keymap_new_from_string(input->display->xkb_context, + map_str, + XKB_KEYMAP_FORMAT_TEXT_V1, + 0); munmap(map_str, size); close(fd); @@ -2833,7 +2832,7 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, state = xkb_state_new(keymap); if (!state) { fprintf(stderr, "failed to create XKB state\n"); - xkb_map_unref(keymap); + xkb_keymap_unref(keymap); return; } @@ -2843,11 +2842,11 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, input->xkb.state = state; input->xkb.control_mask = - 1 << xkb_map_mod_get_index(input->xkb.keymap, "Control"); + 1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Control"); input->xkb.alt_mask = - 1 << xkb_map_mod_get_index(input->xkb.keymap, "Mod1"); + 1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Mod1"); input->xkb.shift_mask = - 1 << xkb_map_mod_get_index(input->xkb.keymap, "Shift"); + 1 << xkb_keymap_mod_get_index(input->xkb.keymap, "Shift"); } static void @@ -2895,7 +2894,15 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, if (!window || !input->xkb.state) return; - num_syms = xkb_key_get_syms(input->xkb.state, code, &syms); + /* We only use input grabs for pointer events for now, so just + * ignore key presses if a grab is active. We expand the key + * event delivery mechanism to route events to widgets to + * properly handle key grabs. In the meantime, this prevents + * key event devlivery while a grab is active. */ + if (input->grab && input->grab_button == 0) + return; + + num_syms = xkb_state_key_get_syms(input->xkb.state, code, &syms); sym = XKB_KEY_NoSymbol; if (num_syms == 1) @@ -2930,10 +2937,10 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, input->repeat_sym = sym; input->repeat_key = key; input->repeat_time = time; - its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 25 * 1000 * 1000; - its.it_value.tv_sec = 0; - its.it_value.tv_nsec = 400 * 1000 * 1000; + its.it_interval.tv_sec = input->repeat_rate_sec; + its.it_interval.tv_nsec = input->repeat_rate_nsec; + its.it_value.tv_sec = input->repeat_delay_sec; + its.it_value.tv_nsec = input->repeat_delay_nsec; timerfd_settime(input->repeat_timer_fd, 0, &its, NULL); } } @@ -2954,8 +2961,8 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); mask = xkb_state_serialize_mods(input->xkb.state, - XKB_STATE_DEPRESSED | - XKB_STATE_LATCHED); + XKB_STATE_MODS_DEPRESSED | + XKB_STATE_MODS_LATCHED); input->modifiers = 0; if (mask & input->xkb.control_mask) input->modifiers |= MOD_CONTROL_MASK; @@ -2965,12 +2972,44 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, input->modifiers |= MOD_SHIFT_MASK; } +static void +set_repeat_info(struct input *input, int32_t rate, int32_t delay) +{ + input->repeat_rate_sec = input->repeat_rate_nsec = 0; + input->repeat_delay_sec = input->repeat_delay_nsec = 0; + + /* a rate of zero disables any repeating, regardless of the delay's + * value */ + if (rate == 0) + return; + + if (rate == 1) + input->repeat_rate_sec = 1; + else + input->repeat_rate_nsec = 1000000000 / rate; + + input->repeat_delay_sec = delay / 1000; + delay -= (input->repeat_delay_sec * 1000); + input->repeat_delay_nsec = delay * 1000 * 1000; +} + +static void +keyboard_handle_repeat_info(void *data, struct wl_keyboard *keyboard, + int32_t rate, int32_t delay) +{ + struct input *input = data; + + set_repeat_info(input, rate, delay); +} + static const struct wl_keyboard_listener keyboard_listener = { keyboard_handle_keymap, keyboard_handle_enter, keyboard_handle_leave, keyboard_handle_key, keyboard_handle_modifiers, + keyboard_handle_repeat_info + }; static void @@ -2990,9 +3029,18 @@ touch_handle_down(void *data, struct wl_touch *wl_touch, return; } - widget = window_find_widget(input->touch_focus, - wl_fixed_to_double(x_w), - wl_fixed_to_double(y_w)); + if (surface != input->touch_focus->main_surface->surface) { + DBG("Ignoring input event from subsurface %p\n", surface); + input->touch_focus = NULL; + return; + } + + if (input->grab) + widget = input->grab; + else + widget = window_find_widget(input->touch_focus, + wl_fixed_to_double(x_w), + wl_fixed_to_double(y_w)); if (widget) { struct touch_point *tp = xmalloc(sizeof *tp); if (tp) { @@ -3086,9 +3134,6 @@ touch_handle_frame(void *data, struct wl_touch *wl_touch) if (tp->widget->touch_frame_handler) (*tp->widget->touch_frame_handler)(tp->widget, input, tp->widget->user_data); - - wl_list_remove(&tp->link); - free(tp); } } @@ -3528,7 +3573,8 @@ void input_set_selection(struct input *input, struct wl_data_source *source, uint32_t time) { - wl_data_device_set_selection(input->data_device, source, time); + if (input->data_device) + wl_data_device_set_selection(input->data_device, source, time); } void @@ -3764,6 +3810,9 @@ window_do_resize(struct window *window) surface_set_synchronized(surface); surface_resize(surface); } + + if (!window->fullscreen && !window->maximized) + window->saved_allocation = window->pending_allocation; } static void @@ -3843,55 +3892,82 @@ widget_schedule_resize(struct widget *widget, int32_t width, int32_t height) window_schedule_resize(widget->window, width, height); } -static void -handle_surface_configure(void *data, struct xdg_surface *xdg_surface, - int32_t width, int32_t height) +static int +window_get_shadow_margin(struct window *window) { - struct window *window = data; - - window_schedule_resize(window, width, height); + if (window->frame && !window->fullscreen) + return frame_get_shadow_margin(window->frame->frame); + else + return 0; } static void -handle_surface_focused_set(void *data, struct xdg_surface *xdg_surface) +handle_surface_configure(void *data, struct xdg_surface *xdg_surface, + int32_t width, int32_t height, + struct wl_array *states, uint32_t serial) { struct window *window = data; - window->focused = 1; -} + uint32_t *p; -static void -handle_surface_focused_unset(void *data, struct xdg_surface *xdg_surface) -{ - struct window *window = data; + window->maximized = 0; + window->fullscreen = 0; + window->resizing = 0; window->focused = 0; -} -static void -handle_surface_request_set_maximized(void *data, struct xdg_surface *xdg_surface) -{ - struct window *window = data; - window_set_maximized(window, 1); -} + wl_array_for_each(p, states) { + uint32_t state = *p; + switch (state) { + case XDG_SURFACE_STATE_MAXIMIZED: + window->maximized = 1; + break; + case XDG_SURFACE_STATE_FULLSCREEN: + window->fullscreen = 1; + break; + case XDG_SURFACE_STATE_RESIZING: + window->resizing = 1; + break; + case XDG_SURFACE_STATE_ACTIVATED: + window->focused = 1; + break; + default: + /* Unknown state */ + break; + } + } -static void -handle_surface_request_unset_maximized(void *data, struct xdg_surface *xdg_surface) -{ - struct window *window = data; - window_set_maximized(window, 0); -} + if (window->frame) { + if (window->maximized) { + frame_set_flag(window->frame->frame, FRAME_FLAG_MAXIMIZED); + } else { + frame_unset_flag(window->frame->frame, FRAME_FLAG_MAXIMIZED); + } -static void -handle_surface_request_set_fullscreen(void *data, struct xdg_surface *xdg_surface) -{ - struct window *window = data; - window_set_fullscreen(window, 1); -} + if (window->focused) { + frame_set_flag(window->frame->frame, FRAME_FLAG_ACTIVE); + } else { + frame_unset_flag(window->frame->frame, FRAME_FLAG_ACTIVE); + } + } -static void -handle_surface_request_unset_fullscreen(void *data, struct xdg_surface *xdg_surface) -{ - struct window *window = data; - window_set_fullscreen(window, 0); + if (width > 0 && height > 0) { + /* The width / height params are for window geometry, + * but window_schedule_resize takes allocation. Add + * on the shadow margin to get the difference. */ + int margin = window_get_shadow_margin(window); + + window_schedule_resize(window, + width + margin * 2, + height + margin * 2); + } else { + window_schedule_resize(window, + window->saved_allocation.width, + window->saved_allocation.height); + } + + xdg_surface_ack_configure(window->xdg_surface, serial); + + if (window->state_changed_handler) + window->state_changed_handler(window, window->user_data); } static void @@ -3903,50 +3979,63 @@ handle_surface_delete(void *data, struct xdg_surface *xdg_surface) static const struct xdg_surface_listener xdg_surface_listener = { handle_surface_configure, - handle_surface_request_set_maximized, - handle_surface_request_unset_maximized, - handle_surface_request_set_fullscreen, - handle_surface_request_unset_fullscreen, - handle_surface_focused_set, - handle_surface_focused_unset, handle_surface_delete, }; static void -window_sync_transient_for(struct window *window) +window_sync_parent(struct window *window) { struct wl_surface *parent_surface; if (!window->xdg_surface) return; - if (window->transient_for) - parent_surface = window->transient_for->main_surface->surface; + if (window->parent) + parent_surface = window->parent->main_surface->surface; else parent_surface = NULL; - xdg_surface_set_transient_for(window->xdg_surface, parent_surface); + if (parent_surface == window->last_parent_surface) + return; + + xdg_surface_set_parent(window->xdg_surface, parent_surface); + window->last_parent_surface = parent_surface; } static void -window_sync_margin(struct window *window) +window_get_geometry(struct window *window, struct rectangle *geometry) +{ + if (window->frame && !window->fullscreen) + frame_input_rect(window->frame->frame, + &geometry->x, + &geometry->y, + &geometry->width, + &geometry->height); + else + window_get_allocation(window, geometry); +} + +static void +window_sync_geometry(struct window *window) { - int margin; + struct rectangle geometry; if (!window->xdg_surface) return; - if (!window->frame) + window_get_geometry(window, &geometry); + if (geometry.x == window->last_geometry.x && + geometry.y == window->last_geometry.y && + geometry.width == window->last_geometry.width && + geometry.height == window->last_geometry.height) return; - margin = frame_get_shadow_margin(window->frame->frame); - - /* Shadow size is the same on every side. */ - xdg_surface_set_margin(window->xdg_surface, - margin, - margin, - margin, - margin); + xdg_surface_set_window_geometry(window->xdg_surface, + geometry.x, + geometry.y, + geometry.width, + geometry.height); + window->last_geometry = geometry; } static void @@ -3955,17 +4044,9 @@ window_flush(struct window *window) struct surface *surface; if (!window->custom) { - if (!window->xdg_popup && !window->xdg_surface) { - window->xdg_surface = xdg_shell_get_xdg_surface(window->display->xdg_shell, - window->main_surface->surface); - fail_on_null(window->xdg_surface); - - xdg_surface_set_user_data(window->xdg_surface, window); - xdg_surface_add_listener(window->xdg_surface, - &xdg_surface_listener, window); - - window_sync_transient_for(window); - window_sync_margin(window); + if (window->xdg_surface) { + window_sync_parent(window); + window_sync_geometry(window); } } @@ -4139,39 +4220,6 @@ window_schedule_redraw(struct window *window) window_schedule_redraw_task(window); } -static void -configure_sync_callback(void *data, - struct wl_callback *callback, uint32_t time) -{ - struct window *window = data; - - DBG("scheduling redraw from maximize sync callback\n"); - - wl_callback_destroy(callback); - - window->redraw_task_scheduled = 0; - window_schedule_redraw_task(window); -} - -static struct wl_callback_listener configure_sync_callback_listener = { - configure_sync_callback, -}; - -static void -window_delay_redraw(struct window *window) -{ - struct wl_callback *callback; - - DBG("delay scheduled redraw for maximize configure\n"); - if (window->redraw_task_scheduled) - wl_list_remove(&window->redraw_task.link); - - window->redraw_task_scheduled = 1; - callback = wl_display_sync(window->display->display); - wl_callback_add_listener(callback, - &configure_sync_callback_listener, window); -} - int window_is_fullscreen(struct window *window) { @@ -4187,13 +4235,10 @@ window_set_fullscreen(struct window *window, int fullscreen) if (window->fullscreen == fullscreen) return; - window->fullscreen = fullscreen; - if (window->fullscreen) - xdg_surface_set_fullscreen(window->xdg_surface); + if (fullscreen) + xdg_surface_set_fullscreen(window->xdg_surface, NULL); else xdg_surface_unset_fullscreen(window->xdg_surface); - - window_delay_redraw(window); } int @@ -4211,13 +4256,25 @@ window_set_maximized(struct window *window, int maximized) if (window->maximized == maximized) return; - window->maximized = maximized; - if (window->maximized) + if (maximized) xdg_surface_set_maximized(window->xdg_surface); else xdg_surface_unset_maximized(window->xdg_surface); +} + +int +window_is_resizing(struct window *window) +{ + return window->resizing; +} + +void +window_set_minimized(struct window *window) +{ + if (!window->xdg_surface) + return; - window_delay_redraw(window); + xdg_surface_set_minimized(window->xdg_surface); } void @@ -4280,6 +4337,13 @@ window_set_output_handler(struct window *window, } void +window_set_state_changed_handler(struct window *window, + window_state_changed_handler_t handler) +{ + window->state_changed_handler = handler; +} + +void window_set_title(struct window *window, const char *title) { free(window->title); @@ -4401,6 +4465,17 @@ surface_create(struct window *window) return surface; } +static enum window_buffer_type +get_preferred_buffer_type(struct display *display) +{ +#ifdef HAVE_CAIRO_EGL + if (display->argb_device && !getenv("TOYTOOLKIT_NO_EGL")) + return WINDOW_BUFFER_TYPE_EGL_WINDOW; +#endif + + return WINDOW_BUFFER_TYPE_SHM; +} + static struct window * window_create_internal(struct display *display, int custom) { @@ -4414,19 +4489,12 @@ window_create_internal(struct display *display, int custom) surface = surface_create(window); window->main_surface = surface; - fail_on_null(display->xdg_shell); + assert(custom || display->xdg_shell); window->custom = custom; window->preferred_format = WINDOW_PREFERRED_FORMAT_NONE; - if (display->argb_device) -#ifdef HAVE_CAIRO_EGL - surface->buffer_type = WINDOW_BUFFER_TYPE_EGL_WINDOW; -#else - surface->buffer_type = WINDOW_BUFFER_TYPE_SHM; -#endif - else - surface->buffer_type = WINDOW_BUFFER_TYPE_SHM; + surface->buffer_type = get_preferred_buffer_type(display); wl_surface_set_user_data(surface->surface, window); wl_list_insert(display->window_list.prev, &window->link); @@ -4440,7 +4508,20 @@ window_create_internal(struct display *display, int custom) struct window * window_create(struct display *display) { - return window_create_internal(display, 0); + struct window *window; + + window = window_create_internal(display, 0); + + window->xdg_surface = + xdg_shell_get_xdg_surface(window->display->xdg_shell, + window->main_surface->surface); + fail_on_null(window->xdg_surface); + + xdg_surface_set_user_data(window->xdg_surface, window); + xdg_surface_add_listener(window->xdg_surface, + &xdg_surface_listener, window); + + return window; } struct window * @@ -4450,17 +4531,17 @@ window_create_custom(struct display *display) } void -window_set_transient_for(struct window *window, - struct window *parent_window) +window_set_parent(struct window *window, + struct window *parent_window) { - window->transient_for = parent_window; - window_sync_transient_for(window); + window->parent = parent_window; + window_sync_parent(window); } struct window * -window_get_transient_for(struct window *window) +window_get_parent(struct window *window) { - return window->transient_for; + return window->parent; } static void @@ -4524,8 +4605,7 @@ menu_button_handler(struct widget *widget, (menu->release_count > 0 || time - menu->time > 500)) { /* Either relase after press-drag-release or * click-motion-click. */ - menu->func(menu->parent, input, - menu->current, menu->parent->user_data); + menu->func(menu->user_data, input, menu->current); input_ungrab(input); menu_destroy(menu); } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) { @@ -4534,6 +4614,20 @@ menu_button_handler(struct widget *widget, } static void +menu_touch_up_handler(struct widget *widget, + struct input *input, + uint32_t serial, + uint32_t time, + int32_t id, + void *data) +{ + struct menu *menu = data; + + input_ungrab(input); + menu_destroy(menu); +} + +static void menu_redraw_handler(struct widget *widget, void *data) { cairo_t *cr; @@ -4587,31 +4681,28 @@ static const struct xdg_popup_listener xdg_popup_listener = { handle_popup_popup_done, }; -void -window_show_menu(struct display *display, - struct input *input, uint32_t time, struct window *parent, - int32_t x, int32_t y, - menu_func_t func, const char **entries, int count) +static struct menu * +create_menu(struct display *display, + struct input *input, uint32_t time, + menu_func_t func, const char **entries, int count, + void *user_data) { struct window *window; struct menu *menu; - int32_t ix, iy; menu = malloc(sizeof *menu); if (!menu) - return; + return NULL; - window = window_create_internal(parent->display, 0); + window = window_create_internal(display, 0); if (!window) { free(menu); - return; + return NULL; } menu->window = window; - menu->parent = parent; + menu->user_data = user_data; menu->widget = window_add_widget(menu->window, menu); - window_set_buffer_scale (menu->window, window_get_buffer_scale (parent)); - window_set_buffer_transform (menu->window, window_get_buffer_transform (parent)); menu->frame = frame_create(window->display->theme, 0, 0, FRAME_BUTTON_NONE, NULL); fail_on_null(menu->frame); @@ -4622,8 +4713,6 @@ window_show_menu(struct display *display, menu->time = time; menu->func = func; menu->input = input; - window->x = x; - window->y = y; input_ungrab(input); @@ -4632,6 +4721,7 @@ window_show_menu(struct display *display, widget_set_leave_handler(menu->widget, menu_leave_handler); widget_set_motion_handler(menu->widget, menu_motion_handler); widget_set_button_handler(menu->widget, menu_button_handler); + widget_set_touch_up_handler(menu->widget, menu_touch_up_handler); input_grab(input, menu->widget, 0); frame_resize_inside(menu->frame, 200, count * 20); @@ -4639,6 +4729,47 @@ window_show_menu(struct display *display, window_schedule_resize(window, frame_width(menu->frame), frame_height(menu->frame)); + return menu; +} + +struct window * +window_create_menu(struct display *display, + struct input *input, uint32_t time, + menu_func_t func, const char **entries, int count, + void *user_data) +{ + struct menu *menu; + menu = create_menu(display, input, time, func, entries, count, user_data); + + if (menu == NULL) + return NULL; + + return menu->window; +} + +void +window_show_menu(struct display *display, + struct input *input, uint32_t time, struct window *parent, + int32_t x, int32_t y, + menu_func_t func, const char **entries, int count) +{ + struct menu *menu; + struct window *window; + int32_t ix, iy; + + menu = create_menu(display, input, time, func, entries, count, parent); + + if (menu == NULL) + return; + + window = menu->window; + + window_set_buffer_scale (menu->window, window_get_buffer_scale (parent)); + window_set_buffer_transform (menu->window, window_get_buffer_transform (parent)); + + window->x = x; + window->y = y; + frame_interior(menu->frame, &ix, &iy, NULL, NULL); window->xdg_popup = xdg_shell_get_xdg_popup(display->xdg_shell, @@ -4662,6 +4793,12 @@ window_set_buffer_type(struct window *window, enum window_buffer_type type) window->main_surface->buffer_type = type; } +enum window_buffer_type +window_get_buffer_type(struct window *window) +{ + return window->main_surface->buffer_type; +} + void window_set_preferred_format(struct window *window, enum preferred_format format) @@ -4679,6 +4816,7 @@ window_add_subsurface(struct window *window, void *data, struct wl_subcompositor *subcompo = window->display->subcompositor; surface = surface_create(window); + surface->buffer_type = window_get_buffer_type(window); widget = widget_create(window, surface, data); wl_list_init(&widget->link); surface->widget = widget; @@ -4722,6 +4860,14 @@ display_handle_geometry(void *data, output->allocation.x = x; output->allocation.y = y; output->transform = transform; + + if (output->make) + free(output->make); + output->make = strdup(make); + + if (output->model) + free(output->model); + output->model = strdup(model); } static void @@ -4909,11 +5055,23 @@ output_get_scale(struct output *output) return output->scale; } +const char * +output_get_make(struct output *output) +{ + return output->make; +} + +const char * +output_get_model(struct output *output) +{ + return output->model; +} + static void fini_xkb(struct input *input) { xkb_state_unref(input->xkb.state); - xkb_map_unref(input->xkb.keymap); + xkb_keymap_unref(input->xkb.keymap); } #define MIN(a,b) ((a) < (b) ? a : b) @@ -4926,7 +5084,7 @@ display_add_input(struct display *d, uint32_t id) input = xzalloc(sizeof *input); input->display = d; input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, - MIN(d->seat_version, 3)); + MIN(d->seat_version, 4)); input->touch_focus = NULL; input->pointer_focus = NULL; input->keyboard_focus = NULL; @@ -4936,14 +5094,19 @@ display_add_input(struct display *d, uint32_t id) wl_seat_add_listener(input->seat, &seat_listener, input); wl_seat_set_user_data(input->seat, input); - input->data_device = - wl_data_device_manager_get_data_device(d->data_device_manager, - input->seat); - wl_data_device_add_listener(input->data_device, &data_device_listener, - input); + if (d->data_device_manager) { + input->data_device = + wl_data_device_manager_get_data_device(d->data_device_manager, + input->seat); + wl_data_device_add_listener(input->data_device, + &data_device_listener, + input); + } input->pointer_surface = wl_compositor_create_surface(d->compositor); + set_repeat_info(input, 40, 400); + input->repeat_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); input->repeat_task.run = keyboard_repeat_func; @@ -4963,7 +5126,8 @@ input_destroy(struct input *input) if (input->selection_offer) data_offer_destroy(input->selection_offer); - wl_data_device_destroy(input->data_device); + if (input->data_device) + wl_data_device_destroy(input->data_device); if (input->display->seat_version >= 3) { if (input->pointer) @@ -5017,7 +5181,7 @@ static const struct xdg_shell_listener xdg_shell_listener = { xdg_shell_ping, }; -#define XDG_VERSION 2 /* The version of xdg-shell that we implement */ +#define XDG_VERSION 4 /* The version of xdg-shell that we implement */ #ifdef static_assert static_assert(XDG_VERSION == XDG_SHELL_VERSION_CURRENT, "Interface version doesn't match implementation version"); @@ -5446,7 +5610,10 @@ display_get_egl_display(struct display *d) struct wl_data_source * display_create_data_source(struct display *display) { - return wl_data_device_manager_create_data_source(display->data_device_manager); + if (display->data_device_manager) + return wl_data_device_manager_create_data_source(display->data_device_manager); + else + return NULL; } EGLConfig