implement wl client session recovery

another small feature patch brought to you by insomnia

 #SamsungFeatures
This commit is contained in:
Mike Blumenkrantz 2016-05-05 10:22:04 -04:00
parent e0d1a572a1
commit ef1772b8cb
17 changed files with 582 additions and 739 deletions

View File

@ -221,7 +221,6 @@ src/bin/e_zone.h
if HAVE_WAYLAND
ENLIGHTENMENTHEADERS += \
src/bin/e_uuid_store.h \
src/bin/e_comp_wl_data.h \
src/bin/e_comp_wl_input.h \
src/bin/e_comp_wl.h
@ -394,11 +393,10 @@ endif
if HAVE_WAYLAND
enlightenment_src += \
src/bin/e_uuid_store.c \
src/bin/generated/www-protocol.c \
src/bin/generated/www-protocol.h \
src/bin/generated/session-recovery-protocol.c \
src/bin/generated/session-recovery-server-protocol.h \
src/bin/generated/session-recovery.c \
src/bin/generated/session-recovery.h \
src/bin/generated/e_comp_wl_screenshooter_server.c \
src/bin/generated/e_comp_wl_screenshooter_server.h \
src/bin/e_comp_wl_data.c \

View File

@ -133,7 +133,6 @@ void *alloca (size_t);
# ifdef HAVE_WAYLAND
# include <Ecore_Wl2.h>
# include <uuid.h>
# endif
# ifdef E_API

View File

@ -554,6 +554,7 @@ _e_client_free(E_Client *ec)
eina_stringshare_replace(&ec->netwm.icon_name, NULL);
eina_stringshare_replace(&ec->internal_icon, NULL);
eina_stringshare_replace(&ec->internal_icon_key, NULL);
eina_stringshare_replace(&ec->uuid, NULL);
focus_stack = eina_list_remove(focus_stack, ec);
raise_stack = eina_list_remove(raise_stack, ec);
@ -570,10 +571,6 @@ _e_client_free(E_Client *ec)
evas_object_del(ec->frame);
E_OBJECT(ec)->references--;
#ifdef HAVE_WAYLAND
e_uuid_store_entry_del(ec->uuid);
#endif
free(ec);
}
@ -2346,10 +2343,6 @@ e_client_new(E_Pixmap *cp, int first_map, int internal)
if (!ec) return NULL;
e_object_del_func_set(E_OBJECT(ec), E_OBJECT_CLEANUP_FUNC(_e_client_del));
#ifdef HAVE_WAYLAND
uuid_generate(ec->uuid);
#endif
ec->focus_policy_override = E_FOCUS_LAST;
ec->w = 1;
ec->h = 1;

View File

@ -686,9 +686,7 @@ struct E_Client
E_Focus_Policy focus_policy_override;
#ifdef HAVE_WAYLAND
uuid_t uuid;
#endif
Eina_Stringshare *uuid;
Eina_Bool override : 1;
Eina_Bool input_only : 1;

View File

@ -1603,15 +1603,13 @@ _e_comp_wl_compositor_cb_surface_create(struct wl_client *client, struct wl_reso
ec = e_client_new(ep, 0, 0);
}
if (ec)
{
if (ec->new_client)
e_comp->new_clients--;
ec->new_client = 0;
if ((!ec->client.w) && (ec->client.h))
ec->client.w = ec->client.h = 1;
ec->comp_data->surface = res;
}
if (ec->new_client)
e_comp->new_clients--;
ec->new_client = 0;
if ((!ec->client.w) && (ec->client.h))
ec->client.w = ec->client.h = 1;
ec->comp_data->surface = res;
ec->netwm.pid = pid;
/* set reference to pixmap so we can fetch it later */
DBG("\tUsing Client: %p", ec);

View File

