aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--configure.ac4
-rw-r--r--data/Makefile.am4
-rw-r--r--data/flags/Makefile.am97
-rw-r--r--data/flags/ad_flag.pngbin0 -> 2983 bytes
-rw-r--r--data/flags/af_flag.pngbin0 -> 3238 bytes
-rw-r--r--data/flags/al_flag.pngbin0 -> 3833 bytes
-rw-r--r--data/flags/am_flag.pngbin0 -> 318 bytes
-rw-r--r--data/flags/ara_flag.pngbin0 -> 3546 bytes
-rw-r--r--data/flags/at_flag.pngbin0 -> 379 bytes
-rw-r--r--data/flags/az_flag.pngbin0 -> 1073 bytes
-rw-r--r--data/flags/ba_flag.pngbin0 -> 3039 bytes
-rw-r--r--data/flags/bd_flag.pngbin0 -> 1361 bytes
-rw-r--r--data/flags/be_flag.pngbin0 -> 334 bytes
-rw-r--r--data/flags/bg_flag.pngbin0 -> 322 bytes
-rw-r--r--data/flags/br_flag.pngbin0 -> 3998 bytes
-rw-r--r--data/flags/brai_flag.pngbin0 -> 7550 bytes
-rw-r--r--data/flags/bt_flag.pngbin0 -> 6709 bytes
-rw-r--r--data/flags/bw_flag.pngbin0 -> 416 bytes
-rw-r--r--data/flags/by_flag.pngbin0 -> 2828 bytes
-rw-r--r--data/flags/ca_flag.pngbin0 -> 1341 bytes
-rw-r--r--data/flags/cd_flag.pngbin0 -> 4667 bytes
-rw-r--r--data/flags/ch_flag.pngbin0 -> 588 bytes
-rw-r--r--data/flags/cn_flag.pngbin0 -> 1627 bytes
-rw-r--r--data/flags/cz_flag.pngbin0 -> 1513 bytes
-rw-r--r--data/flags/de_flag.pngbin0 -> 317 bytes
-rw-r--r--data/flags/dk_flag.pngbin0 -> 466 bytes
-rw-r--r--data/flags/ee_flag.pngbin0 -> 375 bytes
-rw-r--r--data/flags/epo_flag.pngbin0 -> 1173 bytes
-rw-r--r--data/flags/es_flag.pngbin0 -> 2395 bytes
-rw-r--r--data/flags/et_flag.pngbin0 -> 3178 bytes
-rw-r--r--data/flags/fi_flag.pngbin0 -> 522 bytes
-rw-r--r--data/flags/fo_flag.pngbin0 -> 629 bytes
-rw-r--r--data/flags/fr_flag.pngbin0 -> 327 bytes
-rw-r--r--data/flags/gb_flag.pngbin0 -> 4182 bytes
-rw-r--r--data/flags/ge_flag.pngbin0 -> 1657 bytes
-rw-r--r--data/flags/gh_flag.pngbin0 -> 1084 bytes
-rw-r--r--data/flags/gn_flag.pngbin0 -> 440 bytes
-rw-r--r--data/flags/gr_flag.pngbin0 -> 744 bytes
-rw-r--r--data/flags/hr_flag.pngbin0 -> 2288 bytes
-rw-r--r--data/flags/hu_flag.pngbin0 -> 325 bytes
-rw-r--r--data/flags/ie_flag.pngbin0 -> 326 bytes
-rw-r--r--data/flags/il_flag.pngbin0 -> 1611 bytes
-rw-r--r--data/flags/in_flag.pngbin0 -> 1411 bytes
-rw-r--r--data/flags/iq_flag.pngbin0 -> 1771 bytes
-rw-r--r--data/flags/ir_flag.pngbin0 -> 4471 bytes
-rw-r--r--data/flags/is_flag.pngbin0 -> 471 bytes
-rw-r--r--data/flags/it_flag.pngbin0 -> 326 bytes
-rw-r--r--data/flags/jp_flag.pngbin0 -> 1573 bytes
-rw-r--r--data/flags/ke_flag.pngbin0 -> 2582 bytes
-rw-r--r--data/flags/kg_flag.pngbin0 -> 4056 bytes
-rw-r--r--data/flags/kh_flag.pngbin0 -> 3029 bytes
-rw-r--r--data/flags/kr_flag.pngbin0 -> 4368 bytes
-rw-r--r--data/flags/kz_flag.pngbin0 -> 4344 bytes
-rw-r--r--data/flags/la_flag.pngbin0 -> 1054 bytes
-rw-r--r--data/flags/latam_flag.pngbin0 -> 9496 bytes
-rw-r--r--data/flags/lk_flag.pngbin0 -> 3735 bytes
-rw-r--r--data/flags/lt_flag.pngbin0 -> 330 bytes
-rw-r--r--data/flags/lv_flag.pngbin0 -> 351 bytes
-rw-r--r--data/flags/ma_flag.pngbin0 -> 2307 bytes
-rw-r--r--data/flags/mao_flag.pngbin0 -> 3545 bytes
-rw-r--r--data/flags/me_flag.pngbin0 -> 3519 bytes
-rw-r--r--data/flags/mk_flag.pngbin0 -> 2952 bytes
-rw-r--r--data/flags/ml_flag.pngbin0 -> 437 bytes
-rw-r--r--data/flags/mm_flag.pngbin0 -> 2593 bytes
-rw-r--r--data/flags/mn_flag.pngbin0 -> 1781 bytes
-rw-r--r--data/flags/mt_flag.pngbin0 -> 946 bytes
-rw-r--r--data/flags/mv_flag.pngbin0 -> 1038 bytes
-rw-r--r--data/flags/ng_flag.pngbin0 -> 508 bytes
-rw-r--r--data/flags/nl_flag.pngbin0 -> 366 bytes
-rw-r--r--data/flags/no_flag.pngbin0 -> 592 bytes
-rw-r--r--data/flags/np_flag.pngbin0 -> 14010 bytes
-rw-r--r--data/flags/ph_flag.pngbin0 -> 2965 bytes
-rw-r--r--data/flags/pk_flag.pngbin0 -> 2011 bytes
-rw-r--r--data/flags/pl_flag.pngbin0 -> 320 bytes
-rw-r--r--data/flags/pt_flag.pngbin0 -> 3615 bytes
-rw-r--r--data/flags/ro_flag.pngbin0 -> 327 bytes
-rw-r--r--data/flags/rs_flag.pngbin0 -> 3697 bytes
-rw-r--r--data/flags/ru_flag.pngbin0 -> 362 bytes
-rw-r--r--data/flags/se_flag.pngbin0 -> 428 bytes
-rw-r--r--data/flags/si_flag.pngbin0 -> 1237 bytes
-rw-r--r--data/flags/sk_flag.pngbin0 -> 2244 bytes
-rw-r--r--data/flags/sn_flag.pngbin0 -> 1060 bytes
-rw-r--r--data/flags/sy_flag.pngbin0 -> 1533 bytes
-rw-r--r--data/flags/th_flag.pngbin0 -> 409 bytes
-rw-r--r--data/flags/tj_flag.pngbin0 -> 1688 bytes
-rw-r--r--data/flags/tm_flag.pngbin0 -> 6504 bytes
-rw-r--r--data/flags/tr_flag.pngbin0 -> 1784 bytes
-rw-r--r--data/flags/tw_flag.pngbin0 -> 1993 bytes
-rw-r--r--data/flags/tz_flag.pngbin0 -> 3550 bytes
-rw-r--r--data/flags/ua_flag.pngbin0 -> 332 bytes
-rw-r--r--data/flags/unknown_flag.pngbin0 -> 5602 bytes
-rw-r--r--data/flags/us_flag.pngbin0 -> 2869 bytes
-rw-r--r--data/flags/uz_flag.pngbin0 -> 1350 bytes
-rw-r--r--data/flags/vn_flag.pngbin0 -> 1473 bytes
-rw-r--r--data/flags/za_flag.pngbin0 -> 3222 bytes
-rw-r--r--data/themes/default.edc135
-rw-r--r--po/POTFILES.in7
-rw-r--r--src/modules/Makefile.am4
-rw-r--r--src/modules/conf_display/e_int_config_display.c843
-rw-r--r--src/modules/xkbswitch/Makefile.am34
-rw-r--r--src/modules/xkbswitch/e-module-xkbswitch.edjbin0 -> 9213 bytes
-rw-r--r--src/modules/xkbswitch/e_mod_config.c768
-rw-r--r--src/modules/xkbswitch/e_mod_keybindings.c194
-rw-r--r--src/modules/xkbswitch/e_mod_keybindings.h16
-rw-r--r--src/modules/xkbswitch/e_mod_main.c770
-rw-r--r--src/modules/xkbswitch/e_mod_main.h97
-rw-r--r--src/modules/xkbswitch/e_mod_parse.c310
-rw-r--r--src/modules/xkbswitch/e_mod_parse.h52
-rw-r--r--src/modules/xkbswitch/module.desktop.in6
110 files changed, 3046 insertions, 296 deletions
diff --git a/AUTHORS b/AUTHORS
index 6b0f204d4..e58a155ad 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -32,3 +32,4 @@ Sthitha <iamsthitha@gmail>
Doyoun Kang <doyoun.kang@samsung.com>
Gwanglim Lee <gl77.lee@samsung.com>
Thomas Gstädtner <thomas@gstaedtner.net>
+q66 <quaker66@gmail.com>
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
--- /dev/null
+++ b/data/flags/ad_flag.png
Binary files differ
diff --git a/data/flags/af_flag.png b/data/flags/af_flag.png
new file mode 100644
index 000000000..84f583021
--- /dev/null
+++ b/data/flags/af_flag.png
Binary files differ
diff --git a/data/flags/al_flag.png b/data/flags/al_flag.png
new file mode 100644
index 000000000..fec5a7502
--- /dev/null
+++ b/data/flags/al_flag.png
Binary files differ
diff --git a/data/flags/am_flag.png b/data/flags/am_flag.png
new file mode 100644
index 000000000..74d914800
--- /dev/null
+++ b/data/flags/am_flag.png
Binary files differ
diff --git a/data/flags/ara_flag.png b/data/flags/ara_flag.png
new file mode 100644
index 000000000..c1b17643d
--- /dev/null
+++ b/data/flags/ara_flag.png
Binary files differ
diff --git a/data/flags/at_flag.png b/data/flags/at_flag.png
new file mode 100644
index 000000000..c9851fe60
--- /dev/null
+++ b/data/flags/at_flag.png
Binary files differ
diff --git a/data/flags/az_flag.png b/data/flags/az_flag.png
new file mode 100644
index 000000000..1511ee05e
--- /dev/null
+++ b/data/flags/az_flag.png
Binary files differ
diff --git a/data/flags/ba_flag.png b/data/flags/ba_flag.png
new file mode 100644
index 000000000..79920af51
--- /dev/null
+++ b/data/flags/ba_flag.png
Binary files differ
diff --git a/data/flags/bd_flag.png b/data/flags/bd_flag.png
new file mode 100644
index 000000000..975b54c68
--- /dev/null
+++ b/data/flags/bd_flag.png
Binary files differ
diff --git a/data/flags/be_flag.png b/data/flags/be_flag.png
new file mode 100644
index 000000000..43a9442d3
--- /dev/null
+++ b/data/flags/be_flag.png
Binary files differ
diff --git a/data/flags/bg_flag.png b/data/flags/bg_flag.png
new file mode 100644
index 000000000..c7b795738
--- /dev/null
+++ b/data/flags/bg_flag.png
Binary files differ
diff --git a/data/flags/br_flag.png b/data/flags/br_flag.png
new file mode 100644
index 000000000..98bba07aa
--- /dev/null
+++ b/data/flags/br_flag.png
Binary files differ
diff --git a/data/flags/brai_flag.png b/data/flags/brai_flag.png
new file mode 100644
index 000000000..3eda749e9
--- /dev/null
+++ b/data/flags/brai_flag.png
Binary files differ
diff --git a/data/flags/bt_flag.png b/data/flags/bt_flag.png
new file mode 100644
index 000000000..3d0f0b01a
--- /dev/null
+++ b/data/flags/bt_flag.png
Binary files differ
diff --git a/data/flags/bw_flag.png b/data/flags/bw_flag.png
new file mode 100644
index 000000000..d557d29b1
--- /dev/null
+++ b/data/flags/bw_flag.png
Binary files differ
diff --git a/data/flags/by_flag.png b/data/flags/by_flag.png
new file mode 100644
index 000000000..890148f2b
--- /dev/null
+++ b/data/flags/by_flag.png
Binary files differ
diff --git a/data/flags/ca_flag.png b/data/flags/ca_flag.png
new file mode 100644
index 000000000..42c1babfa
--- /dev/null
+++ b/data/flags/ca_flag.png
Binary files differ
diff --git a/data/flags/cd_flag.png b/data/flags/cd_flag.png
new file mode 100644
index 000000000..dff2fa1cb
--- /dev/null
+++ b/data/flags/cd_flag.png
Binary files differ
diff --git a/data/flags/ch_flag.png b/data/flags/ch_flag.png
new file mode 100644
index 000000000..5d2937934
--- /dev/null
+++ b/data/flags/ch_flag.png
Binary files differ
diff --git a/data/flags/cn_flag.png b/data/flags/cn_flag.png
new file mode 100644
index 000000000..43c8498ae
--- /dev/null
+++ b/data/flags/cn_flag.png
Binary files differ
diff --git a/data/flags/cz_flag.png b/data/flags/cz_flag.png
new file mode 100644
index 000000000..559efd62d
--- /dev/null
+++ b/data/flags/cz_flag.png
Binary files differ
diff --git a/data/flags/de_flag.png b/data/flags/de_flag.png
new file mode 100644
index 000000000..cd29a19ff
--- /dev/null
+++ b/data/flags/de_flag.png
Binary files differ
diff --git a/data/flags/dk_flag.png b/data/flags/dk_flag.png
new file mode 100644
index 000000000..4cf042cf7
--- /dev/null
+++ b/data/flags/dk_flag.png
Binary files differ
diff --git a/data/flags/ee_flag.png b/data/flags/ee_flag.png
new file mode 100644
index 000000000..35fcb0e85
--- /dev/null
+++ b/data/flags/ee_flag.png
Binary files differ
diff --git a/data/flags/epo_flag.png b/data/flags/epo_flag.png
new file mode 100644
index 000000000..dde003b0d
--- /dev/null
+++ b/data/flags/epo_flag.png
Binary files differ
diff --git a/data/flags/es_flag.png b/data/flags/es_flag.png
new file mode 100644
index 000000000..ea801a381
--- /dev/null
+++ b/data/flags/es_flag.png
Binary files differ
diff --git a/data/flags/et_flag.png b/data/flags/et_flag.png
new file mode 100644
index 000000000..62fa8c148
--- /dev/null
+++ b/data/flags/et_flag.png
Binary files differ
diff --git a/data/flags/fi_flag.png b/data/flags/fi_flag.png
new file mode 100644
index 000000000..bd9e089b9
--- /dev/null
+++ b/data/flags/fi_flag.png
Binary files differ
diff --git a/data/flags/fo_flag.png b/data/flags/fo_flag.png
new file mode 100644
index 000000000..cb1615352
--- /dev/null
+++ b/data/flags/fo_flag.png
Binary files differ
diff --git a/data/flags/fr_flag.png b/data/flags/fr_flag.png
new file mode 100644
index 000000000..cd01be597
--- /dev/null
+++ b/data/flags/fr_flag.png
Binary files differ
diff --git a/data/flags/gb_flag.png b/data/flags/gb_flag.png
new file mode 100644
index 000000000..9246d8cc8
--- /dev/null
+++ b/data/flags/gb_flag.png
Binary files differ
diff --git a/data/flags/ge_flag.png b/data/flags/ge_flag.png
new file mode 100644
index 000000000..239b3a668
--- /dev/null
+++ b/data/flags/ge_flag.png
Binary files differ
diff --git a/data/flags/gh_flag.png b/data/flags/gh_flag.png
new file mode 100644
index 000000000..2e1ace276
--- /dev/null
+++ b/data/flags/gh_flag.png
Binary files differ
diff --git a/data/flags/gn_flag.png b/data/flags/gn_flag.png
new file mode 100644
index 000000000..0379766f1
--- /dev/null
+++ b/data/flags/gn_flag.png
Binary files differ
diff --git a/data/flags/gr_flag.png b/data/flags/gr_flag.png
new file mode 100644
index 000000000..e6ee4cbd6
--- /dev/null
+++ b/data/flags/gr_flag.png
Binary files differ
diff --git a/data/flags/hr_flag.png b/data/flags/hr_flag.png
new file mode 100644
index 000000000..675758750
--- /dev/null
+++ b/data/flags/hr_flag.png
Binary files differ
diff --git a/data/flags/hu_flag.png b/data/flags/hu_flag.png
new file mode 100644
index 000000000..dcbbc4396
--- /dev/null
+++ b/data/flags/hu_flag.png
Binary files differ
diff --git a/data/flags/ie_flag.png b/data/flags/ie_flag.png
new file mode 100644
index 000000000..33c3db8b7
--- /dev/null
+++ b/data/flags/ie_flag.png
Binary files differ
diff --git a/data/flags/il_flag.png b/data/flags/il_flag.png
new file mode 100644
index 000000000..0d801719b
--- /dev/null
+++ b/data/flags/il_flag.png
Binary files differ
diff --git a/data/flags/in_flag.png b/data/flags/in_flag.png
new file mode 100644
index 000000000..697a0d02b
--- /dev/null
+++ b/data/flags/in_flag.png
Binary files differ
diff --git a/data/flags/iq_flag.png b/data/flags/iq_flag.png
new file mode 100644
index 000000000..4fb13e728
--- /dev/null
+++ b/data/flags/iq_flag.png
Binary files differ
diff --git a/data/flags/ir_flag.png b/data/flags/ir_flag.png
new file mode 100644
index 000000000..c80febd59
--- /dev/null
+++ b/data/flags/ir_flag.png
Binary files differ
diff --git a/data/flags/is_flag.png b/data/flags/is_flag.png
new file mode 100644
index 000000000..d781a1232
--- /dev/null
+++ b/data/flags/is_flag.png
Binary files differ
diff --git a/data/flags/it_flag.png b/data/flags/it_flag.png
new file mode 100644
index 000000000..270d1666c
--- /dev/null
+++ b/data/flags/it_flag.png
Binary files differ
diff --git a/data/flags/jp_flag.png b/data/flags/jp_flag.png
new file mode 100644
index 000000000..49af2cf85
--- /dev/null
+++ b/data/flags/jp_flag.png
Binary files differ
diff --git a/data/flags/ke_flag.png b/data/flags/ke_flag.png
new file mode 100644
index 000000000..461992875
--- /dev/null
+++ b/data/flags/ke_flag.png
Binary files differ
diff --git a/data/flags/kg_flag.png b/data/flags/kg_flag.png
new file mode 100644
index 000000000..a707e21d5
--- /dev/null
+++ b/data/flags/kg_flag.png
Binary files differ
diff --git a/data/flags/kh_flag.png b/data/flags/kh_flag.png
new file mode 100644
index 000000000..558fb0a75
--- /dev/null
+++ b/data/flags/kh_flag.png
Binary files differ
diff --git a/data/flags/kr_flag.png b/data/flags/kr_flag.png
new file mode 100644
index 000000000..ae035a4f8
--- /dev/null
+++ b/data/flags/kr_flag.png
Binary files differ
diff --git a/data/flags/kz_flag.png b/data/flags/kz_flag.png
new file mode 100644
index 000000000..b004cf5fd
--- /dev/null
+++ b/data/flags/kz_flag.png
Binary files differ
diff --git a/data/flags/la_flag.png b/data/flags/la_flag.png
new file mode 100644
index 000000000..8a94ff18f
--- /dev/null
+++ b/data/flags/la_flag.png
Binary files differ
diff --git a/data/flags/latam_flag.png b/data/flags/latam_flag.png
new file mode 100644
index 000000000..3480ad5c1
--- /dev/null
+++ b/data/flags/latam_flag.png
Binary files differ
diff --git a/data/flags/lk_flag.png b/data/flags/lk_flag.png
new file mode 100644
index 000000000..63d98f533
--- /dev/null
+++ b/data/flags/lk_flag.png
Binary files differ
diff --git a/data/flags/lt_flag.png b/data/flags/lt_flag.png
new file mode 100644
index 000000000..3b2704c7e
--- /dev/null
+++ b/data/flags/lt_flag.png
Binary files differ
diff --git a/data/flags/lv_flag.png b/data/flags/lv_flag.png
new file mode 100644
index 000000000..e32b8fc24
--- /dev/null
+++ b/data/flags/lv_flag.png
Binary files differ
diff --git a/data/flags/ma_flag.png b/data/flags/ma_flag.png
new file mode 100644
index 000000000..8ed48d2c3
--- /dev/null
+++ b/data/flags/ma_flag.png
Binary files differ
diff --git a/data/flags/mao_flag.png b/data/flags/mao_flag.png
new file mode 100644
index 000000000..57053d499
--- /dev/null
+++ b/data/flags/mao_flag.png
Binary files differ
diff --git a/data/flags/me_flag.png b/data/flags/me_flag.png
new file mode 100644
index 000000000..cfee5ea8d
--- /dev/null
+++ b/data/flags/me_flag.png
Binary files differ
diff --git a/data/flags/mk_flag.png b/data/flags/mk_flag.png
new file mode 100644
index 000000000..50815fa72
--- /dev/null
+++ b/data/flags/mk_flag.png
Binary files differ
diff --git a/data/flags/ml_flag.png b/data/flags/ml_flag.png
new file mode 100644
index 000000000..d0325baff
--- /dev/null
+++ b/data/flags/ml_flag.png
Binary files differ
diff --git a/data/flags/mm_flag.png b/data/flags/mm_flag.png
new file mode 100644
index 000000000..10c3ea27e
--- /dev/null
+++ b/data/flags/mm_flag.png
Binary files differ
diff --git a/data/flags/mn_flag.png b/data/flags/mn_flag.png
new file mode 100644
index 000000000..1f59c7f52
--- /dev/null
+++ b/data/flags/mn_flag.png
Binary files differ
diff --git a/data/flags/mt_flag.png b/data/flags/mt_flag.png
new file mode 100644
index 000000000..926144330
--- /dev/null
+++ b/data/flags/mt_flag.png
Binary files differ
diff --git a/data/flags/mv_flag.png b/data/flags/mv_flag.png
new file mode 100644
index 000000000..1cd95c43f
--- /dev/null
+++ b/data/flags/mv_flag.png
Binary files differ
diff --git a/data/flags/ng_flag.png b/data/flags/ng_flag.png
new file mode 100644
index 000000000..919b3456c
--- /dev/null
+++ b/data/flags/ng_flag.png
Binary files differ
diff --git a/data/flags/nl_flag.png b/data/flags/nl_flag.png
new file mode 100644
index 000000000..3b82622bf
--- /dev/null
+++ b/data/flags/nl_flag.png
Binary files differ
diff --git a/data/flags/no_flag.png b/data/flags/no_flag.png
new file mode 100644
index 000000000..6e992f831
--- /dev/null
+++ b/data/flags/no_flag.png
Binary files differ
diff --git a/data/flags/np_flag.png b/data/flags/np_flag.png
new file mode 100644
index 000000000..3a38889c7
--- /dev/null
+++ b/data/flags/np_flag.png
Binary files differ
diff --git a/data/flags/ph_flag.png b/data/flags/ph_flag.png
new file mode 100644
index 000000000..32c32205f
--- /dev/null
+++ b/data/flags/ph_flag.png
Binary files differ
diff --git a/data/flags/pk_flag.png b/data/flags/pk_flag.png
new file mode 100644
index 000000000..3e1dfe18c
--- /dev/null
+++ b/data/flags/pk_flag.png
Binary files differ
diff --git a/data/flags/pl_flag.png b/data/flags/pl_flag.png
new file mode 100644
index 000000000..fd89ea3aa
--- /dev/null
+++ b/data/flags/pl_flag.png
Binary files differ
diff --git a/data/flags/pt_flag.png b/data/flags/pt_flag.png
new file mode 100644
index 000000000..721bbb86a
--- /dev/null
+++ b/data/flags/pt_flag.png
Binary files differ
diff --git a/data/flags/ro_flag.png b/data/flags/ro_flag.png
new file mode 100644
index 000000000..4b1213fa6
--- /dev/null
+++ b/data/flags/ro_flag.png
Binary files differ
diff --git a/data/flags/rs_flag.png b/data/flags/rs_flag.png
new file mode 100644
index 000000000..ea7757a7d
--- /dev/null
+++ b/data/flags/rs_flag.png
Binary files differ
diff --git a/data/flags/ru_flag.png b/data/flags/ru_flag.png
new file mode 100644
index 000000000..856c01ecd
--- /dev/null
+++ b/data/flags/ru_flag.png
Binary files differ
diff --git a/data/flags/se_flag.png b/data/flags/se_flag.png
new file mode 100644
index 000000000..b161f1bd2
--- /dev/null
+++ b/data/flags/se_flag.png
Binary files differ
diff --git a/data/flags/si_flag.png b/data/flags/si_flag.png
new file mode 100644
index 000000000..8b946e64b
--- /dev/null
+++ b/data/flags/si_flag.png
Binary files differ
diff --git a/data/flags/sk_flag.png b/data/flags/sk_flag.png
new file mode 100644
index 000000000..bb8b380e1
--- /dev/null
+++ b/data/flags/sk_flag.png
Binary files differ
diff --git a/data/flags/sn_flag.png b/data/flags/sn_flag.png
new file mode 100644
index 000000000..98a9029e2
--- /dev/null
+++ b/data/flags/sn_flag.png
Binary files differ
diff --git a/data/flags/sy_flag.png b/data/flags/sy_flag.png
new file mode 100644
index 000000000..17575eca4
--- /dev/null
+++ b/data/flags/sy_flag.png
Binary files differ
diff --git a/data/flags/th_flag.png b/data/flags/th_flag.png
new file mode 100644
index 000000000..68029ee39
--- /dev/null
+++ b/data/flags/th_flag.png
Binary files differ
diff --git a/data/flags/tj_flag.png b/data/flags/tj_flag.png
new file mode 100644
index 000000000..5dca210a8
--- /dev/null
+++ b/data/flags/tj_flag.png
Binary files differ
diff --git a/data/flags/tm_flag.png b/data/flags/tm_flag.png
new file mode 100644
index 000000000..3b8d26104
--- /dev/null
+++ b/data/flags/tm_flag.png
Binary files differ
diff --git a/data/flags/tr_flag.png b/data/flags/tr_flag.png
new file mode 100644
index 000000000..037a41656
--- /dev/null
+++ b/data/flags/tr_flag.png
Binary files differ
diff --git a/data/flags/tw_flag.png b/data/flags/tw_flag.png
new file mode 100644
index 000000000..f89d56e18
--- /dev/null
+++ b/data/flags/tw_flag.png
Binary files differ
diff --git a/data/flags/tz_flag.png b/data/flags/tz_flag.png
new file mode 100644
index 000000000..45a8daf86
--- /dev/null
+++ b/data/flags/tz_flag.png
Binary files differ
diff --git a/data/flags/ua_flag.png b/data/flags/ua_flag.png
new file mode 100644
index 000000000..061135db5
--- /dev/null
+++ b/data/flags/ua_flag.png
Binary files differ
diff --git a/data/flags/unknown_flag.png b/data/flags/unknown_flag.png
new file mode 100644
index 000000000..2cee86839
--- /dev/null
+++ b/data/flags/unknown_flag.png
Binary files differ
diff --git a/data/flags/us_flag.png b/data/flags/us_flag.png
new file mode 100644
index 000000000..f1f8d096b
--- /dev/null
+++ b/data/flags/us_flag.png
Binary files differ
diff --git a/data/flags/uz_flag.png b/data/flags/uz_flag.png
new file mode 100644
index 000000000..899f1781e
--- /dev/null
+++ b/data/flags/uz_flag.png
Binary files differ
diff --git a/data/flags/vn_flag.png b/data/flags/vn_flag.png
new file mode 100644
index 000000000..15c1913cc
--- /dev/null
+++ b/data/flags/vn_flag.png
Binary files differ
diff --git a/data/flags/za_flag.png b/data/flags/za_flag.png
new file mode 100644
index 000000000..dec515f48
--- /dev/null
+++ b/data/flags/za_flag.png
Binary files 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,226 +5,473 @@
* 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);
-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);
-static Eina_Bool _deferred_noxrandr_error (void *data);
-static Eina_Bool _deferred_norates_error (void *data);
-static int _sort_resolutions (const void *d1, const void *d2);
-
-typedef struct _Resolution Resolution;
-typedef struct _SureBox SureBox;
-
-struct _Resolution
-{
- int id;
- Ecore_X_Randr_Screen_Size size;
- int size_index;
- Eina_List *rates;
-};
-
-struct _SureBox
-{
- E_Dialog *dia;
- Ecore_Timer *timer;
- int iterations;
- E_Config_Dialog *cfd;
- 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;
+
+ Evas_Object *scr_list;
+ Evas_Object *res_list;
+ Evas_Object *policy_list;
+
+ const char *cur_scr;
+
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_Config_Dialog *
+e_int_config_display(E_Container *con, const char *params __UNUSED__)
{
- E_Dialog *dia;
- SureBox *sb;
E_Config_Dialog *cfd;
+ E_Config_Dialog_View *v;
- 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));
+ 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
-_surebox_dialog_cb_yes(void *data, E_Dialog *dia)
+_fill_data(E_Config_Dialog_Data *cfdata)
{
- SureBox *sb;
-
- sb = data;
+}
- if (sb->cfdata->restore)
- e_randr_11_store_configuration(E_RANDR_CONFIGURATION_STORE_ALL);
+static void *
+_create_data(E_Config_Dialog *cfd)
+{
+ E_Config_Dialog_Data *cfdata;
- _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);
+ cfdata = E_NEW(E_Config_Dialog_Data, 1);
+ _fill_data(cfdata);
+ cfdata->cfd = cfd;
+ return cfdata;
}
static void
-_surebox_dialog_cb_no(void *data, E_Dialog *dia)
+_free_data(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
{
- SureBox *sb;
+ if (cfdata->cur_scr) eina_stringshare_del(cfdata->cur_scr);
+ E_FREE(cfdata);
+}
- 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 int
+_basic_check_changed(E_Config_Dialog *cfd __UNUSED__, E_Config_Dialog_Data *cfdata)
+{
+ return 1;
}
-static void
-_surebox_text_fill(SureBox *sb)
+static int
+_basic_apply_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata)
{
- char buf[4096];
+ return 1;
+}
- if (!sb->dia) return;
- if (sb->iterations > 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)
{
- if (sb->cfdata->has_rates)
- snprintf(buf, sizeof(buf),
- _("Does this look OK? <hilight>Save</hilight> if it does, or Restore if not.<br>"
- "If you do not press a button, the old resolution of<br>"
- "%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? <hilight>Save</hilight> if it does, or Restore if not.<br>"
- "If you do not press a button, the old resolution of<br>"
- "%dx%d will be restored in %d seconds."),
- sb->cfdata->orig_size.width, sb->cfdata->orig_size.height,
- sb->iterations);
+ 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;
+ }
}
- else
+ if (!oi) return;
+ if (!oi->monitor) return;
+
+ switch (oi->policy)
{
- if (sb->cfdata->has_rates)
- snprintf(buf, sizeof(buf),
- _("Does this look OK? <hilight>Save</hilight> if it does, or Restore if not.<br>"
- "If you do not press a button, the old resolution of<br>"
- "%dx%d at %d Hz will be restored <hilight>IMMEDIATELY</hilight>."),
- sb->cfdata->orig_size.width, sb->cfdata->orig_size.height,
- sb->cfdata->orig_rate);
- else
- snprintf(buf, sizeof(buf),
- _("Does this look OK? <hilight>Save</hilight> if it does, or Restore if not.<br>"
- "If you do not press a button, the old resolution of<br>"
- "%dx%d will be restored <hilight>IMMEDIATELY</hilight>."),
- sb->cfdata->orig_size.width, sb->cfdata->orig_size.height);
+ 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);
+ }
}
- e_dialog_text_set(sb->dia, buf);
}
-static Eina_Bool
-_surebox_timer_cb(void *data)
+static void
+_screens_select(void *data)
{
- SureBox *sb;
+ E_Config_Dialog_Data *cfdata = data;
+ _res_get(cfdata);
+}
- sb = data;
- sb->iterations--;
- _surebox_text_fill(sb);
- if (sb->iterations == 0)
+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)
{
- _surebox_dialog_cb_no(sb, sb->dia);
- return ECORE_CALLBACK_CANCEL;
+ 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);
+ }
}
- return ECORE_CALLBACK_RENEW;
}
-static SureBox *
-_surebox_new(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)
{
- SureBox *sb;
+ Evas_Object *o, *of, *ob, *ot;
+ E_Radio_Group *rg;
- 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;
+ 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;
}
-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())
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#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_timer_add(0.5, _deferred_noxrandr_error, NULL);
- fprintf(stderr, "XRandR not present on this display.\n");
- return NULL;
+ 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);
}
- 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;
+ E_FREE(sizes);
- cfd = e_config_dialog_new(con, _("Screen Resolution Settings"),
- "E", "screen/screen_resolution",
- "preferences-system-screen-resolution", 0, v, NULL);
- return cfd;
-}
+ _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);
+static Eina_Bool _deferred_noxrandr_error (void *data);
+static Eina_Bool _deferred_norates_error (void *data);
+static int _sort_resolutions (const void *d1, const void *d2);
+
+typedef struct _Resolution Resolution;
+typedef struct _SureBox SureBox;
+
+struct _Resolution
+{
+ int id;
+ Ecore_X_Randr_Screen_Size size;
+ int size_index;
+ Eina_List *rates;
+};
+
+struct _SureBox
+{
+ E_Dialog *dia;
+ Ecore_Timer *timer;
+ int iterations;
+ E_Config_Dialog *cfd;
+ E_Config_Dialog_Data *cfdata;
+};
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 <hilight>damage</hilight> 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? <hilight>Save</hilight> if it does, or Restore if not.<br>"
+ "If you do not press a button, the old resolution of<br>"
+ "%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? <hilight>Save</hilight> if it does, or Restore if not.<br>"
+ "If you do not press a button, the old resolution of<br>"
+ "%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? <hilight>Save</hilight> if it does, or Restore if not.<br>"
+ "If you do not press a button, the old resolution of<br>"
+ "%dx%d at %d Hz will be restored <hilight>IMMEDIATELY</hilight>."),
+ sb->cfdata->orig_size.width, sb->cfdata->orig_size.height,
+ sb->cfdata->orig_rate);
+ else
+ snprintf(buf, sizeof(buf),
+ _("Does this look OK? <hilight>Save</hilight> if it does, or Restore if not.<br>"
+ "If you do not press a button, the old resolution of<br>"
+ "%dx%d will be restored <hilight>IMMEDIATELY</hilight>."),
+ 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
--- /dev/null
+++ b/src/modules/xkbswitch/e-module-xkbswitch.edj
Binary files 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<br> has been"
+ " wiped and a new set of defaults initialized. "
+ "This<br>will happen regularly during "
+ "development, so don't report a<br>bug. "
+ "This simply means the module needs "
+ "new configuration<br>data by default for "
+ "usable functionality that your old<br>"
+ "configuration simply lacks. This new set of "
+ "defaults will fix<br>that by adding it in. "
+ "You can re-configure things now to your<br>"
+ "liking. Sorry for the inconvenience.<br>"));
+ }
+ /* 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<br>strange. This should not happen unless"
+ " you downgraded<br>the module or "
+ "copied the configuration from a place where"
+ "<br>a newer version of the module "
+ "was running. This is bad and<br>as a "
+ "precaution your configuration has been now "
+ "restored to<br>defaults. Sorry for the "
+ "inconvenience.<br>"));
+ }
+ }
+
+ 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