add hooking for WL_SURFACE_ID atom on XWayland windows and composite them

in order to maximize the amount of reused code the following details the current
process for xwayland compositing:

* get map request from window
* force reparenting
* show window
* await WL_SURFACE_ID x11 message
* move x11 client data + pixmap onto corresponding wayland client
* business as usual with wayland compositing

this is pretty similar to the method of the reference code in weston,
except that there's no x11 compositor in weston
This commit is contained in:
Mike Blumenkrantz 2015-06-25 19:55:37 -04:00
parent c8bdacc727
commit 2b38147c43
4 changed files with 161 additions and 21 deletions

View File

@ -40,7 +40,7 @@ _e_comp_wl_focus_check(void)
if (stopping) return;
ec = e_client_focused_get();
if ((!ec) || (e_pixmap_type_get(ec->pixmap) != E_PIXMAP_TYPE_WL))
if ((!ec) || e_pixmap_is_x(ec->pixmap))
e_grabinput_focus(e_comp->ee_win, E_FOCUS_METHOD_PASSIVE);
}
@ -1442,7 +1442,8 @@ static void
_e_comp_wl_compositor_cb_surface_create(struct wl_client *client, struct wl_resource *resource, uint32_t id)
{
struct wl_resource *res;
E_Client *ec = NULL;
E_Client *wc, *ec = NULL;
Eina_List *l;
pid_t pid;
DBG("Compositor Cb Surface Create: %d", id);
@ -1491,7 +1492,15 @@ _e_comp_wl_compositor_cb_surface_create(struct wl_client *client, struct wl_reso
/* set reference to pixmap so we can fetch it later */
wl_resource_set_user_data(res, ec);
#ifndef HAVE_WAYLAND_ONLY
EINA_LIST_FOREACH(e_comp->wl_comp_data->xwl_pending, l, wc)
{
if (!e_pixmap_is_x(wc->pixmap)) continue;
if (wl_resource_get_id(res) != ((E_Comp_X_Client_Data*)ec->comp_data)->surface_id) continue;
e_comp_x_xwayland_client_setup(wc, ec);
break;
}
#endif
/* emit surface create signal */
wl_signal_emit(&e_comp->wl_comp_data->signals.surface.create, res);
}
@ -2964,3 +2973,9 @@ e_comp_wl_output_remove(const char *id)
/* free(output); */
}
}
EINTERN void
e_comp_wl_xwayland_client_queue(E_Client *ec)
{
e_comp->wl_comp_data->xwl_pending = eina_list_append(e_comp->wl_comp_data->xwl_pending, ec);
}

View File

@ -1,5 +1,7 @@
#ifdef E_TYPEDEFS
# ifndef HAVE_WAYLAND_ONLY
# include "e_comp_x.h"
# endif
#else
# ifndef E_COMP_WL_H
# define E_COMP_WL_H
@ -13,6 +15,10 @@
# include <xkbcommon/xkbcommon.h>
# ifndef HAVE_WAYLAND_ONLY
# include "e_comp_x.h"
# endif
/* # ifdef HAVE_WAYLAND_EGL */
/* # include <EGL/egl.h> */
/* # define GL_GLEXT_PROTOTYPES */
@ -211,6 +217,7 @@ struct _E_Comp_Wl_Data
Ecore_Idler *idler;
struct wl_client *xwl_client;
Eina_List *xwl_pending;
/* Eina_List *retry_clients; */
/* Ecore_Timer *retry_timer; */
@ -254,6 +261,10 @@ struct _E_Comp_Wl_Client_Data
{
int32_t x, y;
} popup;
#ifndef HAVE_WAYLAND_ONLY
E_Pixmap *xwayland_pixmap;
E_Comp_X_Client_Data *xwayland_data;
#endif
Eina_Bool keep_buffer : 1;
Eina_Bool mapped : 1;
@ -294,6 +305,27 @@ E_API struct wl_signal e_comp_wl_surface_create_signal_get(void);
E_API double e_comp_wl_idle_time_get(void);
E_API Eina_Bool e_comp_wl_output_init(const char *id, const char *make, const char *model, int x, int y, int w, int h, int pw, int ph, unsigned int refresh, unsigned int subpixel, unsigned int transform);
E_API void e_comp_wl_output_remove(const char *id);
# ifndef HAVE_WAYLAND_ONLY
EINTERN void e_comp_wl_xwayland_client_queue(E_Client *ec);
static inline E_Comp_X_Client_Data *
e_comp_wl_client_xwayland_data(const E_Client *ec)
{
return ec->comp_data ? ((E_Comp_Wl_Client_Data*)ec->comp_data)->xwayland_data : NULL;
}
static inline E_Pixmap *
e_comp_wl_client_xwayland_pixmap(const E_Client *ec)
{
return ((E_Comp_Wl_Client_Data*)ec->comp_data)->xwayland_pixmap;
}
static inline void
e_comp_wl_client_xwayland_setup(E_Client *ec, E_Comp_X_Client_Data *cd, E_Pixmap *ep)
{
((E_Comp_Wl_Client_Data*)ec->comp_data)->xwayland_data = cd;
((E_Comp_Wl_Client_Data*)ec->comp_data)->xwayland_pixmap = ep;
e_comp->wl_comp_data->xwl_pending = eina_list_remove(e_comp->wl_comp_data->xwl_pending, ec);
}
# endif
# endif
#endif