@ -1,8 +1,10 @@
#define E_COMP_WL
#include "e.h"
#include <uuid.h>
#include "e_comp_wl_screenshooter_server.h"
#include "session-recovery-server-protocol.h"
#include "session-recovery.h"
#include "www-protocol.h"
static void
@ -24,9 +26,62 @@ _e_comp_wl_extensions_client_move_end(void *d EINA_UNUSED, E_Client *ec)
}
static void
_e_comp_wl_sr_cb_provide_uuid(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, const char *uuid)
_e_comp_wl_session_recovery_get_uuid(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *surface)
{
DBG("Provide UUID callback called for UUID: %s", uuid);
E_Client *ec;
uuid_t u;
char uuid[37];
ec = wl_resource_get_user_data(surface);
if (e_object_is_del(E_OBJECT(ec))) return;
if (ec->internal || ec->uuid) return;
uuid_generate(u);
uuid_unparse_lower(u, uuid);
eina_stringshare_replace(&ec->uuid, uuid);
zwp_e_session_recovery_send_create_uuid(resource, surface, uuid);
if (ec->remember)
e_remember_unuse(ec->remember);
ec->remember = e_remember_new();
e_remember_use(ec->remember);
ec->remember->apply = E_REMEMBER_APPLY_POS | E_REMEMBER_APPLY_DESKTOP |
E_REMEMBER_APPLY_LAYER | E_REMEMBER_APPLY_ZONE | E_REMEMBER_APPLY_UUID;
e_remember_update(ec);
}
static void
_e_comp_wl_session_recovery_set_uuid(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, struct wl_resource *surface, const char *uuid)
{
E_Client *ec;
E_Remember *rem;
ec = wl_resource_get_user_data(surface);
if (e_object_is_del(E_OBJECT(ec))) return;
if (ec->internal || ec->uuid) return; //FIXME: error
eina_stringshare_replace(&ec->uuid, uuid);
rem = e_remember_find_usable(ec);
if ((!rem) || (rem == ec->remember)) return;
if (ec->remember)
e_remember_unuse(ec->remember);
ec->remember = rem;
e_remember_use(rem);
e_remember_apply(rem, ec);
ec->re_manage = 1;
}
static void
_e_comp_wl_session_recovery_destroy_uuid(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, struct wl_resource *surface, const char *uuid)
{
E_Client *ec;
ec = wl_resource_get_user_data(surface);
if (!eina_streq(ec->uuid, uuid)) return; //FIXME: error
eina_stringshare_replace(&ec->uuid, NULL);
e_remember_unuse(ec->remember);
e_remember_del(ec->remember);
ec->remember = e_remember_find_usable(ec);
if (!ec->remember) return;
e_remember_use(ec->remember);
e_remember_apply(ec->remember, ec);
}
static void
@ -145,7 +200,9 @@ _e_comp_wl_www_cb_create(struct wl_client *client, struct wl_resource *resource,
static const struct zwp_e_session_recovery_interface _e_session_recovery_interface =
{
_e_comp_wl_sr_cb_provide_uuid,
_e_comp_wl_session_recovery_get_uuid,
_e_comp_wl_session_recovery_set_uuid,
_e_comp_wl_session_recovery_destroy_uuid,
};
static const struct screenshooter_interface _e_screenshooter_interface =

View File

@ -384,6 +384,8 @@ _e_config_edd_init(Eina_Bool old)
E_CONFIG_VAL(D, T, prop.desktop_file, STR);
E_CONFIG_VAL(D, T, prop.offer_resistance, UCHAR);
E_CONFIG_VAL(D, T, prop.opacity, UCHAR);
E_CONFIG_VAL(D, T, uuid, STR);
E_CONFIG_VAL(D, T, pid, INT);
_e_config_color_class_edd = E_CONFIG_DD_NEW("E_Color_Class", E_Color_Class);
#undef T

View File

@ -157,5 +157,4 @@
# include "e_comp_wl.h"
# include "e_comp_wl_data.h"
# include "e_comp_wl_input.h"
# include "e_uuid_store.h"
#endif

View File

@ -536,19 +536,6 @@ main(int argc, char **argv)
_e_main_shutdown_push(e_alert_shutdown);
#endif
#if 0
//#ifdef HAVE_WAYLAND
/* init uuid store for window/surface properties */
TS("E_UUID_Store Init");
if (!e_uuid_store_init())
{
e_error_message_show(_("Enlightenment cannot initialize its UUID store.\n"));
_e_main_shutdown(-1);
}
TS("E_UUID_Store Init Done");
_e_main_shutdown_push(e_uuid_store_shutdown);
#endif
TS("E Directories Init");
/* setup directories we will be using for configurations storage etc. */
if (!_e_main_dirs_init())

View File

@ -268,411 +268,10 @@ e_remember_del(E_Remember *rem)
_e_remember_free(rem);
}
E_API E_Remember *
e_remember_find_usable(E_Client *ec)
{
E_Remember *rem;
rem = _e_remember_find(ec, 1);
return rem;
}
E_API E_Remember *
e_remember_find(E_Client *ec)
{
E_Remember *rem;
rem = _e_remember_find(ec, 0);
return rem;
}
E_API void
e_remember_match_update(E_Remember *rem)
e_remember_apply(E_Remember *rem, E_Client *ec)
{
int max_count = 0;
if (rem->match & E_REMEMBER_MATCH_NAME) max_count += 2;
if (rem->match & E_REMEMBER_MATCH_CLASS) max_count += 2;
if (rem->match & E_REMEMBER_MATCH_TITLE) max_count += 2;
if (rem->match & E_REMEMBER_MATCH_ROLE) max_count += 2;
if (rem->match & E_REMEMBER_MATCH_TYPE) max_count += 2;
if (rem->match & E_REMEMBER_MATCH_TRANSIENT) max_count += 2;
if (rem->apply_first_only) max_count++;
if (max_count != rem->max_score)
{
/* The number of matches for this remember has changed so we
* need to remove from list and insert back into the appropriate
* location. */
Eina_List *l = NULL;
E_Remember *r;
rem->max_score = max_count;
e_config->remembers = eina_list_remove(e_config->remembers, rem);
EINA_LIST_FOREACH(e_config->remembers, l, r)
{
if (r->max_score <= rem->max_score) break;
}
if (l)
e_config->remembers = eina_list_prepend_relative_list(e_config->remembers, rem, l);
else
e_config->remembers = eina_list_append(e_config->remembers, rem);
}
}
E_API int
e_remember_default_match_set(E_Remember *rem, E_Client *ec)
{
const char *title, *clasz, *name, *role;
int match;
eina_stringshare_replace(&rem->name, NULL);
eina_stringshare_replace(&rem->class, NULL);
eina_stringshare_replace(&rem->title, NULL);
eina_stringshare_replace(&rem->role, NULL);
name = ec->icccm.name;
if (!name || name[0] == 0) name = NULL;
clasz = ec->icccm.class;
if (!clasz || clasz[0] == 0) clasz = NULL;
role = ec->icccm.window_role;
if (!role || role[0] == 0) role = NULL;
match = E_REMEMBER_MATCH_TRANSIENT;
if (ec->icccm.transient_for != 0)
rem->transient = 1;
else
rem->transient = 0;
if (name && clasz)
{
match |= E_REMEMBER_MATCH_NAME | E_REMEMBER_MATCH_CLASS;
rem->name = eina_stringshare_ref(name);
rem->class = eina_stringshare_ref(clasz);
}
else if ((title = e_client_util_name_get(ec)) && title[0])
{
match |= E_REMEMBER_MATCH_TITLE;
rem->title = eina_stringshare_ref(title);
}
if (role)
{
match |= E_REMEMBER_MATCH_ROLE;
rem->role = eina_stringshare_ref(role);
}
if (ec->netwm.type != E_WINDOW_TYPE_UNKNOWN)
{
match |= E_REMEMBER_MATCH_TYPE;
rem->type = ec->netwm.type;
}
rem->match = match;
return match;
}
E_API void
e_remember_update(E_Client *ec)
{
#ifdef HAVE_WAYLAND
/* Use this as e_remeber_update is called in all the right places already */
e_uuid_store_entry_update(ec->uuid, ec);
#endif
if (ec->new_client) return;
if (!ec->remember) return;
if (ec->remember->keep_settings) return;
_e_remember_update(ec, ec->remember);
e_config_save_queue();
}
static void
_e_remember_event_free(void *d EINA_UNUSED, void *event)
{
E_Event_Remember_Update *ev = event;
UNREFD(ev->ec, 10);
e_object_unref(E_OBJECT(ev->ec));
free(ev);
}
static void
_e_remember_update(E_Client *ec, E_Remember *rem)
{
if (rem->apply & E_REMEMBER_APPLY_POS ||
rem->apply & E_REMEMBER_APPLY_SIZE)
{
if (ec->fullscreen || ec->maximized)
{
rem->prop.pos_x = ec->saved.x;
rem->prop.pos_y = ec->saved.y;
rem->prop.pos_w = ec->saved.w;
rem->prop.pos_h = ec->saved.h;
}
else
{
rem->prop.pos_x = ec->x - ec->zone->x;
rem->prop.pos_y = ec->y - ec->zone->y;
rem->prop.res_x = ec->zone->w;
rem->prop.res_y = ec->zone->h;
rem->prop.pos_w = ec->client.w;
rem->prop.pos_h = ec->client.h;
rem->prop.w = ec->client.w;
rem->prop.h = ec->client.h;
}
rem->prop.maximize = ec->maximized & E_MAXIMIZE_DIRECTION;
}
if (rem->apply & E_REMEMBER_APPLY_LAYER)
{
if (ec->fullscreen)
rem->prop.layer = ec->saved.layer;
else
rem->prop.layer = ec->layer;
}
if (rem->apply & E_REMEMBER_APPLY_LOCKS)
{
rem->prop.lock_user_location = ec->lock_user_location;
rem->prop.lock_client_location = ec->lock_client_location;
rem->prop.lock_user_size = ec->lock_user_size;
rem->prop.lock_client_size = ec->lock_client_size;
rem->prop.lock_user_stacking = ec->lock_user_stacking;
rem->prop.lock_client_stacking = ec->lock_client_stacking;
rem->prop.lock_user_iconify = ec->lock_user_iconify;
rem->prop.lock_client_iconify = ec->lock_client_iconify;
rem->prop.lock_user_desk = ec->lock_user_desk;
rem->prop.lock_client_desk = ec->lock_client_desk;
rem->prop.lock_user_sticky = ec->lock_user_sticky;
rem->prop.lock_client_sticky = ec->lock_client_sticky;
rem->prop.lock_user_shade = ec->lock_user_shade;
rem->prop.lock_client_shade = ec->lock_client_shade;
rem->prop.lock_user_maximize = ec->lock_user_maximize;
rem->prop.lock_client_maximize = ec->lock_client_maximize;
rem->prop.lock_user_fullscreen = ec->lock_user_fullscreen;
rem->prop.lock_client_fullscreen = ec->lock_client_fullscreen;
rem->prop.lock_border = ec->lock_border;
rem->prop.lock_close = ec->lock_close;
rem->prop.lock_focus_in = ec->lock_focus_in;
rem->prop.lock_focus_out = ec->lock_focus_out;
rem->prop.lock_life = ec->lock_life;
}
if (rem->apply & E_REMEMBER_APPLY_SHADE)
{
if (ec->shaded)
rem->prop.shaded = (100 + ec->shade_dir);
else
rem->prop.shaded = (50 + ec->shade_dir);
}
if (rem->apply & E_REMEMBER_APPLY_ZONE)
{
rem->prop.zone = ec->zone->num;
}
if (rem->apply & E_REMEMBER_APPLY_SKIP_WINLIST)
rem->prop.skip_winlist = ec->user_skip_winlist;
if (rem->apply & E_REMEMBER_APPLY_STICKY)
rem->prop.sticky = ec->sticky;
if (rem->apply & E_REMEMBER_APPLY_SKIP_PAGER)
rem->prop.skip_pager = ec->netwm.state.skip_pager;
if (rem->apply & E_REMEMBER_APPLY_SKIP_TASKBAR)
rem->prop.skip_taskbar = ec->netwm.state.skip_taskbar;
if (rem->apply & E_REMEMBER_APPLY_ICON_PREF)
rem->prop.icon_preference = ec->icon_preference;
if (rem->apply & E_REMEMBER_APPLY_DESKTOP)
e_desk_xy_get(ec->desk, &rem->prop.desk_x, &rem->prop.desk_y);
if (rem->apply & E_REMEMBER_APPLY_FULLSCREEN)
rem->prop.fullscreen = ec->fullscreen;
if (rem->apply & E_REMEMBER_APPLY_OFFER_RESISTANCE)
rem->prop.offer_resistance = ec->offer_resistance;
if (rem->apply & E_REMEMBER_APPLY_OPACITY)
rem->prop.opacity = ec->netwm.opacity;
if (rem->apply & E_REMEMBER_APPLY_BORDER)
{
if (ec->borderless)
eina_stringshare_replace(&rem->prop.border, "borderless");
else
eina_stringshare_replace(&rem->prop.border, ec->bordername);
}
rem->no_reopen = ec->internal_no_reopen;
{
E_Event_Remember_Update *ev;
ev = malloc(sizeof(E_Event_Remember_Update));
if (!ev) return;
ev->ec = ec;
REFD(ec, 10);
e_object_ref(E_OBJECT(ec));
ecore_event_add(E_EVENT_REMEMBER_UPDATE, ev, _e_remember_event_free, NULL);
}
}
/* local subsystem functions */
static E_Remember *
_e_remember_find(E_Client *ec, int check_usable)
{
Eina_List *l = NULL;
E_Remember *rem;
#if REMEMBER_SIMPLE
EINA_LIST_FOREACH(e_config->remembers, l, rem)
{
int required_matches;
int matches;
const char *title = "";
matches = 0;
required_matches = 0;
if (rem->match & E_REMEMBER_MATCH_NAME) required_matches++;
if (rem->match & E_REMEMBER_MATCH_CLASS) required_matches++;
if (rem->match & E_REMEMBER_MATCH_TITLE) required_matches++;
if (rem->match & E_REMEMBER_MATCH_ROLE) required_matches++;
if (rem->match & E_REMEMBER_MATCH_TYPE) required_matches++;
if (rem->match & E_REMEMBER_MATCH_TRANSIENT) required_matches++;
if (ec->netwm.name) title = ec->netwm.name;
else title = ec->icccm.title;
if ((rem->match & E_REMEMBER_MATCH_NAME) &&
((!e_util_strcmp(rem->name, ec->icccm.name)) ||
(e_util_both_str_empty(rem->name, ec->icccm.name))))
matches++;
if ((rem->match & E_REMEMBER_MATCH_CLASS) &&
((!e_util_strcmp(rem->class, ec->icccm.class)) ||
(e_util_both_str_empty(rem->class, ec->icccm.class))))
matches++;
if ((rem->match & E_REMEMBER_MATCH_TITLE) &&
((!e_util_strcmp(rem->title, title)) ||
(e_util_both_str_empty(rem->title, title))))
matches++;
if ((rem->match & E_REMEMBER_MATCH_ROLE) &&
((!e_util_strcmp(rem->role, ec->icccm.window_role)) ||
(e_util_both_str_empty(rem->role, ec->icccm.window_role))))
matches++;
if ((rem->match & E_REMEMBER_MATCH_TYPE) &&
(rem->type == ec->netwm.type))
matches++;
if ((rem->match & E_REMEMBER_MATCH_TRANSIENT) &&
(((rem->transient) && (ec->icccm.transient_for != 0)) ||
((!rem->transient) && (ec->icccm.transient_for == 0))))
matches++;
if (matches >= required_matches)
return rem;
}
return NULL;
#endif
#if REMEMBER_HIERARCHY
/* This search method finds the best possible match available and is
* based on the fact that the list is sorted, with those remembers
* with the most possible matches at the start of the list. This
* means, as soon as a valid match is found, it is a match
* within the set of best possible matches. */
EINA_LIST_FOREACH(e_config->remembers, l, rem)
{
const char *title = "";
if ((check_usable) && (!e_remember_usable_get(rem)))
continue;
if (ec->netwm.name) title = ec->netwm.name;
else title = ec->icccm.title;
/* For each type of match, check whether the match is
* required, and if it is, check whether there's a match. If
* it fails, then go to the next remember */
if (rem->match & E_REMEMBER_MATCH_NAME &&
!e_util_glob_match(ec->icccm.name, rem->name))
continue;
if (rem->match & E_REMEMBER_MATCH_CLASS &&
!e_util_glob_match(ec->icccm.class, rem->class))
continue;
if (rem->match & E_REMEMBER_MATCH_TITLE &&
!e_util_glob_match(title, rem->title))
continue;
if (rem->match & E_REMEMBER_MATCH_ROLE &&
e_util_strcmp(rem->role, ec->icccm.window_role) &&
!e_util_both_str_empty(rem->role, ec->icccm.window_role))
continue;
if (rem->match & E_REMEMBER_MATCH_TYPE &&
rem->type != (int)ec->netwm.type)
continue;
if (rem->match & E_REMEMBER_MATCH_TRANSIENT &&
!(rem->transient && ec->icccm.transient_for != 0) &&
!(!rem->transient) && (ec->icccm.transient_for == 0))
continue;
return rem;
}
return NULL;
#endif
}
static void
_e_remember_free(E_Remember *rem)
{
e_config->remembers = eina_list_remove(e_config->remembers, rem);
if (rem->name) eina_stringshare_del(rem->name);
if (rem->class) eina_stringshare_del(rem->class);
if (rem->title) eina_stringshare_del(rem->title);
if (rem->role) eina_stringshare_del(rem->role);
if (rem->prop.border) eina_stringshare_del(rem->prop.border);
if (rem->prop.command) eina_stringshare_del(rem->prop.command);
if (rem->prop.desktop_file) eina_stringshare_del(rem->prop.desktop_file);
free(rem);
}
static void
_e_remember_cb_hook_eval_post_new_client(void *data EINA_UNUSED, E_Client *ec)
{
// remember only when window was modified
// if (!ec->new_client) return;
if (e_client_util_ignored_get(ec)) return;
if ((ec->internal) && (!ec->remember) &&
(e_config->remember_internal_windows) &&
(!ec->internal_no_remember) &&
(ec->icccm.class && ec->icccm.class[0]))
{
E_Remember *rem;
if (!strncmp(ec->icccm.class, "e_fwin", 6))
{
if (!e_config->remember_internal_fm_windows) return;
}
else
{
if (!e_config->remember_internal_windows)
return;
}
rem = e_remember_new();
if (!rem) return;
e_remember_default_match_set(rem, ec);
rem->apply = E_REMEMBER_APPLY_POS | E_REMEMBER_APPLY_SIZE | E_REMEMBER_APPLY_BORDER;
e_remember_use(rem);
e_remember_update(ec);
ec->remember = rem;
}
}
static void
_e_remember_cb_hook_pre_post_fetch(void *data EINA_UNUSED, E_Client *ec)
{
E_Remember *rem = NULL;
int temporary = 0;
if ((!ec->new_client) || ec->internal_no_remember || e_client_util_ignored_get(ec)) return;
if (!ec->remember)
{
rem = e_remember_find_usable(ec);
if (rem)
{
ec->remember = rem;
e_remember_use(rem);
}
}
if (ec->internal && remembers && ec->icccm.class && ec->icccm.class[0])
{
Eina_List *l;
@ -952,6 +551,423 @@ _e_remember_cb_hook_pre_post_fetch(void *data EINA_UNUSED, E_Client *ec)
_e_remember_free(rem);
}
E_API E_Remember *
e_remember_find_usable(E_Client *ec)
{
E_Remember *rem;
rem = _e_remember_find(ec, 1);
return rem;
}
E_API E_Remember *
e_remember_find(E_Client *ec)
{
E_Remember *rem;
rem = _e_remember_find(ec, 0);
return rem;
}
E_API void
e_remember_match_update(E_Remember *rem)
{
int max_count = 0;
if (rem->match & E_REMEMBER_MATCH_NAME) max_count += 2;
if (rem->match & E_REMEMBER_MATCH_CLASS) max_count += 2;
if (rem->match & E_REMEMBER_MATCH_TITLE) max_count += 2;
if (rem->match & E_REMEMBER_MATCH_ROLE) max_count += 2;
if (rem->match & E_REMEMBER_MATCH_TYPE) max_count += 2;
if (rem->match & E_REMEMBER_MATCH_TRANSIENT) max_count += 2;
if (rem->apply_first_only) max_count++;
if (max_count != rem->max_score)
{
/* The number of matches for this remember has changed so we
* need to remove from list and insert back into the appropriate
* location. */
Eina_List *l = NULL;
E_Remember *r;
rem->max_score = max_count;
e_config->remembers = eina_list_remove(e_config->remembers, rem);
EINA_LIST_FOREACH(e_config->remembers, l, r)
{
if (r->max_score <= rem->max_score) break;
}
if (l)
e_config->remembers = eina_list_prepend_relative_list(e_config->remembers, rem, l);
else
e_config->remembers = eina_list_append(e_config->remembers, rem);
}
}
E_API int
e_remember_default_match_set(E_Remember *rem, E_Client *ec)
{
const char *title, *clasz, *name, *role;
int match;
eina_stringshare_replace(&rem->name, NULL);
eina_stringshare_replace(&rem->class, NULL);
eina_stringshare_replace(&rem->title, NULL);
eina_stringshare_replace(&rem->role, NULL);
name = ec->icccm.name;
if (!name || name[0] == 0) name = NULL;
clasz = ec->icccm.class;
if (!clasz || clasz[0] == 0) clasz = NULL;
role = ec->icccm.window_role;
if (!role || role[0] == 0) role = NULL;
match = E_REMEMBER_MATCH_TRANSIENT;
if (ec->icccm.transient_for != 0)
rem->transient = 1;
else
rem->transient = 0;
if (name && clasz)
{
match |= E_REMEMBER_MATCH_NAME | E_REMEMBER_MATCH_CLASS;
rem->name = eina_stringshare_ref(name);
rem->class = eina_stringshare_ref(clasz);
}
else if ((title = e_client_util_name_get(ec)) && title[0])
{
match |= E_REMEMBER_MATCH_TITLE;
rem->title = eina_stringshare_ref(title);
}
if (role)
{
match |= E_REMEMBER_MATCH_ROLE;
rem->role = eina_stringshare_ref(role);
}
if (ec->netwm.type != E_WINDOW_TYPE_UNKNOWN)
{
match |= E_REMEMBER_MATCH_TYPE;
rem->type = ec->netwm.type;
}
rem->match = match;
return match;
}
E_API void
e_remember_update(E_Client *ec)
{
if (ec->new_client) return;
if (!ec->remember) return;
if (ec->remember->keep_settings) return;
_e_remember_update(ec, ec->remember);
e_config_save_queue();
}
static void
_e_remember_event_free(void *d EINA_UNUSED, void *event)
{
E_Event_Remember_Update *ev = event;
UNREFD(ev->ec, 10);
e_object_unref(E_OBJECT(ev->ec));
free(ev);
}
static void
_e_remember_update(E_Client *ec, E_Remember *rem)
{
if (rem->apply & E_REMEMBER_APPLY_POS ||
rem->apply & E_REMEMBER_APPLY_SIZE)
{
if (ec->fullscreen || ec->maximized)
{
rem->prop.pos_x = ec->saved.x;
rem->prop.pos_y = ec->saved.y;
rem->prop.pos_w = ec->saved.w;
rem->prop.pos_h = ec->saved.h;
}
else
{
rem->prop.pos_x = ec->x - ec->zone->x;
rem->prop.pos_y = ec->y - ec->zone->y;
rem->prop.res_x = ec->zone->w;
rem->prop.res_y = ec->zone->h;
rem->prop.pos_w = ec->client.w;
rem->prop.pos_h = ec->client.h;
rem->prop.w = ec->client.w;
rem->prop.h = ec->client.h;
}
rem->prop.maximize = ec->maximized & E_MAXIMIZE_DIRECTION;
}
if (rem->apply & E_REMEMBER_APPLY_LAYER)
{
if (ec->fullscreen)
rem->prop.layer = ec->saved.layer;
else
rem->prop.layer = ec->layer;
}
if (rem->apply & E_REMEMBER_APPLY_LOCKS)
{
rem->prop.lock_user_location = ec->lock_user_location;
rem->prop.lock_client_location = ec->lock_client_location;
rem->prop.lock_user_size = ec->lock_user_size;
rem->prop.lock_client_size = ec->lock_client_size;
rem->prop.lock_user_stacking = ec->lock_user_stacking;
rem->prop.lock_client_stacking = ec->lock_client_stacking;
rem->prop.lock_user_iconify = ec->lock_user_iconify;
rem->prop.lock_client_iconify = ec->lock_client_iconify;
rem->prop.lock_user_desk = ec->lock_user_desk;
rem->prop.lock_client_desk = ec->lock_client_desk;
rem->prop.lock_user_sticky = ec->lock_user_sticky;
rem->prop.lock_client_sticky = ec->lock_client_sticky;
rem->prop.lock_user_shade = ec->lock_user_shade;
rem->prop.lock_client_shade = ec->lock_client_shade;
rem->prop.lock_user_maximize = ec->lock_user_maximize;
rem->prop.lock_client_maximize = ec->lock_client_maximize;
rem->prop.lock_user_fullscreen = ec->lock_user_fullscreen;
rem->prop.lock_client_fullscreen = ec->lock_client_fullscreen;
rem->prop.lock_border = ec->lock_border;
rem->prop.lock_close = ec->lock_close;
rem->prop.lock_focus_in = ec->lock_focus_in;
rem->prop.lock_focus_out = ec->lock_focus_out;
rem->prop.lock_life = ec->lock_life;
}
if (rem->apply & E_REMEMBER_APPLY_SHADE)
{
if (ec->shaded)
rem->prop.shaded = (100 + ec->shade_dir);
else
rem->prop.shaded = (50 + ec->shade_dir);
}
if (rem->apply & E_REMEMBER_APPLY_ZONE)
{
rem->prop.zone = ec->zone->num;
}
if (rem->apply & E_REMEMBER_APPLY_SKIP_WINLIST)
rem->prop.skip_winlist = ec->user_skip_winlist;
if (rem->apply & E_REMEMBER_APPLY_STICKY)
rem->prop.sticky = ec->sticky;
if (rem->apply & E_REMEMBER_APPLY_SKIP_PAGER)
rem->prop.skip_pager = ec->netwm.state.skip_pager;
if (rem->apply & E_REMEMBER_APPLY_SKIP_TASKBAR)
rem->prop.skip_taskbar = ec->netwm.state.skip_taskbar;
if (rem->apply & E_REMEMBER_APPLY_ICON_PREF)
rem->prop.icon_preference = ec->icon_preference;
if (rem->apply & E_REMEMBER_APPLY_DESKTOP)
e_desk_xy_get(ec->desk, &rem->prop.desk_x, &rem->prop.desk_y);
if (rem->apply & E_REMEMBER_APPLY_FULLSCREEN)
rem->prop.fullscreen = ec->fullscreen;
if (rem->apply & E_REMEMBER_APPLY_OFFER_RESISTANCE)
rem->prop.offer_resistance = ec->offer_resistance;
if (rem->apply & E_REMEMBER_APPLY_OPACITY)
rem->prop.opacity = ec->netwm.opacity;
if (rem->apply & E_REMEMBER_APPLY_BORDER)
{
if (ec->borderless)
eina_stringshare_replace(&rem->prop.border, "borderless");
else
eina_stringshare_replace(&rem->prop.border, ec->bordername);
}
if (rem->apply & E_REMEMBER_APPLY_UUID)
{
eina_stringshare_refplace(&rem->uuid, ec->uuid);
rem->pid = ec->netwm.pid;
rem->apply_first_only = 1;
}
rem->no_reopen = ec->internal_no_reopen;
{
E_Event_Remember_Update *ev;
ev = malloc(sizeof(E_Event_Remember_Update));
if (!ev) return;
ev->ec = ec;
REFD(ec, 10);
e_object_ref(E_OBJECT(ec));
ecore_event_add(E_EVENT_REMEMBER_UPDATE, ev, _e_remember_event_free, NULL);
}
}
/* local subsystem functions */
static E_Remember *
_e_remember_find(E_Client *ec, int check_usable)
{
Eina_List *l = NULL;
E_Remember *rem;
#if REMEMBER_SIMPLE
EINA_LIST_FOREACH(e_config->remembers, l, rem)
{
int required_matches;
int matches;
const char *title = "";
matches = 0;
required_matches = 0;
if (rem->match & E_REMEMBER_MATCH_NAME) required_matches++;
if (rem->match & E_REMEMBER_MATCH_CLASS) required_matches++;
if (rem->match & E_REMEMBER_MATCH_TITLE) required_matches++;
if (rem->match & E_REMEMBER_MATCH_ROLE) required_matches++;
if (rem->match & E_REMEMBER_MATCH_TYPE) required_matches++;
if (rem->match & E_REMEMBER_MATCH_TRANSIENT) required_matches++;
if (ec->netwm.name) title = ec->netwm.name;
else title = ec->icccm.title;
if ((rem->match & E_REMEMBER_MATCH_NAME) &&
((!e_util_strcmp(rem->name, ec->icccm.name)) ||
(e_util_both_str_empty(rem->name, ec->icccm.name))))
matches++;
if ((rem->match & E_REMEMBER_MATCH_CLASS) &&
((!e_util_strcmp(rem->class, ec->icccm.class)) ||
(e_util_both_str_empty(rem->class, ec->icccm.class))))
matches++;
if ((rem->match & E_REMEMBER_MATCH_TITLE) &&
((!e_util_strcmp(rem->title, title)) ||
(e_util_both_str_empty(rem->title, title))))
matches++;
if ((rem->match & E_REMEMBER_MATCH_ROLE) &&
((!e_util_strcmp(rem->role, ec->icccm.window_role)) ||
(e_util_both_str_empty(rem->role, ec->icccm.window_role))))
matches++;
if ((rem->match & E_REMEMBER_MATCH_TYPE) &&
(rem->type == ec->netwm.type))
matches++;
if ((rem->match & E_REMEMBER_MATCH_TRANSIENT) &&
(((rem->transient) && (ec->icccm.transient_for != 0)) ||
((!rem->transient) && (ec->icccm.transient_for == 0))))
matches++;
if (matches >= required_matches)
return rem;
}
return NULL;
#endif
#if REMEMBER_HIERARCHY
/* This search method finds the best possible match available and is
* based on the fact that the list is sorted, with those remembers
* with the most possible matches at the start of the list. This
* means, as soon as a valid match is found, it is a match
* within the set of best possible matches. */
EINA_LIST_FOREACH(e_config->remembers, l, rem)
{
const char *title = "";
if ((check_usable) && (!e_remember_usable_get(rem)))
continue;
if (!eina_streq(rem->uuid, ec->uuid)) continue;
if (rem->uuid)
{
if (rem->pid != ec->netwm.pid) continue;
return rem;
}
if (ec->netwm.name) title = ec->netwm.name;
else title = ec->icccm.title;
/* For each type of match, check whether the match is
* required, and if it is, check whether there's a match. If
* it fails, then go to the next remember */
if (rem->match & E_REMEMBER_MATCH_NAME &&
!e_util_glob_match(ec->icccm.name, rem->name))
continue;
if (rem->match & E_REMEMBER_MATCH_CLASS &&
!e_util_glob_match(ec->icccm.class, rem->class))
continue;
if (rem->match & E_REMEMBER_MATCH_TITLE &&
!e_util_glob_match(title, rem->title))
continue;
if (rem->match & E_REMEMBER_MATCH_ROLE &&
e_util_strcmp(rem->role, ec->icccm.window_role) &&
!e_util_both_str_empty(rem->role, ec->icccm.window_role))
continue;
if (rem->match & E_REMEMBER_MATCH_TYPE &&
rem->type != (int)ec->netwm.type)
continue;
if (rem->match & E_REMEMBER_MATCH_TRANSIENT &&
!(rem->transient && ec->icccm.transient_for != 0) &&
!(!rem->transient) && (ec->icccm.transient_for == 0))
continue;
return rem;
}
return NULL;
#endif
}
static void
_e_remember_free(E_Remember *rem)
{
e_config->remembers = eina_list_remove(e_config->remembers, rem);
if (rem->name) eina_stringshare_del(rem->name);
if (rem->class) eina_stringshare_del(rem->class);
if (rem->title) eina_stringshare_del(rem->title);
if (rem->role) eina_stringshare_del(rem->role);
if (rem->prop.border) eina_stringshare_del(rem->prop.border);
if (rem->prop.command) eina_stringshare_del(rem->prop.command);
if (rem->prop.desktop_file) eina_stringshare_del(rem->prop.desktop_file);
eina_stringshare_del(rem->uuid);
free(rem);
}
static void
_e_remember_cb_hook_eval_post_new_client(void *data EINA_UNUSED, E_Client *ec)
{
// remember only when window was modified
// if (!ec->new_client) return;
if (e_client_util_ignored_get(ec)) return;
if ((ec->internal) && (!ec->remember) &&
(e_config->remember_internal_windows) &&
(!ec->internal_no_remember) &&
(ec->icccm.class && ec->icccm.class[0]))
{
E_Remember *rem;
if (!strncmp(ec->icccm.class, "e_fwin", 6))
{
if (!e_config->remember_internal_fm_windows) return;
}
else
{
if (!e_config->remember_internal_windows)
return;
}
rem = e_remember_new();
if (!rem) return;
e_remember_default_match_set(rem, ec);
rem->apply = E_REMEMBER_APPLY_POS | E_REMEMBER_APPLY_SIZE | E_REMEMBER_APPLY_BORDER;
e_remember_use(rem);
e_remember_update(ec);
ec->remember = rem;
}
}
static void
_e_remember_cb_hook_pre_post_fetch(void *data EINA_UNUSED, E_Client *ec)
{
E_Remember *rem = NULL;
if ((!ec->new_client) || ec->internal_no_remember || e_client_util_ignored_get(ec)) return;
if (!ec->remember)
{
rem = e_remember_find_usable(ec);
if (rem)
{
ec->remember = rem;
e_remember_use(rem);
}
}
e_remember_apply(rem, ec);
}
static void
_e_remember_init_edd(void)
{

View File

@ -35,6 +35,7 @@ typedef struct _E_Remember E_Remember;
#define E_REMEMBER_APPLY_FULLSCREEN (1 << 15)
#define E_REMEMBER_APPLY_OFFER_RESISTANCE (1 << 16)
#define E_REMEMBER_APPLY_OPACITY (1 << 17)
#define E_REMEMBER_APPLY_UUID (1 << 18)
#define E_REMEMBER_INTERNAL_DIALOGS (1 << 0)
#define E_REMEMBER_INTERNAL_FM_WINS (1 << 1)
@ -109,6 +110,8 @@ struct _E_Remember
const char *desktop_file;
unsigned char opacity;
} prop;
Eina_Stringshare *uuid;
int pid;
};
EINTERN int e_remember_init(E_Startup_Mode mode);
@ -124,5 +127,7 @@ E_API void e_remember_match_update(E_Remember *rem);
E_API void e_remember_update(E_Client *ec);
E_API int e_remember_default_match_set(E_Remember *rem, E_Client *ec);
E_API void e_remember_internal_save(void);
E_API void e_remember_apply(E_Remember *rem, E_Client *ec);
#endif
#endif

