From d431ef4a3ca6228954ddb21e2e4a88f0cf9e8624 Mon Sep 17 00:00:00 2001 From: Sergey Udaltsov Date: Thu, 25 Nov 2004 23:17:30 +0000 Subject: first commit with xmodmap support --- ChangeLog | 7 + Doxyfile.in | 692 ++++++++++++++++++++++++++++--------- configure.in | 32 +- libxklavier/Makefile.am | 20 +- libxklavier/xklavier.c | 85 +++-- libxklavier/xklavier.h | 75 +++- libxklavier/xklavier_config.c | 76 +++- libxklavier/xklavier_config.h | 5 - libxklavier/xklavier_config_i18n.c | 10 +- libxklavier/xklavier_config_xkb.c | 37 +- libxklavier/xklavier_config_xmm.c | 36 +- libxklavier/xklavier_evt.c | 97 +++--- libxklavier/xklavier_evt_xkb.c | 18 +- libxklavier/xklavier_evt_xmm.c | 130 ++++++- libxklavier/xklavier_private.h | 115 ++++-- libxklavier/xklavier_private_xkb.h | 6 +- libxklavier/xklavier_private_xmm.h | 52 ++- libxklavier/xklavier_props.c | 66 ++-- libxklavier/xklavier_util.c | 21 +- libxklavier/xklavier_xkb.c | 55 +-- libxklavier/xklavier_xmm.c | 219 +++++++++++- libxklavier/xklavier_xmm_opts.c | 104 ++++++ tests/test_config.c | 49 +-- tests/test_monitor.c | 54 ++- 24 files changed, 1556 insertions(+), 505 deletions(-) create mode 100644 libxklavier/xklavier_xmm_opts.c diff --git a/ChangeLog b/ChangeLog index 9215dd0..ed61206 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ +2004-11-25 23:00 svu + + * libxklavier, tests: MASSIVE commit. First version + with somewhat working xmodmap support. Broken API + 2004-11-04 19:00 svu + * libxklavier/Makefile.am, + * libxklavier/Makefile.am, libxklavier/xklavier.c, libxklavier/xklavier_config_xkb.c, diff --git a/Doxyfile.in b/Doxyfile.in index ad44261..371a6a0 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -1,4 +1,4 @@ -# Doxyfile 1.2.8.1 +# Doxyfile 1.3.9.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project @@ -11,7 +11,7 @@ # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- -# General configuration options +# Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded @@ -32,47 +32,36 @@ PROJECT_NUMBER = @VERSION@ OUTPUT_DIRECTORY = doc +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of source +# files, where putting all generated files in the same directory would otherwise +# cause performance problems for the file system. + +CREATE_SUBDIRS = NO + # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: -# Brazilian, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French, -# German, Hungarian, Italian, Japanese, Korean, Norwegian, Polish, -# Portuguese, Romanian, Russian, Slovak, Slovene, Spanish and Swedish. +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. OUTPUT_LANGUAGE = English -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). -EXTRACT_STATIC = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these class will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO +USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in @@ -88,12 +77,30 @@ BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is used +# as the annotated text. Otherwise, the brief description is used as-is. If left +# blank, the following values are used ("$name" is automatically replaced with the +# name of the entity): "The $name class" "The $name widget" "The $name file" +# "is" "provides" "specifies" "contains" "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. @@ -101,87 +108,191 @@ ALWAYS_DETAILED_SEC = NO FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user defined part of the path. Stripping is +# can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of -# the path. It is allowed to use relative paths in the argument list. +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. STRIP_FROM_PATH = -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. -INTERNAL_DOCS = NO +STRIP_FROM_INC_PATH = -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a class diagram (in Html and LaTeX) for classes with base or -# super classes. Setting the tag to NO turns the diagrams off. +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. -CLASS_DIAGRAMS = YES +SHORT_NAMES = NO -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. -SOURCE_BROWSER = NO +JAVADOC_AUTOBRIEF = NO -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. -INLINE_SOURCES = NO +MULTILINE_CPP_IS_BRIEF = NO -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. -STRIP_CODE_COMMENTS = YES +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower case letters. If set to YES upper case letters are also +# file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows -# users are adviced to set this option to NO. +# and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put list of the files that are included by a file in the documentation +# will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like the Qt-style comments (thus requiring an -# explict @brief command for a brief description. - -JAVADOC_AUTOBRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# reimplements. - -INHERIT_DOCS = YES - # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. @@ -194,22 +305,22 @@ INLINE_INFO = YES SORT_MEMBER_DOCS = YES -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. -DISTRIBUTE_GROUP_DOC = NO +SORT_BRIEF_DOCS = NO -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. -TAB_SIZE = 8 - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = +SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo @@ -229,17 +340,19 @@ GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. -ALIASES = +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consist of for it to appear in +# the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the @@ -248,19 +361,18 @@ ALIASES = MAX_INITIALIZER_LINES = 30 -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. -# For instance some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. + +SHOW_DIRECTORIES = YES + #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- @@ -282,6 +394,13 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the @@ -309,9 +428,12 @@ INPUT = libxklavier # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left -# blank all files are included. +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm -FILE_PATTERNS = xklavier.h xklavier_config.h +FILE_PATTERNS = xklavier.h \ + xklavier_config.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. @@ -325,6 +447,11 @@ RECURSIVE = NO EXCLUDE = +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. @@ -344,6 +471,13 @@ EXAMPLE_PATH = EXAMPLE_PATTERNS = +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). @@ -355,16 +489,66 @@ IMAGE_PATH = # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes -# to standard output. +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. INPUT_FILTER = +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source -# files to browse. +# files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -403,6 +587,12 @@ GENERATE_HTML = YES HTML_OUTPUT = +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. @@ -415,10 +605,12 @@ HTML_HEADER = HTML_FOOTER = -# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = @@ -435,6 +627,20 @@ HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). @@ -448,7 +654,7 @@ GENERATE_CHI = NO BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the Html help documentation and to the tree view. +# to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO @@ -466,8 +672,9 @@ ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports -# JavaScript and frames is required (for instance Netscape 4.0+ -# or Internet explorer 4.0+). +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. GENERATE_TREEVIEW = NO @@ -492,6 +699,17 @@ GENERATE_LATEX = NO LATEX_OUTPUT = +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. @@ -536,12 +754,18 @@ USE_PDFLATEX = NO LATEX_BATCHMODE = NO +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimised for Word 97 and may not look very pretty with +# The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO @@ -568,7 +792,7 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assigments. You only have to provide +# config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = @@ -598,14 +822,94 @@ MAN_OUTPUT = MAN_EXTENSION = -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- @@ -651,22 +955,45 @@ INCLUDE_FILE_PATTERNS = # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. PREDEFINED = -# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + #--------------------------------------------------------------------------- -# Configuration::addtions related to external references +# Configuration::additions related to external references #--------------------------------------------------------------------------- -# The TAGFILES tag can be used to specify one or more tagfiles. +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. TAGFILES = @@ -681,6 +1008,12 @@ GENERATE_TAGFILE = ALLEXTERNALS = NO +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). @@ -690,6 +1023,20 @@ PERL_PATH = # Configuration options related to the dot tool #--------------------------------------------------------------------------- +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superseded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section @@ -711,6 +1058,17 @@ CLASS_GRAPH = YES COLLABORATION_GRAPH = YES +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with @@ -725,16 +1083,36 @@ INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within @@ -751,6 +1129,17 @@ MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes that +# lay further from the root node will be omitted. Note that setting this option to +# 1 or 2 may greatly reduce the computation time needed for large code bases. Also +# note that a graph may be further truncated if the graph's image dimensions are +# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). +# If 0 is used for the depth value (the default), the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. @@ -758,51 +1147,16 @@ MAX_DOT_GRAPH_HEIGHT = 1024 GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermedate dot files that are used to generate +# remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- -# Configuration::addtions related to the search engine +# Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO - -# The CGI_NAME tag should be the name of the CGI script that -# starts the search engine (doxysearch) with the correct parameters. -# A script with this name will be generated by doxygen. - -CGI_NAME = - -# The CGI_URL tag should be the absolute URL to the directory where the -# cgi binaries are located. See the documentation of your http daemon for -# details. - -CGI_URL = - -# The DOC_URL tag should be the absolute URL to the directory where the -# documentation is located. If left blank the absolute path to the -# documentation, with file:// prepended to it, will be used. - -DOC_URL = - -# The DOC_ABSPATH tag should be the absolute path to the directory where the -# documentation is located. If left blank the directory on the local machine -# will be used. - -DOC_ABSPATH = - -# The BIN_ABSPATH tag must point to the directory where the doxysearch binary -# is installed. - -BIN_ABSPATH = - -# The EXT_DOC_PATHS tag can be used to specify one or more paths to -# documentation generated for other projects. This allows doxysearch to search -# the documentation for these projects as well. - -EXT_DOC_PATHS = diff --git a/configure.in b/configure.in index b8a4c74..f695e6e 100644 --- a/configure.in +++ b/configure.in @@ -2,9 +2,9 @@ AC_INIT(libxklavier/xklavier.c) PACKAGE=libxklavier MAJOR_VERSION=1 -MINOR_VERSION=11 +MINOR_VERSION=12 VERSION=$MAJOR_VERSION.$MINOR_VERSION -VERSION_INFO=9:0:0 +VERSION_INFO=10:0:0 AC_SUBST(MAJOR_VERSION) AC_SUBST(MINOR_VERSION) @@ -58,10 +58,6 @@ AC_ARG_WITH( xkb_base, xkb_base="$withval", xkb_base="$x_libraries/X11/xkb" ) -if ! test -d $xkb_base; then - AC_MSG_ERROR([The path $xkb_base does not denote the directory]) -fi - AC_DEFINE_UNQUOTED(XKB_BASE,"${xkb_base}",Base for XKB configuration) AC_ARG_WITH( xkb_default_ruleset, @@ -71,6 +67,16 @@ AC_ARG_WITH( xkb_default_ruleset, AC_DEFINE_UNQUOTED(XKB_DEFAULT_RULESET,"${xkb_default_ruleset}",Default XKB set of rules) +AC_ARG_WITH( xmodmap_base, + [ --with-xmodmap-base=DIR xmodmap base path (by default it is /usr/share/xmodmap)], + xmodmap_base="$withval", + xmodmap_base="/usr/share/xmodmap" ) + +AC_DEFINE_UNQUOTED(XMODMAP_BASE,"${xmodmap_base}",Base for xmodmap configuration) + +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -I$x_includes" + ac_xkblib_include="\ #include #include @@ -83,12 +89,26 @@ AM_CONDITIONAL(XKB_HEADERS_PRESENT, test "$xkb_headers_present" = "yes") AC_SUBST(xkbheaders_present) +CFLAGS="$save_CFLAGS" + AC_ARG_ENABLE(doxygen, [ --enable-doxygen Build doxygen documentation], , enable_doxygen=no) AC_SUBST(DO_DOXYGEN,"${enable_doxygen}") +AC_ARG_ENABLE(xkb-support, +[ --enable-xkb-support Enable XKB support], +, enable_xkb_support=yes) + +AM_CONDITIONAL(ENABLE_XKB_SUPPORT, test "$enable_xkb_support" = "yes") + +AC_ARG_ENABLE(xmm-support, +[ --enable-xmm-support Enable xmodmap support], +, enable_xmm_support=no) + +AM_CONDITIONAL(ENABLE_XMM_SUPPORT, test "$enable_xmm_support" = "yes") + dnl Checks for libraries. PKG_CHECK_MODULES(XML, \ libxml-2.0 >= 2.0.0) diff --git a/libxklavier/Makefile.am b/libxklavier/Makefile.am index 2525209..1643522 100644 --- a/libxklavier/Makefile.am +++ b/libxklavier/Makefile.am @@ -2,7 +2,23 @@ if XKB_HEADERS_PRESENT XKB_HEADERS_PRESENT_CFLAG = -DXKB_HEADERS_PRESENT=1 endif -AM_CFLAGS = -Wall -Werror -DDATA_DIR=\"$(datadir)/$(PACKAGE)\" -I. -I$(includedir) $(XML_CFLAGS) -I$(x_includes) -I$(top_srcdir) $(XKB_HEADERS_PRESENT_CFLAG) +if ENABLE_XKB_SUPPORT + ENABLE_XKB_SUPPORT_CFLAG = -DENABLE_XKB_SUPPORT=1 +else + ENABLE_XKB_SUPPORT_CFLAG = -DDISABLE_XKB_SUPPORT=1 +endif + +if ENABLE_XMM_SUPPORT + ENABLE_XMM_SUPPORT_CFLAG = -DENABLE_XMM_SUPPORT=1 +else + ENABLE_XMM_SUPPORT_CFLAG = -DDISABLE_XMM_SUPPORT=1 +endif + +AM_CFLAGS=-Wall -Werror -DDATA_DIR=\"$(datadir)/$(PACKAGE)\" \ + -I. -I$(includedir) $(XML_CFLAGS) -I$(x_includes) -I$(top_srcdir) \ + $(XKB_HEADERS_PRESENT_CFLAG) \ + $(ENABLE_XKB_SUPPORT_CFLAG) \ + $(ENABLE_XMM_SUPPORT_CFLAG) lib_LTLIBRARIES = libxklavier.la noinst_HEADERS = xklavier_private.h xklavier_private_xkb.h xklavier_private_xmm.h @@ -12,7 +28,7 @@ xklavierinc_HEADERS = xklavier.h xklavier_config.h libxklavier_la_SOURCES = xklavier.c xklavier_evt.c xklavier_config.c \ xklavier_xkb.c xklavier_evt_xkb.c xklavier_config_xkb.c \ - xklavier_xmm.c xklavier_evt_xmm.c xklavier_config_xmm.c \ + xklavier_xmm.c xklavier_xmm_opts.c xklavier_evt_xmm.c xklavier_config_xmm.c \ xklavier_util.c xklavier_config_i18n.c xklavier_props.c xklavier_dump.c \ $(noinst_HEADERS) $(xklavierinc_HEADERS) libxklavier_la_LDFLAGS = -version-info @VERSION_INFO@ $(XML_LIBS) -lxkbfile -L$(x_libraries) $(LIBICONV) diff --git a/libxklavier/xklavier.c b/libxklavier/xklavier.c index 1a70046..5cfd752 100644 --- a/libxklavier/xklavier.c +++ b/libxklavier/xklavier.c @@ -37,6 +37,8 @@ int _xklDebugLevel = 0; Window _xklPrevAppWindow; +int _xklListenerType = 0; + XklVTable *xklVTable = NULL; XklConfigCallback _xklConfigCallback = NULL; @@ -132,8 +134,15 @@ void XklSetLogAppender( XklLogAppender fun ) logAppender = fun; } -int XklStartListen( ) +int XklStartListen( int what ) { + _xklListenerType = what; + + if( !( xklVTable->features & XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT ) && + ( what & XKLL_MANAGE_LAYOUTS ) ) + XklDebug( 0, "The backend does not require manual layout management - " + "but it is provided by the application" ); + XklResumeListen( ); _XklLoadWindowTree( ); XFlush( _xklDpy ); @@ -183,10 +192,19 @@ int XklInit( Display * a_dpy ) _xklAtoms[XKLAVIER_TRANSPARENT] = XInternAtom( _xklDpy, "XKLAVIER_TRANSPARENT", False ); + rv = -1; + XklDebug( 150, "Trying all backends:\n" ); +#ifdef ENABLE_XKB_SUPPORT + XklDebug( 150, "Trying XKB backend\n" ); rv = _XklXkbInit(); - if ( rv != 0 ) +#endif +#ifdef ENABLE_XMM_SUPPORT + XklDebug( 150, "Trying XMM backend\n" ); + if( rv != 0 ) rv = _XklXmmInit(); - return rv; +#endif + return ( rv == 0 ) ? + ( _XklLoadAllInfo() ? 0 : _xklLastErrorCode ) : -1; } int XklTerm( ) @@ -202,28 +220,28 @@ int XklTerm( ) return 0; } -Bool XklGrabKey( int key, unsigned modifiers ) +Bool XklGrabKey( int keycode, unsigned modifiers ) { - int keyCode; Bool retCode; char *keyName; - keyCode = XKeysymToKeycode( _xklDpy, key ); - keyName = XKeysymToString( key ); - - XklDebug( 100, "listen to the key %X(%d/%s)/%d\n", key, keyCode, keyName, - modifiers ); + if( _xklDebugLevel >= 100 ) + { + keyName = XKeysymToString( XKeycodeToKeysym( _xklDpy, keycode, 0 ) ); + XklDebug( 100, "Listen to the key %d/(%s)/%d\n", + keycode, keyName, modifiers ); + } - if( ( KeyCode ) NULL == keyCode ) + if( ( KeyCode ) NULL == keycode ) return False; _xklLastErrorCode = Success; - retCode = XGrabKey( _xklDpy, keyCode, modifiers, _xklRootWindow, + retCode = XGrabKey( _xklDpy, keycode, modifiers, _xklRootWindow, True, GrabModeAsync, GrabModeAsync ); XSync( _xklDpy, False ); - XklDebug( 100, "trying to listen: %d/%d\n", retCode, _xklLastErrorCode ); + XklDebug( 100, "XGrabKey recode %d/error %d\n", retCode, _xklLastErrorCode ); retCode = ( _xklLastErrorCode == Success ); @@ -233,16 +251,12 @@ Bool XklGrabKey( int key, unsigned modifiers ) return retCode; } -Bool XklUngrabKey( int key, unsigned modifiers ) +Bool XklUngrabKey( int keycode, unsigned modifiers ) { - int keyCode; - - keyCode = XKeysymToKeycode( _xklDpy, key ); - - if( ( KeyCode ) NULL == keyCode ) + if( ( KeyCode ) NULL == keycode ) return False; - return Success == XUngrabKey( _xklDpy, keyCode, 0, _xklRootWindow ); + return Success == XUngrabKey( _xklDpy, keycode, 0, _xklRootWindow ); } int XklGetNextGroup( ) @@ -284,7 +298,7 @@ void XklSetTransparent( Window win, Bool transparent ) { XklDebug( 150, "No app window!\n" ); appWin = win; -// return; +/* return; */ } wasTransparent = XklIsTransparent( appWin ); @@ -488,9 +502,10 @@ Bool _XklLoadWindowTree( ) { Window focused; int revert; - Bool retval, haveAppWindow; + Bool retval = True, haveAppWindow; - retval = _XklLoadSubtree( _xklRootWindow, 0, &_xklCurState ); + if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) + retval = _XklLoadSubtree( _xklRootWindow, 0, &_xklCurState ); XGetInputFocus( _xklDpy, &focused, &revert ); @@ -624,7 +639,7 @@ void _XklSelectInput( Window win, long mask ) { if( _xklRootWindow == win ) XklDebug( 160, - "Someone is looking for " WINID_FORMAT " on root window ***\n", + "Someone is looking for %lx on root window ***\n", mask ); XSelectInput( _xklDpy, win, mask ); @@ -664,7 +679,7 @@ void _XklTryCallStateCallback( XklStateChange changeType, XklDebug( 150, "secondary -> go next\n" ); group = XklGetNextGroup( ); XklLockGroup( group ); - return; // we do not need to revalidate + return; /* we do not need to revalidate */ } } _xklAllowSecondaryGroupOnce = False; @@ -706,6 +721,16 @@ void _XklEnsureVTableInited( void ) } } +const char *XklGetBackendName( void ) +{ + return xklVTable->id; +} + +int XklGetBackendFeatures( void ) +{ + return xklVTable->features; +} + /** * Calling through vtable */ @@ -736,7 +761,15 @@ int XklPauseListen( void ) int XklResumeListen( void ) { _XklEnsureVTableInited(); - return (*xklVTable->xklResumeListenHandler)(); + XklDebug( 150, "listenerType: %x\n", _xklListenerType ); + if( (*xklVTable->xklResumeListenHandler)() ) + return 1; + + _XklSelectInputMerging( _xklRootWindow, + SubstructureNotifyMask | PropertyChangeMask ); + _XklEnsureVTableInited(); + (*xklVTable->xklGetRealStateHandler)( &_xklCurState ); + return 0; } Bool _XklLoadAllInfo( void ) diff --git a/libxklavier/xklavier.h b/libxklavier/xklavier.h index 8c08cb0..b9c5348 100644 --- a/libxklavier/xklavier.h +++ b/libxklavier/xklavier.h @@ -27,6 +27,32 @@ extern "C" } XklStateChange; +/** + * Backend allows to toggls indicators on/off + */ +#define XKLF_CAN_TOGGLE_INDICATORS 0x01 +/** + * Backend allows to write ascii representation of the configuration + */ +#define XKLF_CAN_OUTPUT_CONFIG_AS_ASCII 0x02 + +/** + * Backend allows to write binary representation of the configuration + */ +#define XKLF_CAN_OUTPUT_CONFIG_AS_BINARY 0x04 + +/** + * Backend supports multiple layouts + */ +#define XKLF_MULTIPLE_LAYOUTS_SUPPORTED 0x08 + +/** + * Backend requires manual configuration, + * some daemon should do + * XklStartListen( XKLL_MANAGE_LAYOUTS ); + */ +#define XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT 0x10 + /** * XKB state. Can be global or per-window */ @@ -59,6 +85,18 @@ extern "C" */ extern int XklTerm( void ); +/** + * What kind of backend if used + * @return some string id of the backend + */ + extern const char *XklGetBackendName( void ); + +/** + * Provides information regarding available backend features + * (combination of XKLF_* constants) + * @return ORed XKLF_* constants + */ + extern int XklGetBackendFeatures( void ); /** @} */ /** @@ -66,11 +104,29 @@ extern "C" * @{ */ +/** + * The listener process should handle the per-window states + * and all the related activity + */ +#define XKLL_MANAGE_WINDOW_STATES 0x01 + +/** + * Just track the state and pass it to the application above. + */ +#define XKLL_TRACK_KEYBOARD_STATE 0x02 + +/** + * The listener process should help backend to maintain the configuration + * (manually switch layouts etc). + */ +#define XKLL_MANAGE_LAYOUTS 0x04 + /** * Starts listening for XKB-related events + * @param what any combination of XKLL_* constants * @return 0 */ - extern int XklStartListen( void ); + extern int XklStartListen( int what ); /** * Stops listening for XKB-related events @@ -92,19 +148,19 @@ extern "C" /** * Grabs some key - * @param key is a keysym + * @param keycode is a keycode * @param modifiers is a bitmask of modifiers * @return True on success */ - extern Bool XklGrabKey( int key, unsigned modifiers ); + extern Bool XklGrabKey( int keycode, unsigned modifiers ); /** * Ungrabs some key - * @param key is a keysym + * @param keycode is a keycode * @param modifiers is a bitmask of modifiers * @return True on success */ - extern Bool XklUngrabKey( int key, unsigned modifiers ); + extern Bool XklUngrabKey( int keycode, unsigned modifiers ); /** * Processes X events. Should be included into the main event cycle of an @@ -450,12 +506,21 @@ extern "C" */ extern void XklSetDebugLevel( int level ); +/* Just to make doxygen happy - two block with/without @param format */ +#if defined(G_HAVE_GNUC_VARARGS) /** * Output (optionally) some debug info * @param level is a level of the message * @param format is a format (like in printf) * @see _XklDebug */ +#else +/** + * Output (optionally) some debug info + * @param level is a level of the message + * @see _XklDebug + */ +#endif #ifdef G_HAVE_ISO_VARARGS #define XklDebug( level, ... ) \ _XklDebug( __FILE__, __func__, level, __VA_ARGS__ ) diff --git a/libxklavier/xklavier_config.c b/libxklavier/xklavier_config.c index e8b8dfb..dd109c8 100644 --- a/libxklavier/xklavier_config.c +++ b/libxklavier/xklavier_config.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -85,11 +86,11 @@ static Bool _XklReadConfigItem( xmlNodePtr iptr, XklConfigItemPtr pci ) if( lang != NULL ) { int priority = _XklGetLanguagePriority( lang ); - if( !strcmp( nptr->name, "description" ) && ( priority > maxDescPriority ) ) // higher priority + if( !strcmp( nptr->name, "description" ) && ( priority > maxDescPriority ) ) /* higher priority */ { descElement = nptr; maxDescPriority = priority; - } else if( !strcmp( nptr->name, "shortDescription" ) && ( priority > maxShortDescPriority ) ) // higher priority + } else if( !strcmp( nptr->name, "shortDescription" ) && ( priority > maxShortDescPriority ) ) /* higher priority */ { shortDescElement = nptr; maxShortDescPriority = priority; @@ -105,16 +106,16 @@ static Bool _XklReadConfigItem( xmlNodePtr iptr, XklConfigItemPtr pci ) nptr = nptr->next; } - // if no language-specific description found - use the ones without lang + /* if no language-specific description found - use the ones without lang */ if( descElement == NULL ) descElement = ntDescElement; if( shortDescElement == NULL ) shortDescElement = ntShortDescElement; - // - // Actually, here we should have some code to find the correct localized description... - // + /** + * Actually, here we should have some code to find the correct localized description... + */ if( nameElement != NULL && nameElement->children != NULL ) strncat( pci->name, nameElement->children->content, @@ -302,7 +303,7 @@ void _XklConfigRecSplitByComma( char ***array, if( merged == NULL || merged[0] == '\0' ) return; - // first count the elements + /* first count the elements */ while( ( npc = strchr( pc, ',' ) ) != NULL ) { ( *arraySize )++; @@ -320,7 +321,7 @@ void _XklConfigRecSplitByComma( char ***array, while( ( npc = strchr( pc, ',' ) ) != NULL ) { int len = npc - pc; - //*ppc = ( char * ) strndup( pc, len ); + /* *ppc = ( char * ) strndup( pc, len ); */ *ppc = ( char * ) malloc( len + 1 ); if ( *ppc != NULL ) { @@ -332,15 +333,34 @@ void _XklConfigRecSplitByComma( char ***array, pc = npc + 1; } - //len = npc - pc; + /* len = npc - pc; */ len = strlen( pc ); - //*ppc = ( char * ) strndup( pc, len ); + /* *ppc = ( char * ) strndup( pc, len ); */ *ppc = ( char * ) malloc( len + 1 ); if ( *ppc != NULL ) strcpy( *ppc, pc ); } } +char* _XklGetRulesSetName( const char defaultRuleset[] ) +{ + static char rulesSetName[1024] = ""; + if ( !rulesSetName[0] ) + { + char* rf = NULL; + if( !XklGetNamesProp( xklVTable->baseConfigAtom, &rf, NULL ) || ( rf == NULL ) ) + { + strncpy( rulesSetName, defaultRuleset, sizeof rulesSetName ); + XklDebug( 100, "Using default rules set: [%s]\n", rulesSetName ); + return rulesSetName; + } + strncpy( rulesSetName, rf, sizeof rulesSetName ); + free( rf ); + } + XklDebug( 100, "Rules set: [%s]\n", rulesSetName ); + return rulesSetName; +} + void XklConfigInit( void ) { xmlXPathInit( ); @@ -532,17 +552,41 @@ Bool XklConfigLoadRegistry( void ) return (*xklVTable->xklConfigLoadRegistryHandler)(); } -Bool XklMultipleLayoutsSupported( void ) -{ - _XklEnsureVTableInited(); - return (*xklVTable->xklConfigMultipleLayoutsSupportedHandler)(); -} - Bool XklConfigWriteFile( const char *fileName, const XklConfigRecPtr data, const Bool binary ) { + if( ( !binary && + !( xklVTable->features & XKLF_CAN_OUTPUT_CONFIG_AS_ASCII ) ) || + ( binary && + !( xklVTable->features & XKLF_CAN_OUTPUT_CONFIG_AS_BINARY ) ) ) + { + _xklLastErrorMsg = "Function not supported at backend"; + return False; + } _XklEnsureVTableInited(); return (*xklVTable->xklConfigWriteFileHandler)( fileName, data, binary ); } +void XklConfigDump( FILE* file, + XklConfigRecPtr data ) +{ + int i,j; + char**p; + fprintf( file, " model: [%s]\n", data->model ); + + fprintf( file, " layouts(%d):\n", data->numLayouts ); + p = data->layouts; + for( i = data->numLayouts, j = 0; --i >= 0; ) + fprintf( file, " %d: [%s]\n", j++, *p++ ); + + fprintf( file, " variants(%d):\n", data->numVariants ); + p = data->variants; + for( i = data->numVariants, j = 0; --i >= 0; ) + fprintf( file, " %d: [%s]\n", j++, *p++ ); + + fprintf( file, " options(%d):\n", data->numOptions ); + p = data->options; + for( i = data->numOptions, j = 0; --i >= 0; ) + fprintf( file, " %d: [%s]\n", j++, *p++ ); +} diff --git a/libxklavier/xklavier_config.h b/libxklavier/xklavier_config.h index 4441c54..7917d74 100644 --- a/libxklavier/xklavier_config.h +++ b/libxklavier/xklavier_config.h @@ -252,11 +252,6 @@ extern "C" * @{ */ -/** - * Determines whether multiple layouts (by Ivan Pascal) are supported. - * @return True if so. - */ - extern Bool XklMultipleLayoutsSupported( void ); /** * Activates some XKB configuration * @param data is a valid XKB configuration diff --git a/libxklavier/xklavier_config_i18n.c b/libxklavier/xklavier_config_i18n.c index 4535659..fc20c14 100644 --- a/libxklavier/xklavier_config_i18n.c +++ b/libxklavier/xklavier_config_i18n.c @@ -31,9 +31,9 @@ static const char *_XklParseLC_ALL2LC_MESSAGES( const char *lcAll ) return lcAll; lcMsgPos += 12; lcMsgEnd = strchr( lcMsgPos, ';' ); - if( lcMsgEnd == NULL ) // LC_MESSAGES is the last piece of LC_ALL + if( lcMsgEnd == NULL ) /* LC_MESSAGES is the last piece of LC_ALL */ { - return lcMsgPos; //safe to return! + return lcMsgPos; /* safe to return! */ } len = lcMsgEnd - lcMsgPos; if( len > sizeof( buf ) ) @@ -43,7 +43,7 @@ static const char *_XklParseLC_ALL2LC_MESSAGES( const char *lcAll ) return buf; } -// Taken from gnome-vfs +/* Taken from gnome-vfs */ static Bool _XklGetCharset( const char **a ) { static const char *charset = NULL; @@ -54,7 +54,7 @@ static Bool _XklGetCharset( const char **a ) if( charset == NULL || charset[0] == '\0' ) { -// taken from gnome-vfs +/* taken from gnome-vfs */ #ifdef HAVE_LANGINFO_CODESET charset = nl_langinfo( CODESET ); if( charset == NULL || charset[0] == '\0' ) @@ -208,7 +208,7 @@ void _XklI18NInit( ) } XklDebug( 150, "Locale search order:\n" ); - XklDebug( 150, " 0: %s\n", localeSubStrings[0] ); // full locale - highest priority + XklDebug( 150, " 0: %s\n", localeSubStrings[0] ); /* full locale - highest priority */ XklDebug( 150, " 1: %s\n", localeSubStrings[1] ); XklDebug( 150, " 2: %s\n", localeSubStrings[2] ); } diff --git a/libxklavier/xklavier_config_xkb.c b/libxklavier/xklavier_config_xkb.c index 9306f36..25a9a73 100644 --- a/libxklavier/xklavier_config_xkb.c +++ b/libxklavier/xklavier_config_xkb.c @@ -21,7 +21,7 @@ #include #endif -// For "bad" X servers we hold our own copy +/* For "bad" X servers we hold our own copy */ #define XML_CFG_FALLBACK_PATH ( DATA_DIR "/xfree86.xml" ) #define XKBCOMP ( XKB_BASE "/xkbcomp" ) @@ -37,34 +37,11 @@ static XkbComponentNamesRec componentNames; static char *locale; #endif -static char* _XklGetRulesSetName( void ) -{ -#ifdef XKB_HEADERS_PRESENT - static char rulesSetName[_XKB_RF_NAMES_PROP_MAXLEN] = ""; - if ( !rulesSetName[0] ) - { - char* rf = NULL; - if( !XklGetNamesProp( _xklAtoms[XKB_RF_NAMES_PROP_ATOM], &rf, NULL ) || ( rf == NULL ) ) - { - strncpy( rulesSetName, XKB_DEFAULT_RULESET, sizeof rulesSetName ); - XklDebug( 100, "Using default rules set: [%s]\n", rulesSetName ); - return rulesSetName; - } - strncpy( rulesSetName, rf, sizeof rulesSetName ); - free( rf ); - } - XklDebug( 100, "Rules set: [%s]\n", rulesSetName ); - return rulesSetName; -#else - return NULL; -#endif -} - #ifdef XKB_HEADERS_PRESENT static XkbRF_RulesPtr _XklLoadRulesSet( void ) { char fileName[MAXPATHLEN] = ""; - char* rf = _XklGetRulesSetName(); + char* rf = _XklGetRulesSetName( XKB_DEFAULT_RULESET ); _xklRules = NULL; if( rf == NULL ) @@ -110,7 +87,7 @@ Bool _XklXkbConfigLoadRegistry( void ) { struct stat statBuf; char fileName[MAXPATHLEN] = ""; - char* rf = _XklGetRulesSetName(); + char* rf = _XklGetRulesSetName( XKB_DEFAULT_RULESET ); if ( rf == NULL ) return False; @@ -318,7 +295,7 @@ static XkbDescPtr _XklConfigGetKeyboard( Bool activate ) } #endif -// check only client side support +/* check only client side support */ Bool _XklXkbConfigMultipleLayoutsSupported( void ) { enum { NON_SUPPORTED, SUPPORTED, UNCHECKED }; @@ -394,9 +371,9 @@ Bool _XklXkbConfigActivate( const XklConfigRecPtr data ) if( xkb != NULL ) { if( XklSetNamesProp - ( _xklAtoms[XKB_RF_NAMES_PROP_ATOM], _XklGetRulesSetName(), data ) ) - // We do not need to check the result of _XklGetRulesSetName - - // because PrepareBeforeKbd did it for us + ( xklVTable->baseConfigAtom, _XklGetRulesSetName( XKB_DEFAULT_RULESET ), data ) ) + /* We do not need to check the result of _XklGetRulesSetName - + because PrepareBeforeKbd did it for us */ rv = True; else _xklLastErrorMsg = "Could not set names property"; diff --git a/libxklavier/xklavier_config_xmm.c b/libxklavier/xklavier_config_xmm.c index b8b696f..abceec0 100644 --- a/libxklavier/xklavier_config_xmm.c +++ b/libxklavier/xklavier_config_xmm.c @@ -25,23 +25,31 @@ void _XklXmmConfigInit( void ) Bool _XklXmmConfigLoadRegistry( void ) { - return False; -} + struct stat statBuf; + char fileName[MAXPATHLEN] = ""; + char* rf = _XklGetRulesSetName( "" ); -// check only client side support -Bool _XklXmmConfigMultipleLayoutsSupported( void ) -{ - return False; -} + if ( rf == NULL || rf[0] == '\0' ) + return False; -Bool _XklXmmConfigActivate( const XklConfigRecPtr data ) -{ - return False; + snprintf( fileName, sizeof fileName, XMODMAP_BASE "/%s.xml", rf ); + + if( stat( fileName, &statBuf ) != 0 ) + { + _xklLastErrorMsg = "No rules file found"; + return False; + } + + return XklConfigLoadRegistryFromFile( fileName ); } -Bool _XklXmmConfigWriteFile( const char *fileName, - const XklConfigRecPtr data, - const Bool binary ) +Bool _XklXmmConfigActivate( const XklConfigRecPtr data ) { - return False; + Bool rv; + rv = XklSetNamesProp( xklVTable->baseConfigAtom, + currentXmmRules, + data ); + if( rv ) + _XklXmmLockGroup( 0 ); + return rv; } diff --git a/libxklavier/xklavier_evt.c b/libxklavier/xklavier_evt.c index 1099673..2950424 100644 --- a/libxklavier/xklavier_evt.c +++ b/libxklavier/xklavier_evt.c @@ -33,27 +33,26 @@ int XklFilterEvents( XEvent * xev ) xev->xdestroywindow.window ); break; case UnmapNotify: - XklDebug( 200, "UnmapNotify\n" ); + XklDebug( 200, "%s\n", _XklGetEventName( xev->type ) ); break; case MapNotify: - XklDebug( 200, "MapNotify\n" ); + XklDebug( 200, "%s\n", _XklGetEventName( xev->type ) ); break; case MappingNotify: - XklDebug( 200, "MappingNotify\n" ); + XklDebug( 200, "%s\n", _XklGetEventName( xev->type ) ); _XklFreeAllInfo( ); _XklLoadAllInfo( ); break; case GravityNotify: - XklDebug( 200, "GravityNotify\n" ); + XklDebug( 200, "%s\n", _XklGetEventName( xev->type ) ); break; case ReparentNotify: - XklDebug( 200, "ReparentNotify\n" ); + XklDebug( 200, "%s\n", _XklGetEventName( xev->type ) ); break; /* Ignore these events */ default: { - const char *name = _XklGetEventName( xev->type ); XklDebug( 200, "Unknown event %d [%s]\n", xev->type, - ( name == NULL ? "??" : name ) ); + _XklGetEventName( xev->type ) ); return 1; } } @@ -71,6 +70,9 @@ void _XklFocusInEvHandler( XFocusChangeEvent * fev ) Window appWin; XklState selectedWindowState; + if( !( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) ) + return; + win = fev->window; switch ( fev->mode ) @@ -129,7 +131,7 @@ void _XklFocusInEvHandler( XFocusChangeEvent * fev ) if( XklIsGroupPerApp() == !newWinTransparent ) { - // We skip restoration only if we return to the same app window + /* We skip restoration only if we return to the same app window */ Bool doSkip = False; if( _xklSkipOneRestore ) { @@ -168,7 +170,8 @@ void _XklFocusInEvHandler( XFocusChangeEvent * fev ) } } - if( XklGetIndicatorsHandling( ) ) + if( ( xklVTable->features & XKLF_CAN_TOGGLE_INDICATORS ) && + XklGetIndicatorsHandling( ) ) { XklDebug( 150, "Restoring the indicators from %X to %X after gaining focus\n", @@ -206,6 +209,9 @@ void _XklFocusInEvHandler( XFocusChangeEvent * fev ) */ void _XklFocusOutEvHandler( XFocusChangeEvent * fev ) { + if( !( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) ) + return; + if( fev->mode != NotifyNormal ) { XklDebug( 200, @@ -238,7 +244,10 @@ void _XklFocusOutEvHandler( XFocusChangeEvent * fev ) /** * PropertyChange handler - * Interested in WM_STATE property only + * Interested in : + * + for XKLL_MANAGE_WINDOW_STATES + * - WM_STATE property for all windows + * - Configuration property of the root window */ void _XklPropertyEvHandler( XPropertyEvent * pev ) { @@ -257,49 +266,55 @@ void _XklPropertyEvHandler( XPropertyEvent * pev ) } } - if( pev->atom == _xklAtoms[WM_STATE] ) + if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) { - Bool hasXklState = XklGetState( pev->window, NULL ); - - if( pev->state == PropertyNewValue ) + if( pev->atom == _xklAtoms[WM_STATE] ) { - XklDebug( 160, "New value of WM_STATE on window " WINID_FORMAT "\n", - pev->window ); - if( !hasXklState ) /* Is this event the first or not? */ + Bool hasXklState = XklGetState( pev->window, NULL ); + + if( pev->state == PropertyNewValue ) { - _XklAddAppWindow( pev->window, ( Window ) NULL, False, - &_xklCurState ); + XklDebug( 160, "New value of WM_STATE on window " WINID_FORMAT "\n", + pev->window ); + if( !hasXklState ) /* Is this event the first or not? */ + { + _XklAddAppWindow( pev->window, ( Window ) NULL, False, + &_xklCurState ); + } + } else + { /* ev->xproperty.state == PropertyDelete, either client or WM can remove it, ICCCM 4.1.3.1 */ + XklDebug( 160, "Something (%d) happened to WM_STATE of window 0x%x\n", + pev->state, pev->window ); + _XklSelectInputMerging( pev->window, PropertyChangeMask ); + if( hasXklState ) + { + XklDelState( pev->window ); + } } } else - { /* ev->xproperty.state == PropertyDelete, either client or WM can remove it, ICCCM 4.1.3.1 */ - XklDebug( 160, "Something (%d) happened to WM_STATE of window 0x%x\n", - pev->state, pev->window ); - _XklSelectInputMerging( pev->window, PropertyChangeMask ); - if( hasXklState ) + if( pev->atom == xklVTable->baseConfigAtom + && pev->window == _xklRootWindow ) + { + if( pev->state == PropertyNewValue ) { - XklDelState( pev->window ); + XklDebug( 160, "New value of *_NAMES_PROP_ATOM on root window\n" ); + /* If root window got new *_NAMES_PROP_ATOM - + it most probably means new keyboard config is loaded by somebody */ + _XklFreeAllInfo( ); + _XklLoadAllInfo( ); } } - } else - if( pev->atom == _xklAtoms[XKB_RF_NAMES_PROP_ATOM] - && pev->window == _xklRootWindow ) - { - if( pev->state == PropertyNewValue ) - { - XklDebug( 160, "New value of XKB_RF_NAMES_PROP_ATOM on root window\n" ); - // If root window got new _XKB_RF_NAMES_PROP_ATOM - - // it most probably means new xkb is loaded by somebody - _XklFreeAllInfo( ); - _XklLoadAllInfo( ); - } - } + } /* XKLL_MANAGE_WINDOW_STATES */ } /** - * * CreateNotify handler. Just interested in properties and focus events... - * */ + * CreateNotify handler. Just interested in properties and focus events... + */ void _XklCreateEvHandler( XCreateWindowEvent * cev ) { + if( !( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) ) + return; + XklDebug( 200, "Under-root window " WINID_FORMAT "/%s (%d,%d,%d x %d) is created\n", cev->window, @@ -339,7 +354,7 @@ void _XklErrHandler( Display * dpy, XErrorEvent * evt ) case BadWindow: case BadAccess: { - // in most cases this means we are late:) + /* in most cases this means we are late:) */ XklDebug( 200, "ERROR: %p, " WINID_FORMAT ", %d, %d, %d\n", dpy, ( unsigned long ) evt->resourceid, diff --git a/libxklavier/xklavier_evt_xkb.c b/libxklavier/xklavier_evt_xkb.c index 805b845..616f878 100644 --- a/libxklavier/xklavier_evt_xkb.c +++ b/libxklavier/xklavier_evt_xkb.c @@ -30,7 +30,7 @@ static void _XklStdXkbHandler( int grp, XklStateChange changeType, unsigned inds } if( !_XklGetAppWindow( focused, &focusedApp ) ) - focusedApp = _xklCurClient; //what else can I do + focusedApp = _xklCurClient; /* what else can I do */ XklDebug( 150, "Focused window: " WINID_FORMAT ", '%s'\n", focusedApp, _XklGetDebugWindowTitle( focusedApp ) ); @@ -43,7 +43,8 @@ static void _XklStdXkbHandler( int grp, XklStateChange changeType, unsigned inds { _XklUpdateCurState( grp, inds, "Updating the state from new focused window" ); - _XklAddAppWindow( focusedApp, ( Window ) NULL, False, &_xklCurState ); + if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) + _XklAddAppWindow( focusedApp, ( Window ) NULL, False, &_xklCurState ); } else { @@ -54,8 +55,8 @@ static void _XklStdXkbHandler( int grp, XklStateChange changeType, unsigned inds XklDebug( 160, "CurClient:changed to " WINID_FORMAT ", '%s'\n", _xklCurClient, _XklGetDebugWindowTitle( _xklCurClient ) ); } - // if the window already has this this state - we are just restoring it! - // (see the second parameter of stateCallback + /* if the window already has this this state - we are just restoring it! + (see the second parameter of stateCallback */ haveState = _XklGetAppState( _xklCurClient, &oldState ); if( setGroup || haveState ) @@ -68,7 +69,8 @@ static void _XklStdXkbHandler( int grp, XklStateChange changeType, unsigned inds if( haveState ) _XklTryCallStateCallback( changeType, &oldState ); - _XklSaveAppState( _xklCurClient, &_xklCurState ); + if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) + _XklSaveAppState( _xklCurClient, &_xklCurState ); } #endif @@ -86,8 +88,12 @@ int _XklXkbEventHandler( XEvent *xev ) if( xev->type != _xklXkbEventType ) return 0; - XklDebug( 150, "Xkb event detected\n" ); + if( !( _xklListenerType & + ( XKLL_MANAGE_WINDOW_STATES | XKLL_TRACK_KEYBOARD_STATE ) ) ) + return 0; + XklDebug( 150, "Xkb event detected\n" ); + switch ( kev->any.xkb_type ) { case XkbStateNotify: diff --git a/libxklavier/xklavier_evt_xmm.c b/libxklavier/xklavier_evt_xmm.c index 4a30e79..1046757 100644 --- a/libxklavier/xklavier_evt_xmm.c +++ b/libxklavier/xklavier_evt_xmm.c @@ -4,18 +4,144 @@ #include #include #include +#include #include "xklavier_private.h" #include "xklavier_private_xmm.h" +static int _XklXmmKeypressEventHandler( XKeyPressedEvent* kpe ) +{ + if( _xklListenerType & XKLL_MANAGE_LAYOUTS ) + { + XklDebug( 200, "Processing the KeyPress event\n" ); + int currentShortcut = 0; + const XmmSwitchOptionPtr sop = _XklXmmFindSwitchOption( kpe->keycode, + kpe->state, + ¤tShortcut ); + if( sop != NULL ) + { + XklDebug( 150, "It is THE shortcut\n" ); + XklState state; + _XklXmmGetRealState( &state ); + if( state.group != -1 ) + { + int newGroup = ( state.group + sop->shortcutSteps[currentShortcut] ) % + currentXmmConfig.numLayouts; + XklDebug( 150, "Setting new xmm group %d\n", newGroup ); + _XklXmmLockGroup( newGroup ); + return 1; + } + } + } + return 0; +} + +static int _XklXmmPropertyEventHandler( XPropertyEvent* kpe ) +{ + XklDebug( 200, "Processing the PropertyNotify event: %d/%d\n", + kpe->atom, xmmStateAtom ); + if( kpe->atom == xmmStateAtom ) + { + if( _xklListenerType & XKLL_MANAGE_LAYOUTS ) + { + XklState state; + _XklXmmGetRealState( &state ); + XklDebug( 150, "Current group from the root window property %d\n", state.group ); + _XklXmmUngrabShortcuts(); + _XklXmmActualizeGroup( state.group ); + _XklXmmGrabShortcuts(); + return 1; + } + } + return 0; +} + /** - * XKB event handler + * XMM event handler */ int _XklXmmEventHandler( XEvent *xev ) { + switch( xev->type ) + { + case KeyPress: + return _XklXmmKeypressEventHandler( (XKeyPressedEvent*)xev ); + case PropertyNotify: + return _XklXmmPropertyEventHandler( (XPropertyEvent*)xev ); + } return 0; } -void _XklXmmSetIndicators( const XklState *windowState ) +/** + * We have to find which of Shift/Lock/Control/ModX masks + * belong to Caps/Num/Scroll lock + */ +static void _XklXmmInitXmmIndicatorsMap( int* pCapsLockMask, + int* pNumLockMask, + int* pScrollLockMask ) +{ + XModifierKeymap *xmkm = NULL; + KeyCode *kcmap, nlkc, clkc, slkc; + int m, k, mask; + + xmkm = XGetModifierMapping( _xklDpy ); + if( xmkm ) + { + clkc = XKeysymToKeycode( _xklDpy, XK_Num_Lock ); + nlkc = XKeysymToKeycode( _xklDpy, XK_Caps_Lock ); + slkc = XKeysymToKeycode( _xklDpy, XK_Scroll_Lock ); + + kcmap = xmkm->modifiermap; + mask = 1; + for( m = 8; --m >= 0; mask <<= 1 ) + for( k = xmkm->max_keypermod; --k >= 0; kcmap++ ) + { + if( *kcmap == clkc ) + *pCapsLockMask = mask; + if( *kcmap == slkc ) + *pScrollLockMask = mask; + if( *kcmap == nlkc ) + *pNumLockMask = mask; + } + XFreeModifiermap( xmkm ); + } +} + +void _XklXmmGrabIgnoringIndicators( int keycode, int modifiers ) { + int CapsLockMask = 0, NumLockMask = 0, ScrollLockMask = 0; + + _XklXmmInitXmmIndicatorsMap( &CapsLockMask, &NumLockMask, &ScrollLockMask ); + +#define GRAB(mods) \ + XklGrabKey( keycode, modifiers|(mods) ) + + GRAB( 0 ); + GRAB( CapsLockMask ); + GRAB( NumLockMask ); + GRAB( ScrollLockMask ); + GRAB( CapsLockMask | NumLockMask ); + GRAB( CapsLockMask | ScrollLockMask ); + GRAB( NumLockMask | ScrollLockMask ); + GRAB( CapsLockMask | NumLockMask | ScrollLockMask ); +#undef GRAB +} + +void _XklXmmUngrabIgnoringIndicators( int keycode, int modifiers ) +{ + int CapsLockMask = 0, NumLockMask = 0, ScrollLockMask = 0; + + _XklXmmInitXmmIndicatorsMap( &CapsLockMask, &NumLockMask, &ScrollLockMask ); + +#define UNGRAB(mods) \ + XklUngrabKey( keycode, modifiers|(mods) ) + + UNGRAB( 0 ); + UNGRAB( CapsLockMask ); + UNGRAB( NumLockMask ); + UNGRAB( ScrollLockMask ); + UNGRAB( CapsLockMask | NumLockMask ); + UNGRAB( CapsLockMask | ScrollLockMask ); + UNGRAB( NumLockMask | ScrollLockMask ); + UNGRAB( CapsLockMask | NumLockMask | ScrollLockMask ); +#undef UNGRAB } diff --git a/libxklavier/xklavier_private.h b/libxklavier/xklavier_private.h index a0af474..42f93c3 100644 --- a/libxklavier/xklavier_private.h +++ b/libxklavier/xklavier_private.h @@ -11,8 +11,6 @@ typedef void ( *XklConfigInitHandler )( void ); typedef Bool ( *XklConfigLoadRegistryHandler )( void ); -typedef Bool ( *XklConfigMultipleLayoutsSupportedHandler )( void ); - typedef Bool ( *XklConfigWriteFileHandler )( const char *fileName, const XklConfigRecPtr data, const Bool binary ); @@ -25,6 +23,8 @@ typedef const char **( *XklGetGroupNamesHandler )( void ); typedef unsigned ( *XklGetNumGroupsHandler )( void ); +typedef void ( *XklGetRealStateHandler)( XklState * curState_return ); + typedef Bool ( *XklLoadAllInfoHandler )( void ); typedef void ( *XklLockGroupHandler )( int group ); @@ -35,96 +35,133 @@ typedef void ( *XklSetIndicatorsHandler )( const XklState *windowState ); typedef struct { + /** + * Backend name + */ + const char *id; + /** + * Functions supported by the backend, combination of XKLF_* constants + */ + int features; /** * Activates the configuration. * xkb: create proper the XkbDescRec and send it to the server - * TODO: xmodmap + * xmodmap: save the property, init layout #1 */ XklConfigActivateHandler xklConfigActivateHandler; /** * Background-specific initialization. * xkb: XkbInitAtoms - init internal xkb atoms table - * TODO: xmodmap + * xmodmap: void. */ XklConfigInitHandler xklConfigInitHandler; /* private */ /** * Loads the registry tree into DOM (using whatever path(s)) * The XklConfigFreeRegistry is static - no virtualization necessary. * xkb: loads xml from XKB_BASE+"/rules/"+ruleset+".xml" - * TODO: xmodmap + * xmodmap: loads xml from XMODMAP_BASE+"/"+ruleset+".xml" */ XklConfigLoadRegistryHandler xklConfigLoadRegistryHandler; - /** - * Can the system combine layouts in one configuration - or not? - * xkb: checks the simple rule with 2 layouts - * xmodmap: return true - */ - XklConfigMultipleLayoutsSupportedHandler xklConfigMultipleLayoutsSupportedHandler; /** * Write the configuration into the file (binary/textual) * xkb: write xkb or xkm file - * TODO: xmodmap + * xmodmap: if text requested, just dump XklConfigRec to the + * file - not really useful. If binary - fail (not supported) */ XklConfigWriteFileHandler xklConfigWriteFileHandler; /** * Handles X events. * xkb: XkbEvent handling - * TODO: xmodmap: .... (scariest thing) + * xmodmap: keep track on the root window properties. What else can we do? */ XklEventHandler xklEventHandler; /** * Flushes the cached server config info. * xkb: frees XkbDesc - * TODO: xmodmap + * xmodmap: frees internal XklConfigRec */ XklFreeAllInfoHandler xklFreeAllInfoHandler; /* private */ /** * Get the list of the group names * xkb: return cached list of the group names - * TODO: xmodmap + * xmodmap: return the list of layouts from the internal XklConfigRec */ XklGetGroupNamesHandler xklGetGroupNamesHandler; /** * Get the number of loaded groups * xkb: return from the cached XkbDesc - * TODO: xmodmap + * xmodmap: return number of layouts from internal XklConfigRec */ XklGetNumGroupsHandler xklGetNumGroupsHandler; + + /** + * Gets the current stateCallback + * xkb: XkbGetState and XkbGetIndicatorState + * xmodmap: check the root window property (regarding the group) + */ + XklGetRealStateHandler xklGetRealStateHandler; + /** * Loads the configuration info from the server * xkb: loads XkbDesc, names, indicators - * TODO: xmodmap + * xmodmap: loads internal XklConfigRec from server */ XklLoadAllInfoHandler xklLoadAllInfoHandler; /* private */ /** * Switches the keyboard to the group N * xkb: simple one-liner to call the XKB function - * TODO: xmodmap + * xmodmap: changes the root window property + * (listener invokes xmodmap with appropriate config file). */ XklLockGroupHandler xklLockGroupHandler; /** * Stop tracking the keyboard-related events * xkb: XkbSelectEvents(..., 0) - * TODO: xmodmap + * xmodmap: Ungrab the switching shortcut. */ XklPauseResumeListenHandler xklPauseListenHandler; /** * Start tracking the keyboard-related events - * xkb: XkbSelectEvents + XkbSelectEventDetails + GetRealState - * TODO: xmodmap + * xkb: XkbSelectEvents + XkbSelectEventDetails + * xmodmap: Grab the switching shortcut. */ XklPauseResumeListenHandler xklResumeListenHandler; /** * Set the indicators state from the XklState * xkb: _XklSetIndicator for all indicators - * TODO: xmodmap + * xmodmap: NULL. Not supported */ XklSetIndicatorsHandler xklSetIndicatorsHandler; /* private */ + + /* all data is private - no direct access */ + /** + * The base configuration atom. + * xkb: _XKB_RF_NAMES_PROP_ATOM + * xmodmap: "_XMM_NAMES" + */ + Atom baseConfigAtom; + + /** + * The configuration backup atom + * xkb: "_XKB_RULES_NAMES_BACKUP" + * xmodmap: "_XMM_NAMES_BACKUP" + */ + Atom backupConfigAtom; + + /** + * Fallback for missing model + */ + const char* defaultModel; + + /** + * Fallback for missing layout + */ + const char* defaultLayout; + } XklVTable; extern void _XklEnsureVTableInited( void ); -extern void _XklGetRealState( XklState * curState_return ); extern void _XklAddAppWindow( Window win, Window parent, Bool force, XklState * initState ); extern Bool _XklGetAppWindowBottomToTop( Window win, Window * appWin_return ); @@ -171,6 +208,11 @@ extern char *_XklLocaleFromUtf8( const char *utf8string ); extern int _XklGetLanguagePriority( const char *language ); +extern char* _XklGetRulesSetName( const char defaultRuleset[] ); + +extern Bool _XklConfigGetFullFromServer( char **rulesFileOut, + XklConfigRecPtr data ); + extern char *_XklConfigRecMergeByComma( const char **array, const int arrayLength ); @@ -192,6 +234,9 @@ extern void _XklConfigRecSplitVariants( XklConfigRecPtr data, extern void _XklConfigRecSplitOptions( XklConfigRecPtr data, const char *merged ); +extern void XklConfigDump( FILE* file, + XklConfigRecPtr data ); + extern const char *_XklGetEventName( int type ); extern Bool _XklIsTransparentAppWindow( Window appWin ); @@ -218,19 +263,12 @@ extern XErrorHandler _xklDefaultErrHandler; extern char *_xklIndicatorNames[]; -#define WM_NAME 0 -#define WM_STATE 1 -#define XKLAVIER_STATE 2 -#define XKLAVIER_TRANSPARENT 3 - -// XKB ones -#define XKB_RF_NAMES_PROP_ATOM 4 -#define XKB_RF_NAMES_PROP_ATOM_BACKUP 5 -#define TOTAL_ATOMS 6 +enum { WM_NAME, WM_STATE, XKLAVIER_STATE, XKLAVIER_TRANSPARENT, + TOTAL_ATOMS }; #define XKLAVIER_STATE_PROP_LENGTH 2 -// taken from XFree86 maprules.c +/* taken from XFree86 maprules.c */ #define _XKB_RF_NAMES_PROP_MAXLEN 1024 extern Atom _xklAtoms[]; @@ -245,6 +283,8 @@ extern int _xklSecondaryGroupsMask; extern int _xklDebugLevel; +extern int _xklListenerType; + extern Window _xklPrevAppWindow; #define WINID_FORMAT "%lx" @@ -255,4 +295,13 @@ extern void *_xklConfigCallbackData; extern XklVTable *xklVTable; +#ifdef __STRICT_ANSI__ +/* these are functions which are NOT in ANSI C. + Probably we should provide the implementation */ +extern int snprintf( char *s, size_t maxlen, + const char *format, ... ); + +extern char *strdup( const char *s ); +#endif + #endif diff --git a/libxklavier/xklavier_private_xkb.h b/libxklavier/xklavier_private_xkb.h index 3906881..00ca966 100644 --- a/libxklavier/xklavier_private_xkb.h +++ b/libxklavier/xklavier_private_xkb.h @@ -18,6 +18,8 @@ extern XkbDescPtr _xklXkb; extern void XklDumpXkbDesc( const char *filename, XkbDescPtr kbd ); +extern Bool _XklXkbConfigMultipleLayoutsSupported( void ); + /* Start VTable methods */ extern Bool _XklXkbConfigActivate( const XklConfigRecPtr data ); @@ -26,8 +28,6 @@ extern void _XklXkbConfigInit( void ); extern Bool _XklXkbConfigLoadRegistry( void ); -extern Bool _XklXkbConfigMultipleLayoutsSupported( void ); - extern Bool _XklXkbConfigWriteFile( const char *fileName, const XklConfigRecPtr data, const Bool binary ); @@ -40,6 +40,8 @@ extern const char **_XklXkbGetGroupNames( void ); extern unsigned _XklXkbGetNumGroups( void ); +extern void _XklXkbGetRealState( XklState * curState_return ); + extern Bool _XklXkbLoadAllInfo( void ); extern void _XklXkbLockGroup( int group ); diff --git a/libxklavier/xklavier_private_xmm.h b/libxklavier/xklavier_private_xmm.h index 0824f29..996a035 100644 --- a/libxklavier/xklavier_private_xmm.h +++ b/libxklavier/xklavier_private_xmm.h @@ -1,6 +1,48 @@ #ifndef __XKLAVIER_PRIVATE_XMM_H__ #define __XKLAVIER_PRIVATE_XMM_H__ +typedef struct _XmmShortcut +{ + int keysym; + int modifiers; +} XmmShortcut, *XmmShortcutPtr; + +#define MAX_SHORTCUTS_PER_OPTION 4 +typedef struct _XmmSwitchOption +{ + const char* optionName; + int numShortcuts; + XmmShortcut shortcuts[MAX_SHORTCUTS_PER_OPTION]; + int shortcutSteps[MAX_SHORTCUTS_PER_OPTION]; +} XmmSwitchOption, *XmmSwitchOptionPtr; + +extern char* currentXmmRules; + +extern XklConfigRec currentXmmConfig; + +extern Atom xmmStateAtom; + +/* in the ideal world this should be a hashmap */ +extern XmmSwitchOption allSwitchOptions[]; + +extern void _XklXmmGrabIgnoringIndicators( int keycode, int modifiers ); + +extern void _XklXmmUngrabIgnoringIndicators( int keycode, int modifiers ); + +extern void _XklXmmGrabShortcuts( void ); + +extern void _XklXmmUngrabShortcuts( void ); + +extern const char* _XklXmmGetCurrentShortcutOptionName( void ); + +extern const XmmSwitchOptionPtr _XklXmmGetCurrentShortcut( void ); + +extern void _XklXmmActualizeGroup( int group ); + +extern const XmmSwitchOptionPtr _XklXmmFindSwitchOption( unsigned keycode, + unsigned state, + int * currentShortcut_rv ); + /* Start VTable methods */ extern Bool _XklXmmConfigActivate( const XklConfigRecPtr data ); @@ -9,12 +51,6 @@ extern void _XklXmmConfigInit( void ); extern Bool _XklXmmConfigLoadRegistry( void ); -extern Bool _XklXmmConfigMultipleLayoutsSupported( void ); - -extern Bool _XklXmmConfigWriteFile( const char *fileName, - const XklConfigRecPtr data, - const Bool binary ); - extern int _XklXmmEventHandler( XEvent * kev ); extern void _XklXmmFreeAllInfo( void ); @@ -23,6 +59,8 @@ extern const char **_XklXmmGetGroupNames( void ); extern unsigned _XklXmmGetNumGroups( void ); +extern void _XklXmmGetRealState( XklState * curState_return ); + extern Bool _XklXmmLoadAllInfo( void ); extern void _XklXmmLockGroup( int group ); @@ -31,8 +69,6 @@ extern int _XklXmmPauseListen( void ); extern int _XklXmmResumeListen( void ); -extern void _XklXmmSetIndicators( const XklState *windowState ); - /* End of VTable methods */ #endif diff --git a/libxklavier/xklavier_props.c b/libxklavier/xklavier_props.c index 99c12e0..7435ae2 100644 --- a/libxklavier/xklavier_props.c +++ b/libxklavier/xklavier_props.c @@ -13,12 +13,9 @@ #include "xklavier_config.h" #include "xklavier_private.h" -#define XKB_DEFAULT_MODEL "pc101" -#define XKB_DEFAULT_LAYOUT "us" - void XklConfigRecInit( XklConfigRecPtr data ) { - // clear the structure VarDefsPtr... + /* clear the structure VarDefsPtr... */ memset( ( void * ) data, 0, sizeof( XklConfigRec ) ); } @@ -50,11 +47,11 @@ static Bool _XklGetDefaultNamesProp( char **rulesFileOut, XklConfigRecPtr data ) { if ( rulesFileOut != NULL ) *rulesFileOut = strdup( XKB_DEFAULT_RULESET ); - data->model = strdup( XKB_DEFAULT_MODEL ); -// keeping Nvariants = Nlayouts + data->model = strdup( xklVTable->defaultModel ); +/* keeping Nvariants = Nlayouts */ data->numLayouts = data->numVariants = 1; data->layouts = malloc( sizeof( char * ) ); - data->layouts[0] = strdup( XKB_DEFAULT_LAYOUT ); + data->layouts[0] = strdup( xklVTable->defaultLayout ); data->variants = malloc( sizeof( char * ) ); data->variants[0] = strdup( "" ); data->numOptions = 0; @@ -62,6 +59,17 @@ static Bool _XklGetDefaultNamesProp( char **rulesFileOut, XklConfigRecPtr data ) return True; } +Bool _XklConfigGetFullFromServer( char **rulesFileOut, XklConfigRecPtr data ) +{ + Bool rv = + XklGetNamesProp( xklVTable->baseConfigAtom, rulesFileOut, data ); + + if( !rv ) + rv = _XklGetDefaultNamesProp( rulesFileOut, data ); + + return rv; +} + Bool XklConfigRecEquals( XklConfigRecPtr data1, XklConfigRecPtr data2 ) { if ( data1 == data2 ) @@ -116,19 +124,13 @@ void XklConfigRecReset( XklConfigRecPtr data ) Bool XklConfigGetFromServer( XklConfigRecPtr data ) { - Bool rv = - XklGetNamesProp( _xklAtoms[XKB_RF_NAMES_PROP_ATOM], NULL, data ); - - if( !rv ) - rv = _XklGetDefaultNamesProp( NULL, data ); - - return rv; + return _XklConfigGetFullFromServer( NULL, data ); } Bool XklConfigGetFromBackup( XklConfigRecPtr data ) { Bool rv = - XklGetNamesProp( _xklAtoms[XKB_RF_NAMES_PROP_ATOM_BACKUP], NULL, data ); + XklGetNamesProp( xklVTable->backupConfigAtom, NULL, data ); return rv; } @@ -142,16 +144,14 @@ Bool XklBackupNamesProp( ) XklConfigRecInit( &data ); if( XklGetNamesProp - ( _xklAtoms[XKB_RF_NAMES_PROP_ATOM_BACKUP], NULL, &data ) ) + ( xklVTable->backupConfigAtom, NULL, &data ) ) { XklConfigRecDestroy( &data ); return True; } - // "backup" property is not defined + /* "backup" property is not defined */ XklConfigRecReset( &data ); - cgp = XklGetNamesProp( _xklAtoms[XKB_RF_NAMES_PROP_ATOM], &rf, &data ); - if ( !cgp ) - cgp = _XklGetDefaultNamesProp( &rf, &data ); + cgp = _XklConfigGetFullFromServer( &rf, &data ); if ( cgp ) { @@ -171,7 +171,7 @@ Bool XklBackupNamesProp( ) for( i = data.numOptions; --i >= 0; ) XklDebug( 150, "%d: [%s]\n", i, data.options[i] ); #endif - if( !XklSetNamesProp( _xklAtoms[XKB_RF_NAMES_PROP_ATOM_BACKUP], rf, &data ) ) + if( !XklSetNamesProp( xklVTable->backupConfigAtom, rf, &data ) ) { XklDebug( 150, "Could not backup the configuration" ); rv = False; @@ -194,13 +194,13 @@ Bool XklRestoreNamesProp( ) XklConfigRec data; XklConfigRecInit( &data ); - if( !XklGetNamesProp( _xklAtoms[XKB_RF_NAMES_PROP_ATOM_BACKUP], NULL, &data ) ) + if( !XklGetNamesProp( xklVTable->backupConfigAtom, NULL, &data ) ) { XklConfigRecDestroy( &data ); return False; } - if( !XklSetNamesProp( _xklAtoms[XKB_RF_NAMES_PROP_ATOM], rf, &data ) ) + if( !XklSetNamesProp( xklVTable->baseConfigAtom, rf, &data ) ) { XklDebug( 150, "Could not backup the configuration" ); rv = False; @@ -218,7 +218,7 @@ Bool XklGetNamesProp( Atom rulesAtom, char *propData = NULL, *out; Status rtrn; - // no such atom! + /* no such atom! */ if( rulesAtom == None ) /* property cannot exist */ { _xklLastErrorMsg = "Could not find the atom"; @@ -230,17 +230,17 @@ Bool XklGetNamesProp( Atom rulesAtom, _XKB_RF_NAMES_PROP_MAXLEN, False, XA_STRING, &realPropType, &fmt, &nitems, &extraBytes, ( unsigned char ** ) ( void * ) &propData ); - // property not found! + /* property not found! */ if( rtrn != Success ) { _xklLastErrorMsg = "Could not get the property"; return False; } - // set rules file to "" + /* set rules file to "" */ if( rulesFileOut ) *rulesFileOut = NULL; - // has to be array of strings + /* has to be array of strings */ if( ( extraBytes > 0 ) || ( realPropType != XA_STRING ) || ( fmt != 8 ) ) { if( propData ) @@ -255,13 +255,13 @@ Bool XklGetNamesProp( Atom rulesAtom, return False; } - // rules file + /* rules file */ out = propData; if( out && ( *out ) && rulesFileOut ) *rulesFileOut = strdup( out ); out += strlen( out ) + 1; - // if user is interested in rules only - don't waste the time + /* if user is interested in rules only - don't waste the time */ if( !data ) { XFree( propData ); @@ -298,7 +298,7 @@ Bool XklGetNamesProp( Atom rulesAtom, ( data->numLayouts - data->numVariants ) * sizeof( char * ) ); data->numVariants = data->numLayouts; } - // take variants from layouts like ru(winkeys) + /* take variants from layouts like ru(winkeys) */ theLayout = data->layouts; theVariant = data->variants; for( i = data->numLayouts; --i >= 0; theLayout++, theVariant++ ) @@ -313,7 +313,7 @@ Bool XklGetNamesProp( Atom rulesAtom, { int varlen = varend - varstart; int laylen = varstart - *theLayout; - // I am not sure - but I assume variants in layout have priority + /* I am not sure - but I assume variants in layout have priority */ char *var = *theVariant = ( *theVariant != NULL ) ? realloc( *theVariant, varlen ) : malloc( varlen ); memcpy( var, varstart + 1, --varlen ); @@ -330,13 +330,13 @@ Bool XklGetNamesProp( Atom rulesAtom, if( ( out - propData ) < nitems ) { _XklConfigRecSplitOptions( data, out ); -// out += strlen( out ) + 1; +/* out += strlen( out ) + 1; */ } XFree( propData ); return True; } -// taken from XFree86 maprules.c +/* taken from XFree86 maprules.c */ Bool XklSetNamesProp( Atom rulesAtom, char *rulesFile, const XklConfigRecPtr data ) { diff --git a/libxklavier/xklavier_util.c b/libxklavier/xklavier_util.c index f88c8cf..6504b3b 100644 --- a/libxklavier/xklavier_util.c +++ b/libxklavier/xklavier_util.c @@ -65,6 +65,9 @@ void XklSaveState( Window win, XklState * state ) { Window appWin; + if( !( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) ) + return; + if( _XklGetAppWindow( win, &appWin ) ) _XklSaveAppState( appWin, state ); } @@ -117,23 +120,23 @@ Bool _XklLoadSubtree( Window window, int level, XklState * initState ) child = children; while( num ) { - XklDebug( 150, "Looking at child " WINID_FORMAT " '%s'\n", *child, - _XklGetDebugWindowTitle( *child ) ); if( _XklHasWmState( *child ) ) { - XklDebug( 150, "It has WM_STATE so we'll add it\n" ); + XklDebug( 160, "Window " WINID_FORMAT " '%s' has WM_STATE so we'll add it\n", + *child, _XklGetDebugWindowTitle( *child ) ); _XklAddAppWindow( *child, window, True, initState ); } else { - XklDebug( 150, "It does not have have WM_STATE so we'll not add it\n" ); + XklDebug( 200, "Window " WINID_FORMAT " '%s' does not have have WM_STATE so we'll not add it\n", + *child, _XklGetDebugWindowTitle( *child ) ); if( level == 0 ) { - XklDebug( 150, "But we are at level 0 so we'll spy on it\n" ); + XklDebug( 200, "But we are at level 0 so we'll spy on it\n" ); _XklSelectInputMerging( *child, FocusChangeMask | PropertyChangeMask ); } else - XklDebug( 150, "And we are at level %d so we'll not spy on it\n", + XklDebug( 200, "And we are at level %d so we'll not spy on it\n", level ); retval = _XklLoadSubtree( *child, level + 1, initState ); @@ -216,8 +219,8 @@ Status _XklStatusQueryTree( Display * display, const char *_XklGetEventName( int type ) { - // Not really good to use the fact of consecutivity - // but X protocol is already standartized so... + /* Not really good to use the fact of consecutivity + but X protocol is already standartized so... */ static const char *evtNames[] = { "KeyPress", "KeyRelease", @@ -253,7 +256,7 @@ const char *_XklGetEventName( int type ) }; type -= KeyPress; if( type < 0 || type > ( sizeof( evtNames ) / sizeof( evtNames[0] ) ) ) - return NULL; + return "UNKNOWN"; return evtNames[type]; } diff --git a/libxklavier/xklavier_xkb.c b/libxklavier/xklavier_xkb.c index 6e78936..5b2ffe4 100644 --- a/libxklavier/xklavier_xkb.c +++ b/libxklavier/xklavier_xkb.c @@ -28,13 +28,14 @@ const char **_XklXkbGetGroupNames( void ) int _XklXkbPauseListen( ) { XkbSelectEvents( _xklDpy, XkbUseCoreKbd, XkbAllEventsMask, 0 ); -// XkbSelectEventDetails( _xklDpy, - // XkbUseCoreKbd, - // XkbStateNotify, - // 0, - // 0 ); +/* XkbSelectEventDetails( _xklDpy, + XkbUseCoreKbd, + XkbStateNotify, + 0, + 0 ); - //!!_XklSelectInput( _xklRootWindow, 0 ); + !!_XklSelectInput( _xklRootWindow, 0 ); +*/ return 0; } @@ -66,9 +67,6 @@ int _XklXkbResumeListen( ) XkbUseCoreKbd, XkbNamesNotify, XKB_NAMES_EVT_DTL_MASK, XKB_NAMES_EVT_DTL_MASK ); - _XklSelectInputMerging( _xklRootWindow, - SubstructureNotifyMask | PropertyChangeMask ); - _XklGetRealState( &_xklCurState ); return 0; } @@ -184,7 +182,7 @@ void _XklXkbLockGroup( int group ) /** * Updates current internal state from X state */ -void _XklGetRealState( XklState * curState_return ) +void _XklXkbGetRealState( XklState * curState_return ) { XkbStateRec state; @@ -197,7 +195,7 @@ void _XklGetRealState( XklState * curState_return ) &curState_return->indicators ) ) curState_return->indicators &= _xklXkb->indicators->phys_indicators; else - curState_return->indicators = 0; + curState_return->indicators = 0; } /* @@ -228,7 +226,7 @@ Bool _XklSetIndicator( int indicatorNum, Bool set ) { case XkbIM_NoExplicit | XkbIM_NoAutomatic: { - // Can do nothing. Just ignore the indicator + /* Can do nothing. Just ignore the indicator */ return True; } @@ -275,9 +273,9 @@ Bool _XklSetIndicator( int indicatorNum, Bool set ) } /* The 'which_groups' field tells when this indicator turns on - * * for the 'groups' field: base (0x1), latched (0x2), locked (0x4), - * * or effective (0x8). - * */ + * for the 'groups' field: base (0x1), latched (0x2), locked (0x4), + * or effective (0x8). + */ if( map->groups ) { int i; @@ -298,13 +296,13 @@ Bool _XklSetIndicator( int indicatorNum, Bool set ) } if( map->which_groups & ( XkbIM_UseLocked | XkbIM_UseEffective ) ) { - // Important: Groups should be ignored here - because they are handled separately! - // XklLockGroup( group ); + /* Important: Groups should be ignored here - because they are handled separately! */ + /* XklLockGroup( group ); */ } else if( map->which_groups & XkbIM_UseLatched ) XkbLatchGroup( _xklDpy, XkbUseCoreKbd, group ); else { - // Can do nothing. Just ignore the indicator + /* Can do nothing. Just ignore the indicator */ return True; } } else @@ -364,15 +362,19 @@ int _XklXkbInit( void ) int opcode; static XklVTable xklXkbVTable = { + "XKB", + XKLF_CAN_TOGGLE_INDICATORS | + XKLF_CAN_OUTPUT_CONFIG_AS_ASCII | + XKLF_CAN_OUTPUT_CONFIG_AS_BINARY, _XklXkbConfigActivate, _XklXkbConfigInit, _XklXkbConfigLoadRegistry, - _XklXkbConfigMultipleLayoutsSupported, _XklXkbConfigWriteFile, _XklXkbEventHandler, _XklXkbFreeAllInfo, _XklXkbGetGroupNames, _XklXkbGetNumGroups, + _XklXkbGetRealState, _XklXkbLoadAllInfo, _XklXkbLockGroup, _XklXkbPauseListen, @@ -394,14 +396,23 @@ int _XklXkbInit( void ) "xkbEvenType: %X, xkbError: %X, display: %p, root: " WINID_FORMAT "\n", _xklXkbEventType, _xklXkbError, _xklDpy, _xklRootWindow ); - _xklAtoms[XKB_RF_NAMES_PROP_ATOM] = + xklXkbVTable.baseConfigAtom = XInternAtom( _xklDpy, _XKB_RF_NAMES_PROP_ATOM, False ); - _xklAtoms[XKB_RF_NAMES_PROP_ATOM_BACKUP] = + xklXkbVTable.backupConfigAtom = XInternAtom( _xklDpy, "_XKB_RULES_NAMES_BACKUP", False ); + xklXkbVTable.defaultModel = "pc101"; + xklXkbVTable.defaultLayout = "us"; + xklVTable = &xklXkbVTable; + + /* First, we have to assign xklVTable - + because this function uses it */ + + if( _XklXkbConfigMultipleLayoutsSupported() ) + xklXkbVTable.features |= XKLF_MULTIPLE_LAYOUTS_SUPPORTED; - return _XklLoadAllInfo( ) ? 0 : _xklLastErrorCode; + return 0; #else XklDebug( 160, "NO XKB LIBS, display: %p, root: " WINID_FORMAT diff --git a/libxklavier/xklavier_xmm.c b/libxklavier/xklavier_xmm.c index d565732..2d68637 100755 --- a/libxklavier/xklavier_xmm.c +++ b/libxklavier/xklavier_xmm.c @@ -1,71 +1,266 @@ #include #include +#include #include #include #include #include +#include + +#include "config.h" #include "xklavier_private.h" #include "xklavier_private_xmm.h" +#define SHORTCUT_OPTION_PREFIX "grp:" + +char* currentXmmRules = NULL; + +XklConfigRec currentXmmConfig; + +Atom xmmStateAtom; + const char **_XklXmmGetGroupNames( void ) { - return ( const char ** ) NULL; + return (const char **)currentXmmConfig.layouts; } -int _XklXmmPauseListen( ) +void _XklXmmGrabShortcuts( ) { - return 0; + int i; + XmmShortcutPtr shortcut; + const XmmSwitchOptionPtr option = _XklXmmGetCurrentShortcut(); + + XklDebug( 150, "Found shortcut option: %p\n", option ); + if( option == NULL ) + return; + + shortcut = option->shortcuts; + for( i = option->numShortcuts; --i >= 0; shortcut++ ) + { + int keycode = XKeysymToKeycode( _xklDpy, shortcut->keysym ); + _XklXmmGrabIgnoringIndicators( keycode, + shortcut->modifiers ); + } +} + +void _XklXmmUngrabShortcuts( ) +{ + int i; + XmmShortcutPtr shortcut; + const XmmSwitchOptionPtr option = _XklXmmGetCurrentShortcut(); + + if( option == NULL ) + return; + + shortcut = option->shortcuts; + for( i = option->numShortcuts; --i >= 0; shortcut++ ) + { + int keycode = XKeysymToKeycode( _xklDpy, shortcut->keysym ); + _XklXmmUngrabIgnoringIndicators( keycode, + shortcut->modifiers ); + } +} + +const XmmSwitchOptionPtr _XklXmmGetCurrentShortcut() +{ + const char* optionName = _XklXmmGetCurrentShortcutOptionName(); + XklDebug( 150, "Configured switch option: [%s]\n", optionName ); + if( optionName == NULL ) + return NULL; + XmmSwitchOptionPtr switchOption = allSwitchOptions; + while( switchOption->optionName != NULL ) + { + if( !strcmp( switchOption->optionName, optionName ) ) + return switchOption; + switchOption++; + } + return NULL; +} + +const char* _XklXmmGetCurrentShortcutOptionName( ) +{ + int i; + char** option = currentXmmConfig.options; + for( i = currentXmmConfig.numOptions; --i >= 0; option++ ) + { + /* starts with "grp:" */ + if( strstr( *option, SHORTCUT_OPTION_PREFIX ) != NULL ) + { + return *option + sizeof SHORTCUT_OPTION_PREFIX - 1; + } + } + return NULL; +} + +const XmmSwitchOptionPtr _XklXmmFindSwitchOption( unsigned keycode, + unsigned state, + int* currentShortcut_rv ) +{ + const XmmSwitchOptionPtr rv = _XklXmmGetCurrentShortcut(); + int i; + + if( rv != NULL ) + { + XmmShortcutPtr sc = rv->shortcuts; + for( i=rv->numShortcuts; --i>=0; sc++ ) + { + if( ( XKeysymToKeycode( _xklDpy, sc->keysym ) == keycode ) && + ( ( state & sc->modifiers ) == sc->modifiers ) ) + { + return rv; + } + } + } + return NULL; } int _XklXmmResumeListen( ) { + if( _xklListenerType & XKLL_MANAGE_LAYOUTS ) + _XklXmmGrabShortcuts(); return 0; } -unsigned _XklXmmGetNumGroups( void ) +int _XklXmmPauseListen( ) { + if( _xklListenerType & XKLL_MANAGE_LAYOUTS ) + _XklXmmUngrabShortcuts(); return 0; } +unsigned _XklXmmGetNumGroups( void ) +{ + return currentXmmConfig.numLayouts; +} + void _XklXmmFreeAllInfo( ) { + if( currentXmmRules != NULL ) + { + free( currentXmmRules ); + currentXmmRules = NULL; + } + XklConfigRecReset( ¤tXmmConfig ); } Bool _XklXmmLoadAllInfo( ) { - return False; + return _XklConfigGetFullFromServer( ¤tXmmRules, ¤tXmmConfig ); +} + +void _XklXmmGetRealState( XklState * state ) +{ + unsigned char *propval = NULL; + Atom actualType; + int actualFormat; + unsigned long bytesRemaining; + unsigned long actualItems; + int result; + + memset( state, 0, sizeof( *state ) ); + + result = XGetWindowProperty( _xklDpy, _xklRootWindow, xmmStateAtom, 0L, 1L, + False, XA_INTEGER, &actualType, &actualFormat, + &actualItems, &bytesRemaining, + &propval ); + + if( Success != result ) + { + XklDebug( 160, "Could not get the xmodmap current group: %d\n", result ); + return; + } + + if( actualFormat != 32 || + actualItems != 1 ) + { + XklDebug( 160, "Could not get the xmodmap current group\n" ); + return; + } + + state->group = *(CARD32*)propval; + XFree( propval ); + state->indicators = 0; +} + +void _XklXmmActualizeGroup( int group ) +{ + char cmd[1024]; + int res; + const char* layoutName = NULL; + + if( currentXmmConfig.numLayouts < group ) + return; + + layoutName = currentXmmConfig.layouts[group]; + + snprintf( cmd, sizeof cmd, + "xmodmap %s/xmodmap.%s", + XMODMAP_BASE, layoutName ); + + res = system( cmd ); + if( res > 0 ) + { + XklDebug( 0, "xmodmap error %d\n", res ); + } else if( res < 0 ) + { + XklDebug( 0, "Could not execute xmodmap: %d\n", res ); + } + XSync( _xklDpy, False ); } void _XklXmmLockGroup( int group ) { + CARD32 propval; + + if( currentXmmConfig.numLayouts < group ) + return; + + /* updating the status property */ + propval = group; + XChangeProperty( _xklDpy, _xklRootWindow, xmmStateAtom, + XA_INTEGER, 32, PropModeReplace, + (unsigned char*)&propval, 1 ); + XSync( _xklDpy, False ); } int _XklXmmInit( void ) { static XklVTable xklXmmVTable = { + "xmodmap", + XKLF_MULTIPLE_LAYOUTS_SUPPORTED | + XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT, _XklXmmConfigActivate, _XklXmmConfigInit, _XklXmmConfigLoadRegistry, - _XklXmmConfigMultipleLayoutsSupported, - _XklXmmConfigWriteFile, + NULL, _XklXmmEventHandler, _XklXmmFreeAllInfo, _XklXmmGetGroupNames, _XklXmmGetNumGroups, + _XklXmmGetRealState, _XklXmmLoadAllInfo, _XklXmmLockGroup, _XklXmmPauseListen, _XklXmmResumeListen, - _XklXmmSetIndicators, + NULL, }; + xklXmmVTable.baseConfigAtom = + XInternAtom( _xklDpy, "_XMM_NAMES", False ); + xklXmmVTable.backupConfigAtom = + XInternAtom( _xklDpy, "_XMM_NAMES_BACKUP", False ); + + xmmStateAtom = + XInternAtom( _xklDpy, "_XMM_STATE", False ); + + xklXmmVTable.defaultModel = "generic"; + xklXmmVTable.defaultLayout = "us"; + xklVTable = &xklXmmVTable; - XklDebug( 160, - "Xmodmap support activated, display: %p, root: " WINID_FORMAT - "\n", _xklDpy, _xklRootWindow ); - return -1; + XklDebug( 0, "XMM backend inited\n" ); + return 0; } diff --git a/libxklavier/xklavier_xmm_opts.c b/libxklavier/xklavier_xmm_opts.c new file mode 100644 index 0000000..d082482 --- /dev/null +++ b/libxklavier/xklavier_xmm_opts.c @@ -0,0 +1,104 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "config.h" + +#include "xklavier_private.h" +#include "xklavier_private_xmm.h" + +#define SHORTCUT_OPTION_PREFIX "grp:" + +XmmSwitchOption allSwitchOptions[] = +{ + { + "ralt_toggle", 1, + { { XK_Alt_R, 0 } }, { 1 } + }, + { + "lalt_toggle", 1, + { { XK_Alt_L, 0 } }, { 1 } + }, + { + "caps_toggle", 1, + { { XK_Caps_Lock, 0 } }, { 1 } + }, + { + "shift_caps_toggle", 1, + { { XK_Caps_Lock, ShiftMask } }, { 1 } + }, + { + "shifts_toggle", 2, + { { XK_Shift_R, ShiftMask }, + { XK_Shift_L, ShiftMask } }, { 1, -1 } + }, + { + "alts_toggle", 2, + { { XK_Alt_R, Mod1Mask }, + { XK_Alt_L, Mod1Mask } }, { 1, -1 } + }, + { + "ctrls_toggle", 2, + { { XK_Control_R, ControlMask }, + { XK_Control_L, ControlMask } }, { 1, -1 } + }, + { + "ctrl_shift_toggle", 4, + { { XK_Control_R, ShiftMask }, + { XK_Control_L, ShiftMask }, + { XK_Shift_R, ControlMask }, + { XK_Shift_L, ControlMask } }, { 1, -1, 1, -1 } + }, + { + "ctrl_alt_toggle", 4, + { { XK_Control_R, Mod1Mask }, + { XK_Control_L, Mod1Mask }, + { XK_Alt_R, ControlMask }, + { XK_Alt_L, ControlMask } }, { 1, -1, 1, -1 } + }, + { + "alt_shift_toggle", 4, + { { XK_Shift_R, Mod1Mask }, + { XK_Shift_L, Mod1Mask }, + { XK_Alt_R, ShiftMask }, + { XK_Alt_L, ShiftMask } }, { 1, -1, 1, -1 } + }, + { + "menu_toggle", 1, + { { XK_Menu, 0 } }, { 1 } + }, + { + "lwin_toggle", 1, + { { XK_Super_L, 0 } }, { 1 } + }, + { + "rwin_toggle", 1, + { { XK_Super_R, 0 } }, { 1 } + }, + { + "lshift_toggle", 1, + { { XK_Shift_L, 0 } }, { 1 } + }, + { + "rshift_toggle", 1, + { { XK_Shift_R, 0 } }, { 1 } + }, + { + "lctrl_toggle", 1, + { { XK_Control_L, 0 } }, { 1 } + }, + { + "rctrl_toggle", 1, + { { XK_Control_R, 0 } }, { 1 } + }, + { + NULL, 1, + { { 0, 0 } }, { 1 } + } +}; diff --git a/tests/test_config.c b/tests/test_config.c index ad2c4f0..cf01482 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -1,12 +1,22 @@ #include #include #include +#include #include #include #include #include #include +#ifdef __STRICT_ANSI__ +/* these are functions which are NOT in ANSI C. + Probably we should provide the implementation */ +extern char *strdup( const char *s ); +#endif + +extern void XklConfigDump( FILE* file, + XklConfigRecPtr data ); + enum { ACTION_NONE, ACTION_GET, ACTION_SET, ACTION_WRITE }; static void printUsage() @@ -21,28 +31,6 @@ static void printUsage() printf( " -h - Show this help\n" ); } -static void dump( XklConfigRecPtr ptr ) -{ - int i,j; - char**p; - XklDebug( 0, " model: [%s]\n", ptr->model ); - - XklDebug( 0, " layouts(%d):\n", ptr->numLayouts ); - p = ptr->layouts; - for( i = ptr->numLayouts, j = 0; --i >= 0; ) - XklDebug( 0, " %d: [%s]\n", j++, *p++ ); - - XklDebug( 0, " variants(%d):\n", ptr->numVariants ); - p = ptr->variants; - for( i = ptr->numVariants, j = 0; --i >= 0; ) - XklDebug( 0, " %d: [%s]\n", j++, *p++ ); - - XklDebug( 0, " options(%d):\n", ptr->numOptions ); - p = ptr->options; - for( i = ptr->numOptions, j = 0; --i >= 0; ) - XklDebug( 0, " %d: [%s]\n", j++, *p++ ); -} - int main( int argc, char * const argv[] ) { int c, i; @@ -50,7 +38,7 @@ int main( int argc, char * const argv[] ) const char* model = NULL; const char* layouts = NULL; const char* options = NULL; - int debugLevel = 0; + int debugLevel = -1; int binary = 0; Display *dpy; @@ -109,13 +97,14 @@ int main( int argc, char * const argv[] ) if ( !XklInit( dpy ) ) { XklConfigRec currentConfig, r2; - XklSetDebugLevel( debugLevel ); + if( debugLevel != -1 ) + XklSetDebugLevel( debugLevel ); XklDebug( 0, "Xklavier initialized\n" ); XklConfigInit(); XklConfigLoadRegistry(); XklDebug( 0, "Xklavier registry loaded\n" ); - XklDebug( 0, "Multiple layouts are %ssupported\n", - XklMultipleLayoutsSupported() ? "" : "not " ); + XklDebug( 0, "Bakend: [%s]\n", XklGetBackendName() ); + XklDebug( 0, "Supported features: 0x0%X\n", XklGetBackendFeatures() ); XklConfigRecInit( ¤tConfig ); XklConfigGetFromServer( ¤tConfig ); @@ -124,14 +113,14 @@ int main( int argc, char * const argv[] ) { case ACTION_GET: XklDebug( 0, "Got config from the server\n" ); - dump( ¤tConfig ); + XklConfigDump( stdout, ¤tConfig ); XklConfigRecInit( &r2 ); if ( XklConfigGetFromBackup( &r2 ) ) { XklDebug( 0, "Got config from the backup\n" ); - dump( &r2 ); + XklConfigDump( stdout, &r2 ); } if ( XklConfigActivate( &r2 ) ) @@ -191,7 +180,7 @@ int main( int argc, char * const argv[] ) } XklDebug( 0, "New config:\n" ); - dump( ¤tConfig ); + XklConfigDump( stdout, ¤tConfig ); if ( XklConfigActivate( ¤tConfig ) ) XklDebug( 0, "Set the config\n" ); else @@ -215,7 +204,7 @@ int main( int argc, char * const argv[] ) XklTerm(); } else { - fprintf( stderr, "Could not init Xklavier\n" ); + fprintf( stderr, "Could not init Xklavier: %s\n", XklGetLastError() ); exit(2); } printf( "closing display: %p\n", dpy ); diff --git a/tests/test_monitor.c b/tests/test_monitor.c index 8808b62..515c328 100644 --- a/tests/test_monitor.c +++ b/tests/test_monitor.c @@ -1,52 +1,41 @@ #include #include #include +#include #include #include #include #include #include +extern void XklConfigDump( FILE* file, + XklConfigRecPtr data ); + static void printUsage() { - printf( "Usage: test_monitor (-h)|(-d )\n" ); + printf( "Usage: test_monitor (-l1)(-l2)(-l3)(-h)(-d )\n" ); printf( "Options:\n" ); printf( " -d - Set the debug level (by default, 0)\n" ); printf( " -h - Show this help\n" ); -} - -void dump( XklConfigRecPtr ptr ) -{ - int i,j; - char**p; - XklDebug( 0, " model: [%s]\n", ptr->model ); - - XklDebug( 0, " layouts(%d):\n", ptr->numLayouts ); - p = ptr->layouts; - for( i = ptr->numLayouts, j = 0; --i >= 0; ) - XklDebug( 0, " %d: [%s]\n", j++, *p++ ); - - XklDebug( 0, " variants(%d):\n", ptr->numVariants ); - p = ptr->variants; - for( i = ptr->numVariants, j = 0; --i >= 0; ) - XklDebug( 0, " %d: [%s]\n", j++, *p++ ); - - XklDebug( 0, " options(%d):\n", ptr->numOptions ); - p = ptr->options; - for( i = ptr->numOptions, j = 0; --i >= 0; ) - XklDebug( 0, " %d: [%s]\n", j++, *p++ ); + printf( " -l1 - listen to manage layouts\n" ); + printf( " -l2 - listen to manage window states\n" ); + printf( " -l3 - listen to track the keyboard state\n" ); } int main( int argc, char * argv[] ) { int c; - int debugLevel = 0; + int debugLevel = -1; XkbEvent ev; Display* dpy; + int listenerType = 0, lt; + int listenerTypes[] = { XKLL_MANAGE_LAYOUTS, + XKLL_MANAGE_WINDOW_STATES, + XKLL_TRACK_KEYBOARD_STATE }; while (1) { - c = getopt( argc, argv, "hd:" ); + c = getopt( argc, argv, "hd:l:" ); if ( c == -1 ) break; switch (c) @@ -57,6 +46,11 @@ int main( int argc, char * argv[] ) case 'd': debugLevel = atoi( optarg ); break; + case 'l': + lt = optarg[0] - '1'; + if( lt >= 0 && lt < sizeof(listenerTypes)/sizeof(listenerTypes[0]) ) + listenerType |= listenerTypes[lt]; + break; default: fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); printUsage(); @@ -71,10 +65,11 @@ int main( int argc, char * argv[] ) exit(1); } printf( "opened display: %p\n", dpy ); - if ( !XklInit( dpy ) ) + if( !XklInit( dpy ) ) { XklConfigRec currentConfig; - XklSetDebugLevel( debugLevel ); + if( debugLevel != -1 ) + XklSetDebugLevel( debugLevel ); XklDebug( 0, "Xklavier initialized\n" ); XklConfigInit(); XklConfigLoadRegistry(); @@ -83,7 +78,8 @@ int main( int argc, char * argv[] ) XklConfigRecInit( ¤tConfig ); XklConfigGetFromServer( ¤tConfig ); - XklStartListen(); + XklDebug( 0, "Now, listening...\n" ); + XklStartListen( listenerType ); while (1) { @@ -103,7 +99,7 @@ int main( int argc, char * argv[] ) XklTerm(); } else { - fprintf( stderr, "Could not init Xklavier\n" ); + fprintf( stderr, "Could not init Xklavier: %s\n", XklGetLastError() ); exit(2); } printf( "closing display: %p\n", dpy ); -- cgit v1.2.1