diff --git a/Jamfile b/Jamfile index 9895e3d..d1840ec 100644 --- a/Jamfile +++ b/Jamfile @@ -24,6 +24,7 @@ SubInclude TOP ede-conf ; SubInclude TOP ede-desktop ; SubInclude TOP ede-desktop-conf ; SubInclude TOP ede-dialog ; +SubInclude TOP ede-keyboard-conf ; SubInclude TOP ede-screensaver-conf ; SubInclude TOP ede-help ; SubInclude TOP ede-image-view ; diff --git a/ede-keyboard-conf/Jamfile b/ede-keyboard-conf/Jamfile new file mode 100644 index 0000000..f509393 --- /dev/null +++ b/ede-keyboard-conf/Jamfile @@ -0,0 +1,18 @@ +# +# $Id$ +# +# Part of Equinox Desktop Environment (EDE). +# Copyright (c) 2009 EDE Authors. +# +# This program is licensed under terms of the +# GNU General Public License version 2 or newer. +# See COPYING for details. + +SubDir TOP ede-keyboard-conf ; + +SRC = ede-keyboard-conf.cpp ; + +EdeProgram ede-keyboard-conf : $(SRC) ; +LinkAgainst ede-keyboard-conf : -lxkbfile ; + +TranslationStrings locale : $(SRC) ; diff --git a/ede-keyboard-conf/ede-keyboard-conf.cpp b/ede-keyboard-conf/ede-keyboard-conf.cpp new file mode 100644 index 0000000..c8ae872 --- /dev/null +++ b/ede-keyboard-conf/ede-keyboard-conf.cpp @@ -0,0 +1,240 @@ +/* + * $Id$ + * + * ede-keyboard-conf, a tool to configure keyboard + * Part of Equinox Desktop Environment (EDE). + * Copyright (c) 2009 EDE Authors. + * + * This program is licensed under terms of the + * GNU General Public License version 2 or newer. + * See COPYING for details. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#define CONFIG_NAME "ede-keyboard" + +EDELIB_NS_USING_AS(Window, AppWindow) +EDELIB_NS_USING(String) +EDELIB_NS_USING(Resource) + +static Fl_Hold_Browser *layout_browser; +static Fl_Check_Button *repeat_press; +static Fl_Check_Button *show_flag; +static bool dialog_canceled; + +static const char *x11_dirs[] = { + "/etc/X11/", + "/usr/share/X11/", + "/usr/local/share/X11/", + "/usr/X11R6/lib/X11/", + "/usr/X11R6/lib64/X11/", + "/usr/local/X11R6/lib/X11/", + "/usr/local/X11R6/lib64/X11/", + "/usr/lib/X11/", + "/usr/lib64/X11/", + "/usr/local/lib/X11/", + "/usr/local/lib64/X11/", + "/usr/pkg/share/X11/", + "/usr/pkg/xorg/lib/X11/", + 0 +}; + +static const char *x11_rules[] = { + "xkb/rules/xorg", + "xkb/rules/xfree86", + 0 +}; + +static void cancel_cb(Fl_Widget*, void* win) { + AppWindow *ww = (AppWindow*)win; + ww->hide(); + + dialog_canceled = true; +} + +static void ok_cb(Fl_Widget*, void* win) { + AppWindow *ww = (AppWindow*)win; + ww->hide(); + + dialog_canceled = false; +} + +static void fetch_current_layout(String &ret, String &rules_file_ret) { + char *tmp = NULL; + XkbRF_VarDefsRec vd; + + E_ASSERT(fl_display != NULL); + + /* get the layout straight from X since the layout can be changed during X session */ + if(!XkbRF_GetNamesProp(fl_display, &tmp, &vd) || !vd.layout) + return; + + ret = vd.layout; + + /* remember rules filename too (on X.org is 'xorg')*/ + rules_file_ret = tmp; + + /* manually free each member */ + XFree(tmp); + XFree(vd.layout); + XFree(vd.model); + XFree(vd.options); + XFree(vd.variant); +} + +static void fetch_all_layouts(const String ¤t) { + char buf[256]; + XkbRF_RulesPtr xkb_rules = NULL; + + /* try to locate rules file */ + for(int i = 0; x11_dirs[i]; i++) { + for(int j = 0; x11_rules[j]; j++) { + snprintf(buf, sizeof(buf), "%s%s", x11_dirs[i], x11_rules[j]); + + xkb_rules = XkbRF_Load(buf, "", True, True); + if(xkb_rules) + goto done; + } + } + + if(!xkb_rules) { + E_WARNING(E_STRLOC ": Unable to load keyboard rules file\n"); + return; + } + +done: + for(int i = 0; i < xkb_rules->layouts.num_desc; i++) { + snprintf(buf, sizeof(buf), "%s\t%s", xkb_rules->layouts.desc[i].name, xkb_rules->layouts.desc[i].desc); + layout_browser->add(buf); + + if(current == xkb_rules->layouts.desc[i].name) { + /* Fl_Browser counts items from 1 */ + layout_browser->select(i + 1); + } + } + + XkbRF_Free(xkb_rules, True); +} + +static void read_config(void) { + Resource r; + if(!r.load(CONFIG_NAME)) + return; + + /* + * NOTE: keyboard layout is not read from config file to set applet flag/name; + * this is done using X call. Keyboard layout is only read when '--apply' was given + * to this program, so it can be set when EDE is started + */ + bool state; + r.get("Keyboard", "show_country_flag", state, true); + show_flag->value((int)state); + + r.get("Keyboard", "repeat_key_press", state, true); + repeat_press->value((int)state); +} + +static void save_config(const String &layout) { + Resource r; + + r.set("Keyboard", "show_country_flag", (bool)show_flag->value()); + r.set("Keyboard", "repeat_key_press", (bool)repeat_press->value()); + r.set("Keyboard", "layout", layout.c_str()); + + r.save(CONFIG_NAME); +} + +static void apply_layout_on_x(const String &layout, const String &rules_filename) { + XkbRF_VarDefsRec vd; + vd.layout = (char*)layout.c_str(); + + XkbRF_SetNamesProp(fl_display, (char*)rules_filename.c_str(), &vd); +} + +int main(int argc, char **argv) { + /* needed for fetch_current_layout() */ + fl_open_display(); + dialog_canceled = false; + + AppWindow *win = new AppWindow(340, 320, _("Keyboard configuration tool")); + win->begin(); + Fl_Tabs *tabs = new Fl_Tabs(10, 10, 320, 265); + tabs->begin(); + Fl_Group *layout_group = new Fl_Group(15, 30, 310, 240, _("Layout")); + layout_group->begin(); + layout_browser = new Fl_Hold_Browser(20, 40, 300, 190); + + /* so things can be nicely aligned per column */ + int cwidths [] = {100, 0}; + layout_browser->column_widths(cwidths); + layout_browser->column_char('\t'); + + layout_group->resizable(layout_browser); + + show_flag = new Fl_Check_Button(20, 240, 300, 25, _("Show country flag")); + show_flag->down_box(FL_DOWN_BOX); + show_flag->value(1); + layout_group->end(); + Fl_Group::current()->resizable(layout_group); + + Fl_Group *details_group = new Fl_Group(15, 30, 310, 240, _("Details")); + details_group->hide(); + details_group->begin(); + repeat_press = new Fl_Check_Button(20, 45, 300, 25, _("Repeat pressed key")); + repeat_press->down_box(FL_DOWN_BOX); + repeat_press->value(1); + details_group->end(); + tabs->end(); + + /* resizable box */ + Fl_Box *rbox = new Fl_Box(30, 163, 65, 52); + Fl_Group::current()->resizable(rbox); + + Fl_Button *ok_button = new Fl_Button(145, 285, 90, 25, _("&OK")); + ok_button->callback(ok_cb, win); + + Fl_Button *cancel_button = new Fl_Button(240, 285, 90, 25, _("&Cancel")); + cancel_button->callback(cancel_cb, win); + win->end(); + + /* read layouts */ + String cl, rules_filename; + + fetch_current_layout(cl, rules_filename); + fetch_all_layouts(cl); + + /* read configuration */ + read_config(); + + win->show(argc, argv); + Fl::run(); + + /* do not save configuration if was canceled */ + if(!dialog_canceled) + save_config(cl); + + return 0; +} diff --git a/ede-keyboard-conf/ede-keyboard-conf.fl b/ede-keyboard-conf/ede-keyboard-conf.fl new file mode 100644 index 0000000..e6cceaa --- /dev/null +++ b/ede-keyboard-conf/ede-keyboard-conf.fl @@ -0,0 +1,49 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0108 +header_name {.h} +code_name {.cxx} +Function {} {open +} { + Fl_Window {} { + label {Keyboard configuration tool} open + xywh {592 170 340 320} type Double resizable visible + } { + Fl_Tabs {} { + xywh {10 10 320 265} + } { + Fl_Group {} { + label Layout open + xywh {15 30 310 240} resizable + } { + Fl_Browser {} { + xywh {20 40 300 190} resizable + } + Fl_Check_Button {} { + label {Show country flag} + xywh {20 240 300 25} down_box DOWN_BOX + } + } + Fl_Group {} { + label Details open + xywh {15 30 310 240} hide + } { + Fl_Check_Button {} { + label {Repeat pressed key} + xywh {20 45 300 25} down_box DOWN_BOX + } + } + } + Fl_Box {} {selected + xywh {30 163 65 52} labelsize 14 resizable + code0 {/* resizable box */} + } + Fl_Button {} { + label {&OK} + xywh {145 285 90 25} + } + Fl_Button {} { + label {&Cancel} + xywh {240 285 90 25} + } + } +}