View File

@ -1,210 +0,0 @@
/* vim:ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0
*/
/* 1. Create mmaped memory blob, name the memory object
* 2. Fill in table and keep it up-to-date
* 3. (optional) Write the whole blob into a file on disk for later use)
*/
#include <e.h>
#include <sys/mman.h>
/* Use anonymous mapping if we don't want a persistent file on the disk */
#define OBJECT_NAME "/e_uuid_store"
#define TABLE_SIZE 10*eina_cpu_page_size()
struct uuid_store *store;
void
e_uuid_dump(void)
{
struct uuid_table *table;
int i;
char uuid_string[37];
if (store == NULL) return;
table = store->table;
if (table == NULL) return;
INF("Dump UUID table:");
for (i = 0; i < UUID_STORE_TABLE_SIZE -1; i++)
{
if (uuid_is_null(table->entries[i].uuid)) continue;
uuid_unparse(table->entries[i].uuid, uuid_string);
INF("UUID %s, x=%i, y=%i, width=%i, heigth=%i", uuid_string, table->entries[i].x,
table->entries[i].y, table->entries[i].width,
table->entries[i].heigth);
}
}
/**
* Initialize the UUID store
*
* @returns 1 if init was successful, 0 on failure
*/
EINTERN int
e_uuid_store_init(void)
{
/* FIXME think about refcounting here */
eina_init();
store = calloc(1, sizeof(struct uuid_store));
if (store == NULL) return 0;
/* Try to open existing SHM object */
store->shmfd = shm_open(OBJECT_NAME, O_RDWR, S_IRWXU | S_IRWXG);
if (store->shmfd < 0 && errno == ENOENT)
{
INF("shm_open failed to open an existing file %s", OBJECT_NAME);
if (!e_uuid_store_reload()) return 0;
}
else if (store->shmfd < 0)
{
INF("shm_open failed");
return 0;
}
/* Adjust in memory blob to our given table size */
/* FIXME: How can we make sure we have the right size for our given table? */
if (ftruncate(store->shmfd, TABLE_SIZE) < 0)
{
ERR("ftruncate failed: %s", strerror(errno));
return 0;
}
store->table = (struct uuid_table *)mmap(NULL, TABLE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, store->shmfd, 0);
if (store->table == NULL)
{
ERR("mmap failed");
return 0;
}
INF("mmaped blob with size %i created", TABLE_SIZE);
if (store->table->version)
INF("UUID table with version %i", store->table->version);
else
store->table->version = 1;
INF("UUID table with %i entries", store->table->entry_count);
return 1;
}
EINTERN int
e_uuid_store_shutdown(void)
{
/* Cleanup for shutdown */
if (shm_unlink(OBJECT_NAME) != 0)
{
ERR("shm_unlink failed");
return 0;
}
close(store->shmfd);
free(store);
eina_shutdown();
return 1;
}
Eina_Bool
e_uuid_store_reload(void)
{
/* After crash reload the table with its POSIX object name from memory */
store->shmfd = shm_open(OBJECT_NAME, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG);
if (store->shmfd < 0)
{
INF("shm_open failed");
return EINA_FALSE;
}
return EINA_TRUE;
}
Eina_Bool
e_uuid_store_entry_del(uuid_t uuid)
{
struct uuid_table *table;
int i;
char uuid_string[37];
if (store == NULL) return EINA_FALSE;
table = store->table;
if (table == NULL) return EINA_FALSE;
/* Search through uuid list and delete if found */
for (i = 0; i < UUID_STORE_TABLE_SIZE -1; i++)
{
if (!uuid_compare(table->entries[i].uuid, uuid))
{
uuid_clear(table->entries[i].uuid);
table->entries[i].x = 0;
table->entries[i].x = 0;
table->entries[i].width = 0;
table->entries[i].heigth = 0;
table->entry_count--;
uuid_unparse(uuid, uuid_string);
DBG("Removed entry with UUID %s", uuid_string);
return EINA_TRUE;
}
}
uuid_unparse(uuid, uuid_string);
DBG("NOT removed entry with UUID %s. Entry not found.", uuid_string);
return EINA_FALSE;
}
/* FIXME: Think about having _add and _update functions instead only update */
Eina_Bool
e_uuid_store_entry_update(uuid_t uuid, E_Client *ec)
{
struct uuid_table *table;
int i, index = -1;
char uuid_string[37];
if (store == NULL) return EINA_FALSE;
table = store->table;
if (table == NULL) return EINA_FALSE;
/* Search through uuid list if it already exist if yes update */
for (i = 0; i < UUID_STORE_TABLE_SIZE -1; i++)
{
if (!uuid_compare(table->entries[i].uuid, uuid))
{
table->entries[i].x = ec->x;
table->entries[i].y = ec->y;
table->entries[i].width = ec->client.w;
table->entries[i].heigth = ec->client.h;
uuid_unparse(uuid, uuid_string);
DBG("Updated entry with UUID %s", uuid_string);
return EINA_TRUE;
}
}
/* Find first empty entry */
for (i = 0; i < UUID_STORE_TABLE_SIZE -1; i++)
{
if (uuid_is_null(table->entries[i].uuid))
index = i;
}
if (index == -1)
{
ERR("UUID table full");
return EINA_FALSE;
}
/* We do not have this UUID in the table yet. Create it */
table->entries[index].x = ec->x;
table->entries[index].y = ec->y;
table->entries[index].width = ec->client.w;
table->entries[index].heigth = ec->client.h;
uuid_copy(table->entries[index].uuid, uuid);
table->entry_count++;
uuid_unparse(table->entries[index].uuid, uuid_string);
DBG("Created entry with UUID %s", uuid_string);
return EINA_TRUE;
}