View File

@ -57,6 +57,8 @@ static Eina_Bool screensaver_dimmed = EINA_FALSE;
static Ecore_X_Atom backlight_atom = 0;
extern double e_bl_val;
static void _e_comp_x_hook_client_pre_frame_assign(void *d EINA_UNUSED, E_Client *ec);
static Eina_Bool
_e_comp_x_flusher(void *data EINA_UNUSED)
{
@ -1142,6 +1144,15 @@ _e_comp_x_show_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Eve
ecore_x_window_show(ev->win);
return ECORE_CALLBACK_RENEW;
}
if ((e_comp->comp_type != E_PIXMAP_TYPE_X) && ec->ignored)
{
ec->visible = 1;
if (ec->comp_data->need_reparent)
_e_comp_x_hook_client_pre_frame_assign(NULL, ec);
else
ecore_x_window_show(ev->win);
return ECORE_CALLBACK_RENEW;
}
if ((!ec->comp_data->reparented) && (!e_client_util_ignored_get(ec)))
{
@ -1395,7 +1406,7 @@ _e_comp_x_configure(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_
EINA_RECTANGLE_SET(&ec->client, ev->x, ev->y, ev->w, ev->h);
if (move)
evas_object_move(ec->frame, ev->x, ev->y);
if (resize)
if (resize && e_pixmap_is_x(ec->pixmap))
{
e_pixmap_dirty(ec->pixmap);
evas_object_resize(ec->frame, ev->w, ev->h);
@ -1993,6 +2004,25 @@ _e_comp_x_message(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Cl
break;
}
}
#ifdef HAVE_WAYLAND
else if (ev->message_type == WL_SURFACE_ID)
{
void *res;
E_Client *wc = NULL;
if (e_comp->comp_type != E_PIXMAP_TYPE_WL) return ECORE_CALLBACK_RENEW;
res = wl_client_get_object(e_comp->wl_comp_data->xwl_client, ev->data.l[0]);
if (res)
wc = wl_resource_get_user_data(res);
if (wc)
e_comp_x_xwayland_client_setup(ec, wc);
else
{
ec->comp_data->surface_id = ev->data.l[0];
e_comp_wl_xwayland_client_queue(ec);
}
}
#endif
return ECORE_CALLBACK_PASS_ON;
}
@ -2737,7 +2767,10 @@ _e_comp_x_hook_client_pre_frame_assign(void *d EINA_UNUSED, E_Client *ec)
ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
0, 0, 0, 0, 0,
win, ECORE_X_WINDOW_STACK_ABOVE);
ecore_x_event_mask_set(pwin, ECORE_X_EVENT_MASK_MOUSE_IN | ECORE_X_EVENT_MASK_MOUSE_OUT);
ecore_x_event_mask_set(pwin, ECORE_X_EVENT_MASK_KEY_DOWN | ECORE_X_EVENT_MASK_KEY_UP |
ECORE_X_EVENT_MASK_MOUSE_MOVE | ECORE_X_EVENT_MASK_MOUSE_DOWN |
ECORE_X_EVENT_MASK_MOUSE_UP | ECORE_X_EVENT_MASK_MOUSE_WHEEL |
ECORE_X_EVENT_MASK_MOUSE_IN | ECORE_X_EVENT_MASK_MOUSE_OUT);
ecore_x_window_border_width_set(win, 0);
ec->border_size = 0;
@ -4090,6 +4123,7 @@ _e_comp_x_hook_client_new(void *d EINA_UNUSED, E_Client *ec)
ec->icccm.state = ECORE_X_WINDOW_STATE_HINT_NONE;
if (!_e_comp_x_client_new_helper(ec)) return;
ec->ignored |= e_comp->comp_type == E_PIXMAP_TYPE_WL;
ec->comp_data->first_damage = ec->internal;
@ -4561,16 +4595,19 @@ _e_comp_x_randr_change(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *ev
if ((e_comp->w != e_randr2->w) ||
(e_comp->h != e_randr2->h))
{
e_comp_canvas_resize(e_randr2->w, e_randr2->h);
if (e_comp->comp_type == E_PIXMAP_TYPE_X)
e_comp_canvas_resize(e_randr2->w, e_randr2->h);
}
else
{
E_Client *ec;
ecore_x_netwm_desk_size_set(e_comp->root, e_comp->w, e_comp->h);
e_randr2_screens_setup(e_comp->w, e_comp->h);
if (e_comp->comp_type == E_PIXMAP_TYPE_X)
e_randr2_screens_setup(e_comp->w, e_comp->h);
e_comp_canvas_update();
if (e_comp->comp_type == E_PIXMAP_TYPE_X)
e_comp_canvas_update();
E_CLIENT_FOREACH(ec)
{
if (!e_client_util_ignored_get(ec))
@ -4891,6 +4928,7 @@ _e_comp_x_setup(Ecore_X_Window root, int w, int h)
e_hints_init(root, e_comp->cm_selection);
ecore_x_window_background_color_set(root, 0, 0, 0);
ecore_x_screen_is_composited_set(0, e_comp->cm_selection);
ecore_x_selection_owner_set(e_comp->cm_selection, ecore_x_atom_get("WM_S0"), ecore_x_current_time_get());
e_comp->win = ecore_x_composite_render_window_enable(root);
if (!e_comp->win)
@ -4937,7 +4975,10 @@ _e_comp_x_setup(Ecore_X_Window root, int w, int h)
e_comp->bindings_grab_cb = _e_comp_x_bindings_grab_cb;
e_comp->bindings_ungrab_cb = _e_comp_x_bindings_ungrab_cb;
if (!e_comp_canvas_init(w, h)) return EINA_FALSE;
if (e_comp->comp_type == E_PIXMAP_TYPE_NONE)
{
if (!e_comp_canvas_init(w, h)) return EINA_FALSE;
}
e_grabinput_focus(e_comp->ee_win, E_FOCUS_METHOD_PASSIVE);
@ -4959,6 +5000,7 @@ _e_comp_x_setup(Ecore_X_Window root, int w, int h)
ec->lock_client_stacking = 1;
ec->internal = 1;
ec->visible = 1;
evas_object_del(e_comp->layers[i].obj);
e_comp->layers[i].obj = ec->frame;
evas_object_layer_set(ec->frame, e_comp_canvas_layer_map_to(i));
evas_object_pass_events_set(ec->frame, 1);
@ -4968,11 +5010,14 @@ _e_comp_x_setup(Ecore_X_Window root, int w, int h)
ecore_x_window_lower(e_comp->layers[i].win);
ecore_evas_lower(e_comp->ee);
e_comp->pointer = e_pointer_window_new(e_comp->root, 0);
e_comp->pointer->color = ecore_x_cursor_color_supported_get();
e_pointer_type_push(e_comp->pointer, e_comp->pointer, "default");
if (e_comp->comp_type == E_PIXMAP_TYPE_NONE)
{
e_comp->pointer = e_pointer_window_new(e_comp->root, 0);
e_comp->pointer->color = ecore_x_cursor_color_supported_get();
e_pointer_type_push(e_comp->pointer, e_comp->pointer, "default");
ecore_x_icccm_state_set(ecore_evas_window_get(e_comp->ee), ECORE_X_WINDOW_STATE_HINT_NORMAL);
}
_e_comp_x_manage_windows();
ecore_x_icccm_state_set(ecore_evas_window_get(e_comp->ee), ECORE_X_WINDOW_STATE_HINT_NORMAL);
{
E_Client *ec;
@ -4994,8 +5039,11 @@ _e_comp_x_screens_setup(void)
Ecore_X_Window root;
int rw, rh;
e_comp_x_randr_screen_iface_set();
if (!e_randr2_init()) return 0;
if (e_comp->comp_type == E_PIXMAP_TYPE_NONE)
{
e_comp_x_randr_screen_iface_set();
if (!e_randr2_init()) return 0;
}
root = ecore_x_window_root_first_get();
if (!root)
{
@ -5003,11 +5051,12 @@ _e_comp_x_screens_setup(void)
return 0;
}
ecore_x_window_size_get(root, &rw, &rh);
e_randr2_screens_setup(rw, rh);
if (e_comp->comp_type == E_PIXMAP_TYPE_NONE)
e_randr2_screens_setup(rw, rh);
return _e_comp_x_setup(root, rw, rh);
}
EINTERN Eina_Bool
E_API Eina_Bool
e_comp_x_init(void)
{
if (!ecore_x_init(NULL))
@ -5143,7 +5192,7 @@ e_comp_x_init(void)
return EINA_TRUE;
}
EINTERN void
E_API void
e_comp_x_shutdown(void)
{
E_FREE_LIST(handlers, ecore_event_handler_del);
@ -5170,3 +5219,43 @@ e_comp_x_nocomp_end(void)
ecore_x_composite_redirect_subwindows(e_comp->root, ECORE_X_COMPOSITE_UPDATE_MANUAL);
_e_comp_x_focus_check();
}
#ifdef HAVE_WAYLAND
EINTERN void
e_comp_x_xwayland_client_setup(E_Client *ec, E_Client *wc)
{
Ecore_X_Window win;
E_Comp_X_Client_Data *cd;
win = e_client_util_win_get(ec);
cd = ec->comp_data;
e_comp_wl_client_xwayland_setup(wc, cd, e_pixmap_ref(ec->pixmap));
eina_hash_del(damages_hash, &cd->damage, ec);
ecore_x_damage_free(cd->damage);
E_FREE_FUNC(cd->first_draw_delay, ecore_timer_del);
cd->damage = 0;
ec->comp_data = NULL;
cd->evas_init = 0;
_e_comp_x_client_evas_init(wc);
wc->borderless = ec->borderless;
wc->border.changed = 1;
EC_CHANGED(wc);
wc->depth = ec->depth;
wc->override = ec->override;
wc->placed = ec->placed;
wc->input_only = ec->input_only;
wc->border_size = ec->border_size;
memcpy(&wc->icccm, &ec->icccm, sizeof(ec->icccm));
memcpy(&wc->netwm, &ec->netwm, sizeof(ec->netwm));
memcpy(&wc->e, &ec->e, sizeof(ec->e));
ec->new_client = 1;
e_comp->new_clients++;
eina_hash_set(clients_win_hash, &win, wc);
wc->visible = 1;
evas_object_show(wc->frame);
e_object_del(E_OBJECT(ec));
e_hints_window_visible_set(wc);
_e_comp_x_client_stack(wc);
}
#endif

View File

@ -87,6 +87,9 @@ struct _E_Comp_X_Client_Data
Ecore_X_Illume_Window_State state;
} win_state;
} illume;
#ifdef HAVE_WAYLAND
uint32_t surface_id;
#endif
Eina_Bool moving : 1;
Eina_Bool first_map : 1;
@ -102,10 +105,11 @@ struct _E_Comp_X_Client_Data
Eina_Bool unredirected_single : 1;
};
EINTERN Eina_Bool e_comp_x_init(void);
EINTERN void e_comp_x_shutdown(void);
E_API Eina_Bool e_comp_x_init(void);
E_API void e_comp_x_shutdown(void);
E_API void e_alert_composite_win(Ecore_X_Window root, Ecore_X_Window win);
EINTERN void e_comp_x_nocomp_end(void);
EINTERN void e_comp_x_xwayland_client_setup(E_Client *ec, E_Client *wc);
# endif
#endif