finally - xkbswitch into core e. needs some polishing work. what i
authorCarsten Haitzler <raster@rasterman.com>
Sat, 28 Apr 2012 04:09:56 +0000 (04:09 +0000)
committerCarsten Haitzler <raster@rasterman.com>
Sat, 28 Apr 2012 04:09:56 +0000 (04:09 +0000)
have done here beyond just "copy the code" is:

1. fix up some code that was useless (didnt need to be done).
2. reformat all the code to be closer to efl/e style guidelines
3. add flags to the gadget popup menu to change keyboard
4. fix lots of warnings
5. fix some correctness in c - () vs (void)
6. added q66 to AUTHORS
7. made it use _() intl macro, not D_() (needed)
8. put xkbswitch module stuff in theme (need some prettying/work)
9. added some XXX: comments on things to do

right now xkbswithc is actually very powerful (thanks q66) but its not
that user-friendly. it lets you add a short-list of "keyboard layouts"
you nee/duse. the gagdet lets you quick-switch between them. this
actually works. it has nice little flaggy things to try help you out.

what we probably need to do is:

1. fix a buffer overflow waiting to happen in the kbdswitch changing.
XXX'd
2. add a wizard page asking for kbd layout
3. double-check that "last used kbdlayout" is actually turned on
4. move xkbd config to core e config (not separate in module)
5. pretty up the gagdet (add a shadow around the flag, some
placeholder if no flag is selected etc.)
6. go over the xkb parser - it looks fragile from a read

:)

SVN revision: 70531

