X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fwlt_toolkit.c;h=18a023350579aad66dce9a213425345d9297e6f1;hb=fb08eea3737907bbbc11c0a14427efe116fae92e;hp=60b7c7cdf2309807d4845c2ab5776607812d1594;hpb=0f04e6a86c73d59dbab1971cfbee3bb263baf0e3;p=platform%2Fupstream%2Fkmscon.git diff --git a/src/wlt_toolkit.c b/src/wlt_toolkit.c index 60b7c7c..18a0233 100644 --- a/src/wlt_toolkit.c +++ b/src/wlt_toolkit.c @@ -37,10 +37,13 @@ #include #include #include "eloop.h" -#include "log.h" +#include "shl_array.h" #include "shl_dlist.h" #include "shl_hook.h" +#include "shl_log.h" +#include "shl_misc.h" #include "tsm_vte.h" +#include "wlt_main.h" #include "wlt_toolkit.h" #define LOG_SUBSYSTEM "wlt_toolkit" @@ -57,6 +60,13 @@ enum { STATE_HUP, }; +struct data_offer { + unsigned long ref; + struct wl_data_offer *w_offer; + struct wlt_display *disp; + struct shl_array *types; +}; + struct wlt_display { unsigned long ref; struct ev_eloop *eloop; @@ -65,6 +75,7 @@ struct wlt_display { struct wl_global_listener *dp_listener; struct shl_hook *listeners; unsigned int state; + struct wl_registry *w_registry; struct shl_dlist window_list; @@ -91,6 +102,12 @@ struct wlt_display { struct wlt_window *keyboard_focus; struct ev_timer *repeat_timer; uint32_t repeat_sym; + uint32_t repeat_ascii; + + struct wl_data_device_manager *w_manager; + struct wl_data_device *w_data_dev; + struct data_offer *drag_offer; + struct data_offer *selection_offer; }; struct wlt_window { @@ -109,7 +126,6 @@ struct wlt_window { bool buffer_attached; bool skip_damage; bool need_resize; - bool need_redraw; bool need_frame; bool idle_pending; unsigned int new_width; @@ -118,6 +134,7 @@ struct wlt_window { unsigned int saved_height; unsigned int resize_edges; bool maximized; + bool fullscreen; struct wlt_shm_buffer buffer; struct wl_callback *w_frame; @@ -380,35 +397,45 @@ static void set_cursor(struct wlt_display *disp, unsigned int cursor) wl_surface_attach(disp->w_cursor_surface, buffer, 0, 0); wl_surface_damage(disp->w_cursor_surface, 0, 0, image->width, image->height); + wl_surface_commit(disp->w_cursor_surface); } -static int dp_mask_update(uint32_t mask, void *data) +static void dp_dispatch(struct wlt_display *disp, bool nonblock) { - struct wlt_display *disp = data; int ret; - int mode; - if (!disp->dp_fd) - return 0; + errno = 0; + if (nonblock) + ret = wl_display_dispatch_pending(disp->dp); + else + ret = wl_display_dispatch(disp->dp); - mode = 0; - if (mask & WL_DISPLAY_READABLE) - mode |= EV_READABLE; - if (mask & WL_DISPLAY_WRITABLE) - mode |= EV_WRITEABLE; + if (ret == -1) { + log_error("error during wayland dispatch (%d): %m", errno); + return; + } else if (errno == EAGAIN) { + ret = ev_fd_update(disp->dp_fd, EV_READABLE | EV_WRITEABLE); + if (ret) + log_warning("cannot update wayland-fd event-polling modes (%d)", + ret); + } else { + ret = ev_fd_update(disp->dp_fd, EV_READABLE); + if (ret) + log_warning("cannot update wayland-fd event-polling modes (%d)", + ret); + } +} - ret = ev_fd_update(disp->dp_fd, mode); - if (ret) - log_warning("cannot update wayland-fd event-polling modes (%d)", - ret); +static void dp_pre_event(struct ev_eloop *eloop, void *unused, void *data) +{ + struct wlt_display *disp = data; - return 0; + dp_dispatch(disp, true); } static void dp_event(struct ev_fd *fd, int mask, void *data) { struct wlt_display *disp = data; - int mode; if (mask & (EV_HUP | EV_ERR)) { log_warning("HUP/ERR on wayland socket"); @@ -419,14 +446,10 @@ static void dp_event(struct ev_fd *fd, int mask, void *data) return; } - mode = 0; if (mask & EV_READABLE) - mode |= WL_DISPLAY_READABLE; - if (mask & EV_WRITEABLE) - mode |= WL_DISPLAY_WRITABLE; - - if (mode) - wl_display_iterate(disp->dp, mode); + dp_dispatch(disp, false); + else + dp_dispatch(disp, true); } static void pointer_enter(void *data, struct wl_pointer *w_pointer, @@ -560,9 +583,9 @@ static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, return; } - disp->xkb_keymap = xkb_map_new_from_string(disp->xkb_ctx, map, - XKB_KEYMAP_FORMAT_TEXT_V1, - 0); + disp->xkb_keymap = xkb_keymap_new_from_string(disp->xkb_ctx, map, + XKB_KEYMAP_FORMAT_TEXT_V1, + 0); munmap(map, size); close(fd); @@ -574,7 +597,7 @@ static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, disp->xkb_state = xkb_state_new(disp->xkb_keymap); if (!disp->xkb_state) { log_error("cannot create XKB state object"); - xkb_map_unref(disp->xkb_keymap); + xkb_keymap_unref(disp->xkb_keymap); disp->xkb_keymap = NULL; return; } @@ -617,36 +640,13 @@ static void keyboard_leave(void *data, struct wl_keyboard *keyboard, ev_timer_update(disp->repeat_timer, NULL); } -static unsigned int get_effective_modmask(struct xkb_state *state) -{ - unsigned int mods = 0; - - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_SHIFT, - XKB_STATE_EFFECTIVE)) - mods |= TSM_SHIFT_MASK; - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS, - XKB_STATE_EFFECTIVE)) - mods |= TSM_LOCK_MASK; - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL, - XKB_STATE_EFFECTIVE)) - mods |= TSM_CONTROL_MASK; - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT, - XKB_STATE_EFFECTIVE)) - mods |= TSM_MOD1_MASK; - if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_LOGO, - XKB_STATE_EFFECTIVE)) - mods |= TSM_MOD4_MASK; - - return mods; -} - static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state_w) { struct wlt_display *disp = data; struct wlt_window *wnd = disp->keyboard_focus; - uint32_t code, num_syms; + uint32_t code, num_syms, ascii; unsigned int mask; enum wl_keyboard_key_state state = state_w; const xkb_keysym_t *syms; @@ -654,6 +654,7 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard, struct shl_dlist *iter; struct wlt_widget *widget; struct itimerspec spec; + bool handled; disp->last_serial = serial; if (!disp->xkb_state) @@ -663,28 +664,32 @@ static void keyboard_key(void *data, struct wl_keyboard *keyboard, if (!wnd) return; - mask = get_effective_modmask(disp->xkb_state); - num_syms = xkb_key_get_syms(disp->xkb_state, code, &syms); + mask = shl_get_xkb_mods(disp->xkb_state); + num_syms = xkb_state_key_get_syms(disp->xkb_state, code, &syms); + ascii = shl_get_ascii(disp->xkb_state, code, syms, num_syms); sym = XKB_KEY_NoSymbol; if (num_syms == 1) sym = syms[0]; + handled = false; shl_dlist_for_each(iter, &wnd->widget_list) { widget = shl_dlist_entry(iter, struct wlt_widget, list); - if (widget->keyboard_cb) - widget->keyboard_cb(widget, mask, sym, state, - widget->data); + if (widget->keyboard_cb) { + if (widget->keyboard_cb(widget, mask, sym, ascii, state, + handled, widget->data)) + handled = true; + } } - if (state == WL_KEYBOARD_KEY_STATE_RELEASED && - sym == disp->repeat_sym) { + if (state == WL_KEYBOARD_KEY_STATE_RELEASED) { ev_timer_update(disp->repeat_timer, NULL); } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { disp->repeat_sym = sym; + disp->repeat_ascii = ascii; spec.it_interval.tv_sec = 0; - spec.it_interval.tv_nsec = 25 * 1000000; + spec.it_interval.tv_nsec = wlt_conf.xkb_repeat_rate * 1000000; spec.it_value.tv_sec = 0; - spec.it_value.tv_nsec = 250 * 1000000; + spec.it_value.tv_nsec = wlt_conf.xkb_repeat_delay * 1000000; ev_timer_update(disp->repeat_timer, &spec); } } @@ -696,17 +701,22 @@ static void repeat_event(struct ev_timer *timer, uint64_t num, void *data) struct wlt_widget *widget; struct shl_dlist *iter; unsigned int mask; + bool handled; if (!wnd) return; - mask = get_effective_modmask(disp->xkb_state); + mask = shl_get_xkb_mods(disp->xkb_state); + handled = false; shl_dlist_for_each(iter, &wnd->widget_list) { widget = shl_dlist_entry(iter, struct wlt_widget, list); - if (widget->keyboard_cb) - widget->keyboard_cb(widget, mask, disp->repeat_sym, - WL_KEYBOARD_KEY_STATE_PRESSED, - widget->data); + if (widget->keyboard_cb) { + if (widget->keyboard_cb(widget, mask, disp->repeat_sym, + disp->repeat_ascii, + WL_KEYBOARD_KEY_STATE_PRESSED, + handled, widget->data)) + handled = true; + } } } @@ -733,6 +743,202 @@ static const struct wl_keyboard_listener keyboard_listener = { .modifiers = keyboard_modifiers, }; +static void data_offer_unref(struct data_offer *offer) +{ + unsigned int i, len; + + if (!offer || !offer->ref || --offer->ref) + return; + + len = shl_array_get_length(offer->types); + for (i = 0; i < len; ++i) + free(*SHL_ARRAY_AT(offer->types, char*, i)); + shl_array_free(offer->types); + wl_data_offer_destroy(offer->w_offer); + free(offer); +} + +static void data_offer_offer(void *data, struct wl_data_offer *w_offer, + const char *type) +{ + char *tmp; + int ret; + struct data_offer *offer = wl_data_offer_get_user_data(w_offer); + + tmp = strdup(type); + if (!tmp) + return; + + ret = shl_array_push(offer->types, &tmp); + if (ret) { + free(tmp); + return; + } +} + +static const struct wl_data_offer_listener data_offer_listener = { + .offer = data_offer_offer, +}; + +static void data_dev_data_offer(void *data, struct wl_data_device *w_dev, + struct wl_data_offer *w_offer) +{ + struct data_offer *offer; + struct wlt_display *disp = data; + int ret; + + offer = malloc(sizeof(*offer)); + if (!offer) { + wl_data_offer_destroy(w_offer); + return; + } + memset(offer, 0, sizeof(*offer)); + offer->ref = 1; + offer->w_offer = w_offer; + offer->disp = disp; + + ret = shl_array_new(&offer->types, sizeof(char*), 4); + if (ret) { + wl_data_offer_destroy(w_offer); + free(offer); + return; + } + + wl_data_offer_add_listener(w_offer, &data_offer_listener, offer); + wl_data_offer_set_user_data(w_offer, offer); +} + +static void data_dev_enter(void *data, struct wl_data_device *w_dev, + uint32_t serial, struct wl_surface *w_surface, + wl_fixed_t x, wl_fixed_t y, + struct wl_data_offer *w_offer) +{ + struct wlt_display *disp = data; + + if (disp->drag_offer) { + data_offer_unref(disp->drag_offer); + disp->drag_offer = NULL; + } + + if (!w_offer) + return; + + disp->drag_offer = wl_data_offer_get_user_data(w_offer); +} + +static void data_dev_leave(void *data, struct wl_data_device *w_dev) +{ + struct wlt_display *disp = data; + + if (disp->drag_offer) { + data_offer_unref(disp->drag_offer); + disp->drag_offer = NULL; + } +} + +static void data_dev_motion(void *data, struct wl_data_device *w_dev, + uint32_t time, wl_fixed_t x, wl_fixed_t y) +{ +} + +static void data_dev_drop(void *data, struct wl_data_device *w_dev) +{ +} + +static void data_dev_selection(void *data, struct wl_data_device *w_dev, + struct wl_data_offer *w_offer) +{ + struct wlt_display *disp = data; + + if (disp->selection_offer) { + data_offer_unref(disp->selection_offer); + disp->selection_offer = NULL; + } + + if (!w_offer) + return; + + disp->selection_offer = wl_data_offer_get_user_data(w_offer); +} + +int wlt_display_get_selection_to_fd(struct wlt_display *disp, const char *mime, + int output_fd) +{ + unsigned int i, num; + struct data_offer *offer; + + if (!disp || !mime) + return -EINVAL; + if (!disp->selection_offer) + return -ENOENT; + + offer = disp->selection_offer; + num = shl_array_get_length(offer->types); + for (i = 0; i < num; ++i) { + if (!strcmp(mime, *SHL_ARRAY_AT(offer->types, char*, i))) + break; + } + + if (i == num) + return -EAGAIN; + + wl_data_offer_receive(offer->w_offer, mime, output_fd); + return 0; +} + +int wlt_display_get_selection_fd(struct wlt_display *disp, const char *mime) +{ + int p[2], ret; + + if (pipe2(p, O_CLOEXEC | O_NONBLOCK)) + return -EFAULT; + + ret = wlt_display_get_selection_to_fd(disp, mime, p[1]); + close(p[1]); + + if (ret) { + close(p[0]); + return ret; + } + + return p[0]; +} + +int wlt_display_new_data_source(struct wlt_display *disp, + struct wl_data_source **out) +{ + struct wl_data_source *src; + + if (!disp) + return -EINVAL; + + src = wl_data_device_manager_create_data_source(disp->w_manager); + if (!src) + return -EFAULT; + + *out = src; + return 0; +} + +void wlt_display_set_selection(struct wlt_display *disp, + struct wl_data_source *selection) +{ + if (!disp) + return; + + wl_data_device_set_selection(disp->w_data_dev, selection, + disp->last_serial); +} + +static const struct wl_data_device_listener data_dev_listener = { + .data_offer = data_dev_data_offer, + .enter = data_dev_enter, + .leave = data_dev_leave, + .motion = data_dev_motion, + .drop = data_dev_drop, + .selection = data_dev_selection, +}; + static void check_ready(struct wlt_display *disp) { if (disp->state > STATE_INIT) @@ -743,10 +949,17 @@ static void check_ready(struct wlt_display *disp) disp->w_shell && disp->w_shm && disp->w_pointer && - disp->w_keyboard) { + disp->w_keyboard && + disp->w_manager) { log_debug("wayland display initialized"); load_cursors(disp); + disp->w_data_dev = wl_data_device_manager_get_data_device( + disp->w_manager, disp->w_seat); + wl_data_device_add_listener(disp->w_data_dev, + &data_dev_listener, + disp); + disp->state = STATE_RUNNING; shl_hook_call(disp->listeners, disp, (void*)WLT_DISPLAY_READY); } @@ -776,8 +989,8 @@ static const struct wl_seat_listener seat_listener = { .capabilities = seat_capabilities, }; -static void dp_global(struct wl_display *dp, uint32_t id, const char *iface, - uint32_t version, void *data) +static void dp_global(void *data, struct wl_registry *registry, uint32_t id, + const char *iface, uint32_t version) { struct wlt_display *disp = data; @@ -789,9 +1002,10 @@ static void dp_global(struct wl_display *dp, uint32_t id, const char *iface, log_error("global wl_compositor advertised twice"); return; } - disp->w_comp = wl_display_bind(disp->dp, - id, - &wl_compositor_interface); + disp->w_comp = wl_registry_bind(disp->w_registry, + id, + &wl_compositor_interface, + 1); if (!disp->w_comp) { log_error("cannot bind wl_compositor object"); return; @@ -801,9 +1015,10 @@ static void dp_global(struct wl_display *dp, uint32_t id, const char *iface, log_error("global wl_seat advertised twice"); return; } - disp->w_seat = wl_display_bind(disp->dp, - id, - &wl_seat_interface); + disp->w_seat = wl_registry_bind(disp->w_registry, + id, + &wl_seat_interface, + 1); if (!disp->w_seat) { log_error("cannot bind wl_seat object"); return; @@ -815,9 +1030,10 @@ static void dp_global(struct wl_display *dp, uint32_t id, const char *iface, log_error("global wl_shell advertised twice"); return; } - disp->w_shell = wl_display_bind(disp->dp, - id, - &wl_shell_interface); + disp->w_shell = wl_registry_bind(disp->w_registry, + id, + &wl_shell_interface, + 1); if (!disp->w_shell) { log_error("cannot bind wl_shell object"); return; @@ -827,13 +1043,27 @@ static void dp_global(struct wl_display *dp, uint32_t id, const char *iface, log_error("global wl_shm advertised twice"); return; } - disp->w_shm = wl_display_bind(disp->dp, - id, - &wl_shm_interface); + disp->w_shm = wl_registry_bind(disp->w_registry, + id, + &wl_shm_interface, + 1); if (!disp->w_shm) { log_error("cannot bind wl_shm object"); return; } + } else if (!strcmp(iface, "wl_data_device_manager")) { + if (disp->w_manager) { + log_error("global wl_data_device_manager advertised twice"); + return; + } + disp->w_manager = wl_registry_bind(disp->w_registry, + id, + &wl_data_device_manager_interface, + 1); + if (!disp->w_manager) { + log_error("cannot bind wl_data_device_manager_object"); + return; + } } else { log_debug("ignoring new unknown global %s", iface); return; @@ -844,11 +1074,16 @@ static void dp_global(struct wl_display *dp, uint32_t id, const char *iface, check_ready(disp); } +static const struct wl_registry_listener registry_listener = { + .global = dp_global, + /* TODO: handle .global_remove */ +}; + int wlt_display_new(struct wlt_display **out, struct ev_eloop *eloop) { struct wlt_display *disp; - int ret; + int ret, fd; if (!out || !eloop) return -EINVAL; @@ -876,11 +1111,36 @@ int wlt_display_new(struct wlt_display **out, goto err_listener; } + fd = wl_display_get_fd(disp->dp); + if (fd < 0) { + log_error("cannot retrieve wayland FD"); + ret = -EFAULT; + goto err_dp; + } + + /* TODO: nonblocking wl_display doesn't work, yet. fix that upstream */ + /* + int set; + set = fcntl(fd, F_GETFL); + if (set < 0) { + log_error("cannot retrieve file flags for wayland FD (%d): %m", + errno); + ret = -EFAULT; + goto err_dp; + } + + set |= O_NONBLOCK; + ret = fcntl(fd, F_SETFL, set); + if (ret) { + log_error("cannot set file flags for wayland FD (%d): %m", + errno); + ret = -EFAULT; + goto err_dp; + }*/ + ret = ev_eloop_new_fd(eloop, &disp->dp_fd, - wl_display_get_fd(disp->dp, - dp_mask_update, - disp), + fd, EV_READABLE, dp_event, disp); @@ -890,21 +1150,27 @@ int wlt_display_new(struct wlt_display **out, goto err_dp; } + ret = ev_eloop_register_pre_cb(eloop, dp_pre_event, disp); + if (ret) { + log_error("cannot register pre-cb (%d)", ret); + goto err_dp_fd; + } + ret = ev_eloop_new_timer(eloop, &disp->repeat_timer, NULL, repeat_event, disp); if (ret) { log_error("cannot create repeat-timer"); - goto err_dp_fd; + goto err_pre_cb; } - disp->dp_listener = wl_display_add_global_listener(disp->dp, - dp_global, - disp); - if (!disp->dp_listener) { - log_error("cannot add wayland global listener (%d)", errno); + disp->w_registry = wl_display_get_registry(disp->dp); + if (!disp->w_registry) { + log_error("cannot get wayland registry object"); goto err_timer; } + wl_registry_add_listener(disp->w_registry, ®istry_listener, disp); + disp->xkb_ctx = xkb_context_new(0); if (!disp->xkb_ctx) { log_error("cannot create XKB context"); @@ -919,6 +1185,8 @@ int wlt_display_new(struct wlt_display **out, err_timer: ev_eloop_rm_timer(disp->repeat_timer); +err_pre_cb: + ev_eloop_unregister_pre_cb(disp->eloop, dp_pre_event, disp); err_dp_fd: ev_eloop_rm_fd(disp->dp_fd); err_dp: @@ -944,10 +1212,10 @@ void wlt_display_unref(struct wlt_display *disp) return; unload_cursors(disp); - wl_display_remove_global_listener(disp->dp, disp->dp_listener); wl_display_flush(disp->dp); wl_display_disconnect(disp->dp); ev_eloop_rm_timer(disp->repeat_timer); + ev_eloop_unregister_pre_cb(disp->eloop, dp_pre_event, disp); ev_eloop_rm_fd(disp->dp_fd); xkb_context_unref(disp->xkb_ctx); shl_hook_free(disp->listeners); @@ -961,7 +1229,7 @@ int wlt_display_register_cb(struct wlt_display *disp, if (!disp) return -EINVAL; - return shl_hook_add_cast(disp->listeners, cb, data); + return shl_hook_add_cast(disp->listeners, cb, data, false); } void wlt_display_unregister_cb(struct wlt_display *disp, @@ -985,9 +1253,15 @@ static void wlt_window_do_redraw(struct wlt_window *wnd, { struct shl_dlist *iter; struct wlt_widget *widget; - unsigned int x, y; + unsigned int x, y, flags; struct wlt_rect alloc; + flags = 0; + if (wnd->maximized) + flags |= WLT_WINDOW_MAXIMIZED; + if (wnd->fullscreen) + flags |= WLT_WINDOW_FULLSCREEN; + alloc.x = 0; alloc.y = 0; alloc.width = wnd->buffer.width; @@ -995,7 +1269,7 @@ static void wlt_window_do_redraw(struct wlt_window *wnd, shl_dlist_for_each(iter, &wnd->widget_list) { widget = shl_dlist_entry(iter, struct wlt_widget, list); if (widget->resize_cb) - widget->resize_cb(widget, &alloc, widget->data); + widget->resize_cb(widget, flags, &alloc, widget->data); } memset(wnd->buffer.data, 0, @@ -1005,7 +1279,7 @@ static void wlt_window_do_redraw(struct wlt_window *wnd, shl_dlist_for_each(iter, &wnd->widget_list) { widget = shl_dlist_entry(iter, struct wlt_widget, list); if (widget->redraw_cb) - widget->redraw_cb(widget, widget->data); + widget->redraw_cb(widget, flags, widget->data); } wnd->skip_damage = false; @@ -1025,10 +1299,11 @@ static void wlt_window_do_redraw(struct wlt_window *wnd, wl_surface_damage(wnd->w_surface, 0, 0, wnd->buffer.width, wnd->buffer.height); + wl_surface_commit(wnd->w_surface); } static int resize_window(struct wlt_window *wnd, unsigned int width, - unsigned int height, bool force_redraw) + unsigned int height) { struct shl_dlist *iter; struct wlt_widget *widget; @@ -1036,17 +1311,33 @@ static int resize_window(struct wlt_window *wnd, unsigned int width, struct wlt_pool *old_pool = NULL; size_t nsize; int ret; - unsigned int oldw, oldh, neww, newh; + unsigned int oldw, oldh, neww, newh, minw, minh, flags; + + if (!width) + width = wnd->buffer.width; + if (!height) + height = wnd->buffer.height; - if (!wnd || !width || !height) + if (!width || !height) return -EINVAL; + flags = 0; + if (wnd->maximized) + flags |= WLT_WINDOW_MAXIMIZED; + if (wnd->fullscreen) + flags |= WLT_WINDOW_FULLSCREEN; + neww = 0; newh = 0; + minw = 0; + minh = 0; shl_dlist_for_each(iter, &wnd->widget_list) { widget = shl_dlist_entry(iter, struct wlt_widget, list); if (widget->prepare_resize_cb) - widget->prepare_resize_cb(widget, width, height, + widget->prepare_resize_cb(widget, + flags, + width, height, + &minw, &minh, &neww, &newh, widget->data); } @@ -1058,8 +1349,7 @@ static int resize_window(struct wlt_window *wnd, unsigned int width, if (width == wnd->buffer.width && height == wnd->buffer.height) { - if (force_redraw) - wlt_window_do_redraw(wnd, width, height); + wlt_window_do_redraw(wnd, width, height); return 0; } @@ -1127,33 +1417,28 @@ static const struct wl_callback_listener frame_callback_listener = { static void do_frame(struct wlt_window *wnd) { - bool force; - - wnd->idle_pending = false; - ev_eloop_unregister_idle_cb(wnd->disp->eloop, idle_frame, wnd); + ev_eloop_unregister_idle_cb(wnd->disp->eloop, idle_frame, wnd, + EV_NORMAL); if (wnd->need_resize) { - force = wnd->need_redraw; wnd->need_frame = true; wnd->need_resize = false; - wnd->need_redraw = false; - resize_window(wnd, wnd->new_width, wnd->new_height, force); - } - - if (wnd->need_redraw) { + wnd->w_frame = wl_surface_frame(wnd->w_surface); + wl_callback_add_listener(wnd->w_frame, + &frame_callback_listener, wnd); + resize_window(wnd, wnd->new_width, wnd->new_height); + } else { wnd->need_frame = true; - wnd->need_redraw = false; - wlt_window_do_redraw(wnd, wnd->buffer.width, - wnd->buffer.height); - } - - if (wnd->need_frame) { wnd->w_frame = wl_surface_frame(wnd->w_surface); wl_callback_add_listener(wnd->w_frame, &frame_callback_listener, wnd); + wlt_window_do_redraw(wnd, wnd->buffer.width, + wnd->buffer.height); } } +static void schedule_frame(struct wlt_window *wnd); + static void frame_callback(void *data, struct wl_callback *w_callback, uint32_t time) { @@ -1161,9 +1446,10 @@ static void frame_callback(void *data, struct wl_callback *w_callback, wl_callback_destroy(w_callback); wnd->w_frame = NULL; - wnd->need_frame = false; - do_frame(wnd); + wnd->idle_pending = false; + if (wnd->need_frame) + schedule_frame(wnd); } static void idle_frame(struct ev_eloop *eloop, void *unused, void *data) @@ -1202,13 +1488,16 @@ static void schedule_frame(struct wlt_window *wnd) { int ret; - if (!wnd || wnd->w_frame) + if (!wnd) return; - if (wnd->need_frame || wnd->idle_pending) + wnd->need_frame = true; + + if (wnd->idle_pending) return; - ret = ev_eloop_register_idle_cb(wnd->disp->eloop, idle_frame, wnd); + ret = ev_eloop_register_idle_cb(wnd->disp->eloop, idle_frame, wnd, + EV_NORMAL); if (ret) log_error("cannot schedule idle callback: %d", ret); else @@ -1244,7 +1533,7 @@ static void close_window(struct ev_eloop *eloop, void *unused, void *data) { struct wlt_window *wnd = data; - ev_eloop_unregister_idle_cb(eloop, close_window, wnd); + ev_eloop_unregister_idle_cb(eloop, close_window, wnd, EV_NORMAL); wnd->close_pending = false; if (wnd->close_cb) @@ -1297,7 +1586,7 @@ int wlt_display_create_window(struct wlt_display *disp, &shell_surface_listener, wnd); wl_shell_surface_set_toplevel(wnd->w_shell_surface); - ret = resize_window(wnd, width, height, true); + ret = resize_window(wnd, width, height); if (ret) goto err_shell_surface; @@ -1338,9 +1627,10 @@ void wlt_window_unref(struct wlt_window *wnd) if (wnd->close_pending) ev_eloop_unregister_idle_cb(wnd->disp->eloop, close_window, - wnd); + wnd, EV_NORMAL); if (wnd->idle_pending) - ev_eloop_unregister_idle_cb(wnd->disp->eloop, idle_frame, wnd); + ev_eloop_unregister_idle_cb(wnd->disp->eloop, idle_frame, wnd, + EV_NORMAL); shl_dlist_unlink(&wnd->list); if (wnd->w_frame) wl_callback_destroy(wnd->w_frame); @@ -1370,7 +1660,7 @@ int wlt_window_create_widget(struct wlt_window *wnd, widget->wnd = wnd; widget->data = data; - wlt_window_schedule_redraw(wnd); + wlt_window_set_size(wnd, wnd->buffer.width, wnd->buffer.height); shl_dlist_link_tail(&wnd->widget_list, &widget->list); *out = widget; return 0; @@ -1381,7 +1671,6 @@ void wlt_window_schedule_redraw(struct wlt_window *wnd) if (!wnd) return; - wnd->need_redraw = true; schedule_frame(wnd); } @@ -1393,6 +1682,7 @@ void wlt_window_damage(struct wlt_window *wnd, wl_surface_damage(wnd->w_surface, damage->x, damage->y, damage->width, damage->height); + wl_surface_commit(wnd->w_surface); } void wlt_window_get_buffer(struct wlt_window *wnd, @@ -1462,7 +1752,7 @@ void wlt_window_resize(struct wlt_window *wnd, uint32_t edges) int wlt_window_set_size(struct wlt_window *wnd, unsigned int width, unsigned int height) { - if (!wnd || !width || !height) + if (!wnd) return -EINVAL; wnd->new_width = width; @@ -1496,7 +1786,8 @@ void wlt_window_close(struct wlt_window *wnd) return; wnd->close_pending = true; - ev_eloop_register_idle_cb(wnd->disp->eloop, close_window, wnd); + ev_eloop_register_idle_cb(wnd->disp->eloop, close_window, wnd, + EV_NORMAL); } void wlt_window_toggle_maximize(struct wlt_window *wnd) @@ -1505,17 +1796,60 @@ void wlt_window_toggle_maximize(struct wlt_window *wnd) return; if (wnd->maximized) { - wl_shell_surface_set_toplevel(wnd->w_shell_surface); - wlt_window_set_size(wnd, wnd->saved_width, wnd->saved_height); + if (!wnd->fullscreen) { + wl_shell_surface_set_toplevel(wnd->w_shell_surface); + wlt_window_set_size(wnd, wnd->saved_width, + wnd->saved_height); + } } else { - wnd->saved_width = wnd->buffer.width; - wnd->saved_height = wnd->buffer.height; - wl_shell_surface_set_maximized(wnd->w_shell_surface, NULL); + if (!wnd->fullscreen) { + wnd->saved_width = wnd->buffer.width; + wnd->saved_height = wnd->buffer.height; + wl_shell_surface_set_maximized(wnd->w_shell_surface, + NULL); + } } wnd->maximized = !wnd->maximized; } +bool wlt_window_is_maximized(struct wlt_window *wnd) +{ + return wnd && wnd->maximized; +} + +void wlt_window_toggle_fullscreen(struct wlt_window *wnd) +{ + if (!wnd) + return; + + if (wnd->fullscreen) { + if (wnd->maximized) { + wl_shell_surface_set_maximized(wnd->w_shell_surface, + NULL); + } else { + wl_shell_surface_set_toplevel(wnd->w_shell_surface); + wlt_window_set_size(wnd, wnd->saved_width, + wnd->saved_height); + } + } else { + if (!wnd->maximized) { + wnd->saved_width = wnd->buffer.width; + wnd->saved_height = wnd->buffer.height; + } + wl_shell_surface_set_fullscreen(wnd->w_shell_surface, + WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, + 0, NULL); + } + + wnd->fullscreen = !wnd->fullscreen; +} + +bool wlt_window_is_fullscreen(struct wlt_window *wnd) +{ + return wnd && wnd->fullscreen; +} + struct ev_eloop *wlt_window_get_eloop(struct wlt_window *wnd) { if (!wnd) @@ -1524,6 +1858,14 @@ struct ev_eloop *wlt_window_get_eloop(struct wlt_window *wnd) return wnd->disp->eloop; } +struct wlt_display *wlt_window_get_display(struct wlt_window *wnd) +{ + if (!wnd) + return NULL; + + return wnd->disp; +} + void wlt_widget_destroy(struct wlt_widget *widget) { if (!widget)