View File

@ -1,36 +0,0 @@
#ifndef E_UUID_STORE_H
#define E_UUID_STORE_H
/* vim:ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0
*/
#define UUID_STORE_TABLE_SIZE 100
struct table_entry {
uuid_t uuid;
/* data structure for per application properties */
Evas_Coord x, y;
Evas_Coord width, heigth;
unsigned int virtual_desktop;
int flags;
};
struct uuid_table {
int version; /* Version to allow future extensions */
unsigned int entry_count; /* Entry counter to allow excat memory consuptions needs? */
/* Global settings like current virtual desktop, screen setup, etc */
struct table_entry entries[UUID_STORE_TABLE_SIZE]; /* FIXME make this more adjustable */
};
struct uuid_store {
struct uuid_table *table;
int shmfd;
};
EINTERN int e_uuid_store_init(void);
EINTERN int e_uuid_store_shutdown(void);
E_API void e_uuid_dump(void);
E_API Eina_Bool e_uuid_store_reload(void);
E_API Eina_Bool e_uuid_store_entry_del(uuid_t uuid);
E_API Eina_Bool e_uuid_store_entry_update(uuid_t uuid, E_Client *ec);
#endif

View File

@ -1,43 +0,0 @@
#ifndef E_SESSION_RECOVERY_SERVER_PROTOCOL_H
#define E_SESSION_RECOVERY_SERVER_PROTOCOL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include "wayland-server.h"
struct wl_client;
struct wl_resource;
struct zwp_e_session_recovery;
extern const struct wl_interface zwp_e_session_recovery_interface;
struct zwp_e_session_recovery_interface {
/**
* provide_uuid - (none)
* @uuid: (none)
*/
void (*provide_uuid)(struct wl_client *client,
struct wl_resource *resource,
const char *uuid);
};
#define ZWP_E_SESSION_RECOVERY_UUID 0
#define ZWP_E_SESSION_RECOVERY_UUID_SINCE_VERSION 1
static inline void
zwp_e_session_recovery_send_uuid(struct wl_resource *resource_, const char *uuid)
{
wl_resource_post_event(resource_, ZWP_E_SESSION_RECOVERY_UUID, uuid);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -2,22 +2,31 @@
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_surface_interface;
static const struct wl_interface *types[] = {
&wl_surface_interface,
&wl_surface_interface,
NULL,
&wl_surface_interface,
NULL,
&wl_surface_interface,
NULL,
};
static const struct wl_message zwp_e_session_recovery_requests[] = {
{ "provide_uuid", "s", types + 0 },
{ "get_uuid", "o", types + 0 },
{ "set_uuid", "os", types + 1 },
{ "destroy_uuid", "os", types + 3 },
};
static const struct wl_message zwp_e_session_recovery_events[] = {
{ "uuid", "s", types + 0 },
{ "create_uuid", "os", types + 5 },
};
WL_EXPORT const struct wl_interface zwp_e_session_recovery_interface = {
"zwp_e_session_recovery", 1,
1, zwp_e_session_recovery_requests,
3, zwp_e_session_recovery_requests,
1, zwp_e_session_recovery_events,
};

View File

@ -0,0 +1,62 @@
#ifndef E_SESSION_RECOVERY_SERVER_PROTOCOL_H
#define E_SESSION_RECOVERY_SERVER_PROTOCOL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include "wayland-server.h"
struct wl_client;
struct wl_resource;
struct wl_surface;
struct zwp_e_session_recovery;
extern const struct wl_interface zwp_e_session_recovery_interface;
struct zwp_e_session_recovery_interface {
/**
* get_uuid - (none)
* @surface: (none)
*/
void (*get_uuid)(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface);
/**
* set_uuid - (none)
* @surface: (none)
* @uuid: (none)
*/
void (*set_uuid)(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface,
const char *uuid);
/**
* destroy_uuid - (none)
* @surface: (none)
* @uuid: (none)
*/
void (*destroy_uuid)(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface,
const char *uuid);
};
#define ZWP_E_SESSION_RECOVERY_CREATE_UUID 0
#define ZWP_E_SESSION_RECOVERY_CREATE_UUID_SINCE_VERSION 1
static inline void
zwp_e_session_recovery_send_create_uuid(struct wl_resource *resource_, struct wl_resource *surface, const char *uuid)
{
wl_resource_post_event(resource_, ZWP_E_SESSION_RECOVERY_CREATE_UUID, surface, uuid);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,10 +1,19 @@
<protocol name="e_session_recovery">
<interface name="zwp_e_session_recovery" version="1">
<request name="provide_uuid">
<request name="get_uuid">
<arg name="surface" type="object" interface="wl_surface"/>
</request>
<request name="set_uuid">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="uuid" type="string"/>
</request>
<event name="uuid">
<request name="destroy_uuid">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="uuid" type="string"/>
</request>
<event name="create_uuid">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="uuid" type="string"/>
</event>
</interface>