110 files changed:
AUTHORS
configure.ac
data/Makefile.am
data/flags/Makefile.am [new file with mode: 0644]
data/flags/ad_flag.png [new file with mode: 0644]
data/flags/af_flag.png [new file with mode: 0644]
data/flags/al_flag.png [new file with mode: 0644]
data/flags/am_flag.png [new file with mode: 0644]
data/flags/ara_flag.png [new file with mode: 0644]
data/flags/at_flag.png [new file with mode: 0644]
data/flags/az_flag.png [new file with mode: 0644]
data/flags/ba_flag.png [new file with mode: 0644]
data/flags/bd_flag.png [new file with mode: 0644]
data/flags/be_flag.png [new file with mode: 0644]
data/flags/bg_flag.png [new file with mode: 0644]
data/flags/br_flag.png [new file with mode: 0644]
data/flags/brai_flag.png [new file with mode: 0644]
data/flags/bt_flag.png [new file with mode: 0644]
data/flags/bw_flag.png [new file with mode: 0644]
data/flags/by_flag.png [new file with mode: 0644]
data/flags/ca_flag.png [new file with mode: 0644]
data/flags/cd_flag.png [new file with mode: 0644]
data/flags/ch_flag.png [new file with mode: 0644]
data/flags/cn_flag.png [new file with mode: 0644]
data/flags/cz_flag.png [new file with mode: 0644]
data/flags/de_flag.png [new file with mode: 0644]
data/flags/dk_flag.png [new file with mode: 0644]
data/flags/ee_flag.png [new file with mode: 0644]
data/flags/epo_flag.png [new file with mode: 0644]
data/flags/es_flag.png [new file with mode: 0644]
data/flags/et_flag.png [new file with mode: 0644]
data/flags/fi_flag.png [new file with mode: 0644]
data/flags/fo_flag.png [new file with mode: 0644]
data/flags/fr_flag.png [new file with mode: 0644]
data/flags/gb_flag.png [new file with mode: 0644]
data/flags/ge_flag.png [new file with mode: 0644]
data/flags/gh_flag.png [new file with mode: 0644]
data/flags/gn_flag.png [new file with mode: 0644]
data/flags/gr_flag.png [new file with mode: 0644]
data/flags/hr_flag.png [new file with mode: 0644]
data/flags/hu_flag.png [new file with mode: 0644]
data/flags/ie_flag.png [new file with mode: 0644]
data/flags/il_flag.png [new file with mode: 0644]
data/flags/in_flag.png [new file with mode: 0644]
data/flags/iq_flag.png [new file with mode: 0644]
data/flags/ir_flag.png [new file with mode: 0644]
data/flags/is_flag.png [new file with mode: 0644]
data/flags/it_flag.png [new file with mode: 0644]
data/flags/jp_flag.png [new file with mode: 0644]
data/flags/ke_flag.png [new file with mode: 0644]
data/flags/kg_flag.png [new file with mode: 0644]
data/flags/kh_flag.png [new file with mode: 0644]
data/flags/kr_flag.png [new file with mode: 0644]
data/flags/kz_flag.png [new file with mode: 0644]
data/flags/la_flag.png [new file with mode: 0644]
data/flags/latam_flag.png [new file with mode: 0644]
data/flags/lk_flag.png [new file with mode: 0644]
data/flags/lt_flag.png [new file with mode: 0644]
data/flags/lv_flag.png [new file with mode: 0644]
data/flags/ma_flag.png [new file with mode: 0644]
data/flags/mao_flag.png [new file with mode: 0644]
data/flags/me_flag.png [new file with mode: 0644]
data/flags/mk_flag.png [new file with mode: 0644]
data/flags/ml_flag.png [new file with mode: 0644]
data/flags/mm_flag.png [new file with mode: 0644]
data/flags/mn_flag.png [new file with mode: 0644]
data/flags/mt_flag.png [new file with mode: 0644]
data/flags/mv_flag.png [new file with mode: 0644]
data/flags/ng_flag.png [new file with mode: 0644]
data/flags/nl_flag.png [new file with mode: 0644]
data/flags/no_flag.png [new file with mode: 0644]
data/flags/np_flag.png [new file with mode: 0644]
data/flags/ph_flag.png [new file with mode: 0644]
data/flags/pk_flag.png [new file with mode: 0644]
data/flags/pl_flag.png [new file with mode: 0644]
data/flags/pt_flag.png [new file with mode: 0644]
data/flags/ro_flag.png [new file with mode: 0644]
data/flags/rs_flag.png [new file with mode: 0644]
data/flags/ru_flag.png [new file with mode: 0644]
data/flags/se_flag.png [new file with mode: 0644]
data/flags/si_flag.png [new file with mode: 0644]
data/flags/sk_flag.png [new file with mode: 0644]
data/flags/sn_flag.png [new file with mode: 0644]
data/flags/sy_flag.png [new file with mode: 0644]
data/flags/th_flag.png [new file with mode: 0644]
data/flags/tj_flag.png [new file with mode: 0644]
data/flags/tm_flag.png [new file with mode: 0644]
data/flags/tr_flag.png [new file with mode: 0644]
data/flags/tw_flag.png [new file with mode: 0644]
data/flags/tz_flag.png [new file with mode: 0644]
data/flags/ua_flag.png [new file with mode: 0644]
data/flags/unknown_flag.png [new file with mode: 0644]
data/flags/us_flag.png [new file with mode: 0644]
data/flags/uz_flag.png [new file with mode: 0644]
data/flags/vn_flag.png [new file with mode: 0644]
data/flags/za_flag.png [new file with mode: 0644]
data/themes/default.edc
po/POTFILES.in
src/modules/Makefile.am
src/modules/conf_display/e_int_config_display.c
src/modules/xkbswitch/Makefile.am [new file with mode: 0644]
src/modules/xkbswitch/e-module-xkbswitch.edj [new file with mode: 0644]
src/modules/xkbswitch/e_mod_config.c [new file with mode: 0644]
src/modules/xkbswitch/e_mod_keybindings.c [new file with mode: 0644]
src/modules/xkbswitch/e_mod_keybindings.h [new file with mode: 0644]
src/modules/xkbswitch/e_mod_main.c [new file with mode: 0644]
src/modules/xkbswitch/e_mod_main.h [new file with mode: 0644]
src/modules/xkbswitch/e_mod_parse.c [new file with mode: 0644]
src/modules/xkbswitch/e_mod_parse.h [new file with mode: 0644]
src/modules/xkbswitch/module.desktop.in [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index 6b0f204..e58a155 100644 (file)
--- 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>
index cc8e4b5..fb1995a 100644 (file)
@@ -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
index b7a5119..782c2d9 100644 (file)
@@ -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 (file)
index 0000000..7667f1c
--- /dev/null
@@ -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 (file)
index 0000000..a970afc
Binary files /dev/null and b/data/flags/ad_flag.png differ
diff --git a/data/flags/af_flag.png b/data/flags/af_flag.png
new file mode 100644 (file)
index 0000000..84f5830
Binary files /dev/null and b/data/flags/af_flag.png differ
diff --git a/data/flags/al_flag.png b/data/flags/al_flag.png
new file mode 100644 (file)
index 0000000..fec5a75
Binary files /dev/null and b/data/flags/al_flag.png differ
diff --git a/data/flags/am_flag.png b/data/flags/am_flag.png
new file mode 100644 (file)
index 0000000..74d9148
Binary files /dev/null and b/data/flags/am_flag.png differ
diff --git a/data/flags/ara_flag.png b/data/flags/ara_flag.png
new file mode 100644 (file)
index 0000000..c1b1764
Binary files /dev/null and b/data/flags/ara_flag.png differ
diff --git a/data/flags/at_flag.png b/data/flags/at_flag.png
new file mode 100644 (file)
index 0000000..c9851fe
Binary files /dev/null and b/data/flags/at_flag.png differ
diff --git a/data/flags/az_flag.png b/data/flags/az_flag.png
new file mode 100644 (file)
index 0000000..1511ee0
Binary files /dev/null and b/data/flags/az_flag.png differ
diff --git a/data/flags/ba_flag.png b/data/flags/ba_flag.png
new file mode 100644 (file)
index 0000000..79920af
Binary files /dev/null and b/data/flags/ba_flag.png differ
diff --git a/data/flags/bd_flag.png b/data/flags/bd_flag.png
new file mode 100644 (file)
index 0000000..975b54c
Binary files /dev/null and b/data/flags/bd_flag.png differ
diff --git a/data/flags/be_flag.png b/data/flags/be_flag.png
new file mode 100644 (file)
index 0000000..43a9442
Binary files /dev/null and b/data/flags/be_flag.png differ
diff --git a/data/flags/bg_flag.png b/data/flags/bg_flag.png
new file mode 100644 (file)
index 0000000..c7b7957
Binary files /dev/null and b/data/flags/bg_flag.png differ
diff --git a/data/flags/br_flag.png b/data/flags/br_flag.png
new file mode 100644 (file)
index 0000000..98bba07
Binary files /dev/null and b/data/flags/br_flag.png differ
diff --git a/data/flags/brai_flag.png b/data/flags/brai_flag.png
new file mode 100644 (file)
index 0000000..3eda749
Binary files /dev/null and b/data/flags/brai_flag.png differ
diff --git a/data/flags/bt_flag.png b/data/flags/bt_flag.png
new file mode 100644 (file)
index 0000000..3d0f0b0
Binary files /dev/null and b/data/flags/bt_flag.png differ
diff --git a/data/flags/bw_flag.png b/data/flags/bw_flag.png
new file mode 100644 (file)
index 0000000..d557d29
Binary files /dev/null and b/data/flags/bw_flag.png differ
diff --git a/data/flags/by_flag.png b/data/flags/by_flag.png
new file mode 100644 (file)
index 0000000..890148f
Binary files /dev/null and b/data/flags/by_flag.png differ
diff --git a/data/flags/ca_flag.png b/data/flags/ca_flag.png
new file mode 100644 (file)
index 0000000..42c1bab
Binary files /dev/null and b/data/flags/ca_flag.png differ
diff --git a/data/flags/cd_flag.png b/data/flags/cd_flag.png
new file mode 100644 (file)
index 0000000..dff2fa1
Binary files /dev/null and b/data/flags/cd_flag.png differ
diff --git a/data/flags/ch_flag.png b/data/flags/ch_flag.png
new file mode 100644 (file)
index 0000000..5d29379
Binary files /dev/null and b/data/flags/ch_flag.png differ
diff --git a/data/flags/cn_flag.png b/data/flags/cn_flag.png
new file mode 100644 (file)
index 0000000..43c8498
Binary files /dev/null and b/data/flags/cn_flag.png differ
diff --git a/data/flags/cz_flag.png b/data/flags/cz_flag.png
new file mode 100644 (file)
index 0000000..559efd6
Binary files /dev/null and b/data/flags/cz_flag.png differ
diff --git a/data/flags/de_flag.png b/data/flags/de_flag.png
new file mode 100644 (file)
index 0000000..cd29a19
Binary files /dev/null and b/data/flags/de_flag.png differ
diff --git a/data/flags/dk_flag.png b/data/flags/dk_flag.png
new file mode 100644 (file)
index 0000000..4cf042c
Binary files /dev/null and b/data/flags/dk_flag.png differ
diff --git a/data/flags/ee_flag.png b/data/flags/ee_flag.png
new file mode 100644 (file)
index 0000000..35fcb0e
Binary files /dev/null and b/data/flags/ee_flag.png differ
diff --git a/data/flags/epo_flag.png b/data/flags/epo_flag.png
new file mode 100644 (file)
index 0000000..dde003b
Binary files /dev/null and b/data/flags/epo_flag.png differ
diff --git a/data/flags/es_flag.png b/data/flags/es_flag.png
new file mode 100644 (file)
index 0000000..ea801a3
Binary files /dev/null and b/data/flags/es_flag.png differ
diff --git a/data/flags/et_flag.png b/data/flags/et_flag.png
new file mode 100644 (file)
index 0000000..62fa8c1
Binary files /dev/null and b/data/flags/et_flag.png differ
diff --git a/data/flags/fi_flag.png b/data/flags/fi_flag.png
new file mode 100644 (file)
index 0000000..bd9e089
Binary files /dev/null and b/data/flags/fi_flag.png differ
diff --git a/data/flags/fo_flag.png b/data/flags/fo_flag.png
new file mode 100644 (file)
index 0000000..cb16153
Binary files /dev/null and b/data/flags/fo_flag.png differ
diff --git a/data/flags/fr_flag.png b/data/flags/fr_flag.png
new file mode 100644 (file)
index 0000000..cd01be5
Binary files /dev/null and b/data/flags/fr_flag.png differ
diff --git a/data/flags/gb_flag.png b/data/flags/gb_flag.png
new file mode 100644 (file)
index 0000000..9246d8c
Binary files /dev/null and b/data/flags/gb_flag.png differ
diff --git a/data/flags/ge_flag.png b/data/flags/ge_flag.png
new file mode 100644 (file)
index 0000000..239b3a6
Binary files /dev/null and b/data/flags/ge_flag.png differ
diff --git a/data/flags/gh_flag.png b/data/flags/gh_flag.png
new file mode 100644 (file)
index 0000000..2e1ace2
Binary files /dev/null and b/data/flags/gh_flag.png differ
diff --git a/data/flags/gn_flag.png b/data/flags/gn_flag.png
new file mode 100644 (file)
index 0000000..0379766
Binary files /dev/null and b/data/flags/gn_flag.png differ
diff --git a/data/flags/gr_flag.png b/data/flags/gr_flag.png
new file mode 100644 (file)
index 0000000..e6ee4cb
Binary files /dev/null and b/data/flags/gr_flag.png differ
diff --git a/data/flags/hr_flag.png b/data/flags/hr_flag.png
new file mode 100644 (file)
index 0000000..6757587
Binary files /dev/null and b/data/flags/hr_flag.png differ
diff --git a/data/flags/hu_flag.png b/data/flags/hu_flag.png
new file mode 100644 (file)
index 0000000..dcbbc43
Binary files /dev/null and b/data/flags/hu_flag.png differ
diff --git a/data/flags/ie_flag.png b/data/flags/ie_flag.png
new file mode 100644 (file)
index 0000000..33c3db8
Binary files /dev/null and b/data/flags/ie_flag.png differ
diff --git a/data/flags/il_flag.png b/data/flags/il_flag.png
new file mode 100644 (file)
index 0000000..0d80171
Binary files /dev/null and b/data/flags/il_flag.png differ
diff --git a/data/flags/in_flag.png b/data/flags/in_flag.png
new file mode 100644 (file)
index 0000000..697a0d0
Binary files /dev/null and b/data/flags/in_flag.png differ
diff --git a/data/flags/iq_flag.png b/data/flags/iq_flag.png
new file mode 100644 (file)
index 0000000..4fb13e7
Binary files /dev/null and b/data/flags/iq_flag.png differ
diff --git a/data/flags/ir_flag.png b/data/flags/ir_flag.png
new file mode 100644 (file)
index 0000000..c80febd
Binary files /dev/null and b/data/flags/ir_flag.png differ
diff --git a/data/flags/is_flag.png b/data/flags/is_flag.png
new file mode 100644 (file)
index 0000000..d781a12
Binary files /dev/null and b/data/flags/is_flag.png differ
diff --git a/data/flags/it_flag.png b/data/flags/it_flag.png
new file mode 100644 (file)
index 0000000..270d166
Binary files /dev/null and b/data/flags/it_flag.png differ
diff --git a/data/flags/jp_flag.png b/data/flags/jp_flag.png
new file mode 100644 (file)
index 0000000..49af2cf
Binary files /dev/null and b/data/flags/jp_flag.png differ
diff --git a/data/flags/ke_flag.png b/data/flags/ke_flag.png
new file mode 100644 (file)
index 0000000..4619928
Binary files /dev/null and b/data/flags/ke_flag.png differ
diff --git a/data/flags/kg_flag.png b/data/flags/kg_flag.png
new file mode 100644 (file)
index 0000000..a707e21
Binary files /dev/null and b/data/flags/kg_flag.png differ
diff --git a/data/flags/kh_flag.png b/data/flags/kh_flag.png
new file mode 100644 (file)
index 0000000..558fb0a
Binary files /dev/null and b/data/flags/kh_flag.png differ
diff --git a/data/flags/kr_flag.png b/data/flags/kr_flag.png
new file mode 100644 (file)
index 0000000..ae035a4
Binary files /dev/null and b/data/flags/kr_flag.png differ
diff --git a/data/flags/kz_flag.png b/data/flags/kz_flag.png
new file mode 100644 (file)
index 0000000..b004cf5
Binary files /dev/null and b/data/flags/kz_flag.png differ
diff --git a/data/flags/la_flag.png b/data/flags/la_flag.png
new file mode 100644 (file)
index 0000000..8a94ff1
Binary files /dev/null and b/data/flags/la_flag.png differ
diff --git a/data/flags/latam_flag.png b/data/flags/latam_flag.png
new file mode 100644 (file)
index 0000000..3480ad5
Binary files /dev/null and b/data/flags/latam_flag.png differ
diff --git a/data/flags/lk_flag.png b/data/flags/lk_flag.png
new file mode 100644 (file)
index 0000000..63d98f5
Binary files /dev/null and b/data/flags/lk_flag.png differ
diff --git a/data/flags/lt_flag.png b/data/flags/lt_flag.png
new file mode 100644 (file)
index 0000000..3b2704c
Binary files /dev/null and b/data/flags/lt_flag.png differ
diff --git a/data/flags/lv_flag.png b/data/flags/lv_flag.png
new file mode 100644 (file)
index 0000000..e32b8fc
Binary files /dev/null and b/data/flags/lv_flag.png differ
diff --git a/data/flags/ma_flag.png b/data/flags/ma_flag.png
new file mode 100644 (file)
index 0000000..8ed48d2
Binary files /dev/null and b/data/flags/ma_flag.png differ
diff --git a/data/flags/mao_flag.png b/data/flags/mao_flag.png
new file mode 100644 (file)
index 0000000..57053d4
Binary files /dev/null and b/data/flags/mao_flag.png differ
diff --git a/data/flags/me_flag.png b/data/flags/me_flag.png
new file mode 100644 (file)
index 0000000..cfee5ea
Binary files /dev/null and b/data/flags/me_flag.png differ
diff --git a/data/flags/mk_flag.png b/data/flags/mk_flag.png
new file mode 100644 (file)
index 0000000..50815fa
Binary files /dev/null and b/data/flags/mk_flag.png differ
diff --git a/data/flags/ml_flag.png b/data/flags/ml_flag.png
new file mode 100644 (file)
index 0000000..d0325ba
Binary files /dev/null and b/data/flags/ml_flag.png differ
diff --git a/data/flags/mm_flag.png b/data/flags/mm_flag.png
new file mode 100644 (file)
index 0000000..10c3ea2
Binary files /dev/null and b/data/flags/mm_flag.png differ
diff --git a/data/flags/mn_flag.png b/data/flags/mn_flag.png
new file mode 100644 (file)
index 0000000..1f59c7f
Binary files /dev/null and b/data/flags/mn_flag.png differ
diff --git a/data/flags/mt_flag.png b/data/flags/mt_flag.png
new file mode 100644 (file)
index 0000000..9261443
Binary files /dev/null and b/data/flags/mt_flag.png differ
diff --git a/data/flags/mv_flag.png b/data/flags/mv_flag.png
new file mode 100644 (file)
index 0000000..1cd95c4
Binary files /dev/null and b/data/flags/mv_flag.png differ
diff --git a/data/flags/ng_flag.png b/data/flags/ng_flag.png
new file mode 100644 (file)
index 0000000..919b345
Binary files /dev/null and b/data/flags/ng_flag.png differ
diff --git a/data/flags/nl_flag.png b/data/flags/nl_flag.png
new file mode 100644 (file)
index 0000000..3b82622
Binary files /dev/null and b/data/flags/nl_flag.png differ
diff --git a/data/flags/no_flag.png b/data/flags/no_flag.png
new file mode 100644 (file)
index 0000000..6e992f8
Binary files /dev/null and b/data/flags/no_flag.png differ
diff --git a/data/flags/np_flag.png b/data/flags/np_flag.png
new file mode 100644 (file)
index 0000000..3a38889
Binary files /dev/null and b/data/flags/np_flag.png differ
diff --git a/data/flags/ph_flag.png b/data/flags/ph_flag.png
new file mode 100644 (file)
index 0000000..32c3220
Binary files /dev/null and b/data/flags/ph_flag.png differ
diff --git a/data/flags/pk_flag.png b/data/flags/pk_flag.png
new file mode 100644 (file)
index 0000000..3e1dfe1
Binary files /dev/null and b/data/flags/pk_flag.png differ
diff --git a/data/flags/pl_flag.png b/data/flags/pl_flag.png
new file mode 100644 (file)
index 0000000..fd89ea3
Binary files /dev/null and b/data/flags/pl_flag.png differ
diff --git a/data/flags/pt_flag.png b/data/flags/pt_flag.png
new file mode 100644 (file)
index 0000000..721bbb8
Binary files /dev/null and b/data/flags/pt_flag.png differ
diff --git a/data/flags/ro_flag.png b/data/flags/ro_flag.png
new file mode 100644 (file)
index 0000000..4b1213f
Binary files /dev/null and b/data/flags/ro_flag.png differ
diff --git a/data/flags/rs_flag.png b/data/flags/rs_flag.png
new file mode 100644 (file)
index 0000000..ea7757a
Binary files /dev/null and b/data/flags/rs_flag.png differ
diff --git a/data/flags/ru_flag.png b/data/flags/ru_flag.png
new file mode 100644 (file)
index 0000000..856c01e
Binary files /dev/null and b/data/flags/ru_flag.png differ
diff --git a/data/flags/se_flag.png b/data/flags/se_flag.png
new file mode 100644 (file)
index 0000000..b161f1b
Binary files /dev/null and b/data/flags/se_flag.png differ
diff --git a/data/flags/si_flag.png b/data/flags/si_flag.png
new file mode 100644 (file)
index 0000000..8b946e6
Binary files /dev/null and b/data/flags/si_flag.png differ
diff --git a/data/flags/sk_flag.png b/data/flags/sk_flag.png
new file mode 100644 (file)
index 0000000..bb8b380
Binary files /dev/null and b/data/flags/sk_flag.png differ
diff --git a/data/flags/sn_flag.png b/data/flags/sn_flag.png
new file mode 100644 (file)
index 0000000..98a9029
Binary files /dev/null and b/data/flags/sn_flag.png differ
diff --git a/data/flags/sy_flag.png b/data/flags/sy_flag.png
new file mode 100644 (file)
index 0000000..17575ec
Binary files /dev/null and b/data/flags/sy_flag.png differ
diff --git a/data/flags/th_flag.png b/data/flags/th_flag.png
new file mode 100644 (file)
index 0000000..68029ee
Binary files /dev/null and b/data/flags/th_flag.png differ
diff --git a/data/flags/tj_flag.png b/data/flags/tj_flag.png
new file mode 100644 (file)
index 0000000..5dca210
Binary files /dev/null and b/data/flags/tj_flag.png differ
diff --git a/data/flags/tm_flag.png b/data/flags/tm_flag.png
new file mode 100644 (file)
index 0000000..3b8d261
Binary files /dev/null and b/data/flags/tm_flag.png differ
diff --git a/data/flags/tr_flag.png b/data/flags/tr_flag.png
new file mode 100644 (file)
index 0000000..037a416
Binary files /dev/null and b/data/flags/tr_flag.png differ
diff --git a/data/flags/tw_flag.png b/data/flags/tw_flag.png
new file mode 100644 (file)
index 0000000..f89d56e
Binary files /dev/null and b/data/flags/tw_flag.png differ
diff --git a/data/flags/tz_flag.png b/data/flags/tz_flag.png
new file mode 100644 (file)
index 0000000..45a8daf
Binary files /dev/null and b/data/flags/tz_flag.png differ
diff --git a/data/flags/ua_flag.png b/data/flags/ua_flag.png
new file mode 100644 (file)
index 0000000..061135d
Binary files /dev/null and b/data/flags/ua_flag.png differ
diff --git a/data/flags/unknown_flag.png b/data/flags/unknown_flag.png
new file mode 100644 (file)
index 0000000..2cee868
Binary files /dev/null and b/data/flags/unknown_flag.png differ
diff --git a/data/flags/us_flag.png b/data/flags/us_flag.png
new file mode 100644 (file)
index 0000000..f1f8d09
Binary files /dev/null and b/data/flags/us_flag.png differ
diff --git a/data/flags/uz_flag.png b/data/flags/uz_flag.png
new file mode 100644 (file)
index 0000000..899f178
Binary files /dev/null and b/data/flags/uz_flag.png differ
diff --git a/data/flags/vn_flag.png b/data/flags/vn_flag.png
new file mode 100644 (file)
index 0000000..15c1913
Binary files /dev/null and b/data/flags/vn_flag.png differ
diff --git a/data/flags/za_flag.png b/data/flags/za_flag.png
new file mode 100644 (file)
index 0000000..dec515f
Binary files /dev/null and b/data/flags/za_flag.png differ
index 6fec1d5..6aeaf78 100644 (file)
@@ -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";
+                   }
+               }
+           }
+       }
+    }
 }
