#include "Applet.h" #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include /* needed for XKBrules.h */ #ifdef HAVE_XKBRULES # include # include # include #endif #include #include #include #include #include #include #include #include /* they should match names in ede-keyboard-conf */ #define PANEL_APPLET_ID "ede-keyboard" #define CONFIG_NAME "ede-keyboard" EDELIB_NS_USING(Resource) EDELIB_NS_USING(String) EDELIB_NS_USING(list) EDELIB_NS_USING(run_async) EDELIB_NS_USING(foreign_callback_add) EDELIB_NS_USING(foreign_callback_remove) EDELIB_NS_USING(for_each) EDELIB_NS_USING(RES_SYS_ONLY) static Atom _XA_XKB_RF_NAMES_PROP_ATOM = 0; EDE_PANEL_APPLET_CLASS(KeyLayout, Fl_Button) { private: bool should_show_flag; String path, curr_layout; Fl_Image *img; public: KeyLayout(); ~KeyLayout(); void update_flag(bool read_config); void do_key_layout(); int handle(int e); }; typedef list KeyLayoutList; static KeyLayoutList keylayout_objects; #ifdef HAVE_XKBRULES /* Xkb does not provide this */ static void xkbrf_names_prop_free(XkbRF_VarDefsRec &vd, char *tmp) { XFree(tmp); XFree(vd.model); XFree(vd.layout); XFree(vd.options); XFree(vd.variant); } #endif static void update_key_layout(KeyLayout *k) { k->do_key_layout(); k->update_flag(false); } /* * any layout changes on X will be reported here, executed either via ede-keyboard-conf or * another tool, so there are no needs to read layout from configuration file */ static int xkb_events(int e) { if(fl_xevent->xproperty.atom == _XA_XKB_RF_NAMES_PROP_ATOM) { /* TODO: lock this */ for_each(update_key_layout, keylayout_objects); } return 0; } static void click_cb(Fl_Widget*, void*) { run_async("ede-keyboard-conf"); } static void update_flag_cb(Fl_Window*, void *data) { KeyLayout *k = (KeyLayout*)data; k->update_flag(true); k->redraw(); } KeyLayout::KeyLayout() : Fl_Button(0, 0, 30, 25) { should_show_flag = true; curr_layout = "us"; /* default layout */ img = NULL; box(FL_FLAT_BOX); labelfont(FL_HELVETICA_BOLD); labelsize(10); label("??"); align(FL_ALIGN_CLIP); tooltip(_("Current keyboard layout")); callback(click_cb); foreign_callback_add(window(), PANEL_APPLET_ID, update_flag_cb, this); path = Resource::find_data("icons/kbflags/21x14", RES_SYS_ONLY, NULL); do_key_layout(); update_flag(true); /* TODO: lock this */ keylayout_objects.push_back(this); /* with this, kb layout chages will be catched */ #if HAVE_XKBRULES if(!_XA_XKB_RF_NAMES_PROP_ATOM) _XA_XKB_RF_NAMES_PROP_ATOM = XInternAtom(fl_display, _XKB_RF_NAMES_PROP_ATOM, False); #endif Fl::add_handler(xkb_events); } KeyLayout::~KeyLayout() { foreign_callback_remove(update_flag_cb); } void KeyLayout::update_flag(bool read_config) { if(read_config) { Resource r; if(r.load(CONFIG_NAME)) r.get("Keyboard", "show_country_flag", should_show_flag, true); } /* remove previous image if we aren't going to show it */ if(!should_show_flag) img = NULL; if(should_show_flag && !path.empty()) { /* construct image path that has the same name as layout */ String full_path = path; full_path += E_DIR_SEPARATOR_STR; full_path += curr_layout; full_path += ".png"; img = Fl_Shared_Image::get(full_path.c_str()); } image(img); if(img) label(NULL); else label(curr_layout.c_str()); redraw(); } void KeyLayout::do_key_layout(void) { #ifdef HAVE_XKBRULES char *tmp = NULL; XkbRF_VarDefsRec vd; if(XkbRF_GetNamesProp(fl_display, &tmp, &vd)) { /* do nothing if layout do not exists or the same was catched */ if(!vd.layout || (curr_layout == vd.layout)) return; /* just store it, so update_flag() can do the rest */ curr_layout = vd.layout; xkbrf_names_prop_free(vd, tmp); } #endif } int KeyLayout::handle(int e) { switch(e) { case FL_ENTER: box(FL_THIN_UP_BOX); redraw(); break; case FL_LEAVE: box(FL_FLAT_BOX); redraw(); break; default: break; } return Fl_Button::handle(e); } EDE_PANEL_APPLET_EXPORT ( KeyLayout, EDE_PANEL_APPLET_OPTION_ALIGN_RIGHT, "Keyboard Layout applet", "0.1", "empty", "Sanel Zukan" )