enlightenment/src/modules/illume/e_kbd.c

1103 lines
29 KiB
C

#include "e.h"
#include "e_kbd.h"
#include "e_mod_layout.h"
#include "e_cfg.h"
#include <E_Hal.h>
static void _e_kbd_layout_send(E_Kbd *kbd);
static Eina_List *handlers = NULL;
static Eina_List *kbds = NULL;
static Ecore_X_Atom atom_mb_im_invoker_command = 0;
static Ecore_X_Atom atom_mtp_im_invoker_command = 0;
static Eina_List *border_hooks = NULL;
static E_Border *focused_border = NULL;
static Ecore_X_Atom focused_vkbd_state = 0;
static E_Module *mod = NULL;
//#define ICONIFY_TO_HIDE
static Ecore_Job *_e_kbd_apply_all_job = NULL;
static void
_e_kbd_cb_apply_all_job(void *data __UNUSED__)
{
_e_mod_layout_apply_all();
_e_kbd_apply_all_job = NULL;
}
static void
_e_kbd_apply_all_job_queue(void)
{
if (_e_kbd_apply_all_job) ecore_job_del(_e_kbd_apply_all_job);
_e_kbd_apply_all_job = ecore_job_add(_e_kbd_cb_apply_all_job, NULL);
}
static void
_e_kbd_apply_all_job_queue_end(void)
{
if (_e_kbd_apply_all_job) ecore_job_del(_e_kbd_apply_all_job);
_e_kbd_apply_all_job = NULL;
}
static void
_e_kbd_border_hide(E_Border *bd)
{
if (!bd) return;
#ifdef ICONIFY_TO_HIDE
e_border_iconify(bd);
#else
e_border_hide(bd, 2);
#endif
}
static void
_e_kbd_border_show(E_Kbd *kbd, E_Border *bd)
{
if (!bd) return;
e_border_uniconify(bd);
if (kbd->fullscreen)
e_border_layer_set(kbd->border, 250);
else
e_border_layer_set(kbd->border, 100);
e_border_show(bd);
e_border_raise(bd);
}
static Eina_Bool
_e_kbd_cb_animate(void *data)
{
E_Kbd *kbd;
double t, v;
kbd = data;
t = ecore_loop_time_get() - kbd->start;
if (t > kbd->len) t = kbd->len;
if (kbd->len > 0.0)
{
v = t / kbd->len;
v = 1.0 - v;
v = v * v * v * v;
v = 1.0 - v;
}
else
{
t = kbd->len;
v = 1.0;
}
kbd->adjust = (kbd->adjust_end * v) + (kbd->adjust_start * (1.0 - v));
if (kbd->border)
{
e_border_fx_offset(kbd->border, 0, kbd->border->h - kbd->adjust);
}
if (t == kbd->len)
{
kbd->animator = NULL;
if (!kbd->visible)
{
_e_kbd_border_hide(kbd->border);
kbd->actually_visible = kbd->visible;
}
_e_kbd_apply_all_job_queue();
_e_kbd_layout_send(kbd);
return ECORE_CALLBACK_CANCEL;
}
return ECORE_CALLBACK_RENEW;
}
static void
_e_kbd_free(E_Kbd *kbd)
{
E_Border *bd;
kbds = eina_list_remove(kbds, kbd);
if (kbd->animator) ecore_animator_del(kbd->animator);
if (kbd->delay_hide) ecore_timer_del(kbd->delay_hide);
// FIXME: thought right - on shutdoiwn, this might point to freed data
// if (kbd->border) kbd->border->stolen = 0;
EINA_LIST_FREE(kbd->waiting_borders, bd)
bd->stolen = 0;
//I think this is right? someone who knows illume should probably verify
free(kbd);
}
static void
_e_kbd_slide(E_Kbd *kbd, int visible, double len)
{
_e_kbd_apply_all_job_queue();
kbd->start = ecore_loop_time_get();
kbd->len = len;
kbd->adjust_start = kbd->adjust;
kbd->adjust_end = 0;
if ((visible) && (kbd->border))
kbd->adjust_end = kbd->border->h;
if (!kbd->animator)
kbd->animator = ecore_animator_add(_e_kbd_cb_animate, kbd);
}
static void
_e_kbd_hide(E_Kbd *kbd)
{
if (kbd->visible) return;
if (illume_cfg->sliding.kbd.duration <= 0)
{
_e_kbd_border_hide(kbd->border);
kbd->actually_visible = kbd->visible;
_e_kbd_apply_all_job_queue();
_e_kbd_layout_send(kbd);
}
else
_e_kbd_slide(kbd, 0, (double)illume_cfg->sliding.kbd.duration / 1000.0);
}
static int
_e_kbd_border_is_keyboard(E_Border *bd)
{
if ((bd->client.vkbd.vkbd) || /* explicit hint that its a virtual keyboard */
/* legacy */
( /* trap the matchbox qwerty and multitap kbd's */
(((bd->client.icccm.title) && (!strcmp(bd->client.icccm.title, "Keyboard"))) ||
((bd->client.icccm.name) && ((!strcmp(bd->client.icccm.name, "multitap-pad")))))
&& (bd->client.netwm.state.skip_taskbar)
&& (bd->client.netwm.state.skip_pager)
)
)
return 1;
return 0;
}
static void
_e_kbd_border_adopt(E_Kbd *kbd, E_Border *bd)
{
kbd->border = bd;
bd->sticky = 1;
if (kbd->fullscreen)
e_border_layer_set(kbd->border, 250);
else
e_border_layer_set(kbd->border, 100);
if (!kbd->actually_visible)
{
e_border_fx_offset(kbd->border, 0, kbd->border->h);
_e_kbd_layout_send(kbd);
}
kbd->h = kbd->border->h;
}
static E_Kbd *
_e_kbd_by_border_get(E_Border *bd)
{
Eina_List *l, *l2;
E_Border *over;
E_Kbd *kbd;
if (!bd->stolen) return NULL;
EINA_LIST_FOREACH(kbds, l, kbd)
{
if (kbd->border == bd) return kbd;
EINA_LIST_FOREACH(kbd->waiting_borders, l2, over)
if (over == bd) return kbd;
}
return NULL;
}
static Eina_Bool
_e_kbd_cb_delayed_hide(void *data)
{
E_Kbd *kbd;
kbd = data;
_e_kbd_hide(kbd);
kbd->delay_hide = NULL;
return ECORE_CALLBACK_CANCEL;
}
static void
_e_kbd_all_enable(void)
{
Eina_List *l;
E_Kbd *kbd;
EINA_LIST_FOREACH(kbds, l, kbd)
e_kbd_enable(kbd);
}
static void
_e_kbd_all_disable(void)
{
Eina_List *l;
E_Kbd *kbd;
EINA_LIST_FOREACH(kbds, l, kbd)
e_kbd_disable(kbd);
}
static void
_e_kbd_all_show(void)
{
Eina_List *l;
E_Kbd *kbd;
EINA_LIST_FOREACH(kbds, l, kbd)
e_kbd_show(kbd);
}
static void
_e_kbd_all_layout_set(E_Kbd_Layout layout)
{
Eina_List *l;
E_Kbd *kbd;
EINA_LIST_FOREACH(kbds, l, kbd)
e_kbd_layout_set(kbd, layout);
}
static void
_e_kbd_all_hide(void)
{
Eina_List *l;
E_Kbd *kbd;
EINA_LIST_FOREACH(kbds, l, kbd)
e_kbd_hide(kbd);
}
static void
_e_kbd_all_toggle(void)
{
Eina_List *l;
E_Kbd *kbd;
EINA_LIST_FOREACH(kbds, l, kbd)
{
if (kbd->visible) e_kbd_hide(kbd);
else e_kbd_show(kbd);
}
}
static Eina_Bool
_e_kbd_cb_client_message(void *data __UNUSED__, int type __UNUSED__, void *event)
{
Ecore_X_Event_Client_Message *ev;
ev = event;
if ((ev->win == ecore_x_window_root_first_get()) &&
((ev->message_type == atom_mb_im_invoker_command) ||
(ev->message_type == atom_mtp_im_invoker_command)))
{
if (ev->data.l[0] == 1) _e_kbd_all_show();
else if (ev->data.l[0] == 2) _e_kbd_all_hide();
else if (ev->data.l[0] == 3) _e_kbd_all_toggle();
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_kbd_cb_border_remove(void *data __UNUSED__, int type __UNUSED__, void *event)
{
E_Event_Border_Remove *ev;
E_Kbd *kbd;
ev = event;
if (ev->border == focused_border)
{
focused_border = NULL;
focused_vkbd_state = 0;
return ECORE_CALLBACK_PASS_ON;
}
// if border is in a created kbd - unstore
kbd = _e_kbd_by_border_get(ev->border);
if (!kbd) return ECORE_CALLBACK_PASS_ON;
if (kbd->border == ev->border)
{
kbd->border = NULL;
if (kbd->waiting_borders)
{
E_Border *bd;
bd = kbd->waiting_borders->data;
kbd->waiting_borders = eina_list_remove_list(kbd->waiting_borders, kbd->waiting_borders);
_e_kbd_border_adopt(kbd, bd);
}
if (kbd->visible)
{
kbd->visible = 0;
_e_kbd_border_hide(kbd->border);
kbd->actually_visible = kbd->visible;
e_kbd_show(kbd);
}
_e_kbd_apply_all_job_queue();
}
else
kbd->waiting_borders = eina_list_remove(kbd->waiting_borders, ev->border);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_kbd_cb_border_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event)
{
E_Event_Border_Focus_In *ev;
ev = event;
if (_e_kbd_by_border_get(ev->border)) return ECORE_CALLBACK_PASS_ON;
// FIXME: if ev->border->client.vkbd.state == 0 then this app doesn't know
// how to request for a virtual keyboard and so we should have a manual
// override
if ((ev->border->need_fullscreen) || (ev->border->fullscreen))
e_kbd_fullscreen_set(ev->border->zone, 1);
else e_kbd_fullscreen_set(ev->border->zone, 0);
focused_border = ev->border;
focused_vkbd_state = ev->border->client.vkbd.state;
if (ev->border->client.vkbd.state == 0)
return 1;
if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF)
{
_e_kbd_all_layout_set(E_KBD_LAYOUT_NONE);
_e_kbd_all_hide();
return ECORE_CALLBACK_PASS_ON;
}
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA)
_e_kbd_all_layout_set(E_KBD_LAYOUT_ALPHA);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC)
_e_kbd_all_layout_set(E_KBD_LAYOUT_NUMERIC);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN)
_e_kbd_all_layout_set(E_KBD_LAYOUT_PIN);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER)
_e_kbd_all_layout_set(E_KBD_LAYOUT_PHONE_NUMBER);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX)
_e_kbd_all_layout_set(E_KBD_LAYOUT_HEX);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL)
_e_kbd_all_layout_set(E_KBD_LAYOUT_TERMINAL);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD)
_e_kbd_all_layout_set(E_KBD_LAYOUT_PASSWORD);
else
_e_kbd_all_layout_set(E_KBD_LAYOUT_DEFAULT);
_e_kbd_all_show();
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_kbd_cb_border_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event)
{
E_Event_Border_Focus_Out *ev;
ev = event;
if (_e_kbd_by_border_get(ev->border)) return ECORE_CALLBACK_PASS_ON;
if ((ev->border->need_fullscreen) || (ev->border->fullscreen))
e_kbd_fullscreen_set(ev->border->zone, 1);
else e_kbd_fullscreen_set(ev->border->zone, 0);
_e_kbd_all_layout_set(E_KBD_LAYOUT_NONE);
_e_kbd_all_hide();
focused_border = NULL;
focused_vkbd_state = 0;
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_kbd_cb_border_property(void *data __UNUSED__, int type __UNUSED__, void *event)
{
E_Event_Border_Property *ev;
ev = event;
if (_e_kbd_by_border_get(ev->border)) return ECORE_CALLBACK_PASS_ON;
if (!ev->border->focused) return ECORE_CALLBACK_PASS_ON;
/* nothing happened to vkbd prop - leave everything alone */
if ((ev->border == focused_border) &&
(ev->border->client.vkbd.state == focused_vkbd_state))
return ECORE_CALLBACK_PASS_ON;
focused_vkbd_state = ev->border->client.vkbd.state;
/* app doesn't know what to do - just leave everything as-is */
if ((ev->border->need_fullscreen) || (ev->border->fullscreen))
e_kbd_fullscreen_set(ev->border->zone, 1);
else e_kbd_fullscreen_set(ev->border->zone, 0);
if (ev->border->client.vkbd.state == 0)
return ECORE_CALLBACK_PASS_ON;
/* app wats kbd off - then kbd off it is */
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF)
_e_kbd_all_hide();
/* app wants something else than off... */
else
{
if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA)
_e_kbd_all_layout_set(E_KBD_LAYOUT_ALPHA);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC)
_e_kbd_all_layout_set(E_KBD_LAYOUT_NUMERIC);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN)
_e_kbd_all_layout_set(E_KBD_LAYOUT_PIN);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER)
_e_kbd_all_layout_set(E_KBD_LAYOUT_PHONE_NUMBER);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX)
_e_kbd_all_layout_set(E_KBD_LAYOUT_HEX);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL)
_e_kbd_all_layout_set(E_KBD_LAYOUT_TERMINAL);
else if (ev->border->client.vkbd.state == ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD)
_e_kbd_all_layout_set(E_KBD_LAYOUT_PASSWORD);
else
_e_kbd_all_layout_set(E_KBD_LAYOUT_DEFAULT);
_e_kbd_all_show();
}
return ECORE_CALLBACK_PASS_ON;
}
static void
_e_kbd_cb_border_hook_pre_post_fetch(void *data __UNUSED__, void *data2)
{
E_Border *bd;
if (!(bd = data2)) return;
// check if bd has special kbd properites - if so, store in created kbd
if (!bd->new_client) return;
if (_e_kbd_by_border_get(bd)) return;
if (_e_kbd_border_is_keyboard(bd))
{
Eina_List *l;
E_Kbd *kbd;
EINA_LIST_FOREACH(kbds, l, kbd)
{
if (!kbd->border)
{
_e_kbd_border_adopt(kbd, bd);
bd->stolen = 1;
if (bd->remember)
{
if (bd->bordername)
{
eina_stringshare_del(bd->bordername);
bd->bordername = NULL;
bd->client.border.changed = 1;
}
e_remember_unuse(bd->remember);
bd->remember = NULL;
}
eina_stringshare_replace(&bd->bordername, "borderless");
bd->client.border.changed = 1;
return;
}
else
{
kbd->waiting_borders = eina_list_append(kbd->waiting_borders, bd);
bd->stolen = 1;
if (bd->remember)
{
if (bd->bordername)
{
eina_stringshare_del(bd->bordername);
bd->bordername = NULL;
bd->client.border.changed = 1;
}
e_remember_unuse(bd->remember);
bd->remember = NULL;
}
eina_stringshare_replace(&bd->bordername, "borderless");
bd->client.border.changed = 1;
return;
}
}
}
}
static void
_e_kbd_cb_border_hook_post_fetch(void *data __UNUSED__, void *data2)
{
E_Border *bd;
if (!(bd = data2)) return;
// nothing - all done in _e_kbd_cb_border_hook_pre_post_fetch()
if (!_e_kbd_by_border_get(bd)) return;
}
static void
_e_kbd_cb_border_hook_post_border_assign(void *data __UNUSED__, void *data2)
{
E_Border *bd;
E_Kbd *kbd;
int pbx, pby, pbw, pbh;
if (!(bd = data2)) return; /* is there a point to this? */
kbd = _e_kbd_by_border_get(bd);
if (!kbd) return;
pbx = bd->x;
pby = bd->y;
pbw = bd->w;
pbh = bd->h;
bd->lock_border = 1;
bd->lock_client_location = 1;
bd->lock_client_size = 1;
bd->lock_client_desk = 1;
bd->lock_client_sticky = 1;
bd->lock_client_shade = 1;
bd->lock_client_maximize = 1;
bd->lock_user_location = 1;
bd->lock_user_size = 1;
bd->lock_user_desk = 1;
bd->lock_user_sticky = 1;
bd->lock_user_shade = 1;
bd->lock_user_maximize = 1;
bd->client.icccm.accepts_focus = 0;
bd->client.icccm.take_focus = 0;
bd->w = bd->zone->w;
bd->h = bd->zone->h;
bd->x = bd->zone->x;
bd->y = bd->zone->y + bd->zone->h - bd->h;
bd->client.w = bd->w - bd->client_inset.l - bd->client_inset.r;
bd->client.h = bd->h - bd->client_inset.t - bd->client_inset.b;
bd->changes.size = 1;
bd->placed = 1;
if ((pbx != bd->x) || (pby != bd->y) ||
(pbw != bd->w) || (pbh != bd->h))
{
if (bd->internal_ecore_evas)
{
ecore_evas_managed_move(bd->internal_ecore_evas,
bd->x + bd->fx.x + bd->client_inset.l,
bd->y + bd->fx.y + bd->client_inset.t);
}
ecore_x_icccm_move_resize_send(bd->client.win,
bd->x + bd->fx.x + bd->client_inset.l,
bd->y + bd->fx.y + bd->client_inset.t,
bd->client.w,
bd->client.h);
bd->changed = 1;
bd->changes.pos = 1;
bd->changes.size = 1;
}
if (bd == kbd->border)
{
if (kbd->h != bd->h)
{
if (kbd->animator)
{
if (kbd->adjust_end > kbd->adjust_start)
{
kbd->adjust_start -= (bd->h - kbd->h);
kbd->adjust_end -= (bd->h - kbd->h);
}
}
else if (!kbd->actually_visible)
e_border_fx_offset(kbd->border, 0, kbd->border->h);
kbd->h = bd->h;
}
}
}
static void
_e_kbd_cb_border_hook_end(void *data __UNUSED__, void *data2)
{
E_Kbd *kbd;
E_Border *bd;
if (!(bd = data2)) return;
kbd = _e_kbd_by_border_get(bd);
if (!kbd) return;
if (kbd->border == bd)
{
if (!kbd->actually_visible)
_e_kbd_border_hide(kbd->border);
}
else
_e_kbd_border_hide(bd);
}
static void
_e_kbd_layout_send(E_Kbd *kbd)
{
Ecore_X_Virtual_Keyboard_State type;
if ((kbd->actually_visible) && (!kbd->disabled))
{
type = ECORE_X_VIRTUAL_KEYBOARD_STATE_ON;
if (kbd->layout == E_KBD_LAYOUT_DEFAULT) type = ECORE_X_VIRTUAL_KEYBOARD_STATE_ON;
else if (kbd->layout == E_KBD_LAYOUT_ALPHA) type = ECORE_X_VIRTUAL_KEYBOARD_STATE_ALPHA;
else if (kbd->layout == E_KBD_LAYOUT_NUMERIC) type = ECORE_X_VIRTUAL_KEYBOARD_STATE_NUMERIC;
else if (kbd->layout == E_KBD_LAYOUT_PIN) type = ECORE_X_VIRTUAL_KEYBOARD_STATE_PIN;
else if (kbd->layout == E_KBD_LAYOUT_PHONE_NUMBER) type = ECORE_X_VIRTUAL_KEYBOARD_STATE_PHONE_NUMBER;
else if (kbd->layout == E_KBD_LAYOUT_HEX) type = ECORE_X_VIRTUAL_KEYBOARD_STATE_HEX;
else if (kbd->layout == E_KBD_LAYOUT_TERMINAL) type = ECORE_X_VIRTUAL_KEYBOARD_STATE_TERMINAL;
else if (kbd->layout == E_KBD_LAYOUT_PASSWORD) type = ECORE_X_VIRTUAL_KEYBOARD_STATE_PASSWORD;
else if (kbd->layout == E_KBD_LAYOUT_NONE) type = ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF;
}
else
type = ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF;
if (kbd->border)
ecore_x_e_virtual_keyboard_state_send(kbd->border->client.win, type);
}
// NOTES:
//
// on freerunner these are always there:
//
// /org/freedesktop/Hal/devices/platform_s3c2440_i2c_logicaldev_input
// /org/freedesktop/Hal/devices/platform_neo1973_button_0_logicaldev_input
//
// on desktop (built-in/ps2):
//
// /org/freedesktop/Hal/devices/platform_i8042_i8042_KBD_port_logicaldev_input
//
// on desktop (usb):
//
// /org/freedesktop/Hal/devices/usb_device_46d_c517_noserial_if0_logicaldev_input
//
// this:
//
// /org/freedesktop/Hal/devices/usb_device_a12_1_noserial_if0_bluetooth_hci_bluetooth_hci_logicaldev_input
//
// gets added for a bt kbd - unknown for usb.
//
// chances are i either need a way for a platform config to list devices
// known to be ebuilt-in keyboards but to be ignored when determining
// if a vkbd should be disabled or not... or... i need some other way
static E_DBus_Connection *_e_kbd_dbus_conn = NULL;
static E_DBus_Signal_Handler *_e_kbd_dbus_handler_dev_add = NULL;
static E_DBus_Signal_Handler *_e_kbd_dbus_handler_dev_del = NULL;
static E_DBus_Signal_Handler *_e_kbd_dbus_handler_dev_chg = NULL;
static Eina_List *_e_kbd_dbus_keyboards = NULL;
static int _e_kbd_dbus_have_real_keyboard = 0;
static Eina_List *_e_kbd_dbus_real_ignore = NULL;
static void
_e_kbd_dbus_keyboard_add(const char *udi)
{
const char *str;
Eina_List *l;
EINA_LIST_FOREACH(_e_kbd_dbus_keyboards, l, str)
if (!strcmp(str, udi)) return;
_e_kbd_dbus_keyboards = eina_list_append
(_e_kbd_dbus_keyboards, eina_stringshare_add(udi));
}
static void
_e_kbd_dbus_keyboard_del(const char *udi)
{
Eina_List *l;
char *str;
EINA_LIST_FOREACH(_e_kbd_dbus_keyboards, l, str)
if (!strcmp(str, udi))
{
eina_stringshare_del(str);
_e_kbd_dbus_keyboards = eina_list_remove_list(_e_kbd_dbus_keyboards, l);
return;
}
}
static void
_e_kbd_dbus_keyboard_eval(void)
{
int have_real = 0;
Eina_List *l, *ll;
const char *g, *gg;
have_real = eina_list_count(_e_kbd_dbus_keyboards);
EINA_LIST_FOREACH(_e_kbd_dbus_keyboards, l, g)
EINA_LIST_FOREACH(_e_kbd_dbus_real_ignore, ll, gg)
if (e_util_glob_match(g, gg))
{
have_real--;
break;
}
if (have_real != _e_kbd_dbus_have_real_keyboard)
{
_e_kbd_dbus_have_real_keyboard = have_real;
if (_e_kbd_dbus_have_real_keyboard)
_e_kbd_all_disable();
else
_e_kbd_all_enable();
}
}
static void
_e_kbd_dbus_cb_dev_input_keyboard(void *user_data __UNUSED__, void *reply_data, DBusError *error)
{
E_Hal_Manager_Find_Device_By_Capability_Return *ret = reply_data;
Eina_List *l;
char *device;
if ((!ret) || (!ret->strings)) return;
if (dbus_error_is_set(error))
{
dbus_error_free(error);
return;
}
EINA_LIST_FOREACH(ret->strings, l, device)
{
_e_kbd_dbus_keyboard_add(device);
_e_kbd_dbus_keyboard_eval();
}
}
static void
_e_kbd_dbus_cb_input_keyboard_is(void *user_data, void *reply_data, DBusError *error)
{
char *udi = user_data;
E_Hal_Device_Query_Capability_Return *ret = reply_data;
if (dbus_error_is_set(error))
{
dbus_error_free(error);
goto error;
}
if (ret && ret->boolean)
{
_e_kbd_dbus_keyboard_add(udi);
_e_kbd_dbus_keyboard_eval();
}
error:
eina_stringshare_del(udi);
}
static void
_e_kbd_dbus_cb_dev_add(void *data __UNUSED__, DBusMessage *msg)
{
DBusError err;
char *udi;
dbus_error_init(&err);
dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &udi, DBUS_TYPE_INVALID);
e_hal_device_query_capability(_e_kbd_dbus_conn, eina_stringshare_add(udi),
"input.keyboard",
_e_kbd_dbus_cb_input_keyboard_is,
(void*)eina_stringshare_add(udi));
}
static void
_e_kbd_dbus_cb_dev_del(void *data __UNUSED__, DBusMessage *msg)
{
DBusError err;
char *udi;
dbus_error_init(&err);
dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &udi, DBUS_TYPE_INVALID);
_e_kbd_dbus_keyboard_del(udi);
_e_kbd_dbus_keyboard_eval();
}
static void
_e_kbd_dbus_cb_cap_add(void *data __UNUSED__, DBusMessage *msg)
{
DBusError err;
char *udi, *capability;
dbus_error_init(&err);
dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &udi, DBUS_TYPE_STRING,
&capability, DBUS_TYPE_INVALID);
if (!strcmp(capability, "input.keyboard"))
{
_e_kbd_dbus_keyboard_add(udi);
_e_kbd_dbus_keyboard_eval();
}
}
static void
_e_kbd_dbus_ignore_keyboards_file_load(const char *file)
{
char buf[PATH_MAX];
FILE *f;
f = fopen(file, "r");
if (!f) return;
while (fgets(buf, sizeof(buf), f))
{
char *p;
int len;
if (buf[0] == '#') continue;
len = strlen(buf);
if (len > 0)
{
if (buf[len - 1] == '\n') buf[len - 1] = 0;
}
p = buf;
while (isspace(*p)) p++;
if (*p)
_e_kbd_dbus_real_ignore = eina_list_append
(_e_kbd_dbus_real_ignore, eina_stringshare_add(p));
}
fclose(f);
}
static void
_e_kbd_dbus_ignore_keyboards_load(void)
{
char buf[PATH_MAX];
e_user_dir_concat_static(buf, "keyboards/ignore_built_in_keyboards");
_e_kbd_dbus_ignore_keyboards_file_load(buf);
snprintf(buf, sizeof(buf), "%s/keyboards/ignore_built_in_keyboards", e_module_dir_get(mod));
_e_kbd_dbus_ignore_keyboards_file_load(buf);
}
static void
_e_kbd_dbus_real_kbd_init(void)
{
_e_kbd_dbus_have_real_keyboard = 0;
_e_kbd_dbus_ignore_keyboards_load();
_e_kbd_dbus_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
if (_e_kbd_dbus_conn)
{
e_hal_manager_find_device_by_capability(_e_kbd_dbus_conn, "input.keyboard",
_e_kbd_dbus_cb_dev_input_keyboard, NULL);
_e_kbd_dbus_handler_dev_add =
e_dbus_signal_handler_add(_e_kbd_dbus_conn, E_HAL_SENDER,
E_HAL_MANAGER_PATH,
E_HAL_MANAGER_INTERFACE,
"DeviceAdded", _e_kbd_dbus_cb_dev_add, NULL);
_e_kbd_dbus_handler_dev_del =
e_dbus_signal_handler_add(_e_kbd_dbus_conn, E_HAL_SENDER,
E_HAL_MANAGER_PATH,
E_HAL_MANAGER_INTERFACE,
"DeviceRemoved", _e_kbd_dbus_cb_dev_del, NULL);
_e_kbd_dbus_handler_dev_chg =
e_dbus_signal_handler_add(_e_kbd_dbus_conn, E_HAL_SENDER,
E_HAL_MANAGER_PATH,
E_HAL_MANAGER_INTERFACE,
"NewCapability", _e_kbd_dbus_cb_cap_add, NULL);
}
}
static void
_e_kbd_dbus_real_kbd_shutdown(void)
{
char *str;
if (_e_kbd_dbus_conn)
{
e_dbus_signal_handler_del(_e_kbd_dbus_conn,
_e_kbd_dbus_handler_dev_add);
e_dbus_signal_handler_del(_e_kbd_dbus_conn,
_e_kbd_dbus_handler_dev_del);
e_dbus_signal_handler_del(_e_kbd_dbus_conn,
_e_kbd_dbus_handler_dev_chg);
}
EINA_LIST_FREE(_e_kbd_dbus_real_ignore, str)
eina_stringshare_del(str);
EINA_LIST_FREE(_e_kbd_dbus_keyboards, str)
eina_stringshare_del(str);
_e_kbd_dbus_have_real_keyboard = 0;
}
EAPI int
e_kbd_init(E_Module *m)
{
mod = m;
focused_border = NULL;
focused_vkbd_state = 0;
atom_mb_im_invoker_command = ecore_x_atom_get("_MB_IM_INVOKER_COMMAND");
atom_mtp_im_invoker_command = ecore_x_atom_get("_MTP_IM_INVOKER_COMMAND");
handlers = eina_list_append(handlers,
ecore_event_handler_add
(ECORE_X_EVENT_CLIENT_MESSAGE,
_e_kbd_cb_client_message, NULL));
handlers = eina_list_append(handlers,
ecore_event_handler_add
(E_EVENT_BORDER_REMOVE,
_e_kbd_cb_border_remove, NULL));
handlers = eina_list_append(handlers,
ecore_event_handler_add
(E_EVENT_BORDER_FOCUS_IN,
_e_kbd_cb_border_focus_in, NULL));
handlers = eina_list_append(handlers,
ecore_event_handler_add
(E_EVENT_BORDER_FOCUS_OUT,
_e_kbd_cb_border_focus_out, NULL));
handlers = eina_list_append(handlers,
ecore_event_handler_add
(E_EVENT_BORDER_PROPERTY,
_e_kbd_cb_border_property, NULL));
border_hooks = eina_list_append(border_hooks,
e_border_hook_add
(E_BORDER_HOOK_EVAL_PRE_POST_FETCH,
_e_kbd_cb_border_hook_pre_post_fetch,
NULL));
border_hooks = eina_list_append(border_hooks,
e_border_hook_add
(E_BORDER_HOOK_EVAL_POST_FETCH,
_e_kbd_cb_border_hook_post_fetch,
NULL));
border_hooks = eina_list_append(border_hooks,
e_border_hook_add
(E_BORDER_HOOK_EVAL_POST_BORDER_ASSIGN,
_e_kbd_cb_border_hook_post_border_assign,
NULL));
border_hooks = eina_list_append(border_hooks,
e_border_hook_add
(E_BORDER_HOOK_EVAL_END,
_e_kbd_cb_border_hook_end,
NULL));
_e_kbd_dbus_real_kbd_init();
return 1;
}
EAPI int
e_kbd_shutdown(void)
{
E_Border_Hook *bh;
Ecore_Event_Handler *handle;
_e_kbd_apply_all_job_queue_end();
_e_kbd_dbus_real_kbd_shutdown();
EINA_LIST_FREE(border_hooks, bh)
e_border_hook_del(bh);
EINA_LIST_FREE(handlers, handle)
ecore_event_handler_del(handle);
focused_border = NULL;
focused_vkbd_state = 0;
mod = NULL;
return 1;
}
EAPI E_Kbd *
e_kbd_new(E_Zone *zone __UNUSED__, const char *themedir __UNUSED__, const char *syskbds __UNUSED__, const char *sysdicts __UNUSED__)
{
E_Kbd *kbd;
kbd = E_OBJECT_ALLOC(E_Kbd, E_KBD_TYPE, _e_kbd_free);
if (!kbd) return NULL;
kbds = eina_list_append(kbds, kbd);
kbd->layout = ECORE_X_VIRTUAL_KEYBOARD_STATE_ON;
return kbd;
}
EAPI void
e_kbd_enable(E_Kbd *kbd)
{
if (!kbd->disabled) return;
kbd->disabled = 0;
if (kbd->visible)
{
kbd->visible = 0;
e_kbd_show(kbd);
}
}
EAPI void
e_kbd_disable(E_Kbd *kbd)
{
if (kbd->disabled) return;
if (kbd->visible) e_kbd_hide(kbd);
kbd->disabled = 1;
}
EAPI void
e_kbd_show(E_Kbd *kbd)
{
if (kbd->delay_hide)
{
ecore_timer_del(kbd->delay_hide);
kbd->delay_hide = NULL;
}
if (kbd->visible) return;
kbd->visible = 1;
if (kbd->disabled) return;
kbd->actually_visible = kbd->visible;
_e_kbd_layout_send(kbd);
if (illume_cfg->sliding.kbd.duration <= 0)
{
if (kbd->border)
{
e_border_fx_offset(kbd->border, 0, 0);
_e_kbd_border_show(kbd, kbd->border);
}
kbd->actually_visible = kbd->visible;
_e_kbd_apply_all_job_queue();
}
else
{
if (kbd->border)
{
e_border_fx_offset(kbd->border, 0, kbd->border->h - kbd->adjust);
_e_kbd_border_show(kbd, kbd->border);
}
_e_kbd_slide(kbd, 1, (double)illume_cfg->sliding.kbd.duration / 1000.0);
}
}
EAPI void
e_kbd_layout_set(E_Kbd *kbd, E_Kbd_Layout layout)
{
kbd->layout = layout;
_e_kbd_layout_send(kbd);
}
EAPI void
e_kbd_hide(E_Kbd *kbd)
{
if (!kbd->visible) return;
kbd->visible = 0;
if (!kbd->delay_hide)
kbd->delay_hide = ecore_timer_add(0.2, _e_kbd_cb_delayed_hide, kbd);
}
EAPI void
e_kbd_safe_app_region_get(E_Zone *zone, int *x, int *y, int *w, int *h)
{
Eina_List *l;
if (x) *x = zone->x;
if (y) *y = zone->y;
if (w) *w = zone->w;
if (h) *h = zone->h;
for (l = kbds; l; l = l->next)
{
E_Kbd *kbd;
kbd = l->data;
if ((kbd->border) && (kbd->border->zone == zone))
{
if ((kbd->visible) && (!kbd->animator) && (!kbd->disabled))
/* out finished, not disabled */
{
if (h)
{
*h -= kbd->border->h;
if (*h < 0) *h = 0;
}
}
return;
}
}
}
EAPI void
e_kbd_fullscreen_set(E_Zone *zone __UNUSED__, int fullscreen)
{
Eina_List *l;
E_Kbd *kbd;
EINA_LIST_FOREACH(kbds, l, kbd)
if ((!!fullscreen) != kbd->fullscreen)
{
kbd->fullscreen = fullscreen;
if (kbd->border)
{
if (kbd->fullscreen)
e_border_layer_set(kbd->border, 250);
else
e_border_layer_set(kbd->border, 100);
}
}
}