diff --git a/AUTHORS b/AUTHORS index 6b0f204d4..e58a155ad 100644 --- a/AUTHORS +++ b/AUTHORS @@ -32,3 +32,4 @@ Sthitha Doyoun Kang Gwanglim Lee Thomas Gstädtner +q66 diff --git a/configure.ac b/configure.ac index cc8e4b572..fb1995a0e 100644 --- a/configure.ac +++ b/configure.ac @@ -797,6 +797,7 @@ AC_E_OPTIONAL_MODULE([shot], true) AC_E_OPTIONAL_MODULE([backlight], true) AC_E_OPTIONAL_MODULE([tasks], true) AC_E_OPTIONAL_MODULE([conf_randr], true) +AC_E_OPTIONAL_MODULE([xkbswitch], true) SUSPEND="" HIBERNATE="" @@ -951,9 +952,12 @@ src/modules/backlight/Makefile src/modules/backlight/module.desktop src/modules/tasks/Makefile src/modules/tasks/module.desktop +src/modules/xkbswitch/Makefile +src/modules/xkbswitch/module.desktop src/preload/Makefile data/Makefile data/images/Makefile +data/flags/Makefile data/input_methods/Makefile data/themes/Makefile data/themes/images/Makefile diff --git a/data/Makefile.am b/data/Makefile.am index b7a5119ff..782c2d9ef 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -7,5 +7,5 @@ xsession \ input_methods \ etc \ icons \ -backgrounds - +backgrounds \ +flags diff --git a/data/flags/Makefile.am b/data/flags/Makefile.am new file mode 100644 index 000000000..7667f1c49 --- /dev/null +++ b/data/flags/Makefile.am @@ -0,0 +1,97 @@ +MAINTAINERCLEANFILES = Makefile.in +filesdir = $(datadir)/enlightenment/data/flags +files_DATA = \ +ad_flag.png \ +af_flag.png \ +al_flag.png \ +am_flag.png \ +ara_flag.png \ +at_flag.png \ +az_flag.png \ +ba_flag.png \ +bd_flag.png \ +be_flag.png \ +bg_flag.png \ +brai_flag.png \ +br_flag.png \ +bt_flag.png \ +bw_flag.png \ +by_flag.png \ +ca_flag.png \ +cd_flag.png \ +ch_flag.png \ +cn_flag.png \ +cz_flag.png \ +de_flag.png \ +dk_flag.png \ +ee_flag.png \ +epo_flag.png \ +es_flag.png \ +et_flag.png \ +fi_flag.png \ +fo_flag.png \ +fr_flag.png \ +gb_flag.png \ +ge_flag.png \ +gh_flag.png \ +gn_flag.png \ +gr_flag.png \ +hr_flag.png \ +hu_flag.png \ +ie_flag.png \ +il_flag.png \ +in_flag.png \ +iq_flag.png \ +ir_flag.png \ +is_flag.png \ +it_flag.png \ +jp_flag.png \ +ke_flag.png \ +kg_flag.png \ +kh_flag.png \ +kr_flag.png \ +kz_flag.png \ +la_flag.png \ +latam_flag.png \ +lk_flag.png \ +lt_flag.png \ +lv_flag.png \ +ma_flag.png \ +mao_flag.png \ +me_flag.png \ +mk_flag.png \ +ml_flag.png \ +mm_flag.png \ +mn_flag.png \ +mt_flag.png \ +mv_flag.png \ +ng_flag.png \ +nl_flag.png \ +no_flag.png \ +np_flag.png \ +ph_flag.png \ +pk_flag.png \ +pl_flag.png \ +pt_flag.png \ +ro_flag.png \ +rs_flag.png \ +ru_flag.png \ +se_flag.png \ +si_flag.png \ +sk_flag.png \ +sn_flag.png \ +sy_flag.png \ +th_flag.png \ +tj_flag.png \ +tm_flag.png \ +tr_flag.png \ +tw_flag.png \ +tz_flag.png \ +ua_flag.png \ +unknown_flag.png \ +us_flag.png \ +uz_flag.png \ +vn_flag.png \ +za_flag.png + +EXTRA_DIST = $(files_DATA) diff --git a/data/flags/ad_flag.png b/data/flags/ad_flag.png new file mode 100644 index 000000000..a970afc3c Binary files /dev/null and b/data/flags/ad_flag.png differ diff --git a/data/flags/af_flag.png b/data/flags/af_flag.png new file mode 100644 index 000000000..84f583021 Binary files /dev/null and b/data/flags/af_flag.png differ diff --git a/data/flags/al_flag.png b/data/flags/al_flag.png new file mode 100644 index 000000000..fec5a7502 Binary files /dev/null and b/data/flags/al_flag.png differ diff --git a/data/flags/am_flag.png b/data/flags/am_flag.png new file mode 100644 index 000000000..74d914800 Binary files /dev/null and b/data/flags/am_flag.png differ diff --git a/data/flags/ara_flag.png b/data/flags/ara_flag.png new file mode 100644 index 000000000..c1b17643d Binary files /dev/null and b/data/flags/ara_flag.png differ diff --git a/data/flags/at_flag.png b/data/flags/at_flag.png new file mode 100644 index 000000000..c9851fe60 Binary files /dev/null and b/data/flags/at_flag.png differ diff --git a/data/flags/az_flag.png b/data/flags/az_flag.png new file mode 100644 index 000000000..1511ee05e Binary files /dev/null and b/data/flags/az_flag.png differ diff --git a/data/flags/ba_flag.png b/data/flags/ba_flag.png new file mode 100644 index 000000000..79920af51 Binary files /dev/null and b/data/flags/ba_flag.png differ diff --git a/data/flags/bd_flag.png b/data/flags/bd_flag.png new file mode 100644 index 000000000..975b54c68 Binary files /dev/null and b/data/flags/bd_flag.png differ diff --git a/data/flags/be_flag.png b/data/flags/be_flag.png new file mode 100644 index 000000000..43a9442d3 Binary files /dev/null and b/data/flags/be_flag.png differ diff --git a/data/flags/bg_flag.png b/data/flags/bg_flag.png new file mode 100644 index 000000000..c7b795738 Binary files /dev/null and b/data/flags/bg_flag.png differ diff --git a/data/flags/br_flag.png b/data/flags/br_flag.png new file mode 100644 index 000000000..98bba07aa Binary files /dev/null and b/data/flags/br_flag.png differ diff --git a/data/flags/brai_flag.png b/data/flags/brai_flag.png new file mode 100644 index 000000000..3eda749e9 Binary files /dev/null and b/data/flags/brai_flag.png differ diff --git a/data/flags/bt_flag.png b/data/flags/bt_flag.png new file mode 100644 index 000000000..3d0f0b01a Binary files /dev/null and b/data/flags/bt_flag.png differ diff --git a/data/flags/bw_flag.png b/data/flags/bw_flag.png new file mode 100644 index 000000000..d557d29b1 Binary files /dev/null and b/data/flags/bw_flag.png differ diff --git a/data/flags/by_flag.png b/data/flags/by_flag.png new file mode 100644 index 000000000..890148f2b Binary files /dev/null and b/data/flags/by_flag.png differ diff --git a/data/flags/ca_flag.png b/data/flags/ca_flag.png new file mode 100644 index 000000000..42c1babfa Binary files /dev/null and b/data/flags/ca_flag.png differ diff --git a/data/flags/cd_flag.png b/data/flags/cd_flag.png new file mode 100644 index 000000000..dff2fa1cb Binary files /dev/null and b/data/flags/cd_flag.png differ diff --git a/data/flags/ch_flag.png b/data/flags/ch_flag.png new file mode 100644 index 000000000..5d2937934 Binary files /dev/null and b/data/flags/ch_flag.png differ diff --git a/data/flags/cn_flag.png b/data/flags/cn_flag.png new file mode 100644 index 000000000..43c8498ae Binary files /dev/null and b/data/flags/cn_flag.png differ diff --git a/data/flags/cz_flag.png b/data/flags/cz_flag.png new file mode 100644 index 000000000..559efd62d Binary files /dev/null and b/data/flags/cz_flag.png differ diff --git a/data/flags/de_flag.png b/data/flags/de_flag.png new file mode 100644 index 000000000..cd29a19ff Binary files /dev/null and b/data/flags/de_flag.png differ diff --git a/data/flags/dk_flag.png b/data/flags/dk_flag.png new file mode 100644 index 000000000..4cf042cf7 Binary files /dev/null and b/data/flags/dk_flag.png differ diff --git a/data/flags/ee_flag.png b/data/flags/ee_flag.png new file mode 100644 index 000000000..35fcb0e85 Binary files /dev/null and b/data/flags/ee_flag.png differ diff --git a/data/flags/epo_flag.png b/data/flags/epo_flag.png new file mode 100644 index 000000000..dde003b0d Binary files /dev/null and b/data/flags/epo_flag.png differ diff --git a/data/flags/es_flag.png b/data/flags/es_flag.png new file mode 100644 index 000000000..ea801a381 Binary files /dev/null and b/data/flags/es_flag.png differ diff --git a/data/flags/et_flag.png b/data/flags/et_flag.png new file mode 100644 index 000000000..62fa8c148 Binary files /dev/null and b/data/flags/et_flag.png differ diff --git a/data/flags/fi_flag.png b/data/flags/fi_flag.png new file mode 100644 index 000000000..bd9e089b9 Binary files /dev/null and b/data/flags/fi_flag.png differ diff --git a/data/flags/fo_flag.png b/data/flags/fo_flag.png new file mode 100644 index 000000000..cb1615352 Binary files /dev/null and b/data/flags/fo_flag.png differ diff --git a/data/flags/fr_flag.png b/data/flags/fr_flag.png new file mode 100644 index 000000000..cd01be597 Binary files /dev/null and b/data/flags/fr_flag.png differ diff --git a/data/flags/gb_flag.png b/data/flags/gb_flag.png new file mode 100644 index 000000000..9246d8cc8 Binary files /dev/null and b/data/flags/gb_flag.png differ diff --git a/data/flags/ge_flag.png b/data/flags/ge_flag.png new file mode 100644 index 000000000..239b3a668 Binary files /dev/null and b/data/flags/ge_flag.png differ diff --git a/data/flags/gh_flag.png b/data/flags/gh_flag.png new file mode 100644 index 000000000..2e1ace276 Binary files /dev/null and b/data/flags/gh_flag.png differ diff --git a/data/flags/gn_flag.png b/data/flags/gn_flag.png new file mode 100644 index 000000000..0379766f1 Binary files /dev/null and b/data/flags/gn_flag.png differ diff --git a/data/flags/gr_flag.png b/data/flags/gr_flag.png new file mode 100644 index 000000000..e6ee4cbd6 Binary files /dev/null and b/data/flags/gr_flag.png differ diff --git a/data/flags/hr_flag.png b/data/flags/hr_flag.png new file mode 100644 index 000000000..675758750 Binary files /dev/null and b/data/flags/hr_flag.png differ diff --git a/data/flags/hu_flag.png b/data/flags/hu_flag.png new file mode 100644 index 000000000..dcbbc4396 Binary files /dev/null and b/data/flags/hu_flag.png differ diff --git a/data/flags/ie_flag.png b/data/flags/ie_flag.png new file mode 100644 index 000000000..33c3db8b7 Binary files /dev/null and b/data/flags/ie_flag.png differ diff --git a/data/flags/il_flag.png b/data/flags/il_flag.png new file mode 100644 index 000000000..0d801719b Binary files /dev/null and b/data/flags/il_flag.png differ diff --git a/data/flags/in_flag.png b/data/flags/in_flag.png new file mode 100644 index 000000000..697a0d02b Binary files /dev/null and b/data/flags/in_flag.png differ diff --git a/data/flags/iq_flag.png b/data/flags/iq_flag.png new file mode 100644 index 000000000..4fb13e728 Binary files /dev/null and b/data/flags/iq_flag.png differ diff --git a/data/flags/ir_flag.png b/data/flags/ir_flag.png new file mode 100644 index 000000000..c80febd59 Binary files /dev/null and b/data/flags/ir_flag.png differ diff --git a/data/flags/is_flag.png b/data/flags/is_flag.png new file mode 100644 index 000000000..d781a1232 Binary files /dev/null and b/data/flags/is_flag.png differ diff --git a/data/flags/it_flag.png b/data/flags/it_flag.png new file mode 100644 index 000000000..270d1666c Binary files /dev/null and b/data/flags/it_flag.png differ diff --git a/data/flags/jp_flag.png b/data/flags/jp_flag.png new file mode 100644 index 000000000..49af2cf85 Binary files /dev/null and b/data/flags/jp_flag.png differ diff --git a/data/flags/ke_flag.png b/data/flags/ke_flag.png new file mode 100644 index 000000000..461992875 Binary files /dev/null and b/data/flags/ke_flag.png differ diff --git a/data/flags/kg_flag.png b/data/flags/kg_flag.png new file mode 100644 index 000000000..a707e21d5 Binary files /dev/null and b/data/flags/kg_flag.png differ diff --git a/data/flags/kh_flag.png b/data/flags/kh_flag.png new file mode 100644 index 000000000..558fb0a75 Binary files /dev/null and b/data/flags/kh_flag.png differ diff --git a/data/flags/kr_flag.png b/data/flags/kr_flag.png new file mode 100644 index 000000000..ae035a4f8 Binary files /dev/null and b/data/flags/kr_flag.png differ diff --git a/data/flags/kz_flag.png b/data/flags/kz_flag.png new file mode 100644 index 000000000..b004cf5fd Binary files /dev/null and b/data/flags/kz_flag.png differ diff --git a/data/flags/la_flag.png b/data/flags/la_flag.png new file mode 100644 index 000000000..8a94ff18f Binary files /dev/null and b/data/flags/la_flag.png differ diff --git a/data/flags/latam_flag.png b/data/flags/latam_flag.png new file mode 100644 index 000000000..3480ad5c1 Binary files /dev/null and b/data/flags/latam_flag.png differ diff --git a/data/flags/lk_flag.png b/data/flags/lk_flag.png new file mode 100644 index 000000000..63d98f533 Binary files /dev/null and b/data/flags/lk_flag.png differ diff --git a/data/flags/lt_flag.png b/data/flags/lt_flag.png new file mode 100644 index 000000000..3b2704c7e Binary files /dev/null and b/data/flags/lt_flag.png differ diff --git a/data/flags/lv_flag.png b/data/flags/lv_flag.png new file mode 100644 index 000000000..e32b8fc24 Binary files /dev/null and b/data/flags/lv_flag.png differ diff --git a/data/flags/ma_flag.png b/data/flags/ma_flag.png new file mode 100644 index 000000000..8ed48d2c3 Binary files /dev/null and b/data/flags/ma_flag.png differ diff --git a/data/flags/mao_flag.png b/data/flags/mao_flag.png new file mode 100644 index 000000000..57053d499 Binary files /dev/null and b/data/flags/mao_flag.png differ diff --git a/data/flags/me_flag.png b/data/flags/me_flag.png new file mode 100644 index 000000000..cfee5ea8d Binary files /dev/null and b/data/flags/me_flag.png differ diff --git a/data/flags/mk_flag.png b/data/flags/mk_flag.png new file mode 100644 index 000000000..50815fa72 Binary files /dev/null and b/data/flags/mk_flag.png differ diff --git a/data/flags/ml_flag.png b/data/flags/ml_flag.png new file mode 100644 index 000000000..d0325baff Binary files /dev/null and b/data/flags/ml_flag.png differ diff --git a/data/flags/mm_flag.png b/data/flags/mm_flag.png new file mode 100644 index 000000000..10c3ea27e Binary files /dev/null and b/data/flags/mm_flag.png differ diff --git a/data/flags/mn_flag.png b/data/flags/mn_flag.png new file mode 100644 index 000000000..1f59c7f52 Binary files /dev/null and b/data/flags/mn_flag.png differ diff --git a/data/flags/mt_flag.png b/data/flags/mt_flag.png new file mode 100644 index 000000000..926144330 Binary files /dev/null and b/data/flags/mt_flag.png differ diff --git a/data/flags/mv_flag.png b/data/flags/mv_flag.png new file mode 100644 index 000000000..1cd95c43f Binary files /dev/null and b/data/flags/mv_flag.png differ diff --git a/data/flags/ng_flag.png b/data/flags/ng_flag.png new file mode 100644 index 000000000..919b3456c Binary files /dev/null and b/data/flags/ng_flag.png differ diff --git a/data/flags/nl_flag.png b/data/flags/nl_flag.png new file mode 100644 index 000000000..3b82622bf Binary files /dev/null and b/data/flags/nl_flag.png differ diff --git a/data/flags/no_flag.png b/data/flags/no_flag.png new file mode 100644 index 000000000..6e992f831 Binary files /dev/null and b/data/flags/no_flag.png differ diff --git a/data/flags/np_flag.png b/data/flags/np_flag.png new file mode 100644 index 000000000..3a38889c7 Binary files /dev/null and b/data/flags/np_flag.png differ diff --git a/data/flags/ph_flag.png b/data/flags/ph_flag.png new file mode 100644 index 000000000..32c32205f Binary files /dev/null and b/data/flags/ph_flag.png differ diff --git a/data/flags/pk_flag.png b/data/flags/pk_flag.png new file mode 100644 index 000000000..3e1dfe18c Binary files /dev/null and b/data/flags/pk_flag.png differ diff --git a/data/flags/pl_flag.png b/data/flags/pl_flag.png new file mode 100644 index 000000000..fd89ea3aa Binary files /dev/null and b/data/flags/pl_flag.png differ diff --git a/data/flags/pt_flag.png b/data/flags/pt_flag.png new file mode 100644 index 000000000..721bbb86a Binary files /dev/null and b/data/flags/pt_flag.png differ diff --git a/data/flags/ro_flag.png b/data/flags/ro_flag.png new file mode 100644 index 000000000..4b1213fa6 Binary files /dev/null and b/data/flags/ro_flag.png differ diff --git a/data/flags/rs_flag.png b/data/flags/rs_flag.png new file mode 100644 index 000000000..ea7757a7d Binary files /dev/null and b/data/flags/rs_flag.png differ diff --git a/data/flags/ru_flag.png b/data/flags/ru_flag.png new file mode 100644 index 000000000..856c01ecd Binary files /dev/null and b/data/flags/ru_flag.png differ diff --git a/data/flags/se_flag.png b/data/flags/se_flag.png new file mode 100644 index 000000000..b161f1bd2 Binary files /dev/null and b/data/flags/se_flag.png differ diff --git a/data/flags/si_flag.png b/data/flags/si_flag.png new file mode 100644 index 000000000..8b946e64b Binary files /dev/null and b/data/flags/si_flag.png differ diff --git a/data/flags/sk_flag.png b/data/flags/sk_flag.png new file mode 100644 index 000000000..bb8b380e1 Binary files /dev/null and b/data/flags/sk_flag.png differ diff --git a/data/flags/sn_flag.png b/data/flags/sn_flag.png new file mode 100644 index 000000000..98a9029e2 Binary files /dev/null and b/data/flags/sn_flag.png differ diff --git a/data/flags/sy_flag.png b/data/flags/sy_flag.png new file mode 100644 index 000000000..17575eca4 Binary files /dev/null and b/data/flags/sy_flag.png differ diff --git a/data/flags/th_flag.png b/data/flags/th_flag.png new file mode 100644 index 000000000..68029ee39 Binary files /dev/null and b/data/flags/th_flag.png differ diff --git a/data/flags/tj_flag.png b/data/flags/tj_flag.png new file mode 100644 index 000000000..5dca210a8 Binary files /dev/null and b/data/flags/tj_flag.png differ diff --git a/data/flags/tm_flag.png b/data/flags/tm_flag.png new file mode 100644 index 000000000..3b8d26104 Binary files /dev/null and b/data/flags/tm_flag.png differ diff --git a/data/flags/tr_flag.png b/data/flags/tr_flag.png new file mode 100644 index 000000000..037a41656 Binary files /dev/null and b/data/flags/tr_flag.png differ diff --git a/data/flags/tw_flag.png b/data/flags/tw_flag.png new file mode 100644 index 000000000..f89d56e18 Binary files /dev/null and b/data/flags/tw_flag.png differ diff --git a/data/flags/tz_flag.png b/data/flags/tz_flag.png new file mode 100644 index 000000000..45a8daf86 Binary files /dev/null and b/data/flags/tz_flag.png differ diff --git a/data/flags/ua_flag.png b/data/flags/ua_flag.png new file mode 100644 index 000000000..061135db5 Binary files /dev/null and b/data/flags/ua_flag.png differ diff --git a/data/flags/unknown_flag.png b/data/flags/unknown_flag.png new file mode 100644 index 000000000..2cee86839 Binary files /dev/null and b/data/flags/unknown_flag.png differ diff --git a/data/flags/us_flag.png b/data/flags/us_flag.png new file mode 100644 index 000000000..f1f8d096b Binary files /dev/null and b/data/flags/us_flag.png differ diff --git a/data/flags/uz_flag.png b/data/flags/uz_flag.png new file mode 100644 index 000000000..899f1781e Binary files /dev/null and b/data/flags/uz_flag.png differ diff --git a/data/flags/vn_flag.png b/data/flags/vn_flag.png new file mode 100644 index 000000000..15c1913cc Binary files /dev/null and b/data/flags/vn_flag.png differ diff --git a/data/flags/za_flag.png b/data/flags/za_flag.png new file mode 100644 index 000000000..dec515f48 Binary files /dev/null and b/data/flags/za_flag.png differ diff --git a/data/themes/default.edc b/data/themes/default.edc index 6fec1d56c..6aeaf7890 100644 --- a/data/themes/default.edc +++ b/data/themes/default.edc @@ -41314,4 +41314,139 @@ collections { } } } + + group + { + name: "modules/xkbswitch/main"; + max: 148 128; + + parts + { + part + { + name: "flag"; + type: SWALLOW; + mouse_events: 0; + + description + { + state: "default" 0.0; + align: 0.5 0.5; + } + } + + part + { + name: "event"; + type: RECT; + mouse_events: 1; + + description + { + state: "default" 0.0; + color: 255 255 255 0; + } + } + + part + { + name: "label"; + type: TEXT; + effect: SOFT_SHADOW; + mouse_events: 0; + + description + { + state: "default" 0.0; + align: 0.5 0.5; + + rel1 + { + relative: 0.5 0.5; + offset: 0 0; + } + + rel2 + { + relative: 0.5 0.5; + offset: 0 0; + } + + color: 255 255 255 255; + color3: 0 0 0 128; + + text + { + text: ""; + font: "Sans"; + size: 9; + align: 0.5 0.5; + min: 1 1; + text_class: "module_small"; + } + } + } + } + } + + group + { + name: "modules/xkbswitch/noflag"; + max: 148 128; + + parts + { + part + { + name: "event"; + type: RECT; + mouse_events: 1; + + description + { + state: "default" 0.0; + color: 255 255 255 0; + } + } + + part + { + name: "label"; + type: TEXT; + effect: SOFT_SHADOW; + mouse_events: 0; + + description + { + state: "default" 0.0; + align: 0.5 0.5; + + rel1 + { + relative: 0.5 0.5; + offset: 0 0; + } + + rel2 + { + relative: 0.5 0.5; + offset: 0 0; + } + + color: 255 255 255 255; + color3: 0 0 0 128; + + text + { + text: ""; + font: "Sans"; + size: 9; + align: 0.5 0.5; + min: 1 1; + text_class: "module_small"; + } + } + } + } + } } diff --git a/po/POTFILES.in b/po/POTFILES.in index e2f5046f7..186b52eea 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -246,3 +246,10 @@ src/modules/mixer/conf_module.c src/modules/mixer/e_mod_main.c src/modules/connman/e_mod_main.c src/modules/systray/e_mod_main.c +src/modules/shot/e_mod_main.c +src/modules/tasks/e_mod_main.c +src/modules/tasks/e_mod_config.c +src/modules/xkbswitch/e_mod_main.c +src/modules/xkbswitch/e_mod_config.c +src/modules/xkbswitch/e_mod_keybindings.c +src/modules/xkbswitch/e_mod_parse.c diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index 949fc6303..77a89435c 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -191,6 +191,10 @@ if USE_MODULE_TASKS SUBDIRS += tasks endif +if USE_MODULE_XKBSWITCH +SUBDIRS += xkbswitch +endif + #if HAVE_WAYLAND_DRM # SUBDIRS += wl_drm #endif diff --git a/src/modules/conf_display/e_int_config_display.c b/src/modules/conf_display/e_int_config_display.c index d6de603ee..e544464c7 100644 --- a/src/modules/conf_display/e_int_config_display.c +++ b/src/modules/conf_display/e_int_config_display.c @@ -5,14 +5,447 @@ * Give list some icons. */ -#define RANDR_11 ((1 << 16) | 1) - static void _fill_data (E_Config_Dialog_Data *cfdata); static void *_create_data (E_Config_Dialog *cfd); static void _free_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); static int _basic_check_changed (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); static int _basic_apply_data (E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); static Evas_Object *_basic_create_widgets (E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata); + +struct _E_Config_Dialog_Data +{ + E_Config_Dialog *cfd; + + Evas_Object *scr_list; + Evas_Object *res_list; + Evas_Object *policy_list; + + const char *cur_scr; + + int restore; + int orientation; + int flip_x; + int flip_y; +}; + +E_Config_Dialog * +e_int_config_display(E_Container *con, const char *params __UNUSED__) +{ + E_Config_Dialog *cfd; + E_Config_Dialog_View *v; + + if (e_config_dialog_find("E", "screen/screen_resolution")) return NULL; + v = E_NEW(E_Config_Dialog_View, 1); + v->create_cfdata = _create_data; + v->free_cfdata = _free_data; + v->basic.apply_cfdata = _basic_apply_data; + v->basic.create_widgets = _basic_create_widgets; + v->basic.check_changed = _basic_check_changed; + v->override_auto_apply = 1; + + cfd = e_config_dialog_new(con, _("Screen Resolution Settings"), + "E", "screen/screen_resolution", + "preferences-system-screen-resolution", 0, v, NULL); + return cfd; +} + +static void +_fill_data(E_Config_Dialog_Data *cfdata) +{ +} + +static void * +_create_data(E_Config_Dialog *cfd) +{ + E_Config_Dialog_Data *cfdata; + + cfdata = E_NEW(E_Config_Dialog_Data, 1); + _fill_data(cfdata); + cfdata->cfd = cfd; + return cfdata; +} + +static void +_free_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata) +{ + if (cfdata->cur_scr) eina_stringshare_del(cfdata->cur_scr); + E_FREE(cfdata); +} + +static int +_basic_check_changed(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata) +{ + return 1; +} + +static int +_basic_apply_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + return 1; +} + +static void +_res_get(E_Config_Dialog_Data *cfdata) +{ + Eina_List *l; + E_Randr_Output_Info *oi = NULL; + Ecore_X_Randr_Mode_Info *mode; + + e_widget_ilist_clear(cfdata->res_list); + if (!cfdata->cur_scr) return; + + if (e_randr_screen_info.rrvd_info.randr_info_12) + { + EINA_LIST_FOREACH + (e_randr_screen_info.rrvd_info.randr_info_12->outputs, l, oi) + { + char buf[512]; + + strncpy(buf, oi->name, sizeof(buf) - 1); + buf[oi->name_length] = 0; + if (!strcmp(buf, cfdata->cur_scr)) break; + oi = NULL; + } + } + if (!oi) return; + if (!oi->monitor) return; + + switch (oi->policy) + { + case ECORE_X_RANDR_OUTPUT_POLICY_ABOVE: + printf(" policy: ABOVE\n"); break; + case ECORE_X_RANDR_OUTPUT_POLICY_RIGHT: + printf(" policy: RIGHT\n"); break; + case ECORE_X_RANDR_OUTPUT_POLICY_BELOW: + printf(" policy: BELOW\n"); break; + case ECORE_X_RANDR_OUTPUT_POLICY_LEFT: + printf(" policy: LEFT\n"); break; + case ECORE_X_RANDR_OUTPUT_POLICY_CLONE: + printf(" policy: CLONE\n"); break; + case ECORE_X_RANDR_OUTPUT_POLICY_NONE: + printf(" policy: NONE\n"); break; + default: + printf(" policy: unknown\n"); break; + break; + } + if (oi->crtc) + { + mode = oi->crtc->current_mode; + if (mode) + { + if ((mode->hTotal > 0) && (mode->vTotal > 0) && (mode->dotClock > 0)) + { + double hz = (double)mode->dotClock / + (double)(mode->hTotal * mode->vTotal); + printf( " %ix%i %1.1fHz\n", mode->width, mode->height, hz); + } + } + printf(" geometry: %i %i %ix%i\n", + oi->crtc->geometry.x, oi->crtc->geometry.y, + oi->crtc->geometry.w, oi->crtc->geometry.h); + if (oi->crtc->current_orientation & ECORE_X_RANDR_ORIENTATION_ROT_0) + printf(" orient: 0\n"); + if (oi->crtc->current_orientation & ECORE_X_RANDR_ORIENTATION_ROT_90) + printf(" orient: 90\n"); + if (oi->crtc->current_orientation & ECORE_X_RANDR_ORIENTATION_ROT_180) + printf(" orient: 180\n"); + if (oi->crtc->current_orientation & ECORE_X_RANDR_ORIENTATION_ROT_270) + printf(" orient: 270\n"); + if (oi->crtc->current_orientation & ECORE_X_RANDR_ORIENTATION_FLIP_X) + printf(" orient: flip x\n"); + if (oi->crtc->current_orientation & ECORE_X_RANDR_ORIENTATION_FLIP_Y) + printf(" orient: flip y\n"); + printf(" can do:\n"); + if (oi->crtc->orientations & ECORE_X_RANDR_ORIENTATION_ROT_0) + printf(" orient: 0\n"); + if (oi->crtc->orientations & ECORE_X_RANDR_ORIENTATION_ROT_90) + printf(" orient: 90\n"); + if (oi->crtc->orientations & ECORE_X_RANDR_ORIENTATION_ROT_180) + printf(" orient: 180\n"); + if (oi->crtc->orientations & ECORE_X_RANDR_ORIENTATION_ROT_270) + printf(" orient: 270\n"); + if (oi->crtc->orientations & ECORE_X_RANDR_ORIENTATION_FLIP_X) + printf(" orient: flip x\n"); + if (oi->crtc->orientations & ECORE_X_RANDR_ORIENTATION_FLIP_Y) + printf(" orient: flip y\n"); + } + + printf(" monitor is %ix%i mm\n", + oi->monitor->size_mm.width, oi->monitor->size_mm.height); + + EINA_LIST_FOREACH(oi->monitor->modes, l, mode) + { + char buf[512]; + + if ((mode->hTotal > 0) && (mode->vTotal > 0) && (mode->dotClock > 0)) + { + double hz = (double)mode->dotClock / + (double)(mode->hTotal * mode->vTotal); + + snprintf(buf, sizeof(buf), "%ix%i %1.1fHz", + mode->width, mode->height, hz); + e_widget_ilist_append(cfdata->res_list, NULL, buf, NULL, cfdata, NULL); + } + } +} + +static void +_screens_select(void *data) +{ + E_Config_Dialog_Data *cfdata = data; + _res_get(cfdata); +} + +static void +_screens_get(E_Config_Dialog_Data *cfdata) +{ + Eina_List *l; + E_Randr_Output_Info *oi; + + if (e_randr_screen_info.rrvd_info.randr_info_12) + { + EINA_LIST_FOREACH + (e_randr_screen_info.rrvd_info.randr_info_12->outputs, l, oi) + { + char buf[512]; + + strncpy(buf, oi->name, sizeof(buf) - 1); + buf[oi->name_length] = 0; + printf("%s:\n", buf); + switch (oi->connection_status) + { + case ECORE_X_RANDR_CONNECTION_STATUS_CONNECTED: + printf(" connect: connected\n"); break; + case ECORE_X_RANDR_CONNECTION_STATUS_DISCONNECTED: + printf(" connect: disconnected\n"); break; + default: + printf(" connect: unknown\n"); break; + } + switch (oi->connector_type) + { + case ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DVI: + printf(" type DVI\n"); break; + case ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_HDMI_A: + printf(" type HDMI_A\n"); break; + case ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_HDMI_B: + printf(" type HDMI_B\n"); break; + case ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_MDDI: + printf(" type MDDI\n"); break; + case ECORE_X_RANDR_EDID_DISPLAY_INTERFACE_DISPLAY_PORT: + printf(" type DISPLAY_PORT\n"); break; + default: + printf(" type unknown\n"); break; + } + e_widget_ilist_append(cfdata->scr_list, NULL, buf, _screens_select, cfdata, buf); + } + } +} + +static Evas_Object * +_basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata) +{ + Evas_Object *o, *of, *ob, *ot; + E_Radio_Group *rg; + + o = e_widget_table_add(evas, 0); + + of = e_widget_framelist_add(evas, _("Outputs"), 0); + ob = e_widget_ilist_add(evas, 16, 16, &(cfdata->cur_scr)); + cfdata->scr_list = ob; + e_widget_size_min_set(ob, 128, 200); + e_widget_framelist_object_append(of, ob); + e_widget_table_object_append(o, of, 0, 0, 1, 1, 1, 1, 1, 1); + + of = e_widget_framelist_add(evas, _("Modes"), 0); + ob = e_widget_ilist_add(evas, 16, 16, NULL); + cfdata->res_list = ob; + e_widget_size_min_set(ob, 192, 200); + e_widget_framelist_object_append(of, ob); + e_widget_table_object_append(o, of, 1, 0, 1, 1, 1, 1, 1, 1); + + ob = e_widget_check_add(evas, _("Restore on login"), &cfdata->restore); + e_widget_table_object_append(o, ob, 1, 1, 2, 1, 1, 1, 0, 0); + + ot = e_widget_table_add(evas, 0); + of = e_widget_framelist_add(evas, _("Policy"), 0); + ob = e_widget_ilist_add(evas, 16, 16, NULL); + cfdata->policy_list = ob; + e_widget_size_min_set(ob, 100, 80); + e_widget_framelist_object_append(of, ob); + e_widget_table_object_append(ot, of, 0, 0, 1, 1, 1, 1, 1, 1); + + of = e_widget_framelist_add(evas, _("Rotation"), 0); + rg = e_widget_radio_group_new(&(cfdata->orientation)); + ob = e_widget_radio_icon_add(evas, NULL, "preferences-screen-normal", 24, 24, ECORE_X_RANDR_ORIENTATION_ROT_0, rg); + e_widget_framelist_object_append(of, ob); + ob = e_widget_radio_icon_add(evas, NULL, "preferences-screen-left", 24, 24, ECORE_X_RANDR_ORIENTATION_ROT_90, rg); + e_widget_framelist_object_append(of, ob); + ob = e_widget_radio_icon_add(evas, NULL, "preferences-screen-around", 24, 24, ECORE_X_RANDR_ORIENTATION_ROT_180, rg); + e_widget_framelist_object_append(of, ob); + ob = e_widget_radio_icon_add(evas, NULL, "preferences-screen-right", 24, 24, ECORE_X_RANDR_ORIENTATION_ROT_270, rg); + e_widget_framelist_object_append(of, ob); + e_widget_table_object_append(ot, of, 0, 1, 1, 1, 1, 0, 1, 0); + + of = e_widget_framelist_add(evas, _("Mirroring"), 0); + ob = e_widget_check_icon_add(evas, NULL, "preferences-screen-hflip", 24, 24, &(cfdata->flip_x)); + e_widget_framelist_object_append(of, ob); + ob = e_widget_check_icon_add(evas, NULL, "preferences-screen-vflip", 24, 24, &(cfdata->flip_y)); + e_widget_framelist_object_append(of, ob); + e_widget_table_object_append(ot, of, 0, 2, 1, 1, 1, 0, 1, 0); + + e_widget_table_object_append(o, ot, 2, 0, 1, 1, 1, 1, 1, 1); + e_dialog_resizable_set(cfd->dia, 1); + + _screens_get(cfdata); + return o; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#if 0 + + +/* + man = e_manager_current_get(); + sizes = ecore_x_randr_screen_primary_output_sizes_get(man->root, &s); + cfdata->has_rates = EINA_FALSE; + + if ((!sizes) || (s == 0)) + ecore_timer_add(0.5, _deferred_noxrandr_error, NULL); + else + { + ecore_x_randr_screen_primary_output_current_size_get(man->root, &cfdata->orig_size.width, &cfdata->orig_size.height, NULL, NULL, &cfdata->orig_size_index); + cfdata->orig_rate = ecore_x_randr_screen_primary_output_current_refresh_rate_get(man->root); + + for (i = 0; i < (s - 1); i++) + { + Resolution * res; + Ecore_X_Randr_Refresh_Rate * rates; + int r = 0, j; + + res = E_NEW(Resolution, 1); + if (!res) continue; + + res->size.width = sizes[i].width; + res->size.height = sizes[i].height; + res->size_index = i; + rates = ecore_x_randr_screen_primary_output_refresh_rates_get(man->root, i, &r); + for (j = 0; j < r; j++) + { + Ecore_X_Randr_Refresh_Rate * rt; + + cfdata->has_rates = EINA_TRUE; + rt = E_NEW(Ecore_X_Randr_Refresh_Rate, 1); + if (!rt) continue; + *rt = rates[j]; + res->rates = eina_list_append(res->rates, rt); + } + if (rates) E_FREE(rates); + cfdata->resolutions = eina_list_append(cfdata->resolutions, res); + } + + cfdata->resolutions = eina_list_sort(cfdata->resolutions, + eina_list_count(cfdata->resolutions), _sort_resolutions); + cfdata->resolutions = eina_list_reverse(cfdata->resolutions); + + _load_resolutions(cfdata); + if (!cfdata->has_rates) + ecore_timer_add(0.5, _deferred_norates_error, NULL); + } + + E_FREE(sizes); + + _load_rates(cfdata); + */ + +# define RANDR_11 ((1 << 16) | 1) + static void _load_resolutions (E_Config_Dialog_Data *cfdata); static void _load_rates (E_Config_Dialog_Data *cfdata); static void _ilist_item_change (void *data); @@ -40,192 +473,6 @@ struct _SureBox E_Config_Dialog_Data *cfdata; }; -struct _E_Config_Dialog_Data -{ - E_Config_Dialog *cfd; - Eina_List *resolutions; - Ecore_X_Randr_Screen_Size orig_size; - int orig_size_index; - Ecore_X_Randr_Refresh_Rate orig_rate; - int orig_orientation; - int orig_flip; - int restore; - int can_rotate; - int can_flip; - int orientation; - int flip; - int flip_x; - int flip_y; - Eina_Bool has_rates; - - Evas_Object *rate_list; - Evas_Object *res_list; - SureBox *surebox; -}; - -static void -_surebox_dialog_cb_delete(E_Win *win) -{ - E_Dialog *dia; - SureBox *sb; - E_Config_Dialog *cfd; - - dia = win->data; - sb = dia->data; - sb->cfdata->surebox = NULL; - cfd = sb->cfdata->cfd; - if (sb->timer) ecore_timer_del(sb->timer); - sb->timer = NULL; - free(sb); - e_object_del(E_OBJECT(dia)); - e_object_unref(E_OBJECT(cfd)); -} - -static void -_surebox_dialog_cb_yes(void *data, E_Dialog *dia) -{ - SureBox *sb; - - sb = data; - - if (sb->cfdata->restore) - e_randr_11_store_configuration(E_RANDR_CONFIGURATION_STORE_ALL); - - _fill_data(sb->cfdata); - _load_resolutions(sb->cfdata); - /* No need to load rates as the currently selected resolution has not been - * changed since last selection. */ - if (dia) _surebox_dialog_cb_delete(dia->win); -} - -static void -_surebox_dialog_cb_no(void *data, E_Dialog *dia) -{ - SureBox *sb; - - sb = data; - ecore_x_randr_screen_primary_output_refresh_rate_set(sb->dia->win->container->manager->root, - sb->cfdata->orig_size_index, sb->cfdata->orig_rate); - _load_resolutions(sb->cfdata); - _load_rates(sb->cfdata); - _surebox_dialog_cb_delete(dia->win); -} - -static void -_surebox_text_fill(SureBox *sb) -{ - char buf[4096]; - - if (!sb->dia) return; - if (sb->iterations > 1) - { - if (sb->cfdata->has_rates) - snprintf(buf, sizeof(buf), - _("Does this look OK? Save if it does, or Restore if not.
" - "If you do not press a button, the old resolution of
" - "%dx%d at %d Hz will be restored in %d seconds."), - sb->cfdata->orig_size.width, sb->cfdata->orig_size.height, - sb->cfdata->orig_rate, sb->iterations); - else - snprintf(buf, sizeof(buf), - _("Does this look OK? Save if it does, or Restore if not.
" - "If you do not press a button, the old resolution of
" - "%dx%d will be restored in %d seconds."), - sb->cfdata->orig_size.width, sb->cfdata->orig_size.height, - sb->iterations); - } - else - { - if (sb->cfdata->has_rates) - snprintf(buf, sizeof(buf), - _("Does this look OK? Save if it does, or Restore if not.
" - "If you do not press a button, the old resolution of
" - "%dx%d at %d Hz will be restored IMMEDIATELY."), - sb->cfdata->orig_size.width, sb->cfdata->orig_size.height, - sb->cfdata->orig_rate); - else - snprintf(buf, sizeof(buf), - _("Does this look OK? Save if it does, or Restore if not.
" - "If you do not press a button, the old resolution of
" - "%dx%d will be restored IMMEDIATELY."), - sb->cfdata->orig_size.width, sb->cfdata->orig_size.height); - } - e_dialog_text_set(sb->dia, buf); -} - -static Eina_Bool -_surebox_timer_cb(void *data) -{ - SureBox *sb; - - sb = data; - sb->iterations--; - _surebox_text_fill(sb); - if (sb->iterations == 0) - { - _surebox_dialog_cb_no(sb, sb->dia); - return ECORE_CALLBACK_CANCEL; - } - return ECORE_CALLBACK_RENEW; -} - -static SureBox * -_surebox_new(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) -{ - SureBox *sb; - - sb = E_NEW(SureBox, 1); - sb->dia = e_dialog_new(cfd->con, "E", "_display_res_sure_dialog"); - sb->timer = ecore_timer_add(1.0, _surebox_timer_cb, sb); - sb->iterations = 15; - sb->cfd = cfd; - sb->cfdata = cfdata; - cfdata->surebox = sb; - sb->dia->data = sb; - e_dialog_title_set(sb->dia, _("Resolution change")); - e_dialog_icon_set(sb->dia, "preferences-system-screen-resolution", 48); - _surebox_text_fill(sb); - e_win_delete_callback_set(sb->dia->win, _surebox_dialog_cb_delete); - e_dialog_button_add(sb->dia, _("Save"), NULL, _surebox_dialog_cb_yes, sb); - e_dialog_button_add(sb->dia, _("Restore"), NULL, _surebox_dialog_cb_no, sb); - e_dialog_button_focus_num(sb->dia, 1); - e_win_centered_set(sb->dia->win, 1); - e_win_borderless_set(sb->dia->win, 1); - e_win_layer_set(sb->dia->win, 6); - e_win_sticky_set(sb->dia->win, 1); - e_dialog_show(sb->dia); - e_object_ref(E_OBJECT(cfd)); - return sb; -} - -E_Config_Dialog * -e_int_config_display(E_Container *con, const char *params __UNUSED__) -{ - E_Config_Dialog *cfd; - E_Config_Dialog_View *v; - - if (!ecore_x_randr_query()) - { - ecore_timer_add(0.5, _deferred_noxrandr_error, NULL); - fprintf(stderr, "XRandR not present on this display.\n"); - return NULL; - } - - if (e_config_dialog_find("E", "screen/screen_resolution")) return NULL; - v = E_NEW(E_Config_Dialog_View, 1); - v->create_cfdata = _create_data; - v->free_cfdata = _free_data; - v->basic.apply_cfdata = _basic_apply_data; - v->basic.create_widgets = _basic_create_widgets; - v->basic.check_changed = _basic_check_changed; - v->override_auto_apply = 1; - - cfd = e_config_dialog_new(con, _("Screen Resolution Settings"), - "E", "screen/screen_resolution", - "preferences-system-screen-resolution", 0, v, NULL); - return cfd; -} - static void _fill_data(E_Config_Dialog_Data *cfdata) { @@ -261,17 +508,6 @@ _fill_data(E_Config_Dialog_Data *cfdata) } } -static void * -_create_data(E_Config_Dialog *cfd) -{ - E_Config_Dialog_Data *cfdata; - - cfdata = E_NEW(E_Config_Dialog_Data, 1); - _fill_data(cfdata); - cfdata->cfd = cfd; - return cfdata; -} - static void _free_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata) { @@ -370,127 +606,9 @@ _basic_apply_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) cfdata->orig_orientation = cfdata->orientation; cfdata->orig_flip = cfdata->flip; } - return 1; } -static Evas_Object * -_basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata) -{ - Evas_Object *o, *of, *ob, *ot; - E_Radio_Group *rg; - E_Manager *man; - Ecore_X_Randr_Screen_Size_MM *sizes; - int i, s; - - o = e_widget_table_add(evas, 0); - - of = e_widget_framelist_add(evas, _("Resolution"), 0); - ob = e_widget_ilist_add(evas, 16, 16, NULL); - cfdata->res_list = ob; - e_widget_size_min_set(ob, 170, 215); - e_widget_framelist_object_append(of, ob); - e_widget_table_object_append(o, of, 0, 0, 1, 1, 1, 1, 1, 1); - - ob = e_widget_check_add(evas, _("Restore on login"), &cfdata->restore); - e_widget_table_object_append(o, ob, 0, 1, 2, 1, 1, 1, 0, 0); - - ot = e_widget_table_add(evas, 0); - of = e_widget_framelist_add(evas, _("Refresh"), 0); - ob = e_widget_ilist_add(evas, 16, 16, NULL); - cfdata->rate_list = ob; - e_widget_size_min_set(ob, 100, 80); - e_widget_framelist_object_append(of, ob); - e_widget_table_object_append(ot, of, 0, 0, 1, 1, 1, 1, 1, 1); - - man = e_manager_current_get(); - sizes = ecore_x_randr_screen_primary_output_sizes_get(man->root, &s); - cfdata->has_rates = EINA_FALSE; - - if ((!sizes) || (s == 0)) - ecore_timer_add(0.5, _deferred_noxrandr_error, NULL); - else - { - ecore_x_randr_screen_primary_output_current_size_get(man->root, &cfdata->orig_size.width, &cfdata->orig_size.height, NULL, NULL, &cfdata->orig_size_index); - cfdata->orig_rate = ecore_x_randr_screen_primary_output_current_refresh_rate_get(man->root); - - for (i = 0; i < (s - 1); i++) - { - Resolution * res; - Ecore_X_Randr_Refresh_Rate * rates; - int r = 0, j; - - res = E_NEW(Resolution, 1); - if (!res) continue; - - res->size.width = sizes[i].width; - res->size.height = sizes[i].height; - res->size_index = i; - rates = ecore_x_randr_screen_primary_output_refresh_rates_get(man->root, i, &r); - for (j = 0; j < r; j++) - { - Ecore_X_Randr_Refresh_Rate * rt; - - cfdata->has_rates = EINA_TRUE; - rt = E_NEW(Ecore_X_Randr_Refresh_Rate, 1); - if (!rt) continue; - *rt = rates[j]; - res->rates = eina_list_append(res->rates, rt); - } - if (rates) E_FREE(rates); - cfdata->resolutions = eina_list_append(cfdata->resolutions, res); - } - - cfdata->resolutions = eina_list_sort(cfdata->resolutions, - eina_list_count(cfdata->resolutions), _sort_resolutions); - cfdata->resolutions = eina_list_reverse(cfdata->resolutions); - - _load_resolutions(cfdata); - if (!cfdata->has_rates) - ecore_timer_add(0.5, _deferred_norates_error, NULL); - } - - E_FREE(sizes); - - _load_rates(cfdata); - - if (cfdata->can_rotate) - { - of = e_widget_framelist_add(evas, _("Rotation"), 0); - rg = e_widget_radio_group_new(&(cfdata->orientation)); - ob = e_widget_radio_icon_add(evas, NULL, "preferences-screen-normal", 24, 24, ECORE_X_RANDR_ORIENTATION_ROT_0, rg); - e_widget_framelist_object_append(of, ob); - if (!(cfdata->can_rotate & ECORE_X_RANDR_ORIENTATION_ROT_0)) e_widget_disabled_set(ob, 1); - ob = e_widget_radio_icon_add(evas, NULL, "preferences-screen-left", 24, 24, ECORE_X_RANDR_ORIENTATION_ROT_90, rg); - e_widget_framelist_object_append(of, ob); - if (!(cfdata->can_rotate & ECORE_X_RANDR_ORIENTATION_ROT_90)) e_widget_disabled_set(ob, 1); - ob = e_widget_radio_icon_add(evas, NULL, "preferences-screen-around", 24, 24, ECORE_X_RANDR_ORIENTATION_ROT_180, rg); - e_widget_framelist_object_append(of, ob); - if (!(cfdata->can_rotate & ECORE_X_RANDR_ORIENTATION_ROT_180)) e_widget_disabled_set(ob, 1); - ob = e_widget_radio_icon_add(evas, NULL, "preferences-screen-right", 24, 24, ECORE_X_RANDR_ORIENTATION_ROT_270, rg); - e_widget_framelist_object_append(of, ob); - if (!(cfdata->can_rotate & ECORE_X_RANDR_ORIENTATION_ROT_270)) e_widget_disabled_set(ob, 1); - e_widget_table_object_append(ot, of, 0, 1, 1, 1, 1, 0, 1, 0); - } - - if (cfdata->can_flip) - { - of = e_widget_framelist_add(evas, _("Mirroring"), 0); - ob = e_widget_check_icon_add(evas, NULL, "preferences-screen-hflip", 24, 24, &(cfdata->flip_x)); - e_widget_framelist_object_append(of, ob); - if (!(cfdata->can_flip & ECORE_X_RANDR_ORIENTATION_FLIP_X)) e_widget_disabled_set(ob, 1); - ob = e_widget_check_icon_add(evas, NULL, "preferences-screen-vflip", 24, 24, &(cfdata->flip_y)); - e_widget_framelist_object_append(of, ob); - if (!(cfdata->can_flip & ECORE_X_RANDR_ORIENTATION_FLIP_Y)) - e_widget_disabled_set(ob, 1); - e_widget_table_object_append(ot, of, 0, 2, 1, 1, 1, 0, 1, 0); - } - - e_widget_table_object_append(o, ot, 1, 0, 1, 1, 1, 1, 1, 1); - e_dialog_resizable_set(cfd->dia, 1); - return o; -} - static int _sort_resolutions(const void *d1, const void *d2) { @@ -642,3 +760,140 @@ _deferred_norates_error(void *data __UNUSED__) "the resolution, which may cause damage to your screen.")); return ECORE_CALLBACK_CANCEL; } + + +static void +_surebox_dialog_cb_delete(E_Win *win) +{ + E_Dialog *dia; + SureBox *sb; + E_Config_Dialog *cfd; + + dia = win->data; + sb = dia->data; + sb->cfdata->surebox = NULL; + cfd = sb->cfdata->cfd; + if (sb->timer) ecore_timer_del(sb->timer); + sb->timer = NULL; + free(sb); + e_object_del(E_OBJECT(dia)); + e_object_unref(E_OBJECT(cfd)); +} + +static void +_surebox_dialog_cb_yes(void *data, E_Dialog *dia) +{ + SureBox *sb; + + sb = data; + + if (sb->cfdata->restore) + e_randr_11_store_configuration(E_RANDR_CONFIGURATION_STORE_ALL); + + _fill_data(sb->cfdata); + _load_resolutions(sb->cfdata); + /* No need to load rates as the currently selected resolution has not been + * changed since last selection. */ + if (dia) _surebox_dialog_cb_delete(dia->win); +} + +static void +_surebox_dialog_cb_no(void *data, E_Dialog *dia) +{ + SureBox *sb; + + sb = data; + ecore_x_randr_screen_primary_output_refresh_rate_set(sb->dia->win->container->manager->root, + sb->cfdata->orig_size_index, sb->cfdata->orig_rate); + _load_resolutions(sb->cfdata); + _load_rates(sb->cfdata); + _surebox_dialog_cb_delete(dia->win); +} + +static void +_surebox_text_fill(SureBox *sb) +{ + char buf[4096]; + + if (!sb->dia) return; + if (sb->iterations > 1) + { + if (sb->cfdata->has_rates) + snprintf(buf, sizeof(buf), + _("Does this look OK? Save if it does, or Restore if not.
" + "If you do not press a button, the old resolution of
" + "%dx%d at %d Hz will be restored in %d seconds."), + sb->cfdata->orig_size.width, sb->cfdata->orig_size.height, + sb->cfdata->orig_rate, sb->iterations); + else + snprintf(buf, sizeof(buf), + _("Does this look OK? Save if it does, or Restore if not.
" + "If you do not press a button, the old resolution of
" + "%dx%d will be restored in %d seconds."), + sb->cfdata->orig_size.width, sb->cfdata->orig_size.height, + sb->iterations); + } + else + { + if (sb->cfdata->has_rates) + snprintf(buf, sizeof(buf), + _("Does this look OK? Save if it does, or Restore if not.
" + "If you do not press a button, the old resolution of
" + "%dx%d at %d Hz will be restored IMMEDIATELY."), + sb->cfdata->orig_size.width, sb->cfdata->orig_size.height, + sb->cfdata->orig_rate); + else + snprintf(buf, sizeof(buf), + _("Does this look OK? Save if it does, or Restore if not.
" + "If you do not press a button, the old resolution of
" + "%dx%d will be restored IMMEDIATELY."), + sb->cfdata->orig_size.width, sb->cfdata->orig_size.height); + } + e_dialog_text_set(sb->dia, buf); +} + +static Eina_Bool +_surebox_timer_cb(void *data) +{ + SureBox *sb; + + sb = data; + sb->iterations--; + _surebox_text_fill(sb); + if (sb->iterations == 0) + { + _surebox_dialog_cb_no(sb, sb->dia); + return ECORE_CALLBACK_CANCEL; + } + return ECORE_CALLBACK_RENEW; +} + +static SureBox * +_surebox_new(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata) +{ + SureBox *sb; + + sb = E_NEW(SureBox, 1); + sb->dia = e_dialog_new(cfd->con, "E", "_display_res_sure_dialog"); + sb->timer = ecore_timer_add(1.0, _surebox_timer_cb, sb); + sb->iterations = 15; + sb->cfd = cfd; + sb->cfdata = cfdata; + cfdata->surebox = sb; + sb->dia->data = sb; + e_dialog_title_set(sb->dia, _("Resolution change")); + e_dialog_icon_set(sb->dia, "preferences-system-screen-resolution", 48); + _surebox_text_fill(sb); + e_win_delete_callback_set(sb->dia->win, _surebox_dialog_cb_delete); + e_dialog_button_add(sb->dia, _("Save"), NULL, _surebox_dialog_cb_yes, sb); + e_dialog_button_add(sb->dia, _("Restore"), NULL, _surebox_dialog_cb_no, sb); + e_dialog_button_focus_num(sb->dia, 1); + e_win_centered_set(sb->dia->win, 1); + e_win_borderless_set(sb->dia->win, 1); + e_win_layer_set(sb->dia->win, 6); + e_win_sticky_set(sb->dia->win, 1); + e_dialog_show(sb->dia); + e_object_ref(E_OBJECT(cfd)); + return sb; +} +#endif diff --git a/src/modules/xkbswitch/Makefile.am b/src/modules/xkbswitch/Makefile.am new file mode 100644 index 000000000..a502a1af1 --- /dev/null +++ b/src/modules/xkbswitch/Makefile.am @@ -0,0 +1,34 @@ +MAINTAINERCLEANFILES = Makefile.in +MODULE = xkbswitch + +# data files for the module +filesdir = $(libdir)/enlightenment/modules/$(MODULE) +files_DATA = \ +e-module-$(MODULE).edj module.desktop + +EXTRA_DIST = $(files_DATA) + +# the module .so file +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src/modules/$(MODULE) \ + -I$(top_srcdir)/src/bin \ + -I$(top_builddir)/src/bin \ + -I$(top_srcdir)/src/modules \ + @e_cflags@ +pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH) +pkg_LTLIBRARIES = module.la +module_la_SOURCES = e_mod_main.c \ + e_mod_main.h \ + e_mod_config.c \ + e_mod_parse.c \ + e_mod_parse.h \ + e_mod_keybindings.c \ + e_mod_keybindings.h + +module_la_LIBADD = @e_libs@ @dlopen_libs@ +module_la_LDFLAGS = -module -avoid-version +module_la_DEPENDENCIES = $(top_builddir)/config.h + +uninstall: + rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE) diff --git a/src/modules/xkbswitch/e-module-xkbswitch.edj b/src/modules/xkbswitch/e-module-xkbswitch.edj new file mode 100644 index 000000000..349383ccb Binary files /dev/null and b/src/modules/xkbswitch/e-module-xkbswitch.edj differ diff --git a/src/modules/xkbswitch/e_mod_config.c b/src/modules/xkbswitch/e_mod_config.c new file mode 100644 index 000000000..f613d4737 --- /dev/null +++ b/src/modules/xkbswitch/e_mod_config.c @@ -0,0 +1,768 @@ +#include "e.h" +#include "e_mod_main.h" +#include "e_mod_parse.h" + +/* Local prototypes */ + +static void *_create_data(E_Config_Dialog *cfd); +static void _free_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); +static Evas_Object *_basic_create(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata); +static int _basic_apply(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata); + +static void _cb_add(void *data, void *data2 __UNUSED__); +static void _cb_del(void *data, void *data2 __UNUSED__); + +static void _cb_up(void *data, void *data2 __UNUSED__); +static void _cb_dn(void *data, void *data2 __UNUSED__); + +static void _dlg_add_cb_ok(void *data, E_Dialog *dlg); +static void _dlg_add_cb_cancel(void *data, E_Dialog *dlg); + +static E_Dialog *_dlg_add_new(E_Config_Dialog_Data *cfdata); + +static void _dlg_add_cb_del(void *obj); + +static Eina_Bool _cb_dlg_fill_delay(void *data); + +static void _cb_layout_select(void *data); +static void _cb_used_select (void *data); + +static Eina_Bool _cb_fill_delay(void *data); + +/* Externals */ + +E_Config_Dialog * +e_xkb_cfg_dialog(E_Container *con, const char *params __UNUSED__) +{ + E_Config_Dialog *cfd; + E_Config_Dialog_View *v; + + if (e_config_dialog_find("XKB Switcher", "keyboard_and_mouse/xkbswitch")) + return NULL; + if (!(v = E_NEW(E_Config_Dialog_View, 1))) return NULL; + + v->create_cfdata = _create_data; + v->free_cfdata = _free_data; + v->basic.create_widgets = _basic_create; + v->basic.apply_cfdata = _basic_apply; + + cfd = e_config_dialog_new(con, _("XKB Switcher Module"), "XKB Switcher", + "keyboard_and_mouse/xkbswitch", "preferences-desktop-locale", + 0, v, NULL); + + e_dialog_resizable_set(cfd->dia, 1); + e_xkb_cfg->cfd = cfd; + return cfd; +} + +/* Locals */ + +static void * +_create_data(E_Config_Dialog *cfd __UNUSED__) +{ + E_Config_Dialog_Data *cfdata; + Eina_List *l, *ll, *lll; + E_XKB_Config_Layout *cl, *nl; + E_XKB_Dialog_Option *od; + E_XKB_Option *op; + E_XKB_Option_Group *gr; + + parse_rules(); /* XXX: handle in case nothing was found? */ + + cfdata = E_NEW(E_Config_Dialog_Data, 1); + + cfdata->cfg_layouts = NULL; + EINA_LIST_FOREACH(e_xkb_cfg->used_layouts, l, cl) + { + nl = E_NEW(E_XKB_Config_Layout, 1); + nl->name = eina_stringshare_add(cl->name); + nl->model = eina_stringshare_add(cl->model); + nl->variant = eina_stringshare_add(cl->variant); + + cfdata->cfg_layouts = eina_list_append(cfdata->cfg_layouts, nl); + } + + /* Initialize options */ + + cfdata->only_label = e_xkb_cfg->only_label; + cfdata->cfg_options = NULL; + + lll = e_xkb_cfg->used_options; + EINA_LIST_FOREACH(optgroups, l, gr) + { + EINA_LIST_FOREACH(gr->options, ll, op) + { + od = E_NEW(E_XKB_Dialog_Option, 1); + od->name = eina_stringshare_add(op->name); + if (lll && + (od->name == ((E_XKB_Config_Option*)eina_list_data_get(lll))->name)) + { + od->enabled = 1; + lll = eina_list_next(lll); + } + else od->enabled = 0; + cfdata->cfg_options = eina_list_append(cfdata->cfg_options, od); + } + } + + return cfdata; +} + +static void +_free_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata) +{ + E_XKB_Config_Layout *cl; + E_XKB_Dialog_Option *od; + + e_xkb_cfg->cfd = NULL; + + EINA_LIST_FREE(cfdata->cfg_layouts, cl) + { + eina_stringshare_del(cl->name); + eina_stringshare_del(cl->model); + eina_stringshare_del(cl->variant); + E_FREE(cl); + } + + EINA_LIST_FREE(cfdata->cfg_options, od) + { + eina_stringshare_del(od->name); + E_FREE(od); + } + + eina_stringshare_del(cfdata->default_model); + E_FREE(cfdata); + clear_rules(); +} + +static int +_basic_apply(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata) +{ + Eina_List *l; + E_XKB_Config_Layout *cl, *nl; + E_XKB_Config_Option *oc; + E_XKB_Dialog_Option *od; + + EINA_LIST_FREE(e_xkb_cfg->used_layouts, cl) + { + eina_stringshare_del(cl->name); + eina_stringshare_del(cl->model); + eina_stringshare_del(cl->variant); + E_FREE(cl); + } + + EINA_LIST_FOREACH(cfdata->cfg_layouts, l, cl) + { + nl = E_NEW(E_XKB_Config_Layout, 1); + nl->name = eina_stringshare_add(cl->name); + nl->model = eina_stringshare_add(cl->model); + nl->variant = eina_stringshare_add(cl->variant); + + e_xkb_cfg->used_layouts = + eina_list_append(e_xkb_cfg->used_layouts, nl); + } + + if (e_xkb_cfg->default_model) + eina_stringshare_del(e_xkb_cfg->default_model); + + e_xkb_cfg->default_model = eina_stringshare_add(cfdata->default_model); + + /* Save options */ + e_xkb_cfg->only_label = cfdata->only_label; + + EINA_LIST_FREE(e_xkb_cfg->used_options, oc) + { + eina_stringshare_del(oc->name); + E_FREE(oc); + } + + EINA_LIST_FOREACH(cfdata->cfg_options, l, od) + { + if (!od->enabled) continue; + + oc = E_NEW(E_XKB_Config_Option, 1); + oc->name = eina_stringshare_add(od->name); + e_xkb_cfg->used_options = eina_list_append(e_xkb_cfg->used_options, oc); + } + + e_xkb_update_icon(); + e_xkb_update_layout(); + + e_config_save_queue(); + return 1; +} + +static Evas_Object * +_basic_create(E_Config_Dialog *cfd __UNUSED__, Evas *evas, E_Config_Dialog_Data *cfdata) +{ + /* Holds the dialog contents, displays a toolbar on the top */ + Evas_Object *mainn = e_widget_toolbook_add(evas, 24, 24); + { + /* Holds the used layouts ilist and the button table */ + Evas_Object *layoutss = e_widget_list_add(evas, 0, 0); + { + /* Holds the used layouts */ + Evas_Object *configs = e_widget_ilist_add(evas, 32, 32, NULL); + { + e_widget_size_min_set(configs, 220, 160); + e_widget_ilist_go(configs); + + e_widget_list_object_append(layoutss, configs, 1, 1, 0.5); + cfdata->used_list = configs; + } + + /* Holds the buttons */ + Evas_Object *buttons = e_widget_table_add(evas, 1); + { + cfdata->btn_up = e_widget_button_add(evas, _("Up"), "go-up", _cb_up, cfdata, NULL); + { + e_widget_disabled_set(cfdata->btn_up, EINA_TRUE); + e_widget_table_object_append(buttons, cfdata->btn_up, 0, 0, 1, 1, 1, 1, 1, 0); + } + + cfdata->btn_down = e_widget_button_add(evas, _("Down"), "go-down", _cb_dn, cfdata, NULL); + { + e_widget_disabled_set(cfdata->btn_down, EINA_TRUE); + e_widget_table_object_append(buttons, cfdata->btn_down, 1, 0, 1, 1, 1, 1, 1, 0); + } + + cfdata->btn_add = e_widget_button_add(evas, _("Add"), "list-add", _cb_add, cfdata, NULL); + { + e_widget_table_object_append(buttons, cfdata->btn_add, 0, 1, 1, 1, 1, 1, 1, 0); + } + + cfdata->btn_del = e_widget_button_add(evas, _("Remove"), "list-remove", _cb_del, cfdata, NULL); + { + e_widget_disabled_set(cfdata->btn_del, EINA_TRUE); + e_widget_table_object_append(buttons, cfdata->btn_del, 1, 1, 1, 1, 1, 1, 1, 0); + } + + e_widget_list_object_append(layoutss, buttons, 1, 0, 1); + } + + e_widget_toolbook_page_append(mainn, NULL, _("Configurations"), layoutss, 1, 1, 1, 1, 0.5, 0.0); + } + + /* Holds the default models */ + Evas_Object *modelss = e_widget_ilist_add(evas, 32, 32, &cfdata->default_model); + { + e_widget_size_min_set(modelss, 220, 160); + cfdata->dmodel_list = modelss; + + e_widget_toolbook_page_append(mainn, NULL, _("Models"), modelss, 1, 1, 1, 1, 0.5, 0.0); + } + + /* Holds the options */ + Evas_Object *options = e_widget_list_add(evas, 0, 0); + { + E_XKB_Option *option; + E_XKB_Option_Group *group; + Eina_List *l, *ll, *lll; + Evas_Coord mw, mh; + + Evas_Object *general = e_widget_framelist_add(evas, _("General"), 0); + { + Evas_Object *only_label = e_widget_check_add(evas, _("Label only"), &(cfdata->only_label)); + { + e_widget_framelist_object_append(general, only_label); + } + e_widget_list_object_append(options, general, 1, 1, 0.0); + } + + lll = cfdata->cfg_options; + + EINA_LIST_FOREACH(optgroups, l, group) + { + Evas_Object *grp = e_widget_framelist_add(evas, group->description, 0); + + EINA_LIST_FOREACH(group->options, ll, option) + { + Evas_Object *chk = e_widget_check_add(evas, option->description, + &(((E_XKB_Dialog_Option*) + eina_list_data_get(lll))->enabled)); + e_widget_framelist_object_append(grp, chk); + lll = eina_list_next(lll); + } + e_widget_list_object_append(options, grp, 1, 1, 0.0); + } + + e_widget_size_min_get(options, &mw, &mh); + + if (mw < 220) mw = 220; + if (mh < 160) mh = 160; + + evas_object_resize(options, mw, mh); + + Evas_Object *scroller = e_widget_scrollframe_simple_add(evas, options); + e_widget_size_min_set(scroller, 220, 160); + + e_widget_toolbook_page_append(mainn, NULL, _("Options"), scroller, 1, 1, 1, 1, 0.5, 0.0); + } + + /* Display the first page by default */ + e_widget_toolbook_page_show(mainn, 0); + } + + /* The main evas */ + cfdata->evas = evas; + + /* Clear up any previous timer */ + if (cfdata->fill_delay) + ecore_timer_del(cfdata->fill_delay); + + /* Trigger the fill */ + cfdata->fill_delay = ecore_timer_add(0.2, _cb_fill_delay, cfdata); + + return mainn; +} + +static void +_cb_add(void *data, void *data2 __UNUSED__) +{ + E_Config_Dialog_Data *cfdata; + if (!(cfdata = data)) return; + + if (cfdata->dlg_add_new) e_win_raise(cfdata->dlg_add_new->win); + else cfdata->dlg_add_new = _dlg_add_new(cfdata); +} + +static void +_cb_del(void *data, void *data2 __UNUSED__) +{ + E_Config_Dialog_Data *cfdata; + int n = 0; + + if (!(cfdata = data)) return; + if ((n = e_widget_ilist_selected_get(cfdata->used_list)) < 0) return; + + cfdata->cfg_layouts = eina_list_remove_list(cfdata->cfg_layouts, eina_list_nth_list(cfdata->cfg_layouts, n)); + + /* Update the list */ + evas_event_freeze(cfdata->evas); + edje_freeze(); + e_widget_ilist_freeze(cfdata->used_list); + e_widget_ilist_remove_num(cfdata->used_list, n); + e_widget_ilist_go(cfdata->used_list); + e_widget_ilist_thaw(cfdata->used_list); + edje_thaw(); + evas_event_thaw(cfdata->evas); +} + +static void +_cb_up(void *data, void *data2 __UNUSED__) +{ + E_Config_Dialog_Data *cfdata; + void *nddata; + Evas_Object *ic; + Eina_List *l; + const char *lbl; + int n; + + if (!(cfdata = data)) return; + if ((n = e_widget_ilist_selected_get(cfdata->used_list)) < 0) return; + + l = eina_list_nth_list(cfdata->cfg_layouts, n); + + nddata = eina_list_data_get(eina_list_prev(l)); + eina_list_data_set(eina_list_prev(l), eina_list_data_get(l)); + eina_list_data_set(l, nddata); + + /* Update the list */ + + evas_event_freeze(cfdata->evas); + edje_freeze(); + e_widget_ilist_freeze(cfdata->used_list); + + ic = e_icon_add(cfdata->evas); + e_icon_file_set(ic, e_icon_file_get(e_widget_ilist_nth_icon_get(cfdata->used_list, n))); + lbl = e_widget_ilist_nth_label_get(cfdata->used_list, n); + e_widget_ilist_prepend_relative_full(cfdata->used_list, ic, NULL, lbl, _cb_used_select, cfdata, NULL, (n - 1)); + e_widget_ilist_remove_num(cfdata->used_list, n); + + e_widget_ilist_go(cfdata->used_list); + e_widget_ilist_thaw(cfdata->used_list); + edje_thaw(); + evas_event_thaw(cfdata->evas); + + e_widget_ilist_selected_set(cfdata->used_list, (n - 1)); +} + +static void +_cb_dn(void *data, void *data2 __UNUSED__) +{ + E_Config_Dialog_Data *cfdata; + void *nddata; + Evas_Object *ic; + Eina_List *l; + const char *lbl; + int n; + + if (!(cfdata = data)) return; + if ((n = e_widget_ilist_selected_get(cfdata->used_list)) < 0) return; + + l = eina_list_nth_list(cfdata->cfg_layouts, n); + + nddata = eina_list_data_get(eina_list_next(l)); + eina_list_data_set(eina_list_next(l), eina_list_data_get(l)); + eina_list_data_set(l, nddata); + + /* Update the list */ + + evas_event_freeze(cfdata->evas); + edje_freeze(); + e_widget_ilist_freeze(cfdata->used_list); + + ic = e_icon_add(cfdata->evas); + e_icon_file_set(ic, e_icon_file_get(e_widget_ilist_nth_icon_get(cfdata->used_list, n))); + lbl = e_widget_ilist_nth_label_get(cfdata->used_list, n); + e_widget_ilist_append_relative_full(cfdata->used_list, ic, NULL, lbl, _cb_used_select, cfdata, NULL, n); + e_widget_ilist_remove_num(cfdata->used_list, n); + + e_widget_ilist_go(cfdata->used_list); + e_widget_ilist_thaw(cfdata->used_list); + edje_thaw(); + evas_event_thaw(cfdata->evas); + + e_widget_ilist_selected_set(cfdata->used_list, (n + 1)); +} + +static E_Dialog * +_dlg_add_new(E_Config_Dialog_Data *cfdata) +{ + E_Dialog *dlg; + Evas *evas; + Evas_Coord mw, mh; + + if (!(dlg = e_dialog_new(e_xkb_cfg->cfd->con, "E", "xkbswitch_config_add_dialog"))) return NULL; + + dlg->data = cfdata; + + e_object_del_attach_func_set(E_OBJECT(dlg), _dlg_add_cb_del); + e_win_centered_set(dlg->win, 1); + + evas = e_win_evas_get(dlg->win); + e_dialog_title_set(dlg, _("Add New Configuration")); + + /* The main toolbook, holds the lists and tabs */ + Evas_Object *mainn = e_widget_toolbook_add(evas, 24, 24); + { + /* Holds the available layouts */ + Evas_Object *available = e_widget_ilist_add(evas, 32, 32, NULL); + { + e_widget_size_min_set(available, 220, 160); + e_widget_ilist_go(available); + e_widget_toolbook_page_append(mainn, NULL, _("Available"), available, 1, 1, 1, 1, 0.5, 0.0); + cfdata->layout_list = available; + } + + /* Holds the available models */ + Evas_Object *modelss = e_widget_ilist_add(evas, 32, 32, NULL); + { + e_widget_toolbook_page_append(mainn, NULL, _("Model"), modelss, 1, 1, 1, 1, 0.5, 0.0); + cfdata->model_list = modelss; + } + + /* Holds the available variants */ + Evas_Object *variants = e_widget_ilist_add(evas, 32, 32, NULL); + { + e_widget_toolbook_page_append(mainn, NULL, _("Variant"), variants, 1, 1, 1, 1, 0.5, 0.0); + cfdata->variant_list = variants; + } + e_widget_toolbook_page_show(mainn, 0); + } + + e_widget_size_min_get(mainn, &mw, &mh); + e_dialog_content_set(dlg, mainn, mw, mh); + + cfdata->dlg_evas = evas; + + /* Clear up any previous timer */ + if (cfdata->dlg_fill_delay) ecore_timer_del(cfdata->dlg_fill_delay); + + /* Trigger the fill */ + cfdata->dlg_fill_delay = ecore_timer_add(0.2, _cb_dlg_fill_delay, cfdata); + + /* Some buttons */ + e_dialog_button_add(dlg, _("OK"), NULL, _dlg_add_cb_ok, cfdata); + e_dialog_button_add(dlg, _("Cancel"), NULL, _dlg_add_cb_cancel, cfdata); + + e_dialog_button_disable_num_set(dlg, 0, 1); + e_dialog_button_disable_num_set(dlg, 1, 0); + + e_dialog_resizable_set(dlg, 1); + e_dialog_show(dlg); + + return dlg; +} + +static void +_dlg_add_cb_ok(void *data __UNUSED__, E_Dialog *dlg) +{ + E_Config_Dialog_Data *cfdata = dlg->data; + E_XKB_Config_Layout *cl; + char buf[PATH_MAX]; + /* Configuration information */ + const char *layout = e_widget_ilist_selected_value_get(cfdata->layout_list); + const char *model = e_widget_ilist_selected_value_get(cfdata->model_list); + const char *variant = e_widget_ilist_selected_value_get(cfdata->variant_list); + + /* The new configuration */ + cl = E_NEW(E_XKB_Config_Layout, 1); + cl->name = eina_stringshare_add(layout); + cl->model = eina_stringshare_add(model); + cl->variant = eina_stringshare_add(variant); + + cfdata->cfg_layouts = eina_list_append(cfdata->cfg_layouts, cl); + + /* Update the main list */ + evas_event_freeze(cfdata->evas); + edje_freeze(); + e_widget_ilist_freeze(cfdata->used_list); + + { + Evas_Object *ic = e_icon_add(cfdata->evas); + { + const char *name = cl->name; + + if (strchr(name, '/')) name = strchr(name, '/') + 1; + snprintf(buf, sizeof(buf), "%s/data/flags/%s_flag.png", + e_prefix_data_get(), name); + + if (!ecore_file_exists(buf)) + snprintf(buf, sizeof(buf), "%s/data/flags/unknown_flag.png", + e_prefix_data_get()); + e_icon_file_set(ic, buf); + } + + snprintf(buf, sizeof(buf), "%s (%s, %s)", cl->name, cl->model, cl->variant); + + e_widget_ilist_append_full(cfdata->used_list, ic, NULL, buf, _cb_used_select, cfdata, NULL); + } + + e_widget_ilist_go (cfdata->used_list); + e_widget_ilist_thaw(cfdata->used_list); + edje_thaw(); + evas_event_thaw(cfdata->evas); + + cfdata->dlg_add_new = NULL; + e_object_unref(E_OBJECT(dlg)); +} + +static void +_dlg_add_cb_cancel(void *data __UNUSED__, E_Dialog *dlg) +{ + E_Config_Dialog_Data *cfdata = dlg->data; + cfdata->dlg_add_new = NULL; + e_object_unref(E_OBJECT(dlg)); +} + +static void +_dlg_add_cb_del(void *obj) +{ + E_Dialog *dlg = obj; + E_Config_Dialog_Data *cfdata = dlg->data; + cfdata->dlg_add_new = NULL; + e_object_unref(E_OBJECT(dlg)); +} + +static Eina_Bool +_cb_dlg_fill_delay(void *data) +{ + E_Config_Dialog_Data *cfdata; + Eina_List *l; + E_XKB_Layout *layout; + char buf[PATH_MAX]; + + if (!(cfdata = data)) return ECORE_CALLBACK_RENEW; + + /* Update the list of available layouts */ + evas_event_freeze(cfdata->dlg_evas); + edje_freeze(); + + e_widget_ilist_freeze(cfdata->layout_list); + e_widget_ilist_clear (cfdata->layout_list); + + EINA_LIST_FOREACH(layouts, l, layout) + { + Evas_Object *ic = e_icon_add(cfdata->dlg_evas); + { + const char *name = layout->name; + + if (strchr(name, '/')) name = strchr(name, '/') + 1; + snprintf(buf, sizeof(buf), "%s/data/flags/%s_flag.png", + e_prefix_data_get(), name); + if (!ecore_file_exists(buf)) + snprintf(buf, sizeof(buf), "%s/data/flags/unknown_flag.png", + e_prefix_data_get()); + e_icon_file_set(ic, buf); + } + + snprintf(buf, sizeof(buf), "%s (%s)", layout->description, layout->name); + + e_widget_ilist_append_full(cfdata->layout_list, ic, NULL, buf, _cb_layout_select, cfdata, layout->name); + } + + e_widget_ilist_go (cfdata->layout_list); + e_widget_ilist_thaw(cfdata->layout_list); + + edje_thaw(); + evas_event_thaw(cfdata->dlg_evas); + + cfdata->dlg_fill_delay = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static void +_cb_layout_select(void *data) +{ + E_Config_Dialog_Data *cfdata; + E_XKB_Variant *variant; + E_XKB_Layout *layout; + E_XKB_Model *model; + Eina_List *l; + const char *label; + int n; + char buf[PATH_MAX]; + + if (!(cfdata = data)) return; + + /* Find the right layout */ + + if ((n = e_widget_ilist_selected_get(cfdata->layout_list)) < 0) + return; + if (!(label = e_widget_ilist_nth_label_get(cfdata->layout_list, n))) + return; + + if (!(layout = eina_list_search_unsorted + (layouts, layout_sort_by_name_cb, + e_widget_ilist_nth_value_get(cfdata->layout_list, n) + ))) return; + + /* Update the lists */ + evas_event_freeze(cfdata->dlg_evas); + edje_freeze(); + + /* Models */ + e_widget_ilist_freeze(cfdata->model_list); + e_widget_ilist_clear(cfdata->model_list); + + EINA_LIST_FOREACH(models, l, model) + { + snprintf(buf, sizeof(buf), "%s (%s)", model->description, model->name); + e_widget_ilist_append(cfdata->model_list, NULL, buf, NULL, cfdata, model->name); + } + + e_widget_ilist_go(cfdata->model_list); + e_widget_ilist_thaw(cfdata->model_list); + + /* Variants */ + e_widget_ilist_freeze(cfdata->variant_list); + e_widget_ilist_clear(cfdata->variant_list); + + EINA_LIST_FOREACH(layout->variants, l, variant) + { + snprintf(buf, sizeof(buf), "%s (%s)", variant->name, variant->description); + e_widget_ilist_append(cfdata->variant_list, NULL, buf, NULL, cfdata, variant->name); + } + + e_widget_ilist_go(cfdata->variant_list); + e_widget_ilist_thaw(cfdata->variant_list); + + edje_thaw(); + evas_event_thaw(cfdata->dlg_evas); + + e_widget_ilist_selected_set(cfdata->model_list, 0); + e_widget_ilist_selected_set(cfdata->variant_list, 0); + + e_dialog_button_disable_num_set(cfdata->dlg_add_new, 0, 0); +} + +static Eina_Bool +_cb_fill_delay(void *data) +{ + E_Config_Dialog_Data *cfdata; + Eina_List *l; + E_XKB_Config_Layout *cl; + E_XKB_Model *model; + int n = 0; + char buf[PATH_MAX]; + + if (!(cfdata = data)) return ECORE_CALLBACK_RENEW; + + /* Update the list of used layouts */ + evas_event_freeze(cfdata->evas); + edje_freeze(); + + e_widget_ilist_freeze(cfdata->used_list); + e_widget_ilist_clear(cfdata->used_list); + + EINA_LIST_FOREACH(cfdata->cfg_layouts, l, cl) + { + Evas_Object *ic = e_icon_add(cfdata->evas); + const char *name = cl->name; + + if (strchr(name, '/')) name = strchr(name, '/') + 1; + snprintf(buf, sizeof(buf), "%s/data/flags/%s_flag.png", + e_prefix_data_get(), name); + if (!ecore_file_exists(buf)) + snprintf(buf, sizeof(buf), "%s/flags/unknown_flag.png", + e_prefix_data_get()); + e_icon_file_set(ic, buf); + + snprintf(buf, sizeof(buf), "%s (%s, %s)", cl->name, cl->model, cl->variant); + e_widget_ilist_append_full(cfdata->used_list, ic, NULL, buf, _cb_used_select, cfdata, NULL); + } + + e_widget_ilist_go(cfdata->used_list); + e_widget_ilist_thaw(cfdata->used_list); + + e_widget_ilist_freeze(cfdata->dmodel_list); + e_widget_ilist_clear(cfdata->dmodel_list); + + /* Update the global model list */ + EINA_LIST_FOREACH(models, l, model) + { + snprintf(buf, sizeof(buf), "%s (%s)", model->description, model->name); + e_widget_ilist_append(cfdata->dmodel_list, NULL, buf, NULL, cfdata, model->name); + if (model->name == e_xkb_cfg->default_model) + e_widget_ilist_selected_set(cfdata->dmodel_list, n); + n++; + } + + e_widget_ilist_go(cfdata->dmodel_list); + e_widget_ilist_thaw(cfdata->dmodel_list); + edje_thaw(); + evas_event_thaw(cfdata->evas); + + cfdata->fill_delay = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static void +_cb_used_select(void *data) +{ + E_Config_Dialog_Data *cfdata; + int n, c; + + if (!(cfdata = data)) return; + if ((n = e_widget_ilist_selected_get(cfdata->used_list)) < 0) return; + + c = e_widget_ilist_count(cfdata->used_list); + e_widget_disabled_set(cfdata->btn_del, EINA_FALSE); + + if (n == (c - 1)) + { + e_widget_disabled_set(cfdata->btn_up, EINA_FALSE); + e_widget_disabled_set(cfdata->btn_down, EINA_TRUE ); + } + else if (n == 0) + { + e_widget_disabled_set(cfdata->btn_up, EINA_TRUE ); + e_widget_disabled_set(cfdata->btn_down, EINA_FALSE); + } + else + { + e_widget_disabled_set(cfdata->btn_up, EINA_FALSE); + e_widget_disabled_set(cfdata->btn_down, EINA_FALSE); + } +} diff --git a/src/modules/xkbswitch/e_mod_keybindings.c b/src/modules/xkbswitch/e_mod_keybindings.c new file mode 100644 index 000000000..10206a246 --- /dev/null +++ b/src/modules/xkbswitch/e_mod_keybindings.c @@ -0,0 +1,194 @@ +#include "e.h" +#include "e_mod_main.h" +#include "e_mod_keybindings.h" + +#define E_XKB_ACTION_GROUP _("Keyboard Layouts") +#define E_XKB_ACTION_NEXT _("Switch to the next layout") +#define E_XKB_ACTION_PREV _("Switch to the previous layout") + +#define ACT_FN_GO(act) \ + static void _e_actions_act_##act##_go(E_Object *obj, const char *params) + +#define ACT_GO(name) \ +{ \ + act = e_action_add(#name); \ + if (act) act->func.go = _e_actions_act_##name##_go; \ +} + +ACT_FN_GO(e_xkb_layout_next); +ACT_FN_GO(e_xkb_layout_prev); + +static void _e_xkb_register_module_keybinding(E_Config_Binding_Key *key, const char *action); +static void _e_xkb_unregister_module_keybinding(E_Config_Binding_Key *key, int save); + +int +e_xkb_register_module_actions(void) +{ + E_Action *act; + + e_action_predef_name_set(E_XKB_ACTION_GROUP, E_XKB_ACTION_NEXT, E_XKB_NEXT_ACTION, + NULL, NULL, 0); + e_action_predef_name_set(E_XKB_ACTION_GROUP, E_XKB_ACTION_PREV, E_XKB_PREV_ACTION, + NULL, NULL, 0); + + ACT_GO(e_xkb_layout_next); + ACT_GO(e_xkb_layout_prev); + + return 1; +} + +int +e_xkb_unregister_module_actions(void) +{ + e_action_del(E_XKB_NEXT_ACTION); + e_action_del(E_XKB_PREV_ACTION); + + e_action_predef_name_del(E_XKB_ACTION_GROUP, E_XKB_ACTION_NEXT); + e_action_predef_name_del(E_XKB_ACTION_GROUP, E_XKB_ACTION_PREV); + + return 1; +} + +// XXX: i dont think module should register bindings imho. leave that up to +// standard profiles? +int +e_xkb_register_module_keybindings(void) +{ + e_managers_keys_ungrab(); + + _e_xkb_register_module_keybinding(&(e_xkb_cfg->layout_next_key), E_XKB_NEXT_ACTION); + _e_xkb_register_module_keybinding(&(e_xkb_cfg->layout_prev_key), E_XKB_PREV_ACTION); + + e_managers_keys_grab(); + + return 1; +} + +int +e_xkb_unregister_module_keybindings(void) +{ + e_managers_keys_ungrab(); + + _e_xkb_unregister_module_keybinding(&(e_xkb_cfg->layout_next_key), 1); + _e_xkb_unregister_module_keybinding(&(e_xkb_cfg->layout_prev_key), 1); + + e_managers_keys_grab(); + + return 1; +} + +static void +_e_xkb_unregister_module_keybinding(E_Config_Binding_Key *key, int save) +{ + E_Config_Binding_Key *eb; + Eina_List *l; + Eina_Bool done = EINA_FALSE; + Eina_Bool found = EINA_FALSE; + + if (!key) return; + + while (!done) + { + done = EINA_TRUE; + + EINA_LIST_FOREACH(e_config->key_bindings, l, eb) + { + if (eb && eb->action && eb->action[0] && + (!strcmp(!eb->action ? "" : eb->action, + !key->action ? "" : key->action))) + { + if (save) + { + eina_stringshare_del(key->key); + eina_stringshare_del(key->params); + + key->context = eb->context; + key->key = eina_stringshare_add(eb->key); + key->modifiers = eb->modifiers; + key->any_mod = eb->any_mod; + key->params = (!eb->params ? NULL : eina_stringshare_add(eb->params)); + } + + e_bindings_key_del(eb->context, eb->key, eb->modifiers, eb->any_mod, eb->action, eb->params); + + eina_stringshare_del(eb->key); + eina_stringshare_del(eb->action); + eina_stringshare_del(eb->params); + + E_FREE(eb); + + e_config->key_bindings = eina_list_remove_list(e_config->key_bindings, l); + + found = EINA_TRUE; + done = EINA_FALSE; + + break; + } + } + } + + if (!found) + { + eina_stringshare_del(key->key); + eina_stringshare_del(key->params); + + key->key = NULL; + key->context = E_BINDING_CONTEXT_ANY; + key->modifiers = E_BINDING_MODIFIER_NONE; + key->any_mod = 0; + } +} + +static void +_e_xkb_register_module_keybinding(E_Config_Binding_Key *key, const char *action) +{ + E_Config_Binding_Key *eb; + E_Config_Binding_Key *t; + Eina_List *l; + Eina_Bool found = EINA_FALSE; + + if (!key || !key->key || !key->key[0] || !action) return; + + eb = E_NEW(E_Config_Binding_Key, 1); + + eb->context = key->context; + eb->key = eina_stringshare_add(key->key); + eb->modifiers = key->modifiers; + eb->any_mod = key->any_mod; + eb->action = (!action ? NULL : eina_stringshare_add(action)); + eb->params = (!key->params ? NULL : eina_stringshare_add(key->params)); + + EINA_LIST_FOREACH(e_config->key_bindings, l, t) + { + if (found) break; + if (!strcmp(!t->action ? "" : t->action, eb->action) && !strcmp(!t->params ? "" : t->params, !eb->params ? "" : eb->params)) found = EINA_TRUE; + } + + if (!found) + { + e_config->key_bindings = eina_list_append(e_config->key_bindings, eb); + e_bindings_key_add(key->context, key->key, key->modifiers, + key->any_mod, action, key->params); + } + else + { + eina_stringshare_del(eb->key); + eina_stringshare_del(eb->action); + eina_stringshare_del(eb->params); + E_FREE(eb); + } +} + +ACT_FN_GO(e_xkb_layout_next) +{ + e_xkb_layout_next(); + return; + obj = 0; params = 0; +} + +ACT_FN_GO(e_xkb_layout_prev) +{ + e_xkb_layout_prev(); + return; + obj = 0; params = 0; +} diff --git a/src/modules/xkbswitch/e_mod_keybindings.h b/src/modules/xkbswitch/e_mod_keybindings.h new file mode 100644 index 000000000..de86164ce --- /dev/null +++ b/src/modules/xkbswitch/e_mod_keybindings.h @@ -0,0 +1,16 @@ +#ifdef E_TYPEDEFS +#else +#ifndef E_MOD_KEYBIND_H +#define E_MOD_KEYBIND_H + +#define E_XKB_NEXT_ACTION "e_xkb_layout_next" +#define E_XKB_PREV_ACTION "e_xkb_layout_prev" + +int e_xkb_register_module_actions(void); +int e_xkb_unregister_module_actions(void); + +int e_xkb_register_module_keybindings(void); +int e_xkb_unregister_module_keybindings(void); + +#endif +#endif diff --git a/src/modules/xkbswitch/e_mod_main.c b/src/modules/xkbswitch/e_mod_main.c new file mode 100644 index 000000000..29b83b4da --- /dev/null +++ b/src/modules/xkbswitch/e_mod_main.c @@ -0,0 +1,770 @@ +#include "e.h" +#include "e_mod_main.h" +#include "e_mod_parse.h" +#include "e_mod_keybindings.h" + +/* Static functions + * The static functions specific to the current code unit. + */ + +/* GADCON */ + +static E_Gadcon_Client *_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style); + +static void _gc_shutdown(E_Gadcon_Client *gcc); +static void _gc_orient (E_Gadcon_Client *gcc, E_Gadcon_Orient orient); + +static const char *_gc_label (E_Gadcon_Client_Class *client_class); +static const char *_gc_id_new(E_Gadcon_Client_Class *client_class __UNUSED__); + +static Evas_Object *_gc_icon(E_Gadcon_Client_Class *client_class, Evas *evas); + +/* CONFIG */ + +static void _e_xkb_cfg_new (void); +static void _e_xkb_cfg_free(void); + +static Eina_Bool _e_xkb_cfg_timer(void *data); + +/* EVENTS */ + +static void _e_xkb_cb_mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event); + +static void _e_xkb_cb_menu_post(void *data, E_Menu *menu __UNUSED__); +static void _e_xkb_cb_menu_configure(void *data, E_Menu *mn, E_Menu_Item *mi __UNUSED__); + +static void _e_xkb_cb_lmenu_post(void *data, E_Menu *menu __UNUSED__); +static void _e_xkb_cb_lmenu_set(void *data, E_Menu *mn __UNUSED__, E_Menu_Item *mi __UNUSED__); + +/* Static variables + * The static variables specific to the current code unit. + */ + +/* GADGET INSTANCE */ + +typedef struct _Instance +{ + E_Gadcon_Client *gcc; + + Evas_Object *o_xkbswitch; + Evas_Object *o_xkbflag; + + E_Menu *menu; + E_Menu *lmenu; +} Instance; + +/* LIST OF INSTANCES */ +static Eina_List *instances = NULL; + +/* EET STRUCTURES */ + +static E_Config_DD *e_xkb_cfg_edd = NULL; +static E_Config_DD *e_xkb_cfg_layout_edd = NULL; +static E_Config_DD *e_xkb_cfg_option_edd = NULL; + +/* Global variables + * Global variables shared across the module. + */ + +/* CONFIG STRUCTURE */ +E_XKB_Config *e_xkb_cfg = NULL; + +static const E_Gadcon_Client_Class _gc_class = +{ + GADCON_CLIENT_CLASS_VERSION, + "xkbswitch", + { + _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL, NULL + }, + E_GADCON_CLIENT_STYLE_PLAIN +}; + +EAPI E_Module_Api e_modapi = +{ + E_MODULE_API_VERSION, + "XKB Switcher" +}; + +/* Module initializer + * Initializes the configuration file, checks its versions, populates + * menus, finds the rules file, initializes gadget icon. + */ +EAPI void * +e_modapi_init(E_Module *m) +{ + /* Menus and dialogs */ + e_configure_registry_category_add("keyboard_and_mouse", 80, _("Input"), + NULL, "preferences-behavior"); + e_configure_registry_item_add("keyboard_and_mouse/xkbswitch", 110, + _("XKB Switcher"), NULL, + "preferences-desktop-locale", + e_xkb_cfg_dialog); + e_xkb_cfg_layout_edd = E_CONFIG_DD_NEW("E_XKB_Config_Layout", E_XKB_Config_Layout); +#undef T +#undef D +#define T E_XKB_Config_Layout +#define D e_xkb_cfg_layout_edd + E_CONFIG_VAL(D, T, name, STR); + E_CONFIG_VAL(D, T, model, STR); + E_CONFIG_VAL(D, T, variant, STR); + + e_xkb_cfg_option_edd = E_CONFIG_DD_NEW("E_XKB_Config_Option", E_XKB_Config_Option); +#undef T +#undef D +#define T E_XKB_Config_Option +#define D e_xkb_cfg_option_edd + E_CONFIG_VAL(D, T, name, STR); + + e_xkb_cfg_edd = E_CONFIG_DD_NEW("e_xkb_cfg", E_XKB_Config); +#undef T +#undef D +#define T E_XKB_Config +#define D e_xkb_cfg_edd + E_CONFIG_LIST(D, T, used_layouts, e_xkb_cfg_layout_edd); + E_CONFIG_LIST(D, T, used_options, e_xkb_cfg_option_edd); + E_CONFIG_VAL(D, T, layout_next_key.context, INT); + E_CONFIG_VAL(D, T, layout_next_key.modifiers, INT); + E_CONFIG_VAL(D, T, layout_next_key.key, STR); + E_CONFIG_VAL(D, T, layout_next_key.action, STR); + E_CONFIG_VAL(D, T, layout_next_key.params, STR); + E_CONFIG_VAL(D, T, layout_next_key.any_mod, UCHAR); + E_CONFIG_VAL(D, T, layout_prev_key.context, INT); + E_CONFIG_VAL(D, T, layout_prev_key.modifiers, INT); + E_CONFIG_VAL(D, T, layout_prev_key.key, STR); + E_CONFIG_VAL(D, T, layout_prev_key.action, STR); + E_CONFIG_VAL(D, T, layout_prev_key.params, STR); + E_CONFIG_VAL(D, T, layout_prev_key.any_mod, UCHAR); + E_CONFIG_VAL(D, T, default_model, STR); + E_CONFIG_VAL(D, T, only_label, INT); + E_CONFIG_VAL(D, T, version, INT); + + /* Version check */ + e_xkb_cfg = e_config_domain_load("module.xkbswitch", e_xkb_cfg_edd); + if (e_xkb_cfg) + { + /* Check config version */ + if ((e_xkb_cfg->version >> 16) < MOD_CONFIG_FILE_EPOCH) + { + /* config too old */ + _e_xkb_cfg_free(); + ecore_timer_add(1.0, _e_xkb_cfg_timer, + _("XKB Switcher Module Configuration data needed " + "upgrading. Your old configuration
has been" + " wiped and a new set of defaults initialized. " + "This
will happen regularly during " + "development, so don't report a
bug. " + "This simply means the module needs " + "new configuration
data by default for " + "usable functionality that your old
" + "configuration simply lacks. This new set of " + "defaults will fix
that by adding it in. " + "You can re-configure things now to your
" + "liking. Sorry for the inconvenience.
")); + } + /* Ardvarks */ + else if (e_xkb_cfg->version > MOD_CONFIG_FILE_VERSION) + { + /* config too new...wtf ? */ + _e_xkb_cfg_free(); + ecore_timer_add(1.0, _e_xkb_cfg_timer, + _("Your XKB Switcher Module configuration is NEWER " + "than the module version. This is " + "very
strange. This should not happen unless" + " you downgraded
the module or " + "copied the configuration from a place where" + "
a newer version of the module " + "was running. This is bad and
as a " + "precaution your configuration has been now " + "restored to
defaults. Sorry for the " + "inconvenience.
")); + } + } + + if (!e_xkb_cfg) _e_xkb_cfg_new(); + e_xkb_cfg->module = m; + /* Rules */ + find_rules(); + /* Update the layout - can't update icon, gadgets are not there yet */ + e_xkb_update_layout(); + /* Gadcon */ + e_gadcon_provider_register(&_gc_class); + /* Bindings */ + e_xkb_register_module_actions(); + e_xkb_register_module_keybindings(); + + return m; +} + +/* Module shutdown + * Called when the module gets unloaded. Deregisters the menu state + * and frees up the config. + */ +EAPI int +e_modapi_shutdown(E_Module *m __UNUSED__) +{ + E_XKB_Config_Layout *cl; + E_XKB_Config_Option *op; + + e_configure_registry_item_del("keyboard_and_mouse/xkbswitch"); + e_configure_registry_category_del("keyboard_and_mouse"); + + if (e_xkb_cfg->cfd) e_object_del(E_OBJECT(e_xkb_cfg->cfd)); + + e_xkb_cfg->cfd = NULL; + e_xkb_cfg->module = NULL; + + e_gadcon_provider_unregister(&_gc_class); + + e_xkb_unregister_module_actions(); + e_xkb_unregister_module_keybindings(); + + EINA_LIST_FREE(e_xkb_cfg->used_layouts, cl) + { + eina_stringshare_del(cl->name); + eina_stringshare_del(cl->model); + eina_stringshare_del(cl->variant); + + E_FREE(cl); + } + + EINA_LIST_FREE(e_xkb_cfg->used_options, op) + { + eina_stringshare_del(op->name); + E_FREE(op); + } + + if (e_xkb_cfg->default_model) + eina_stringshare_del(e_xkb_cfg->default_model); + + E_FREE(e_xkb_cfg); + + E_CONFIG_DD_FREE(e_xkb_cfg_layout_edd); + E_CONFIG_DD_FREE(e_xkb_cfg_option_edd); + E_CONFIG_DD_FREE(e_xkb_cfg_edd); + + clear_rules(); + + return 1; +} + +/* Module state save + * Used to save the configuration file. + */ +EAPI int +e_modapi_save(E_Module *m __UNUSED__) +{ + e_config_domain_save("module.xkbswitch", e_xkb_cfg_edd, e_xkb_cfg); + return 1; +} + +/* Updates icons on all available xkbswitch gadgets to reflect the + * current layout state. + */ +void +e_xkb_update_icon(void) +{ + Instance *inst; + Eina_List *l; + + if (!e_xkb_cfg->used_layouts) return; + const char *name = ((E_XKB_Config_Layout*)eina_list_data_get(e_xkb_cfg->used_layouts))->name; + + if ((name) && (strchr(name, '/'))) name = strchr(name, '/') + 1; + + if (e_xkb_cfg->only_label) + { + EINA_LIST_FOREACH(instances, l, inst) + { + if (inst->o_xkbflag) + { + evas_object_del(inst->o_xkbflag); + inst->o_xkbflag = NULL; + } + + e_theme_edje_object_set(inst->o_xkbswitch, + "base/theme/modules/xkbswitch", + "modules/xkbswitch/noflag"); + edje_object_part_text_set(inst->o_xkbswitch, "label", name); + } + } + else + { + char buf[PATH_MAX]; + + snprintf(buf, sizeof(buf), "%s/data/flags/%s_flag.png", + e_prefix_data_get(), name); + + EINA_LIST_FOREACH(instances, l, inst) + { + if (!inst->o_xkbflag) + { + inst->o_xkbflag = e_icon_add(inst->gcc->gadcon->evas); + e_icon_file_set(inst->o_xkbflag, buf); + edje_object_part_swallow(inst->o_xkbswitch, "flag", + inst->o_xkbflag); + } + else + e_icon_file_set(inst->o_xkbflag, buf); + edje_object_part_text_set(inst->o_xkbswitch, "label", name); + } + } +} + +void +e_xkb_update_layout(void) +{ + E_XKB_Config_Layout *cl; + E_XKB_Config_Option *op; + Eina_List *l; + char buf[PATH_MAX]; + + if (!e_xkb_cfg->used_layouts) return; + + /* We put an empty -option here in order to override all previously + * set options. + */ + + // XXX: this is unsafe. doesn't keep into account size of buf + snprintf(buf, sizeof(buf), "setxkbmap "); + EINA_LIST_FOREACH(e_xkb_cfg->used_layouts, l, cl) + { + strcat(buf, cl->name); + break; + if (l->next) strcat(buf, ","); + } + + strcat(buf, " -variant "); + EINA_LIST_FOREACH(e_xkb_cfg->used_layouts, l, cl) + { + strcat(buf, cl->variant); + strcat(buf, ","); + break; + } + + strcat(buf, " -model "); + cl = eina_list_data_get(e_xkb_cfg->used_layouts); + + if (strcmp(cl->model, "default")) + strcat(buf, cl->model); + else if (strcmp(e_xkb_cfg->default_model, "default")) + strcat(buf, e_xkb_cfg->default_model); + else + strcat(buf, "default"); + + EINA_LIST_FOREACH(e_xkb_cfg->used_options, l, op) + { + strcat(buf, " -option "); + strcat(buf, op->name); + break; + } + printf("RUN: '%s'\n", buf); + ecore_exe_run(buf, NULL); +} + +void +e_xkb_layout_next(void) +{ + void *odata, *ndata; + Eina_List *l; + + odata = eina_list_data_get(e_xkb_cfg->used_layouts); + + EINA_LIST_FOREACH(eina_list_next(e_xkb_cfg->used_layouts), l, ndata) + { + eina_list_data_set(eina_list_prev(l), ndata); + } + + eina_list_data_set(eina_list_last(e_xkb_cfg->used_layouts), odata); + e_xkb_update_icon(); + e_xkb_update_layout(); +} + +void +e_xkb_layout_prev(void) +{ + void *odata, *ndata; + Eina_List *l; + + odata = eina_list_data_get(eina_list_last(e_xkb_cfg->used_layouts)); + + for (l = e_xkb_cfg->used_layouts, ndata = eina_list_data_get(l); + l; l = eina_list_next(l)) + { + if (eina_list_next(l)) + ndata = eina_list_data_set(eina_list_next(l), ndata); + } + + eina_list_data_set(e_xkb_cfg->used_layouts, odata); + e_xkb_update_icon(); + e_xkb_update_layout(); +} + +/* LOCAL STATIC FUNCTIONS */ + +static E_Gadcon_Client * +_gc_init(E_Gadcon *gc, const char *gcname, const char *id, const char *style) +{ + Instance *inst; + const char *name; + + char buf[PATH_MAX]; + + if (e_xkb_cfg->used_layouts) + name = ((E_XKB_Config_Layout*)eina_list_data_get(e_xkb_cfg->used_layouts))->name; + else name = NULL; + + if ((name) && (strchr(name, '/'))) name = strchr(name, '/') + 1; + + /* The instance */ + inst = E_NEW(Instance, 1); + /* The gadget */ + inst->o_xkbswitch = edje_object_add(gc->evas); + //XXX add to theme + e_theme_edje_object_set(inst->o_xkbswitch, + "base/theme/modules/xkbswitch", + "modules/xkbswitch/main"); + if (name) edje_object_part_text_set(inst->o_xkbswitch, "label", name); + /* The gadcon client */ + inst->gcc = e_gadcon_client_new(gc, gcname, id, style, inst->o_xkbswitch); + inst->gcc->data = inst; + /* The flag icon */ + if (!e_xkb_cfg->only_label) + { + inst->o_xkbflag = e_icon_add(gc->evas); + snprintf(buf, sizeof(buf), "%s/data/flags/%s_flag.png", + e_prefix_data_get(), name ? name : "unknown"); + e_icon_file_set(inst->o_xkbflag, buf); + /* The icon is part of the gadget. */ + edje_object_part_swallow(inst->o_xkbswitch, "flag", inst->o_xkbflag); + } + else inst->o_xkbflag = NULL; + + /* Hook some menus */ + evas_object_event_callback_add(inst->o_xkbswitch, EVAS_CALLBACK_MOUSE_DOWN, + _e_xkb_cb_mouse_down, inst); + /* Make the list know about the instance */ + instances = eina_list_append(instances, inst); + + return inst->gcc; +} + +static void +_gc_shutdown(E_Gadcon_Client *gcc) +{ + Instance *inst; + + if (!(inst = gcc->data)) return; + instances = eina_list_remove(instances, inst); + + if (inst->menu) + { + e_menu_post_deactivate_callback_set(inst->menu, NULL, NULL); + e_object_del(E_OBJECT(inst->menu)); + inst->menu = NULL; + } + if (inst->lmenu) + { + e_menu_post_deactivate_callback_set(inst->lmenu, NULL, NULL); + e_object_del(E_OBJECT(inst->lmenu)); + inst->lmenu = NULL; + } + if (inst->o_xkbswitch) + { + evas_object_event_callback_del(inst->o_xkbswitch, + EVAS_CALLBACK_MOUSE_DOWN, + _e_xkb_cb_mouse_down); + evas_object_del(inst->o_xkbswitch); + evas_object_del(inst->o_xkbflag); + } + E_FREE(inst); +} + +static void +_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient __UNUSED__) +{ + e_gadcon_client_aspect_set(gcc, 16, 16); + e_gadcon_client_min_size_set(gcc, 16, 16); +} + +static const char * +_gc_label(E_Gadcon_Client_Class *client_class __UNUSED__) +{ + return _("XKB Switcher"); +} + +static const char * +_gc_id_new(E_Gadcon_Client_Class *client_class __UNUSED__) +{ + return _gc_class.name; +} + +static Evas_Object * +_gc_icon(E_Gadcon_Client_Class *client_class __UNUSED__, Evas *evas) +{ + Evas_Object *o; + char buf[PATH_MAX]; + + snprintf(buf, sizeof(buf), "%s/e-module-xkbswitch.edj", + e_xkb_cfg->module->dir); + o = edje_object_add(evas); + edje_object_file_set(o, buf, "icon"); + return o; +} + +static void +_e_xkb_cfg_new(void) +{ + e_xkb_cfg = E_NEW(E_XKB_Config, 1); + + e_xkb_cfg->used_layouts = NULL; + e_xkb_cfg->used_options = NULL; + e_xkb_cfg->version = MOD_CONFIG_FILE_VERSION; + e_xkb_cfg->default_model = eina_stringshare_add("default"); + +#define BIND(act, actname) \ + e_xkb_cfg->layout_##act##_key.context = E_BINDING_CONTEXT_ANY; \ + e_xkb_cfg->layout_##act##_key.key = eina_stringshare_add("comma"); \ + e_xkb_cfg->layout_##act##_key.modifiers = E_BINDING_MODIFIER_CTRL | E_BINDING_MODIFIER_ALT; \ + e_xkb_cfg->layout_##act##_key.any_mod = 0; \ + e_xkb_cfg->layout_##act##_key.action = eina_stringshare_add(actname); \ + e_xkb_cfg->layout_##act##_key.params = NULL + + BIND(next, E_XKB_NEXT_ACTION); + BIND(prev, E_XKB_PREV_ACTION); +#undef BIND + + e_config_save_queue(); +} + +static void +_e_xkb_cfg_free(void) +{ + E_XKB_Config_Layout *cl; + E_XKB_Config_Option *op; + + EINA_LIST_FREE(e_xkb_cfg->used_layouts, cl) + { + eina_stringshare_del(cl->name); + eina_stringshare_del(cl->model); + eina_stringshare_del(cl->variant); + E_FREE(cl); + } + + EINA_LIST_FREE(e_xkb_cfg->used_options, op) + { + eina_stringshare_del(op->name); + E_FREE(op); + } + + if (e_xkb_cfg->default_model) + eina_stringshare_del(e_xkb_cfg->default_model); + E_FREE(e_xkb_cfg); +} + +static Eina_Bool +_e_xkb_cfg_timer(void *data) +{ + e_util_dialog_internal( _("XKB Switcher Configuration Updated"), data); + return EINA_FALSE; +} + +static void +_e_xkb_cb_mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event) +{ + Evas_Event_Mouse_Down *ev = event; + Instance *inst = data; + + if (!inst) return; + + if ((ev->button == 3) && (!inst->menu)) /* Right-click utility menu */ + { + int x, y; + E_Menu_Item *mi; + + /* The menu and menu item */ + inst->menu = e_menu_new(); + mi = e_menu_item_new(inst->menu); + /* Menu item specifics */ + e_menu_item_label_set(mi, _("Settings")); + e_util_menu_item_theme_icon_set(mi, "preferences-system"); + e_menu_item_callback_set(mi, _e_xkb_cb_menu_configure, NULL); + /* Append into the util menu */ + inst->menu = e_gadcon_client_util_menu_items_append(inst->gcc, + inst->menu, 0); + /* Callback */ + e_menu_post_deactivate_callback_set(inst->menu, _e_xkb_cb_menu_post, + inst); + /* Coords */ + e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &x, &y, + NULL, NULL); + /* Activate - we show the menu relative to the gadget */ + e_menu_activate_mouse(inst->menu, + e_util_zone_current_get(e_manager_current_get()), + (x + ev->output.x), (y + ev->output.y), 1, 1, + E_MENU_POP_DIRECTION_AUTO, ev->timestamp); + + evas_event_feed_mouse_up(inst->gcc->gadcon->evas, ev->button, + EVAS_BUTTON_NONE, ev->timestamp, NULL); + } + else if ((ev->button == 1) && (!inst->lmenu)) /* Left-click layout menu */ + { + Evas_Coord x, y, w, h; + int cx, cy; + + /* Coordinates and sizing */ + evas_object_geometry_get(inst->o_xkbswitch, &x, &y, &w, &h); + e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &cx, &cy, + NULL, NULL); + x += cx; + y += cy; + + if (!inst->lmenu) inst->lmenu = e_menu_new(); + + if (inst->lmenu) + { + E_XKB_Config_Layout *cl; + E_Menu_Item *mi; + Eina_List *l; + int dir; + char buf[PATH_MAX]; + + mi = e_menu_item_new(inst->lmenu); + + e_menu_item_label_set(mi, _("Settings")); + e_util_menu_item_theme_icon_set(mi, "preferences-system"); + e_menu_item_callback_set(mi, _e_xkb_cb_menu_configure, NULL); + + mi = e_menu_item_new(inst->lmenu); + e_menu_item_separator_set(mi, 1); + + /* Append all the layouts */ + EINA_LIST_FOREACH(e_xkb_cfg->used_layouts, l, cl) + { + const char *name = cl->name; + + mi = e_menu_item_new(inst->lmenu); + + e_menu_item_radio_set(mi, 1); + e_menu_item_radio_group_set(mi, 1); + e_menu_item_toggle_set(mi, + (l == e_xkb_cfg->used_layouts) ? 1 : 0); + if (strchr(name, '/')) name = strchr(name, '/') + 1; + snprintf(buf, sizeof(buf), "%s/data/flags/%s_flag.png", + e_prefix_data_get(), name); + if (!ecore_file_exists(buf)) + snprintf(buf, sizeof(buf), "%s/data/flags/unknown_flag.png", + e_prefix_data_get()); + e_menu_item_icon_file_set(mi, buf); + snprintf(buf, sizeof(buf), "%s (%s, %s)", cl->name, + cl->model, cl->variant); + e_menu_item_label_set(mi, buf); + e_menu_item_callback_set(mi, _e_xkb_cb_lmenu_set, cl); + } + + /* Deactivate callback */ + e_menu_post_deactivate_callback_set(inst->lmenu, + _e_xkb_cb_lmenu_post, inst); + /* Proper menu orientation */ + switch (inst->gcc->gadcon->orient) + { + case E_GADCON_ORIENT_TOP: + dir = E_MENU_POP_DIRECTION_DOWN; + break; + case E_GADCON_ORIENT_BOTTOM: + dir = E_MENU_POP_DIRECTION_UP; + break; + case E_GADCON_ORIENT_LEFT: + dir = E_MENU_POP_DIRECTION_RIGHT; + break; + case E_GADCON_ORIENT_RIGHT: + dir = E_MENU_POP_DIRECTION_LEFT; + break; + case E_GADCON_ORIENT_CORNER_TL: + dir = E_MENU_POP_DIRECTION_DOWN; + break; + case E_GADCON_ORIENT_CORNER_TR: + dir = E_MENU_POP_DIRECTION_DOWN; + break; + case E_GADCON_ORIENT_CORNER_BL: + dir = E_MENU_POP_DIRECTION_UP; + break; + case E_GADCON_ORIENT_CORNER_BR: + dir = E_MENU_POP_DIRECTION_UP; + break; + case E_GADCON_ORIENT_CORNER_LT: + dir = E_MENU_POP_DIRECTION_RIGHT; + break; + case E_GADCON_ORIENT_CORNER_RT: + dir = E_MENU_POP_DIRECTION_LEFT; + break; + case E_GADCON_ORIENT_CORNER_LB: + dir = E_MENU_POP_DIRECTION_RIGHT; + break; + case E_GADCON_ORIENT_CORNER_RB: + dir = E_MENU_POP_DIRECTION_LEFT; + break; + case E_GADCON_ORIENT_FLOAT: + case E_GADCON_ORIENT_HORIZ: + case E_GADCON_ORIENT_VERT: + default: + dir = E_MENU_POP_DIRECTION_AUTO; + break; + } + + e_gadcon_locked_set(inst->gcc->gadcon, 1); + + /* We display not relatively to the gadget, but similarly to + * the start menu - thus the need for direction etc. + */ + e_menu_activate_mouse(inst->lmenu, + e_util_zone_current_get + (e_manager_current_get()), + x, y, w, h, dir, ev->timestamp); + } + } + else if (ev->button == 2) /* Middle click */ + e_xkb_layout_next(); +} + +static void +_e_xkb_cb_menu_post(void *data, E_Menu *menu __UNUSED__) +{ + Instance *inst = data; + + if (!(inst) || !inst->menu) return; + inst->menu = NULL; +} + +static void +_e_xkb_cb_lmenu_post(void *data, E_Menu *menu __UNUSED__) +{ + Instance *inst = data; + + if (!(inst) || !inst->lmenu) return; + inst->lmenu = NULL; +} + +static void +_e_xkb_cb_menu_configure(void *data __UNUSED__, E_Menu *mn, E_Menu_Item *mi __UNUSED__) +{ + if (!e_xkb_cfg || e_xkb_cfg->cfd) return; + e_xkb_cfg_dialog(mn->zone->container, NULL); +} + +static void +_e_xkb_cb_lmenu_set(void *data, E_Menu *mn __UNUSED__, E_Menu_Item *mi __UNUSED__) +{ + Eina_List *l; + void *ndata; + void *odata = eina_list_data_get(e_xkb_cfg->used_layouts); + + EINA_LIST_FOREACH(e_xkb_cfg->used_layouts, l, ndata) + { + if (ndata == data) eina_list_data_set(l, odata); + } + + eina_list_data_set(e_xkb_cfg->used_layouts, data); + + e_xkb_update_icon(); + e_xkb_update_layout(); +} diff --git a/src/modules/xkbswitch/e_mod_main.h b/src/modules/xkbswitch/e_mod_main.h new file mode 100644 index 000000000..9ca03fd16 --- /dev/null +++ b/src/modules/xkbswitch/e_mod_main.h @@ -0,0 +1,97 @@ +/* + * Main module header. + * Contains some i18n stuff, module versioning, + * config and public prototypes from main. + */ + +#ifndef E_MOD_MAIN_H +#define E_MOD_MAIN_H + +/* Macros used for config file versioning */ +/* You can increment the EPOCH value if the old configuration is not + * compatible anymore, it creates an entire new one. + * You need to increment GENERATION when you add new values to the + * configuration file but is not needed to delete the existing conf */ +#define MOD_CONFIG_FILE_EPOCH 0x0001 +#define MOD_CONFIG_FILE_GENERATION 0x008d +#define MOD_CONFIG_FILE_VERSION \ + ((MOD_CONFIG_FILE_EPOCH << 16) | MOD_CONFIG_FILE_GENERATION) + +typedef struct _E_XKB_Config +{ + /* Not written to disk */ + E_Module *module; + E_Config_Dialog *cfd; + + /* Written to disk */ + E_Config_Binding_Key layout_next_key; + E_Config_Binding_Key layout_prev_key; + + Eina_List *used_layouts; + Eina_List *used_options; + const char *default_model; + + int only_label; + + int version; +} E_XKB_Config; + +/* This represents the node data in used_layouts */ +typedef struct _E_XKB_Config_Layout +{ + const char *name; + const char *model; + const char *variant; +} E_XKB_Config_Layout; + +/* This represents a keyboard option in the config dialog */ +typedef struct _E_XKB_Dialog_Option +{ + int enabled; + const char *name; +} E_XKB_Dialog_Option; + +/* This represents a keyboard option saved into eet */ +typedef struct _E_XKB_Config_Option +{ + const char *name; +} E_XKB_Config_Option; + +/* automatically typedef'd by E */ +struct _E_Config_Dialog_Data +{ + Evas *evas, *dlg_evas; + Evas_Object *layout_list, *used_list; + Evas_Object *dmodel_list, *model_list, *variant_list; + Evas_Object *btn_add, *btn_del, *btn_up, *btn_down; + Ecore_Timer *fill_delay; + Ecore_Timer *dlg_fill_delay; + + Eina_List *cfg_layouts; + Eina_List *cfg_options; + const char *default_model; + + int only_label; + + E_Dialog *dlg_add_new; +}; + +/* Prototypes */ + +EAPI extern E_Module_Api e_modapi; + +EAPI void *e_modapi_init (E_Module *m); +EAPI int e_modapi_shutdown(E_Module *m); +EAPI int e_modapi_save (E_Module *m); + +void e_xkb_update_icon (void); +void e_xkb_update_layout(void); + +void e_xkb_layout_next(void); +void e_xkb_layout_prev(void); + +E_Config_Dialog *e_xkb_cfg_dialog(E_Container *con, const char *params); + +extern E_XKB_Config *e_xkb_cfg; + +#endif diff --git a/src/modules/xkbswitch/e_mod_parse.c b/src/modules/xkbswitch/e_mod_parse.c new file mode 100644 index 000000000..e31632116 --- /dev/null +++ b/src/modules/xkbswitch/e_mod_parse.c @@ -0,0 +1,310 @@ +#include "e.h" +#include "e_mod_parse.h" + +Eina_List *layouts = NULL; +Eina_List *models = NULL; +Eina_List *optgroups = NULL; + +static const char *rules_file = NULL; + +void +find_rules(void) +{ + int i = 0; + const char *lstfiles[] = { + "/usr/share/X11/xkb/rules/xorg.lst", + "/usr/share/X11/xkb/rules/xfree86.lst", + "/usr/local/share/X11/xkb/rules/xorg.lst", + "/usr/local/share/X11/xkb/rules/xfree86.lst", + "/usr/X11R6/lib/X11/xkb/rules/xorg.lst", + "/usr/X11R6/lib/X11/xkb/rules/xfree86.lst", + "/usr/local/X11R6/lib/X11/xkb/rules/xorg.lst", + "/usr/local/X11R6/lib/X11/xkb/rules/xfree86.lst", + NULL + }; + + for (; lstfiles[i]; i++) + { + FILE *f = fopen(lstfiles[i], "r"); + if (f) + { + fclose(f); + rules_file = lstfiles[i]; + break; + } + } +} + +int +parse_rules(void) +{ + E_XKB_Model *model = NULL; + E_XKB_Layout *layout = NULL; + E_XKB_Option *option = NULL; + E_XKB_Variant *variant = NULL; + E_XKB_Option_Group *group = NULL; + char buf[4096]; + + if (!rules_file) return 0; + + layouts = NULL; + models = NULL; + + FILE *f = fopen(rules_file, "r"); + if (!f) return 0; + + /* move on to next line, the first one is useless */ + if (!fgets(buf, sizeof(buf), f)) goto err; + + /* let X decide on this one, also serves as + * "fallback on global" for layout combinations + */ + model = E_NEW(E_XKB_Model, 1); + model->name = eina_stringshare_add("default"); + model->description = eina_stringshare_add("Automatic"); + models = eina_list_append(models, model); + + /* read models here */ + for (;;) + { + if (fgets(buf, sizeof(buf), f)) + { + char *n = strchr(buf, '\n'); + if (n) *n = '\0'; + + /* means end of section */ + if (!buf[0]) break; + /* get rid of initial 2 spaces here */ + char *p = buf + 2; + char *tmp = strdup(p); + + model = E_NEW(E_XKB_Model, 1); + model->name = eina_stringshare_add(strtok(tmp, " ")); + + free(tmp); + + p += strlen(model->name); + while (p[0] == ' ') ++p; + + model->description = eina_stringshare_add(p); + + models = eina_list_append(models, model); + } + else + break; + } + + /* move on again */ + if (!fgets(buf, sizeof(buf), f)) goto err; + + /* read layouts here */ + for (;;) + { + if (fgets(buf, sizeof(buf), f)) + { + char *n = strchr(buf, '\n'); + if (n) *n = '\0'; + + if (!buf[0]) break; + + char *p = buf + 2; + char *tmp = strdup(p); + + layout = E_NEW(E_XKB_Layout, 1); + layout->name = eina_stringshare_add(strtok(tmp, " ")); + + free(tmp); + + p += strlen(layout->name); + while (p[0] == ' ') ++p; + + variant = E_NEW(E_XKB_Variant, 1); + variant->name = eina_stringshare_add("basic"); + variant->description = eina_stringshare_add("Default layout variant"); + + layout->description = eina_stringshare_add(p); + layout->variants = eina_list_append(layout->variants, variant); + + layouts = eina_list_append(layouts, layout); + } + else + break; + } + + /* move on again */ + if (!fgets(buf, sizeof(buf), f)) goto err; + + /* read variants here */ + for (;;) + { + if (fgets(buf, sizeof(buf), f)) + { + char *n = strchr(buf, '\n'); + if (n) *n = '\0'; + + if (!buf[0]) break; + + char *p = buf + 2; + char *tmp = strdup(p); + + variant = E_NEW(E_XKB_Variant, 1); + variant->name = eina_stringshare_add(strtok(tmp, " ")); + + char *tok = strtok(NULL, " "); + *strchr(tok, ':') = '\0'; + + layout = eina_list_search_unsorted(layouts, layout_sort_by_name_cb, tok); + layout->variants = eina_list_append(layout->variants, variant); + + p += strlen(variant->name); + while (p[0] == ' ') ++p; + p += strlen(tok); + p += 2; + + free(tmp); + + variant->description = eina_stringshare_add(p); + } + else + break; + } + + /* move on again */ + if (!fgets(buf, sizeof(buf), f)) goto err; + + /* read options here */ + for (;;) + { + if (fgets(buf, sizeof(buf), f)) + { + char *n = strchr(buf, '\n'); + if (n) *n = '\0'; + + if (!buf[0]) break; + + char *p = buf + 2; + char *tmp = strdup(p); + char *name = strtok(tmp, " "); + + p += strlen(name); + while (p[0] == ' ') ++p; + + if (!strchr(name, ':')) + { + group = E_NEW(E_XKB_Option_Group, 1); + + /* A hack to get it to parse right if + * the group name contains a space + */ + if (strstr(p, " ")) + { + p = strstr(p, " "); + while (p[0] == ' ') ++p; + } + + group->description = eina_stringshare_add(p); + + optgroups = eina_list_append(optgroups, group); + } + else + { + option = E_NEW(E_XKB_Option, 1); + option->name = eina_stringshare_add(name); + option->description = eina_stringshare_add(p); + + group->options = eina_list_append(group->options, option); + } + + free(tmp); + } + else + break; + } + +err: + fclose(f); + + /* Sort layouts */ + layouts = + eina_list_sort(layouts, eina_list_count(layouts), layout_sort_cb); + return 1; +} + +void +clear_rules(void) +{ + E_XKB_Option_Group *og; + E_XKB_Variant *v; + E_XKB_Option *o; + E_XKB_Layout *la; + E_XKB_Model *m; + + EINA_LIST_FREE(layouts, la) + { + eina_stringshare_del(la->name); + eina_stringshare_del(la->description); + + EINA_LIST_FREE(la->variants, v) + { + eina_stringshare_del(v->name); + eina_stringshare_del(v->description); + + E_FREE(v); + } + + E_FREE(la); + } + + EINA_LIST_FREE(models, m) + { + eina_stringshare_del(m->name); + eina_stringshare_del(m->description); + + E_FREE(m); + } + + EINA_LIST_FREE(optgroups, og) + { + eina_stringshare_del(og->description); + + EINA_LIST_FREE(og->options, o) + { + eina_stringshare_del(o->name); + eina_stringshare_del(o->description); + + E_FREE(o); + } + + E_FREE(og); + } + + optgroups = NULL; + layouts = NULL; + models = NULL; +} + +int +layout_sort_cb(const void *data1, const void *data2) +{ + const E_XKB_Layout *l1, *l2; + + if (!(l1 = data1)) return 1; + if (!l1->name) return 1; + if (!(l2 = data2)) return -1; + if (!l2->name) return -1; + + return strcmp(l1->name, l2->name); +} + +int +layout_sort_by_name_cb(const void *data1, const void *data2) +{ + const E_XKB_Layout *l1 = NULL; + const char *l2 = NULL; + + if (!(l1 = data1)) return 1; + if (!l1->name) return 1; + if (!(l2 = data2)) return -1; + + return strcmp(l1->name, l2); +} diff --git a/src/modules/xkbswitch/e_mod_parse.h b/src/modules/xkbswitch/e_mod_parse.h new file mode 100644 index 000000000..0998c781f --- /dev/null +++ b/src/modules/xkbswitch/e_mod_parse.h @@ -0,0 +1,52 @@ +/* + * XML parsing abstraction interface header. + * Contains public structs and lists externs which are further used. + */ + +#ifndef E_MOD_PARSE_H +#define E_MOD_PARSE_H + +typedef struct _E_XKB_Model +{ + const char *name; + const char *description; +} E_XKB_Model; + +typedef struct _E_XKB_Variant +{ + const char *name; + const char *description; +} E_XKB_Variant; + +typedef struct _E_XKB_Layout +{ + const char *name; + const char *description; + + Eina_List *variants; +} E_XKB_Layout; + +typedef struct _E_XKB_Option_Group +{ + const char *description; + Eina_List *options; +} E_XKB_Option_Group; + +typedef struct _E_XKB_Option +{ + const char *name; + const char *description; +} E_XKB_Option; + +int parse_rules(void); +void clear_rules(void); +void find_rules(void); + +int layout_sort_cb (const void *data1, const void *data2); +int layout_sort_by_name_cb(const void *data1, const void *data2); + +extern Eina_List *models; +extern Eina_List *layouts; +extern Eina_List *optgroups; + +#endif diff --git a/src/modules/xkbswitch/module.desktop.in b/src/modules/xkbswitch/module.desktop.in new file mode 100644 index 000000000..4579a66cd --- /dev/null +++ b/src/modules/xkbswitch/module.desktop.in @@ -0,0 +1,6 @@ +[Desktop Entry] +Type=Link +Name=XKBSwitch +Icon=e-module-xkbswitch +X-Enlightenment-ModuleType=utils +Comment=Keyboard layout configuration and switcher