index e2f5046..186b52e 100644 (file)
@@ -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
index 949fc63..77a8943 100644 (file)
@@ -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
index d6de603..e544464 100644 (file)
  * 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__)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#if 0
+
+
+/*
+   man = e_manager_current_get();
+   sizes = ecore_x_randr_screen_primary_output_sizes_get(man->root, &s);
+   cfdata->has_rates = EINA_FALSE;
+
+   if ((!sizes) || (s == 0))
+     ecore_timer_add(0.5, _deferred_noxrandr_error, NULL);
+   else
+     {
+       ecore_x_randr_screen_primary_output_current_size_get(man->root, &cfdata->orig_size.width, &cfdata->orig_size.height, NULL, NULL, &cfdata->orig_size_index);
+       cfdata->orig_rate = ecore_x_randr_screen_primary_output_current_refresh_rate_get(man->root);
+
+       for (i = 0; i < (s - 1); i++)
+         {
+            Resolution * res;
+            Ecore_X_Randr_Refresh_Rate * rates;
+            int r = 0, j;
+
+            res = E_NEW(Resolution, 1);
+            if (!res) continue;
+
+            res->size.width = sizes[i].width;
+            res->size.height = sizes[i].height;
+            res->size_index = i;
+            rates = ecore_x_randr_screen_primary_output_refresh_rates_get(man->root, i, &r);
+            for (j = 0; j < r; j++)
+              {
+                 Ecore_X_Randr_Refresh_Rate * rt;
+
+                 cfdata->has_rates = EINA_TRUE;
+                 rt = E_NEW(Ecore_X_Randr_Refresh_Rate, 1);
+                 if (!rt) continue;
+                 *rt = rates[j];
+                 res->rates = eina_list_append(res->rates, rt);
+              }
+            if (rates) E_FREE(rates);
+            cfdata->resolutions = eina_list_append(cfdata->resolutions, res);
+         }
+
+       cfdata->resolutions = eina_list_sort(cfdata->resolutions,
+             eina_list_count(cfdata->resolutions), _sort_resolutions);
+       cfdata->resolutions = eina_list_reverse(cfdata->resolutions);
+
+       _load_resolutions(cfdata);
+       if (!cfdata->has_rates)
+         ecore_timer_add(0.5, _deferred_norates_error, NULL);
+     }
+
+   E_FREE(sizes);
+
+   _load_rates(cfdata);
+ */
+
+# define RANDR_11 ((1 << 16) | 1)
+
+static void         _load_resolutions        (E_Config_Dialog_Data *cfdata);
+static void         _load_rates              (E_Config_Dialog_Data *cfdata);
+static void         _ilist_item_change       (void *data);
+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_View *v;
-
-   if (!ecore_x_randr_query())
-     {
-        ecore_timer_add(0.5, _deferred_noxrandr_error, NULL);
-        fprintf(stderr, "XRandR not present on this display.\n");
-        return NULL;
-     }
-
-   if (e_config_dialog_find("E", "screen/screen_resolution")) return NULL;
-   v = E_NEW(E_Config_Dialog_View, 1);
-   v->create_cfdata = _create_data;
-   v->free_cfdata = _free_data;
-   v->basic.apply_cfdata = _basic_apply_data;
-   v->basic.create_widgets = _basic_create_widgets;
-   v->basic.check_changed = _basic_check_changed;
-   v->override_auto_apply = 1;
-
-   cfd = e_config_dialog_new(con, _("Screen Resolution Settings"),
-                            "E", "screen/screen_resolution",
-                            "preferences-system-screen-resolution", 0, v, NULL);
-   return cfd;
-}
+   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 (file)
index 0000000..a502a1a
--- /dev/null
@@ -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 (file)
index 0000000..349383c
Binary files /dev/null and b/src/modules/xkbswitch/e-module-xkbswitch.edj differ
diff --git a/src/modules/xkbswitch/e_mod_config.c b/src/modules/xkbswitch/e_mod_config.c
new file mode 100644 (file)
index 0000000..f613d47
--- /dev/null
@@ -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 (file)
index 0000000..10206a2
--- /dev/null
@@ -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 (file)
index 0000000..de86164
--- /dev/null
@@ -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 (file)
index 0000000..29b83b4
--- /dev/null
@@ -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 (file)
index 0000000..9ca03fd
--- /dev/null
@@ -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 (file)
index 0000000..e316321
--- /dev/null
@@ -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 (file)
index 0000000..0998c78
--- /dev/null
@@ -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 (file)
index 0000000..4579a66
--- /dev/null
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Type=Link
+Name=XKBSwitch
+Icon=e-module-xkbswitch
+X-Enlightenment-ModuleType=utils
+Comment=Keyboard layout configuration and switcher