enlightenment/src/modules/wl_desktop_shell/e_mod_input_panel.c

337 lines
8.7 KiB
C

#define E_COMP_WL
#include "e.h"
#include "e_mod_main.h"
#include "e_input_method_protocol.h"
typedef struct _E_Input_Panel E_Input_Panel;
typedef struct _E_Input_Panel_Surface E_Input_Panel_Surface;
struct _E_Input_Panel
{
struct wl_resource *resource;
Eina_List *surfaces;
};
struct _E_Input_Panel_Surface
{
E_Client *ec;
Eina_Bool panel;
Eina_Bool showing;
};
static E_Input_Panel input_panel;
static Eina_List *handlers = NULL;
static struct wl_global *input_panel_global = NULL;
static void
_e_input_panel_surface_cb_toplevel_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *output_resource EINA_UNUSED, uint32_t position EINA_UNUSED)
{
E_Input_Panel_Surface *ips;
ips = wl_resource_get_user_data(resource);
ips->panel = EINA_FALSE;
}
static void
_e_input_panel_surface_cb_overlay_panel_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
E_Input_Panel_Surface *ips;
ips = wl_resource_get_user_data(resource);
ips->panel = EINA_TRUE;
}
static const struct wl_input_panel_surface_interface _e_input_panel_surface_implementation = {
_e_input_panel_surface_cb_toplevel_set,
_e_input_panel_surface_cb_overlay_panel_set
};
static void
_e_input_panel_surface_resource_destroy(struct wl_resource *resource)
{
E_Input_Panel_Surface *ips;
E_Client *ec;
ips = wl_resource_get_user_data(resource);
ec = ips->ec;
if (!e_object_is_del(E_OBJECT(ec)))
{
if (ec->comp_data->mapped)
{
if ((ec->comp_data->shell.surface) &&
(ec->comp_data->shell.unmap))
ec->comp_data->shell.unmap(ec->comp_data->shell.surface);
}
if (ec->parent)
{
ec->parent->transients =
eina_list_remove(ec->parent->transients, ec);
}
ec->comp_data->shell.surface = NULL;
}
input_panel.surfaces = eina_list_remove(input_panel.surfaces, ips);
free(ips);
}
static void
_e_input_panel_position_set(E_Client *ec, int w, int h)
{
int nx, ny;
int zx, zy, zw, zh;
e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
nx = zx + (zw - w) / 2;
ny = zy + zh - h;
e_client_util_move_without_frame(ec, nx, ny);
}
static void
_e_input_panel_surface_visible_update(E_Input_Panel_Surface *ips)
{
E_Client *ec;
ec = ips->ec;
if ((ips->showing) &&
(e_pixmap_usable_get(ec->pixmap)))
{
if (!ips->panel)
_e_input_panel_position_set(ec, ec->client.w, ec->client.h);
ec->visible = EINA_TRUE;
evas_object_geometry_set(ec->frame, ec->x, ec->y, ec->w, ec->h);
evas_object_show(ec->frame);
e_comp_object_damage(ec->frame, ec->x, ec->y, ec->w, ec->h);
}
else
{
ec->visible = EINA_FALSE;
evas_object_hide(ec->frame);
}
}
static void
_e_input_panel_surface_configure(struct wl_resource *resource, Evas_Coord x EINA_UNUSED, Evas_Coord y EINA_UNUSED, Evas_Coord w, Evas_Coord h)
{
E_Input_Panel_Surface *ips;
ips = wl_resource_get_user_data(resource);
e_client_util_resize_without_frame(ips->ec, w, h);
if (ips->showing)
_e_input_panel_surface_visible_update(ips);
}
static void
_e_input_panel_surface_map(struct wl_resource *resource)
{
E_Input_Panel_Surface *ips;
E_Client *ec;
ips = wl_resource_get_user_data(resource);
ec = ips->ec;
if (e_object_is_del(E_OBJECT(ec)))
return;
// NOTE: we need to set mapped, so that avoid showing evas_object and continue buffer's commit process.
if ((!ec->comp_data->mapped) && (e_pixmap_usable_get(ec->pixmap)))
ec->comp_data->mapped = EINA_TRUE;
}
static void
_e_input_panel_surface_unmap(struct wl_resource *resource)
{
E_Input_Panel_Surface *ips;
E_Client *ec;
ips = wl_resource_get_user_data(resource);
ec = ips->ec;
if (e_object_is_del(E_OBJECT(ec)))
return;
if (ec->comp_data->mapped)
{
ec->visible = EINA_FALSE;
evas_object_hide(ec->frame);
ec->comp_data->mapped = EINA_FALSE;
}
}
static void
_e_input_panel_cb_surface_get(struct wl_client *client, struct wl_resource *resource EINA_UNUSED, uint32_t id, struct wl_resource *surface_resource)
{
E_Client *ec;
E_Input_Panel_Surface *ips;
E_Comp_Client_Data *cd;
ec = wl_resource_get_user_data(surface_resource);
if (!ec)
{
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"No Client Set On Surface");
return;
}
cd = ec->comp_data;
if (!cd)
{
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"No Comp Data For Client");
return;
}
/* check for existing shell surface */
if (ec->comp_data->shell.surface)
{
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
"Client already has shell surface");
return;
}
ips = E_NEW(E_Input_Panel_Surface, 1);
if (!ips)
{
wl_client_post_no_memory(client);
return NULL;
}
cd->shell.surface = wl_resource_create(client,
&wl_input_panel_surface_interface,
1, id);
if (!cd->shell.surface)
{
wl_client_post_no_memory(client);
free(ips);
return NULL;
}
ips->ec = ec;
EC_CHANGED(ec);
if (!ec->new_client)
{
ec->new_client = EINA_TRUE;
e_comp->new_clients++;
}
if (ec->ignored)
e_client_unignore(ec);
/* set input panel client properties */
ec->borderless = EINA_TRUE;
ec->argb = EINA_TRUE;
ec->lock_border = EINA_TRUE;
ec->lock_focus_in = ec->lock_focus_out = EINA_TRUE;
ec->netwm.state.skip_taskbar = EINA_TRUE;
ec->netwm.state.skip_pager = EINA_TRUE;
ec->no_shape_cut = EINA_TRUE;
ec->border_size = 0;
ec->netwm.type = E_WINDOW_TYPE_UTILITY;
ec->comp_data->set_win_type = EINA_TRUE;
cd->surface = surface_resource;
cd->shell.configure_send = NULL;
cd->shell.configure = _e_input_panel_surface_configure;
cd->shell.ping = NULL;
cd->shell.map = _e_input_panel_surface_map;
cd->shell.unmap = _e_input_panel_surface_unmap;
wl_resource_set_implementation(cd->shell.surface,
&_e_input_panel_surface_implementation,
ips, _e_input_panel_surface_resource_destroy);
input_panel.surfaces = eina_list_append(input_panel.surfaces, ips);
}
static const struct wl_input_panel_interface _e_input_panel_implementation = {
_e_input_panel_cb_surface_get
};
static void
_e_input_panel_unbind(struct wl_resource *resource EINA_UNUSED)
{
input_panel.resource = NULL;
E_FREE_FUNC(input_panel.surfaces, eina_list_free);
}
static void
_e_input_panel_bind(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create(client, &wl_input_panel_interface, 1, id);
if (!resource)
{
wl_client_post_no_memory(client);
return;
}
if (input_panel.resource)
{
wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
"interface object already bound");
return;
}
input_panel.resource = resource;
wl_resource_set_implementation(resource,
&_e_input_panel_implementation,
NULL, _e_input_panel_unbind);
}
static Eina_Bool
_e_input_panel_cb_visible_change(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
{
E_Event_Text_Input_Panel_Visibility_Change *ev = event;
E_Input_Panel_Surface *ips;
Eina_List *l;
EINA_LIST_FOREACH(input_panel.surfaces, l, ips)
{
if (!ips->ec) continue;
ips->showing = ev->visible;
_e_input_panel_surface_visible_update(ips);
}
return ECORE_CALLBACK_RENEW;
}
EINTERN Eina_Bool
e_input_panel_init(void)
{
E_LIST_HANDLER_APPEND(handlers, E_EVENT_TEXT_INPUT_PANEL_VISIBILITY_CHANGE,
_e_input_panel_cb_visible_change, NULL);
// TODO: add signal handler - update input panel
input_panel_global = wl_global_create(e_comp->wl_comp_data->wl.disp,
&wl_input_panel_interface, 1,
NULL, _e_input_panel_bind);
if (!input_panel_global)
{
ERR("failed to create wl_global for input panel");
return EINA_FALSE;
}
return EINA_TRUE;
}
EINTERN void
e_input_panel_shutdown(void)
{
E_FREE_FUNC(input_panel_global, wl_global_destroy);
E_FREE_LIST(handlers, ecore_event_handler_del);
}