diff options
author | Sergey Udaltsov <svu@gnome.org> | 2006-03-12 04:20:01 +0000 |
---|---|---|
committer | Sergey Udaltsov <svu@gnome.org> | 2006-03-12 04:20:01 +0000 |
commit | 2c88cc80147b72eba939d6358939ef59d403c34e (patch) | |
tree | b6b145f6d50e1f4bba8145bef5963aee8a5f3180 | |
parent | d7bc98fb5f9d55c37a08ceeedbc87cb70ee6f133 (diff) | |
download | libxklavier-2c88cc80147b72eba939d6358939ef59d403c34e.tar.gz |
branching 2.x, merging GLIBing to HEAD
44 files changed, 7201 insertions, 6686 deletions
@@ -1,3 +1,7 @@ +2006-03-12 svu + + * everything: branching 2.x series, merging GLIBing branch to HEAD + 2006-02-14 svu * libxklavier/xklavier.c: libxklavier/xklavier_evt.c: hopefully fixing diff --git a/Doxyfile.in b/Doxyfile.in deleted file mode 100644 index 371a6a0..0000000 --- a/Doxyfile.in +++ /dev/null @@ -1,1162 +0,0 @@ -# Doxyfile 1.3.9.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = @PACKAGE@ - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = @VERSION@ - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -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, 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 - -# 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). - -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 -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -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. - -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 -# only done if one of the specified strings matches the left-hand part of -# 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 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. - -STRIP_FROM_INC_PATH = - -# 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 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. - -JAVADOC_AUTOBRIEF = NO - -# 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. - -MULTILINE_CPP_IS_BRIEF = NO - -# 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. - -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 -# 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 -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# 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 SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# 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 INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# 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. - -SORT_BRIEF_DOCS = NO - -# 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. - -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 -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# 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. - -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 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 -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# 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 -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -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 -# warning originated and the warning text. - -WARN_FORMAT = - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -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 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 - -# 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. -# If left blank NO is used. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -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. - -EXCLUDE_PATTERNS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_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. - -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). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command <filter> <input-file>, where <filter> -# is the value of the INPUT_FILTER tag, and <input-file> is the name of an -# input file. Doxygen will then use the output that the filter program writes -# 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 (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 -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -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. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# 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. 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 = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - -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). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -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. - -TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -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, 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 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -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. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = NO - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = NO - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -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 optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# 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 = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man 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 `man' will be used as the default path. - -MAN_OUTPUT = - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -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 -# 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 -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_PREDEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# 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. 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_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::additions related to external references -#--------------------------------------------------------------------------- - -# 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 = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -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'). - -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 -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -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 -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -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 -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - -MAX_DOT_GRAPH_WIDTH = 1024 - -# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height -# (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 -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - -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. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# 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 diff --git a/Makefile.am b/Makefile.am index f531b81..0170b86 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,18 +4,9 @@ config_xml_DATA = xfree86.xml config_xmldir = $(datadir)/$(PACKAGE) EXTRA_DIST = libxklavier.spec libxklavier.spec.in \ - Doxyfile Doxyfile.in autogen.sh \ - CREDITS libxklavier.pc.in \ + autogen.sh \ + CREDITS libxklavier.pc.in gtk-doc.make \ $(config_xml_DATA) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libxklavier.pc - -doxydocs: libxklavier/xklavier.h libxklavier/xklavier_config.h - if test "x$(DO_DOXYGEN)" = "xyes" ; then \ - doxygen Doxyfile; \ - fi; - -all: doxydocs - -.PHONY: doxydocs @@ -133,12 +133,15 @@ do automake --add-missing --gnu $am_opt echo "Running autoconf ..." autoconf + + echo "Running gtkdocize ..." + gtkdocize || exit 1 ) fi done #conf_flags="--enable-maintainer-mode --enable-compile-warnings" #--enable-iso-c -conf_flags="--enable-doxygen" +conf_flags="--enable-gtk-doc" if test x$NOCONFIGURE = x; then echo Running $srcdir/configure $conf_flags "$@" ... diff --git a/configure.in b/configure.in index c079adb..5bf0630 100644 --- a/configure.in +++ b/configure.in @@ -2,9 +2,9 @@ AC_INIT(libxklavier/xklavier.c) PACKAGE=libxklavier MAJOR_VERSION=2 -MINOR_VERSION=2 +MINOR_VERSION=91 VERSION=$MAJOR_VERSION.$MINOR_VERSION -VERSION_INFO=10:0:0 +VERSION_INFO=11:0:0 AC_SUBST(MAJOR_VERSION) AC_SUBST(MINOR_VERSION) @@ -25,6 +25,7 @@ dnl AC_ARG_PROGRAM AM_PROG_LIBTOOL AM_ICONV +GTK_DOC_CHECK(1.0) dnl From Bruno Haible. dnl From gnoome-vfs @@ -101,12 +102,6 @@ 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) @@ -135,6 +130,11 @@ PKG_CHECK_MODULES(XML, \ AC_SUBST(XML_LIBS) AC_SUBST(XML_CFLAGS) +PKG_CHECK_MODULES(GLIB, \ + glib-2.0 >= 2.6.0 gobject-2.0 >= 2.6.0) +AC_SUBST(GLIB_LIBS) +AC_SUBST(GLIB_CFLAGS) + AC_SUBST(CFLAGS) AC_SUBST(LDFLAGS) @@ -142,9 +142,8 @@ AC_OUTPUT([ Makefile libxklavier/Makefile libxklavier.spec -Doxyfile doc/Makefile -doc/html/Makefile +doc/reference/Makefile tests/Makefile libxklavier.pc ]) diff --git a/doc/Makefile.am b/doc/Makefile.am index 38d9a77..b68c774 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1 +1 @@ -SUBDIRS=html +SUBDIRS=reference diff --git a/doc/html/.cvsignore b/doc/html/.cvsignore deleted file mode 100644 index 4414e3f..0000000 --- a/doc/html/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile Makefile.in *.html *.css *.gif *.png diff --git a/doc/html/Makefile.am b/doc/html/Makefile.am deleted file mode 100644 index ea274a8..0000000 --- a/doc/html/Makefile.am +++ /dev/null @@ -1,62 +0,0 @@ -EXTRA_WEB_FILES = doxygen.css \ - doxygen.png - -HTML_FILES = annotated.html\ - files.html\ - functions.html\ - globals.html\ - group__activation.html\ - group__callbacks.html\ - group__currents.html\ - group__debugerr.html\ - group__enum.html\ - group__lookup.html\ - group__props.html\ - group__settings.html\ - group__wininfo.html\ - group__xkbevents.html\ - group__xkbgroup.html\ - group__xkbinfo.html\ - group__xklconfig.html\ - group__xklconfiginitterm.html\ - group__xklinitterm.html\ - index.html\ - modules.html\ - struct__XklConfigItem.html\ - struct__XklConfigItem-members.html\ - struct__XklConfigRec.html\ - struct__XklConfigRec-members.html\ - structXklState.html\ - structXklState-members.html\ - xklavier_8h.html\ - xklavier_8h-source.html\ - xklavier__config_8h.html\ - xklavier__config_8h-source.html - -DOXYGEN_OUT_FILES = $(EXTRA_WEB_FILES) $(HTML_FILES) - -doc_to = $(datadir)/doc/$(PACKAGE)-$(VERSION)/html - -doc_files = $(DOXYGEN_OUT_FILES) - -EXTRA_DIST= $(doc_files) - -install: - @$(NORMAL_INSTALL) - if test "x$(DO_DOXYGEN)" = "xyes" ; then \ - $(mkinstalldirs) $(DESTDIR)$(doc_to); \ - for p in $(doc_files); do \ - $(INSTALL_DATA) $$p $(DESTDIR)$(doc_to)/$$p; \ - done; \ - fi - -uninstall: - @$(NORMAL_UNINSTALL) - if test "x$(DO_DOXYGEN)" = "xyes" ; then \ - for p in $(doc_files); do \ - rm -f $(DESTDIR)$(doc_to)/$$p; \ - done \ - fi - -MAINTAINERCLEANFILES = $(DOXYGEN_OUT_FILES) - diff --git a/doc/reference/.cvsignore b/doc/reference/.cvsignore new file mode 100644 index 0000000..10c9dba --- /dev/null +++ b/doc/reference/.cvsignore @@ -0,0 +1,11 @@ +*.txt +html +sgml +tmpl +xml +.libs +*.sgml +Makefile +Makefile.in +libxklavier.* +*.stamp diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am new file mode 100644 index 0000000..532876b --- /dev/null +++ b/doc/reference/Makefile.am @@ -0,0 +1,78 @@ +## Process this file with automake to produce Makefile.in + +# We require automake 1.6 at least. +AUTOMAKE_OPTIONS = 1.6 + +# This is a blank Makefile.am for using gtk-doc. +# Copy this to your project's API docs directory and modify the variables to +# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples +# of using the various options. + +# The name of the module, e.g. 'glib'. +DOC_MODULE=libxklavier + +# The top-level SGML file. You can change this if you want to. +DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml + +# The directory containing the source code. Relative to $(srcdir). +# gtk-doc will search all .c & .h files beneath here for inline comments +# documenting the functions and macros. +# e.g. DOC_SOURCE_DIR=../../../gtk +DOC_SOURCE_DIR=../../libxklavier + +# Extra options to pass to gtkdoc-scangobj. Not normally needed. +SCANGOBJ_OPTIONS= + +# Extra options to supply to gtkdoc-scan. +# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" +SCAN_OPTIONS= + +# Extra options to supply to gtkdoc-mkdb. +# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml +MKDB_OPTIONS=--sgml-mode --output-format=xml + +# Extra options to supply to gtkdoc-mktmpl +# e.g. MKTMPL_OPTIONS=--only-section-tmpl +MKTMPL_OPTIONS= + +# Extra options to supply to gtkdoc-fixref. Not normally needed. +# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html +FIXXREF_OPTIONS= + +# Used for dependencies. The docs will be rebuilt if any of these change. +# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h +# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c +HFILE_GLOB= +CFILE_GLOB= + +# Header files to ignore when scanning. +# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h +IGNORE_HFILES=xklavier_private.h xklavier_private_xkb.h xklavier_private_xmm.h xkl_engine_marshal.h + +# Images to copy into HTML directory. +# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png +HTML_IMAGES= + +# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). +# e.g. content_files=running.sgml building.sgml changes-2.0.sgml +content_files= + +# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded +# These files must be listed here *and* in content_files +# e.g. expand_content_files=running.sgml +expand_content_files= + +# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. +# Only needed if you are using gtkdoc-scangobj to dynamically query widget +# signals and properties. +# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) +# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) +INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GLIB_CFLAGS) +GTKDOC_LIBS=$(GLIB_LIBS) -L$(top_builddir)/libxklavier -lxklavier + +# This includes the standard gtk-doc make rules, copied by gtkdocize. +include $(top_srcdir)/gtk-doc.make + +# Other files to distribute +# e.g. EXTRA_DIST += version.xml.in +EXTRA_DIST += diff --git a/libxklavier.spec.in b/libxklavier.spec.in index 547b9dc..0076364 100644 --- a/libxklavier.spec.in +++ b/libxklavier.spec.in @@ -5,7 +5,7 @@ Release: 1 License: LGPL Group: Development/Libraries Url: http://gswitchit.sourceforge.net/ -BuildRequires: doxygen +BuildRequires: gtk-doc Source: http://gswitchit.sourceforge.net/%{name}-%{version}.tar.gz Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root @@ -27,8 +27,7 @@ Libraries, include files, etc you can use to develop libxklavier applications. %build CONFIG_FLAGS="--prefix=%{_prefix} --libdir=%{_libdir} \ - --includedir=%{_includedir} --bindir=%{_bindir} \ - --disable-doxygen" + --includedir=%{_includedir} --bindir=%{_bindir}" if [ ! -f configure ]; then CFLAGS="$RPM_OPT_FLAGS" ./autogen.sh $CONFIG_FLAGS @@ -65,7 +64,8 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version} %files devel %defattr(-, root, root) -%doc doc/html/*.html doc/html/*.png doc/html/*.css %{_libdir}/pkgconfig/*.pc %{_libdir}/*a %{_includedir}/* +%{_datadir}/gtk-doc/html/libxklavier + diff --git a/libxklavier/.indent.pro b/libxklavier/.indent.pro new file mode 100644 index 0000000..dbec33f --- /dev/null +++ b/libxklavier/.indent.pro @@ -0,0 +1,3 @@ +-kr +-i8 +-psl diff --git a/libxklavier/Makefile.am b/libxklavier/Makefile.am index 1643522..3eea793 100644 --- a/libxklavier/Makefile.am +++ b/libxklavier/Makefile.am @@ -14,8 +14,19 @@ else ENABLE_XMM_SUPPORT_CFLAG = -DDISABLE_XMM_SUPPORT=1 endif +EXTRA_DIST=marshal.list + +GLIB_GENMARSHAL = $(shell pkg-config --variable=glib_genmarshal glib-2.0) + +xkl_engine_marshal.h: marshal.list + $(GLIB_GENMARSHAL) --prefix=xkl_engine marshal.list --header > xkl_engine_marshal.h + +xkl_engine_marshal.c: xkl_engine_marshal.h + $(GLIB_GENMARSHAL) --prefix=xkl_engine marshal.list --body > xkl_engine_marshal.c + AM_CFLAGS=-Wall -Werror -DDATA_DIR=\"$(datadir)/$(PACKAGE)\" \ - -I. -I$(includedir) $(XML_CFLAGS) -I$(x_includes) -I$(top_srcdir) \ + -I. -I$(includedir) -I$(x_includes) -I$(top_srcdir) \ + $(XML_CFLAGS) $(GLIB_CFLAGS) \ $(XKB_HEADERS_PRESENT_CFLAG) \ $(ENABLE_XKB_SUPPORT_CFLAG) \ $(ENABLE_XMM_SUPPORT_CFLAG) @@ -24,13 +35,16 @@ lib_LTLIBRARIES = libxklavier.la noinst_HEADERS = xklavier_private.h xklavier_private_xkb.h xklavier_private_xmm.h xklavierincdir = $(includedir)/libxklavier -xklavierinc_HEADERS = xklavier.h xklavier_config.h +xklavierinc_HEADERS = xklavier.h xkl_config_registry.h xkl_engine.h \ + xkl_config_rec.h xkl_config_item.h xkl_engine_marshal.h libxklavier_la_SOURCES = xklavier.c xklavier_evt.c xklavier_config.c \ - xklavier_xkb.c xklavier_evt_xkb.c xklavier_config_xkb.c \ + xklavier_xkb.c xklavier_evt_xkb.c xklavier_config_xkb.c xklavier_toplevel.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 \ + xklavier_util.c xklavier_config_i18n.c xklavier_props.c xklavier_dump.c xkl_engine_marshal.c \ $(noinst_HEADERS) $(xklavierinc_HEADERS) -libxklavier_la_LDFLAGS = -version-info @VERSION_INFO@ $(XML_LIBS) -lxkbfile -L$(x_libraries) $(LIBICONV) +libxklavier_la_LDFLAGS = -version-info @VERSION_INFO@ \ + $(XML_LIBS) $(GLIB_LIBS) \ + -lxkbfile -L$(x_libraries) $(LIBICONV) diff --git a/libxklavier/marshal.list b/libxklavier/marshal.list new file mode 100644 index 0000000..3fcda01 --- /dev/null +++ b/libxklavier/marshal.list @@ -0,0 +1,3 @@ +VOID:VOID +INT:LONG,LONG +VOID:FLAGS,INT,BOOLEAN diff --git a/libxklavier/xkl_config_item.h b/libxklavier/xkl_config_item.h new file mode 100644 index 0000000..bad205a --- /dev/null +++ b/libxklavier/xkl_config_item.h @@ -0,0 +1,116 @@ +#ifndef __XKL_CONFIG_ITEM_H__ +#define __XKL_CONFIG_ITEM_H__ + +#include <glib-object.h> + +/* + * Maximum name length, including '\'0' character + */ +#define XKL_MAX_CI_NAME_LENGTH 32 + +/* + * Maximum short description length, including '\\0' character + * (this length is in bytes, so for UTF-8 encoding in + * XML file the actual maximum length can be smaller) + */ +#define XKL_MAX_CI_SHORT_DESC_LENGTH 10 + +/* + * Maximum description length, including '\\0' character + * (this length is in bytes, so for UTF-8 encoding in + * XML file the actual maximum length can be smaller) + */ +#define XKL_MAX_CI_DESC_LENGTH 192 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + typedef struct _XklConfigItem XklConfigItem; + typedef struct _XklConfigItemClass XklConfigItemClass; + +#define XKL_TYPE_CONFIG_ITEM (xkl_config_item_get_type ()) +#define XKL_CONFIG_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XKL_TYPE_CONFIG_ITEM, XklConfigItem)) +#define XKL_CONFIG_ITEM_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), XKL_CONFIG_ITEM, XklConfigItemClass)) +#define XKL_IS_CONFIG_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XKL_TYPE_CONFIG_ITEM)) +#define XKL_IS_CONFIG_ITEM_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), XKL_TYPE_CONFIG_ITEM)) +#define XKL_CONFIG_ITEM_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), XKL_TYPE_CONFIG_ITEM, XklConfigItemClass)) + +/** + * The configuration item. Corresponds to XML element "configItem". + */ + struct _XklConfigItem { +/** + * The superclass object + */ + GObject parent; +/** + * The configuration item name. Corresponds to XML element "name". + */ + gchar name[XKL_MAX_CI_NAME_LENGTH]; + +/** + * The configuration item short description. Corresponds to XML element "shortDescription". + */ + gchar short_description[XKL_MAX_CI_DESC_LENGTH]; + +/** + * The configuration item description. Corresponds to XML element "description". + */ + gchar description[XKL_MAX_CI_DESC_LENGTH]; + }; + +/** + * The XklConfigItem class, derived from GObject + */ + struct _XklConfigItemClass { + /** + * The superclass + */ + GObjectClass parent_class; + }; +/** + * xkl_config_item_get_type: + * + * Get type info for XklConfigItem + * + * Returns: GType for XklConfigItem + */ + extern GType xkl_config_item_get_type(void); + +/** + * xkl_config_item_new: + * + * Create new XklConfigItem + * + * Returns: new instance + */ + extern XklConfigItem *xkl_config_item_new(void); + +/** + * ConfigItemProcessFunc: + * @item: the item from registry + * @data: anything which can be stored into the pointer + * + * Callback type used for enumerating keyboard models, layouts, variants, options + */ + typedef void (*ConfigItemProcessFunc) (const XklConfigItem * item, + gpointer data); + +/** + * GroupProcessFunc: + * @item: the item from registry + * @allow_multiple_selection: a flag whether this group allows multiple selection + * @data: anything which can be stored into the pointer + * + * Callback type used for enumerating keyboard option groups + */ + typedef void (*GroupProcessFunc) (const XklConfigItem * item, + gboolean + allow_multiple_selection, + gpointer data); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/libxklavier/xkl_config_rec.h b/libxklavier/xkl_config_rec.h new file mode 100644 index 0000000..3170244 --- /dev/null +++ b/libxklavier/xkl_config_rec.h @@ -0,0 +1,220 @@ +#ifndef __XKL_CONFIG_REC_H__ +#define __XKL_CONFIG_REC_H__ + +#include <glib-object.h> +#include <libxklavier/xkl_engine.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + typedef struct _XklConfigRec XklConfigRec; + typedef struct _XklConfigRecClass XklConfigRecClass; + +#define XKL_TYPE_CONFIG_REC (xkl_config_rec_get_type ()) +#define XKL_CONFIG_REC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XKL_TYPE_CONFIG_REC, XklConfigRec)) +#define XKL_CONFIG_REC_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), XKL_CONFIG_REC, XklConfigRecClass)) +#define XKL_IS_CONFIG_REC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XKL_TYPE_CONFIG_REC)) +#define XKL_IS_CONFIG_REC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), XKL_TYPE_CONFIG_REC)) +#define XKL_CONFIG_REC_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), XKL_TYPE_CONFIG_REC, XklConfigRecClass)) + +/* + * Basic configuration params + */ + struct _XklConfigRec { +/* + * The superclass object + */ + GObject parent; +/* + * The keyboard model + */ + gchar *model; +/* + * The array of keyboard layouts + */ + gchar **layouts; +/* + * The array of keyboard layout variants (if any) + */ + gchar **variants; +/* + * The array of keyboard layout options + */ + gchar **options; + }; + +/* + * The XklConfigRec class, derived from GObject + */ + struct _XklConfigRecClass { + /* + * The superclass + */ + GObjectClass parent_class; + }; + +/** + * xkl_config_rec_get_type: + * + * Get type info for XConfigRec + * + * Returns: GType for XConfigRec + */ + extern GType xkl_config_rec_get_type(void); + +/** + * xkl_config_rec_new: + * + * Create new XklConfigRec + * + * Returns: new instance + */ + extern XklConfigRec *xkl_config_rec_new(void); + +/** + * xkl_config_rec_activate: + * @data: valid XKB configuration + * @engine: the engine + * + * Activates some XKB configuration + * description. Can be NULL + * + * Returns: TRUE on success + */ + extern gboolean xkl_config_rec_activate(const XklConfigRec * data, + XklEngine * engine); + +/** + * xkl_config_rec_get_from_server: + * @data: buffer for XKB configuration + * @engine: the engine + * + * Loads the current XKB configuration (from X server) + * + * Returns: TRUE on success + */ + extern gboolean xkl_config_rec_get_from_server(XklConfigRec * data, + XklEngine * engine); + +/** + * xkl_config_rec_get_from_backup: + * @data: buffer for XKB configuration + * @engine: the engine + * + * Loads the current XKB configuration (from backup) + * + * Returns: TRUE on success + */ + extern gboolean xkl_config_rec_get_from_backup(XklConfigRec * data, + XklEngine * engine); + +/** + * xkl_config_rec_write_to_file: + * @file_name: name of the file to create + * @data: valid XKB configuration + * description. Can be NULL + * @binary: flag indicating whether the output file should be binary + * @engine: the engine + * + * Writes some XKB configuration into XKM/XKB/... file + * + * Returns: TRUE on success + */ + extern gboolean xkl_config_rec_write_to_file(XklEngine * engine, + const gchar * + file_name, + const XklConfigRec * + data, + const gboolean + binary); + +/** + * xkl_config_rec_get_from_root_window_property: + * @rules_atom_name: atom name of the root window property to read + * @rules_file_out: pointer to hold the file name + * @config_out: buffer to hold the result + * @engine: the engine + * + * Gets the XKB configuration from any root window property + * + * Returns: TRUE on success + */ + extern gboolean + xkl_config_rec_get_from_root_window_property(XklConfigRec * + config_out, + Atom + rules_atom_name, + gchar ** + rules_file_out, + XklEngine * + engine); + +/** + * xkl_config_rec_set_to_root_window_property: + * @rules_atom_name: atom name of the root window property to write + * @rules_file: rules file name + * @config: configuration to save + * @engine: the engine + * + * Saves the XKB configuration into any root window property + * + * Returns: TRUE on success + */ + extern gboolean xkl_config_rec_set_to_root_window_property(const + XklConfigRec + * + config, + Atom + rules_atom_name, + gchar * + rules_file, + XklEngine + * + engine); + +/** + * xkl_backup_names_prop: + * @engine: the engine + * + * Backups current XKB configuration into some property - + * if this property is not defined yet. + * + * Returns: TRUE on success + */ + extern gboolean xkl_backup_names_prop(XklEngine * engine); + +/** + * xkl_restore_names_prop: + * @engine: the engine + * + * Restores XKB from the property saved by xkl_backup_names_prop + * + * Returns: TRUE on success + */ + extern gboolean xkl_restore_names_prop(XklEngine * engine); + +/** + * xkl_config_rec_reset: + * @data: record to reset + * + * Resets the record (equal to Destroy and Init) + */ + extern void xkl_config_rec_reset(XklConfigRec * data); + +/** + * xkl_config_rec_equals: + * @data1: record to compare + * @data2: another record + * + * Compares two records + * + * Returns: TRUE if records are same + */ + extern gboolean xkl_config_rec_equals(XklConfigRec * data1, + XklConfigRec * data2); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/libxklavier/xkl_config_registry.h b/libxklavier/xkl_config_registry.h new file mode 100644 index 0000000..a1c108e --- /dev/null +++ b/libxklavier/xkl_config_registry.h @@ -0,0 +1,264 @@ +#ifndef __XKL_CONFIG_REGISTRY_H__ +#define __XKL_CONFIG_REGISTRY_H__ + +#include <glib-object.h> +#include <libxklavier/xkl_engine.h> +#include <libxklavier/xkl_config_item.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + typedef struct _XklConfigRegistry XklConfigRegistry; + typedef struct _XklConfigRegistryPrivate XklConfigRegistryPrivate; + typedef struct _XklConfigRegistryClass XklConfigRegistryClass; + +#define XKL_TYPE_CONFIG_REGISTRY (xkl_config_registry_get_type ()) +#define XKL_CONFIG_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XKL_TYPE_CONFIG_REGISTRY, XklConfigRegistry)) +#define XKL_CONFIG_REGISTRY_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), XKL_TYPE_CONFIG_REGISTRY, XklConfigRegistryClass)) +#define XKL_IS_CONFIG_REGISTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XKL_TYPE_CONFIG_REGISTRY)) +#define XKL_IS_CONFIG_REGISTRY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), XKL_TYPE_CONFIG_REGISTRY)) +#define XKL_CONFIG_REGISTRY_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), XKL_TYPE_CONFIG_REGISTRY, XklConfigRegistryClass)) + +/** + * The configuration manager. Corresponds to XML element "configItem". + */ + struct _XklConfigRegistry { +/** + * The superclass object + */ + GObject parent; + + XklConfigRegistryPrivate *priv; + }; + +/** + * The XklConfigRegistry class, derived from GObject + */ + struct _XklConfigRegistryClass { + /** + * The superclass + */ + GObjectClass parent_class; + }; +/** + * xkl_config_registry_get_type: + * + * Get type info for XConfig + * + * Returns: GType for XConfig + */ + extern GType xkl_config_registry_get_type(void); + +/** + * xkl_config_registry_get_instance: + * @engine: the engine to use for accessing X in all the operations + * (like accessing root window properties etc) + * + * Create new XklConfig + * + * Returns: new instance + */ + extern XklConfigRegistry + * xkl_config_registry_get_instance(XklEngine * engine); + +/** + * xkl_config_registry_load_from_file: + * @config: the config registry + * @file_name: file to load + * + * Loads XML configuration registry + * + * Returns: TRUE on success + */ + extern gboolean + xkl_config_registry_load_from_file(XklConfigRegistry * config, + const gchar * file_name); + +/** + * xkl_config_registry_load: + * @config: the config registry + * + * Loads XML configuration registry. The name is taken from X server + * (for XKB/libxkbfile, from the root window property) + * + * Returns: TRUE on success + */ + extern gboolean xkl_config_registry_load(XklConfigRegistry * + config); + +/** + * xkl_config_registry_free: + * @config: the config registry + * + * Frees XML configuration registry + */ + extern void xkl_config_registry_free(XklConfigRegistry * config); + +/** + * xkl_config_registry_foreach_model: + * @config: the config registry + * @func: callback to call for every model + * @data: anything which can be stored into the pointer + * + * Enumerates keyboard models from the XML configuration registry + */ + extern void xkl_config_registry_foreach_model(XklConfigRegistry * + config, + ConfigItemProcessFunc + func, gpointer data); + +/** + * xkl_config_registry_foreach_layout: + * @config: the config registry + * @func: callback to call for every layout + * @data: anything which can be stored into the pointer + * + * Enumerates keyboard layouts from the XML configuration registry + */ + extern void xkl_config_registry_foreach_layout(XklConfigRegistry * + config, + ConfigItemProcessFunc + func, + gpointer data); + +/** + * xkl_config_registry_foreach_layout_variant: + * @config: the config registry + * @layout_name: layout name for which variants will be listed + * @func: callback to call for every layout variant + * @data: anything which can be stored into the pointer + * + * Enumerates keyboard layout variants from the XML configuration registry + */ + extern void + xkl_config_registry_foreach_layout_variant(XklConfigRegistry * + config, + const gchar * + layout_name, + ConfigItemProcessFunc + func, gpointer data); + +/** + * xkl_config_registry_foreach_option_group: + * @config: the config registry + * @func: callback to call for every option group + * @data: anything which can be stored into the pointer + * + * Enumerates keyboard option groups from the XML configuration registry + */ + extern void + xkl_config_registry_foreach_option_group(XklConfigRegistry * + config, + GroupProcessFunc func, + gpointer data); + +/** + * xkl_config_registry_foreach_option: + * @config: the config registry + * @option_group_name: option group name for which variants + * will be listed + * @func: callback to call for every option + * @data: anything which can be stored into the pointer + * + * Enumerates keyboard options from the XML configuration registry + */ + extern void xkl_config_registry_foreach_option(XklConfigRegistry * + config, + const gchar * + option_group_name, + ConfigItemProcessFunc + func, + gpointer data); + +/** + * xkl_config_registry_find_model: + * @config: the config registry + * @item: pointer to a XklConfigItem containing the name of the + * keyboard model. On successfull return, the descriptions are filled. + * + * Loads a keyboard model information from the XML configuration registry. + * + * Returns: TRUE if appropriate element was found and loaded + */ + extern gboolean xkl_config_registry_find_model(XklConfigRegistry * + config, + XklConfigItem * + item); + +/** + * xkl_config_registry_find_layout: + * @config: the config registry + * @item: pointer to a XklConfigItem containing the name of the + * keyboard layout. On successfull return, the descriptions are filled. + * + * Loads a keyboard layout information from the XML configuration registry. + * + * Returns: TRUE if appropriate element was found and loaded + */ + extern gboolean xkl_config_registry_find_layout(XklConfigRegistry * + config, + XklConfigItem * + item); + +/** + * xkl_config_registry_find_variant: + * @config: the config registry + * @layout_name: name of the parent layout + * @item: pointer to a XklConfigItem containing the name of the + * keyboard layout variant. On successfull return, the descriptions are filled. + * + * Loads a keyboard layout variant information from the XML configuration + * registry. + * + * Returns: TRUE if appropriate element was found and loaded + */ + extern gboolean xkl_config_registry_find_variant(XklConfigRegistry + * config, + const char + *layout_name, + XklConfigItem * + item); + +/** + * xkl_config_registry_find_option_group: + * @config: the config registry + * @item: pointer to a XklConfigItem containing the name of the + * keyboard option group. On successfull return, the descriptions are filled. + * @allow_multiple_selection: pointer to some gboolean variable to fill + * the corresponding attribute of XML element "group". + * + * Loads a keyboard option group information from the XML configuration + * registry. + * + * Returns: TRUE if appropriate element was found and loaded + */ + extern gboolean + xkl_config_registry_find_option_group(XklConfigRegistry * + config, + XklConfigItem * item, + gboolean * + allow_multiple_selection); + +/** + * xkl_config_registry_find_option: + * @config: the config registry + * @option_group_name: name of the option group + * @item: pointer to a XklConfigItem containing the name of the + * keyboard option. On successfull return, the descriptions are filled. + * + * Loads a keyboard option information from the XML configuration + * registry. + * + * Returns: TRUE if appropriate element was found and loaded + */ + extern gboolean xkl_config_registry_find_option(XklConfigRegistry * + config, + const gchar * + option_group_name, + XklConfigItem * + item); +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/libxklavier/xkl_engine.h b/libxklavier/xkl_engine.h new file mode 100644 index 0000000..4143059 --- /dev/null +++ b/libxklavier/xkl_engine.h @@ -0,0 +1,547 @@ +#ifndef __XKL_ENGINE_H__ +#define __XKL_ENGINE_H__ + +#include <X11/Xlib.h> + +#include <glib-object.h> + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct _XklEngine XklEngine; + typedef struct _XklEnginePrivate XklEnginePrivate; + typedef struct _XklEngineClass XklEngineClass; + +#define XKL_TYPE_ENGINE (xkl_engine_get_type ()) +#define XKL_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XKL_TYPE_ENGINE, XklEngine)) +#define XKL_ENGINE_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), XKL_TYPE_ENGINE, XklEngineClass)) +#define XKL_IS_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XKL_TYPE_ENGINE)) +#define XKL_IS_ENGINE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), XKL_TYPE_ENGINE)) +#define XKL_ENGINE_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), XKL_TYPE_ENGINE, XklEngineClass)) + +/** + * The type of the keyboard state change + * GroupChanged: Group was changed + * IndicatorsChanged: Indicators were changed + */ + typedef enum { + GROUP_CHANGED, + INDICATORS_CHANGED + } XklEngineStateChange; + +/** + * A set of flags used to indicate the capabilities of the active backend + * CanToggleIndicators: Backend allows to toggls indicators on/off + * CanOutputConfigAsASCII: Backend allows writing ASCII representation of the configuration + * CanOutputConfigAsBinary: Backend allows writing binary representation of the configuration + * MultipleLayoutsSupported: Backend supports multiple layouts + * RequiresManualLayoutManagement: Backend requires manual configuration, some daemon should do + * xkl_start_listen(engine,XKLL_MANAGE_LAYOUTS); + */ + typedef enum { + XKLF_CAN_TOGGLE_INDICATORS = 0x01, + XKLF_CAN_OUTPUT_CONFIG_AS_ASCII = 0x02, + XKLF_CAN_OUTPUT_CONFIG_AS_BINARY = 0x04, + XKLF_MULTIPLE_LAYOUTS_SUPPORTED = 0x08, + XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT = 0x10, + } XklEngineFeatures; + +/** + * XKB state. Can be global or per-window + */ + typedef struct { +/** + * selected group + */ + gint32 group; +/** + * set of active indicators + */ + guint32 indicators; + } XklState; + +/** + * The main Xklavier engine class + */ + struct _XklEngine { +/** + * The superclass object + */ + GObject parent; +/** + * Private data + */ + XklEnginePrivate *priv; + }; + +/** + * The XklEngine class, derived from GObject + */ + struct _XklEngineClass { +/** + * The superclass + */ + GObjectClass parent_class; + +/** + * XklEngine::config-notify: + * @engine: the object on which the signal is emitted + * + * Used for notifying application of the XKB configuration change. + */ + void (*config_notify) (XklEngine * engine); + +/** + * XklEngine::new_window_notify: + * @engine: the object on which the signal is emitted + * @win: new window + * @parent: new window's parent + * + * Used for notifying application of new window creation (actually, + * registration). + * + * Returns: the initial group id for the window (-1 to use the default value) + */ + gint(*new_window_notify) (XklEngine * engine, Window win, + Window parent); +/** + * XklEngine::state_notify + * @engine: the object on which the signal is emitted + * @change_type: mask of changes + * @group: new group + * @restore: whether this state is restored from + * saved state of set as new. + * + * Used for notifying application of the window state change. + */ + void (*state_notify) (XklEngine * engine, + XklEngineStateChange change_type, + gint group, gboolean restore); + + }; + + +/** + * xkl_engine_get_type: + * + * Get type info for XklEngine + * + * Returns: GType for XklEngine + */ + extern GType xkl_engine_get_type(void); + + +/** + * xkl_engine_get_instance: + * @display: the X display used by the application + * + * Get the instance of the XklEngine. Within a process, there is always once instance. + * + * Returns: the singleton instance + */ + extern XklEngine *xkl_engine_get_instance(Display * display); + + +/** + * xkl_engine_get_backend_name: + * @engine: the engine + * + * What kind of backend is used + * + * Returns: some string id of the backend + */ + extern const gchar *xkl_engine_get_backend_name(XklEngine * + engine); + +/** + * xkl_engine_get_features: + * @engine: the engine + * + * Provides information regarding available backend features + * (combination of XKLF_* constants) + * + * Returns: ORed XKLF_* constants + */ + extern guint xkl_engine_get_features(XklEngine * engine); + +/** + * xkl_engine_get_max_num_groups: + * @engine: the engine + * + * Provides the information on maximum number of simultaneously supported + * groups (layouts) + * + * Returns: maximum number of the groups in configuration, + * 0 if no restrictions. + */ + extern guint xkl_engine_get_max_num_groups(XklEngine * engine); + +/** + * The listener action modes: + * ManageWindowStates: The listener process should handle the per-window states + * and all the related activity + * TrackKeyboardState: Just track the state and pass it to the application above. + * ManageLayouts: The listener process should help backend to maintain the configuration + * (manually switch layouts etc). + */ + typedef enum { + XKLL_MANAGE_WINDOW_STATES = 0x01, + XKLL_TRACK_KEYBOARD_STATE = 0x02, + XKLL_MANAGE_LAYOUTS = 0x04 + } XklEngineListenModes; + +/** + * xkl_engine_start_listen: + * @engine: the engine + * @flags: any combination of XKLL_* constants + * + * Starts listening for XKB-related events + * + * Returns: 0 + */ + extern gint xkl_engine_start_listen(XklEngine * engine, + guint flags); + +/** + * xkl_engine_stop_listen: + * @engine: the engine + * + * Stops listening for XKB-related events + * Returns: 0 + */ + extern gint xkl_engine_stop_listen(XklEngine * engine); + +/** + * xkl_engine_pause_listen: + * @engine: the engine + * + * Temporary pauses listening for XKB-related events + * + * Returns: 0 + */ + extern gint xkl_engine_pause_listen(XklEngine * engine); + +/** + * xkl_engine_resume_listen: + * @engine: the engine + * + * Resumes listening for XKB-related events + * + * Returns: 0 + */ + extern gint xkl_engine_resume_listen(XklEngine * engine); + +/** + * xkl_engine_grab_key: + * @engine: the engine + * @keycode: keycode + * @modifiers: bitmask of modifiers + * + * Grabs some key + * + * Returns: TRUE on success + */ + extern gboolean xkl_engine_grab_key(XklEngine * engine, + gint keycode, guint modifiers); + +/** + * xkl_engine_ungrab_key: + * @engine: the engine + * @keycode: keycode + * @modifiers: bitmask of modifiers + * + * Ungrabs some key + * + * Returns: TRUE on success + */ + extern gboolean xkl_engine_ungrab_key(XklEngine * engine, + gint keycode, + guint modifiers); + +/** + * xkl_engine_filter_events: + * @engine: the engine + * @evt: delivered X event + * + * Processes X events. Should be included into the main event cycle of an + * application. One of the most important functions. + * + * Returns: 0 if the event it processed - 1 otherwise + */ + extern gint xkl_engine_filter_events(XklEngine * engine, + XEvent * evt); + +/** + * xkl_engine_allow_one_switch_to_secondary_group: + * @engine: the engine + * + * Allows to switch (once) to the secondary group + * + */ + extern void + xkl_engine_allow_one_switch_to_secondary_group(XklEngine * + engine); + +/** + * xkl_engine_get_current_window: + * @engine: the engine + * + * Returns: currently focused window + */ + extern Window xkl_engine_get_current_window(XklEngine * engine); + +/** + * xkl_engine_get_current_state: + * @engine: the engine + * + * Returns: current state of the keyboard. + * Returned value is a statically allocated buffer, should not be freed. + */ + extern XklState *xkl_engine_get_current_state(XklEngine * engine); + +/** + * xkl_engine_get_window_title: + * @engine: the engine + * @win: X window + * + * Returns: the window title of some window or NULL. + * If not NULL, it should be freed with XFree + */ + extern gchar *xkl_engine_get_window_title(XklEngine * engine, + Window win); + +/** + * xkl_engine_get_state: + * @engine: the engine + * @win: window to query + * @state_out: structure to store the state + * + * Finds the state for a given window (for its "App window"). + * + * Returns: TRUE on success, otherwise FALSE + * (the error message can be obtained using xkl_GetLastError). + */ + extern gboolean xkl_engine_get_state(XklEngine * engine, + Window win, + XklState * state_out); + +/** + * xkl_engine_delete_state: + * @engine: the engine + * @win: target window + * + * Drops the state of a given window (of its "App window"). + */ + extern void xkl_engine_delete_state(XklEngine * engine, + Window win); + +/** + * xkl_engine_save_state: + * @engine: the engine + * @win: target window + * @state: new state of the window + * + * Stores ths state for a given window + */ + extern void xkl_engine_save_state(XklEngine * engine, Window win, + XklState * state); + +/** + * xkl_engine_set_window_transparent: + * @engine: the engine + * @win: window do set the flag for. + * @transparent: if true, the windows is transparent. + * + * Sets the "transparent" flag. It means focus switching onto + * this window will never change the state. + */ + extern void xkl_engine_set_window_transparent(XklEngine * engine, + Window win, + gboolean + transparent); + +/** + * xkl_engine_is_window_transparent: + * @engine: the engine + * @win: window to get the transparent flag from. + * + * Returns: TRUE if the window is "transparent" + */ + extern gboolean xkl_engine_is_window_transparent(XklEngine * + engine, + Window win); + +/** + * xkl_engine_is_window_from_same_toplevel_window: + * @engine: the engine + * @win1: first window + * @win2: second window + * + * Checks whether 2 windows have the same topmost window + * + * Returns: TRUE is windows are in the same application + */ + extern gboolean + xkl_engine_is_window_from_same_toplevel_window(XklEngine * + engine, + Window win1, + Window win2); + +/** + * xkl_engine_get_num_groups: + * @engine: the engine + * + * Returns: the total number of groups in the current configuration + * (keyboard) + */ + extern guint xkl_engine_get_num_groups(XklEngine * engine); + +/** + * xkl_engine_get_groups_names: + * @engine: the engine + * + * Returns: the array of group names for the current XKB configuration + * (keyboard). + * This array is static, should not be freed + */ + extern const gchar **xkl_engine_get_groups_names(XklEngine * + engine); + +/** + * xkl_engine_get_indicators_names: + * @engine: the engine + * + * Returns: the array of indicator names for the current XKB configuration + * (keyboard). + * This array is static, should not be freed + */ + extern const gchar **xkl_engine_get_indicators_names(XklEngine * + engine); + +/** + * xkl_engine_get_next_group: + * @engine: the engine + * + * Calculates next group id. Does not change the state of anything. + * + * Returns: next group id + */ + extern gint xkl_engine_get_next_group(XklEngine * engine); + +/** + * xkl_engine_get_prev_group: + * @engine: the engine + * + * Calculates prev group id. Does not change the state of anything. + * + * Returns: prev group id + */ + extern gint xkl_engine_get_prev_group(XklEngine * engine); + +/** + * xkl_engine_get_current_window_group: + * @engine: the engine + * + * Returns: saved group id of the current window. + */ + extern gint xkl_engine_get_current_window_group(XklEngine * + engine); + +/** + * xkl_engine_lock_group: + * @engine: the engine + * @group: group number for locking + * + * Locks the group. Can be used after xkl_GetXXXGroup functions + */ + extern void xkl_engine_lock_group(XklEngine * engine, gint group); + +/** + * xkl_engine_set_group_per_toplevel_window: + * @engine: the engine + * @is_global: new parameter value + * + * Sets the configuration parameter: group per application + */ + extern void xkl_engine_set_group_per_toplevel_window(XklEngine * + engine, + gboolean + is_global); + +/** + * xkl_engine_is_group_per_toplevel_window: + * @engine: the engine + * + * Returns: the value of the parameter: group per application + */ + extern gboolean xkl_engine_is_group_per_toplevel_window(XklEngine * + engine); + +/** + * xkl_engine_set_indicators_handling: + * @engine: the engine + * @whether_handle: new parameter value + * + * Sets the configuration parameter: perform indicators handling + */ + extern void xkl_engine_set_indicators_handling(XklEngine * engine, + gboolean + whether_handle); + +/** + * xkl_engine_get_indicators_handling: + * @engine: the engine + * + * Returns: the value of the parameter: perform indicator handling + */ + extern gboolean xkl_engine_get_indicators_handling(XklEngine * + engine); + +/** + * xkl_engine_set_secondary_groups_mask: + * @engine: the engine + * @mask: new group mask + * + * Sets the secondary groups (one bit per group). + * Secondary groups require explicit "allowance" for switching + */ + extern void xkl_engine_set_secondary_groups_mask(XklEngine * + engine, + guint mask); + +/** + * xkl_engine_get_secondary_groups_mask: + * @engine: the engine + * + * Returns: the secondary group mask + */ + extern guint xkl_engine_get_secondary_groups_mask(XklEngine * + engine); + +/** + * xkl_engine_group_set_default: + * @engine: the engine + * @group: default group + * + * Configures the default group set on window creation. + * If -1, no default group is used + */ + extern void xkl_engine_group_set_default(XklEngine * engine, + gint group); + +/** + * xkl_engine_group_get_default: + * @engine: the engine + * + * Returns the default group set on window creation + * If -1, no default group is used + * + * Returns: the default group + */ + extern gint xkl_engine_group_get_default(XklEngine * engine); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/libxklavier/xkl_engine_marshal.c b/libxklavier/xkl_engine_marshal.c new file mode 100644 index 0000000..ac10620 --- /dev/null +++ b/libxklavier/xkl_engine_marshal.c @@ -0,0 +1,131 @@ + +#include <glib-object.h> + + +#ifdef G_ENABLE_DEBUG +#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) +#define g_marshal_value_peek_char(v) g_value_get_char (v) +#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) +#define g_marshal_value_peek_int(v) g_value_get_int (v) +#define g_marshal_value_peek_uint(v) g_value_get_uint (v) +#define g_marshal_value_peek_long(v) g_value_get_long (v) +#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) +#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) +#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) +#define g_marshal_value_peek_enum(v) g_value_get_enum (v) +#define g_marshal_value_peek_flags(v) g_value_get_flags (v) +#define g_marshal_value_peek_float(v) g_value_get_float (v) +#define g_marshal_value_peek_double(v) g_value_get_double (v) +#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) +#define g_marshal_value_peek_param(v) g_value_get_param (v) +#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) +#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) +#define g_marshal_value_peek_object(v) g_value_get_object (v) +#else /* !G_ENABLE_DEBUG */ +/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. + * Do not access GValues directly in your code. Instead, use the + * g_value_get_*() functions + */ +#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int +#define g_marshal_value_peek_char(v) (v)->data[0].v_int +#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint +#define g_marshal_value_peek_int(v) (v)->data[0].v_int +#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint +#define g_marshal_value_peek_long(v) (v)->data[0].v_long +#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 +#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 +#define g_marshal_value_peek_enum(v) (v)->data[0].v_long +#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_float(v) (v)->data[0].v_float +#define g_marshal_value_peek_double(v) (v)->data[0].v_double +#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer +#endif /* !G_ENABLE_DEBUG */ + + +/* VOID:VOID (marshal.list:1) */ + +/* INT:LONG,LONG (marshal.list:2) */ +void +xkl_engine_INT__LONG_LONG (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef gint (*GMarshalFunc_INT__LONG_LONG) (gpointer data1, + glong arg_1, + glong arg_2, + gpointer data2); + register GMarshalFunc_INT__LONG_LONG callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + gint v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_INT__LONG_LONG) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_long (param_values + 1), + g_marshal_value_peek_long (param_values + 2), + data2); + + g_value_set_int (return_value, v_return); +} + +/* VOID:FLAGS,INT,BOOLEAN (marshal.list:3) */ +void +xkl_engine_VOID__FLAGS_INT_BOOLEAN (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__FLAGS_INT_BOOLEAN) (gpointer data1, + guint arg_1, + gint arg_2, + gboolean arg_3, + gpointer data2); + register GMarshalFunc_VOID__FLAGS_INT_BOOLEAN callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__FLAGS_INT_BOOLEAN) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_flags (param_values + 1), + g_marshal_value_peek_int (param_values + 2), + g_marshal_value_peek_boolean (param_values + 3), + data2); +} + diff --git a/libxklavier/xkl_engine_marshal.h b/libxklavier/xkl_engine_marshal.h new file mode 100644 index 0000000..c1e4115 --- /dev/null +++ b/libxklavier/xkl_engine_marshal.h @@ -0,0 +1,27 @@ + +#ifndef __xkl_engine_MARSHAL_H__ +#define __xkl_engine_MARSHAL_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS +/* VOID:VOID (marshal.list:1) */ +#define xkl_engine_VOID__VOID g_cclosure_marshal_VOID__VOID +/* INT:LONG,LONG (marshal.list:2) */ +extern void xkl_engine_INT__LONG_LONG(GClosure * closure, + GValue * return_value, + guint n_param_values, + const GValue * param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:FLAGS,INT,BOOLEAN (marshal.list:3) */ +extern void xkl_engine_VOID__FLAGS_INT_BOOLEAN(GClosure * closure, + GValue * return_value, + guint n_param_values, + const GValue * param_values, + gpointer invocation_hint, + gpointer marshal_data); + +G_END_DECLS +#endif /* __xkl_engine_MARSHAL_H__ */ diff --git a/libxklavier/xklavier.c b/libxklavier/xklavier.c index a820f50..d20c873 100644 --- a/libxklavier/xklavier.c +++ b/libxklavier/xklavier.c @@ -1,860 +1,880 @@ +#include <string.h> #include <time.h> #include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#include <X11/Xlibint.h> +#include <X11/Xmd.h> #include "xklavier_private.h" +#include "xkl_engine_marshal.h" -Display *_xklDpy; +static GObjectClass *parent_class = NULL; -XklState _xklCurState; +static XklEngine *the_engine = NULL; -Window _xklCurClient; +gint xkl_debug_level = 0; -Status _xklLastErrorCode; +static XklLogAppender log_appender = xkl_default_log_appender; -const char *_xklLastErrorMsg; +const gchar *xkl_last_error_message; -XErrorHandler _xklDefaultErrHandler; +enum { + PROP_0, + PROP_DISPLAY, + PROP_BACKEND_NAME, + PROP_FEATURES, + PROP_MAX_NUM_GROUPS, + PROP_NUM_GROUPS, + PROP_DEFAULT_GROUP, + PROP_SECONDARY_GROUPS_MASK, + PROP_INDICATORS_HANDLING, +}; -Atom _xklAtoms[TOTAL_ATOMS]; - -Window _xklRootWindow; - -int _xklDefaultGroup; - -Bool _xklSkipOneRestore; - -int _xklSecondaryGroupsMask; - -int _xklDebugLevel = 0; - -Window _xklPrevAppWindow; - -int _xklListenerType = 0; - -XklVTable *xklVTable = NULL; - -XklConfigCallback _xklConfigCallback = NULL; -void *_xklConfigCallbackData; - -static XklStateCallback stateCallback = NULL; -static void *stateCallbackData; - -static XklWinCallback winCallback = NULL; -static void *winCallbackData; - -static XklLogAppender logAppender = XklDefaultLogAppender; - -static Bool groupPerApp = True; - -static Bool handleIndicators = False; - - -void XklSetIndicatorsHandling( Bool whetherHandle ) +void +xkl_engine_set_indicators_handling(XklEngine * engine, + gboolean whether_handle) { - handleIndicators = whetherHandle; + xkl_engine_priv(engine, handle_indicators) = whether_handle; } -Bool XklGetIndicatorsHandling( void ) +gboolean +xkl_engine_get_indicators_handling(XklEngine * engine) { - return handleIndicators; + return xkl_engine_priv(engine, handle_indicators); } -void XklSetDebugLevel( int level ) +void +xkl_set_debug_level(int level) { - _xklDebugLevel = level; + xkl_debug_level = level; } -void XklSetGroupPerApp( Bool isSet ) +void +xkl_engine_set_group_per_toplevel_window(XklEngine * engine, + gboolean is_set) { - groupPerApp = isSet; + xkl_engine_priv(engine, group_per_toplevel_window) = is_set; } -Bool XklIsGroupPerApp( void ) +gboolean +xkl_engine_is_group_per_toplevel_window(XklEngine * engine) { - return groupPerApp; + return xkl_engine_priv(engine, group_per_toplevel_window); } -static void _XklSetSwitchToSecondaryGroup( Bool val ) +static void +xkl_engine_set_switch_to_secondary_group(XklEngine * engine, gboolean val) { - CARD32 propval = (CARD32)val; - XChangeProperty( _xklDpy, _xklRootWindow, _xklAtoms[XKLAVIER_ALLOW_SECONDARY], - XA_INTEGER, 32, PropModeReplace, - (unsigned char*)&propval, 1 ); - XSync( _xklDpy, False ); + CARD32 propval = (CARD32) val; + Display *dpy = xkl_engine_get_display(engine); + XChangeProperty(dpy, + xkl_engine_priv(engine, root_window), + xkl_engine_priv(engine, + atoms)[XKLAVIER_ALLOW_SECONDARY], + XA_INTEGER, 32, PropModeReplace, + (unsigned char *) &propval, 1); + XSync(dpy, False); } -void XklAllowOneSwitchToSecondaryGroup( void ) +void +xkl_engine_allow_one_switch_to_secondary_group(XklEngine * engine) { - XklDebug( 150, "Setting allowOneSwitchToSecondaryGroup flag\n" ); - _XklSetSwitchToSecondaryGroup( True ); + xkl_debug(150, + "Setting allow_one_switch_to_secondary_group flag\n"); + xkl_engine_set_switch_to_secondary_group(engine, TRUE); } -Bool _XklIsOneSwitchToSecondaryGroupAllowed( void ) +gboolean +xkl_engine_is_one_switch_to_secondary_group_allowed(XklEngine * engine) { - Bool rv = False; - unsigned char *propval = NULL; - Atom actualType; - int actualFormat; - unsigned long bytesRemaining; - unsigned long actualItems; - int result; + gboolean rv = FALSE; + unsigned char *propval = NULL; + Atom actual_type; + int actual_format; + unsigned long bytes_remaining; + unsigned long actual_items; + int result; - result = XGetWindowProperty( _xklDpy, _xklRootWindow, - _xklAtoms[XKLAVIER_ALLOW_SECONDARY], 0L, 1L, - False, XA_INTEGER, &actualType, &actualFormat, - &actualItems, &bytesRemaining, - &propval ); + result = + XGetWindowProperty(xkl_engine_get_display(engine), + xkl_engine_priv(engine, root_window), + xkl_engine_priv(engine, atoms) + [XKLAVIER_ALLOW_SECONDARY], 0L, 1L, False, + XA_INTEGER, &actual_type, &actual_format, + &actual_items, &bytes_remaining, &propval); - if( Success == result ) - { - if( actualFormat == 32 && actualItems == 1 ) - { - rv = *(Bool*)propval; - } - XFree( propval ); - } + if (Success == result) { + if (actual_format == 32 && actual_items == 1) { + rv = (gboolean) * (Bool *) propval; + } + XFree(propval); + } - return rv; + return rv; } -void _XklOneSwitchToSecondaryGroupPerformed( void ) +void +xkl_engine_one_switch_to_secondary_group_performed(XklEngine * engine) { - XklDebug( 150, "Resetting allowOneSwitchToSecondaryGroup flag\n" ); - _XklSetSwitchToSecondaryGroup( False ); + xkl_debug(150, + "Resetting allow_one_switch_to_secondary_group flag\n"); + xkl_engine_set_switch_to_secondary_group(engine, FALSE); } -void XklSetDefaultGroup( int group ) +void +xkl_engine_set_default_group(XklEngine * engine, gint group) { - _xklDefaultGroup = group; + xkl_engine_priv(engine, default_group) = group; } -int XklGetDefaultGroup( void ) +gint +xkl_engine_get_default_group(XklEngine * engine) { - return _xklDefaultGroup; + return xkl_engine_priv(engine, default_group); } -void XklSetSecondaryGroupsMask( int mask ) +void +xkl_engine_set_secondary_groups_mask(XklEngine * engine, guint mask) { - _xklSecondaryGroupsMask = mask; + xkl_engine_priv(engine, secondary_groups_mask) = mask; } -int XklGetSecondaryGroupsMask( void ) +guint +xkl_engine_get_secondary_groups_mask(XklEngine * engine) { - return _xklSecondaryGroupsMask; + return xkl_engine_priv(engine, secondary_groups_mask); } -int XklRegisterConfigCallback( XklConfigCallback fun, void *data ) +void +xkl_set_log_appender(XklLogAppender func) { - _xklConfigCallback = fun; - _xklConfigCallbackData = data; - return 0; + log_appender = func; } -int XklRegisterStateCallback( XklStateCallback fun, void *data ) +gint +xkl_engine_start_listen(XklEngine * engine, guint what) { - stateCallback = fun; - stateCallbackData = data; - return 0; -} + xkl_engine_priv(engine, listener_type) = what; -int XklRegisterWindowCallback( XklWinCallback fun, void *data ) -{ - winCallback = fun; - winCallbackData = data; - return 0; -} - -void XklSetLogAppender( XklLogAppender fun ) -{ - logAppender = fun; -} + if (! + (xkl_engine_priv(engine, features) & + XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT) +&& (what & XKLL_MANAGE_LAYOUTS)) + xkl_debug(0, + "The backend does not require manual layout management - " + "but it is provided by the application"); -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 ); - return 0; + xkl_engine_resume_listen(engine); + xkl_engine_load_window_tree(engine); + XFlush(xkl_engine_get_display(engine)); + return 0; } -int XklStopListen( void ) +gint +xkl_engine_stop_listen(XklEngine * engine) { - XklPauseListen( ); - return 0; + xkl_engine_pause_listen(engine); + return 0; } -int XklInit( Display * a_dpy ) +XklEngine * +xkl_engine_get_instance(Display * display) { - int scr; - char *sdl; - int rv; - - sdl = getenv( "XKL_DEBUG" ); - if( sdl != NULL ) - { - XklSetDebugLevel( atoi( sdl ) ); - } - - if( !a_dpy ) - { - XklDebug( 10, "XklInit : display is NULL ?\n"); - return -1; - } - - _xklDefaultErrHandler = - XSetErrorHandler( ( XErrorHandler ) _XklErrHandler ); - - _xklDpy = a_dpy; - scr = DefaultScreen( _xklDpy ); - _xklRootWindow = RootWindow( _xklDpy, scr ); - - _xklSkipOneRestore = False; - _xklDefaultGroup = -1; - _xklSecondaryGroupsMask = 0L; - _xklPrevAppWindow = 0; - - _xklAtoms[WM_NAME] = XInternAtom( _xklDpy, "WM_NAME", False ); - _xklAtoms[WM_STATE] = XInternAtom( _xklDpy, "WM_STATE", False ); - _xklAtoms[XKLAVIER_STATE] = XInternAtom( _xklDpy, "XKLAVIER_STATE", False ); - _xklAtoms[XKLAVIER_TRANSPARENT] = - XInternAtom( _xklDpy, "XKLAVIER_TRANSPARENT", False ); - _xklAtoms[XKLAVIER_ALLOW_SECONDARY] = - XInternAtom( _xklDpy, "XKLAVIER_ALLOW_SECONDARY", False ); + if (the_engine != NULL) { + g_object_ref(G_OBJECT(the_engine)); + return the_engine; + } - _XklOneSwitchToSecondaryGroupPerformed(); + if (!display) { + xkl_debug(10, "xkl_init : display is NULL ?\n"); + return NULL; + } - rv = -1; - XklDebug( 150, "Trying all backends:\n" ); -#ifdef ENABLE_XKB_SUPPORT - XklDebug( 150, "Trying XKB backend\n" ); - rv = _XklXkbInit(); -#endif -#ifdef ENABLE_XMM_SUPPORT - if( rv != 0 ) - { - XklDebug( 150, "Trying XMM backend\n" ); - rv = _XklXmmInit(); - } -#endif - if( rv == 0 ) - { - XklDebug( 150, "Actual backend: %s\n", - XklGetBackendName() ); - } - else - { - XklDebug( 0, "All backends failed, last result: %d\n", rv ); - _xklDpy = NULL; - } + the_engine = + XKL_ENGINE(g_object_new + (xkl_engine_get_type(), "display", display, NULL)); - return ( rv == 0 ) ? - ( _XklLoadAllInfo() ? 0 : _xklLastErrorCode ) : -1; + return the_engine; } -int XklTerm( void ) +gboolean +xkl_engine_grab_key(XklEngine * engine, gint keycode, guint modifiers) { - XSetErrorHandler( ( XErrorHandler ) _xklDefaultErrHandler ); - _xklConfigCallback = NULL; - stateCallback = NULL; - winCallback = NULL; + gboolean ret_code; + gchar *keyname; + Display *dpy = xkl_engine_get_display(engine); - logAppender = XklDefaultLogAppender; - _XklFreeAllInfo( ); - - return 0; -} - -Bool XklGrabKey( int keycode, unsigned modifiers ) -{ - Bool retCode; - char *keyName; + if (xkl_debug_level >= 100) { + keyname = + XKeysymToString(XKeycodeToKeysym(dpy, keycode, 0)); + xkl_debug(100, "Listen to the key %d/(%s)/%d\n", 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 (0 == keycode) + return FALSE; - if( ( KeyCode ) NULL == keycode ) - return False; + xkl_engine_priv(engine, last_error_code) = Success; - _xklLastErrorCode = Success; + ret_code = + XGrabKey(dpy, keycode, modifiers, + xkl_engine_priv(engine, root_window), TRUE, + GrabModeAsync, GrabModeAsync); + XSync(dpy, False); - retCode = XGrabKey( _xklDpy, keycode, modifiers, _xklRootWindow, - True, GrabModeAsync, GrabModeAsync ); - XSync( _xklDpy, False ); + xkl_debug(100, "XGrabKey recode %d/error %d\n", + ret_code, xkl_engine_priv(engine, last_error_code)); - XklDebug( 100, "XGrabKey recode %d/error %d\n", retCode, _xklLastErrorCode ); + ret_code = (xkl_engine_priv(engine, last_error_code) == Success); - retCode = ( _xklLastErrorCode == Success ); + if (!ret_code) + xkl_last_error_message = "Could not grab the key"; - if( !retCode ) - _xklLastErrorMsg = "Could not grab the key"; - - return retCode; + return ret_code; } -Bool XklUngrabKey( int keycode, unsigned modifiers ) +gboolean +xkl_engine_ungrab_key(XklEngine * engine, gint keycode, guint modifiers) { - if( ( KeyCode ) NULL == keycode ) - return False; + if (0 == keycode) + return FALSE; - return Success == XUngrabKey( _xklDpy, keycode, 0, _xklRootWindow ); + return Success == XUngrabKey(xkl_engine_get_display(engine), + keycode, 0, + xkl_engine_priv(engine, root_window)); } -int XklGetNextGroup( void ) +gint +xkl_engine_get_next_group(XklEngine * engine) { - return ( _xklCurState.group + 1 ) % XklGetNumGroups( ); + gint n = xkl_engine_get_num_groups(engine); + return (xkl_engine_priv(engine, curr_state).group + 1) % n; } - -int XklGetPrevGroup( void ) + +gint +xkl_engine_get_prev_group(XklEngine * engine) { - int n = XklGetNumGroups( ); - return ( _xklCurState.group + n - 1 ) % n; + gint n = xkl_engine_get_num_groups(engine); + return (xkl_engine_priv(engine, curr_state).group + n - 1) % n; } -int XklGetRestoreGroup( void ) +gint +xkl_engine_get_current_window_group(XklEngine * engine) { - XklState state; - if( _xklCurClient == ( Window ) NULL ) - { - XklDebug( 150, "cannot restore without current client\n" ); - } else if( XklGetState( _xklCurClient, &state ) ) - { - return state.group; - } else - XklDebug( 150, - "Unbelievable: current client " WINID_FORMAT - ", '%s' has no group\n", _xklCurClient, - _XklGetDebugWindowTitle( _xklCurClient ) ); - return 0; + XklState state; + if (xkl_engine_priv(engine, curr_toplvl_win) == (Window) NULL) { + xkl_debug(150, "cannot restore without current client\n"); + } else + if (xkl_engine_get_toplevel_window_state + (engine, xkl_engine_priv(engine, curr_toplvl_win), + &state)) { + return state.group; + } else + xkl_debug(150, + "Unbelievable: current client " WINID_FORMAT + ", '%s' has no group\n", + xkl_engine_priv(engine, curr_toplvl_win), + xkl_get_debug_window_title(engine, + xkl_engine_priv + (engine, + curr_toplvl_win))); + return 0; } -void XklSetTransparent( Window win, Bool transparent ) +void +xkl_engine_set_transparent(XklEngine * engine, Window win, + gboolean transparent) { - Window appWin; - Bool wasTransparent; - XklDebug( 150, "setting transparent flag %d for " WINID_FORMAT "\n", - transparent, win ); + Window toplevel_win; + xkl_debug(150, + "setting transparent flag %d for " WINID_FORMAT "\n", + transparent, win); - if( !_XklGetAppWindow( win, &appWin ) ) - { - XklDebug( 150, "No app window!\n" ); - /* appWin = win; */ - return; - } + if (!xkl_engine_find_toplevel_window(engine, win, &toplevel_win)) { + xkl_debug(150, "No toplevel window!\n"); + /* toplevel_win = win; */ + return; + } - wasTransparent = XklIsTransparent( appWin ); - XklDebug( 150, "appwin " WINID_FORMAT " was %stransparent\n", appWin, - wasTransparent ? "" : "not " ); - if( transparent && !wasTransparent ) - { - CARD32 prop = 1; - XChangeProperty( _xklDpy, appWin, _xklAtoms[XKLAVIER_TRANSPARENT], - XA_INTEGER, 32, PropModeReplace, - ( const unsigned char * ) &prop, 1 ); - } else if( !transparent && wasTransparent ) - { - XDeleteProperty( _xklDpy, appWin, _xklAtoms[XKLAVIER_TRANSPARENT] ); - } + xkl_engine_set_toplevel_window_transparent(engine, toplevel_win, + transparent); } -Bool XklIsTransparent( Window win ) +gboolean +xkl_engine_is_window_transparent(XklEngine * engine, Window win) { - Window appWin; - - if( !_XklGetAppWindow( win, &appWin ) ) - return False; - return _XklIsTransparentAppWindow( appWin ); + Window toplevel_win; + if (!xkl_engine_find_toplevel_window(engine, win, &toplevel_win)) + return FALSE; + return xkl_engine_is_toplevel_window_transparent(engine, + toplevel_win); } /** - * "Adds" app window to the set of managed windows. - * Actually, no data structures involved. The only thing we do is save app state - * and register ourselves us listeners. - * Note: User's callback is called + * Loads the tree recursively. */ -void _XklAddAppWindow( Window appWin, Window parent, Bool ignoreExistingState, - XklState * initState ) -{ - XklState state = *initState; - int defGroupToUse = -1; - - if( appWin == _xklRootWindow ) - XklDebug( 150, "??? root app win ???\n" ); - - XklDebug( 150, "Trying to add window " WINID_FORMAT "/%s with group %d\n", - appWin, _XklGetDebugWindowTitle( appWin ), initState->group ); - - if( !ignoreExistingState ) - { - Bool have_state = _XklGetAppState( appWin, &state ); - - if( have_state ) - { - XklDebug( 150, - "The window " WINID_FORMAT - " does not require to be added, it already has the xklavier state \n", - appWin ); - return; - } - } - - if( winCallback != NULL ) - defGroupToUse = ( *winCallback ) ( appWin, parent, winCallbackData ); - - if( defGroupToUse == -1 ) - defGroupToUse = _xklDefaultGroup; - - if( defGroupToUse != -1 ) - state.group = defGroupToUse; - - _XklSaveAppState( appWin, &state ); - _XklSelectInputMerging( appWin, FocusChangeMask | PropertyChangeMask ); - - if( defGroupToUse != -1 ) - { - if( _xklCurClient == appWin ) - { - if( ( _xklSecondaryGroupsMask & ( 1 << defGroupToUse ) ) != 0 ) - XklAllowOneSwitchToSecondaryGroup(); - XklLockGroup( defGroupToUse ); - } - } - - if( parent == ( Window ) NULL ) - parent = _XklGetRegisteredParent( appWin ); - - XklDebug( 150, "done\n" ); +gboolean +xkl_engine_load_window_tree(XklEngine * engine) +{ + Window focused; + int revert; + gboolean retval = TRUE, have_toplevel_win; + + if (xkl_engine_priv(engine, listener_type) & + XKLL_MANAGE_WINDOW_STATES) + retval = + xkl_engine_load_subtree(engine, + xkl_engine_priv(engine, + root_window), + 0, &xkl_engine_priv(engine, + curr_state)); + + XGetInputFocus(xkl_engine_get_display(engine), &focused, &revert); + + xkl_debug(160, "initially focused: " WINID_FORMAT ", '%s'\n", + focused, xkl_get_debug_window_title(engine, focused)); + + have_toplevel_win = + xkl_engine_find_toplevel_window(engine, focused, + &xkl_engine_priv(engine, + curr_toplvl_win)); + + if (have_toplevel_win) { + gboolean have_state = + xkl_engine_get_toplevel_window_state(engine, + xkl_engine_priv + (engine, + curr_toplvl_win), + &xkl_engine_priv + (engine, + curr_state)); + xkl_debug(160, + "initial toplevel: " WINID_FORMAT + ", '%s' %s state %d/%X\n", + xkl_engine_priv(engine, curr_toplvl_win), + xkl_get_debug_window_title(engine, + xkl_engine_priv + (engine, + curr_toplvl_win)), + (have_state ? "with" : "without"), + (have_state ? + xkl_engine_priv(engine, curr_state).group : -1), + (have_state ? + xkl_engine_priv(engine, + curr_state).indicators : -1)); + } else { + xkl_debug(160, + "Could not find initial app. " + "Probably, focus belongs to some WM service window. " + "Will try to survive:)"); + } + + return retval; +} + +void +_xkl_debug(const gchar file[], const gchar function[], gint level, + const gchar format[], ...) +{ + va_list lst; + + if (level > xkl_debug_level) + return; + + va_start(lst, format); + if (log_appender != NULL) + (*log_appender) (file, function, level, format, lst); + va_end(lst); +} + +void +xkl_default_log_appender(const gchar file[], const gchar function[], + gint level, const gchar format[], va_list args) +{ + time_t now = time(NULL); + fprintf(stdout, "[%08ld,%03d,%s:%s/] \t", now, level, file, + function); + vfprintf(stdout, format, args); } /** - * Checks the window and goes up + * Just selects some events from the window. */ -Bool _XklGetAppWindowBottomToTop( Window win, Window * appWin_return ) +void +xkl_engine_select_input(XklEngine * engine, Window win, gulong mask) { - Window parent = ( Window ) NULL, rwin = ( Window ) NULL, *children = NULL; - unsigned int num = 0; - - if( win == ( Window ) NULL || win == _xklRootWindow ) - { - *appWin_return = win; - _xklLastErrorMsg = "The window is either 0 or root"; - return False; - } - - if( _XklHasWmState( win ) ) - { - *appWin_return = win; - return True; - } - - _xklLastErrorCode = - _XklStatusQueryTree( _xklDpy, win, &rwin, &parent, &children, &num ); - - if( _xklLastErrorCode != Success ) - { - *appWin_return = ( Window ) NULL; - return False; - } + if (xkl_engine_priv(engine, root_window) == win) + xkl_debug(160, + "Someone is looking for %lx on root window ***\n", + mask); - if( children != NULL ) - XFree( children ); - - return _XklGetAppWindowBottomToTop( parent, appWin_return ); -} - -/** - * Recursively finds "App window" (window with WM_STATE) for given window. - * First, checks the window itself - * Then, for first level of recursion, checks childen, - * Then, goes to parent. - * NOTE: root window cannot be "App window" under normal circumstances - */ -Bool _XklGetAppWindow( Window win, Window * appWin_return ) -{ - Window parent = ( Window ) NULL, - rwin = ( Window ) NULL, *children = NULL, *child; - unsigned int num = 0; - Bool rv; - - if( win == ( Window ) NULL || win == _xklRootWindow ) - { - *appWin_return = ( Window ) NULL; - _xklLastErrorMsg = "The window is either 0 or root"; - XklDebug( 150, - "Window " WINID_FORMAT - " is either 0 or root so could not get the app window for it\n", - win ); - return False; - } - - if( _XklHasWmState( win ) ) - { - *appWin_return = win; - return True; - } - - _xklLastErrorCode = - _XklStatusQueryTree( _xklDpy, win, &rwin, &parent, &children, &num ); - - if( _xklLastErrorCode != Success ) - { - *appWin_return = ( Window ) NULL; - XklDebug( 150, - "Could not get tree for window " WINID_FORMAT - " so could not get the app window for it\n", win ); - return False; - } - - /** - * Here we first check the children (in case win is just above some "App Window") - * and then go upstairs - */ - child = children; - while( num ) - { - if( _XklHasWmState( *child ) ) - { - *appWin_return = *child; - if( children != NULL ) - XFree( children ); - return True; - } - child++; - num--; - } - - if( children != NULL ) - XFree( children ); - - rv = _XklGetAppWindowBottomToTop( parent, appWin_return ); - - if( !rv ) - XklDebug( 200, "Could not get the app window for " WINID_FORMAT "/%s\n", - win, _XklGetDebugWindowTitle( win ) ); - - return rv; + XSelectInput(xkl_engine_get_display(engine), win, mask); } -/** - * Loads the tree recursively. - */ -Bool _XklLoadWindowTree( void ) +void +xkl_engine_select_input_merging(XklEngine * engine, Window win, + gulong mask) { - Window focused; - int revert; - Bool retval = True, haveAppWindow; + XWindowAttributes attrs; + gulong oldmask = 0L, newmask; + memset(&attrs, 0, sizeof(attrs)); + if (XGetWindowAttributes + (xkl_engine_get_display(engine), win, &attrs)) + oldmask = attrs.your_event_mask; - if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) - retval = _XklLoadSubtree( _xklRootWindow, 0, &_xklCurState ); + newmask = oldmask | mask; + if (newmask != oldmask) + xkl_engine_select_input(engine, win, newmask); +} - XGetInputFocus( _xklDpy, &focused, &revert ); +void +xkl_engine_try_call_state_func(XklEngine * engine, + XklEngineStateChange change_type, + XklState * old_state) +{ + gint group = xkl_engine_priv(engine, curr_state).group; + gboolean restore = old_state->group == group; - XklDebug( 160, "initially focused: " WINID_FORMAT ", '%s'\n", - focused, _XklGetDebugWindowTitle( focused ) ); + xkl_debug(150, + "change_type: %d, group: %d, secondary_group_mask: %X, allowsecondary: %d\n", + change_type, group, xkl_engine_priv(engine, + secondary_groups_mask), + xkl_engine_is_one_switch_to_secondary_group_allowed + (engine)); - haveAppWindow = _XklGetAppWindow( focused, &_xklCurClient ); + if (change_type == GROUP_CHANGED) { + if (!restore) { + if ((xkl_engine_priv(engine, secondary_groups_mask) + & (1 << group)) != 0 + && + !xkl_engine_is_one_switch_to_secondary_group_allowed + (engine)) { + xkl_debug(150, "secondary -> go next\n"); + group = xkl_engine_get_next_group(engine); + xkl_engine_lock_group(engine, group); + return; /* we do not need to revalidate */ + } + } + xkl_engine_one_switch_to_secondary_group_performed(engine); + } - if( haveAppWindow ) - { - Bool haveState = _XklGetAppState( _xklCurClient, &_xklCurState ); - XklDebug( 160, - "initial _xklCurClient: " WINID_FORMAT - ", '%s' %s state %d/%X\n", _xklCurClient, - _XklGetDebugWindowTitle( _xklCurClient ), - ( haveState ? "with" : "without" ), - ( haveState ? _xklCurState.group : -1 ), - ( haveState ? _xklCurState.indicators : -1 ) ); - } else - { - XklDebug( 160, - "could not find initial app. Probably, focus belongs to some WM service window. Will try to survive:)" ); - } + g_signal_emit_by_name(engine, "X-state-changed", change_type, + xkl_engine_priv(engine, curr_state).group, + restore); - return retval; } -void _XklDebug( const char file[], const char function[], int level, - const char format[], ... ) +void +xkl_engine_ensure_vtable_inited(XklEngine * engine) { - va_list lst; - - if( level > _xklDebugLevel ) - return; - - va_start( lst, format ); - if( logAppender != NULL ) - ( *logAppender ) ( file, function, level, format, lst ); - va_end( lst ); + char *p; + if (xkl_engine_priv(engine, backend_id) == NULL) { + xkl_debug(0, "ERROR: XKL VTable is NOT initialized.\n"); + /* force the crash! */ + p = NULL; + *p = '\0'; + } } -void XklDefaultLogAppender( const char file[], const char function[], - int level, const char format[], va_list args ) +const gchar * +xkl_engine_get_backend_name(XklEngine * engine) { - time_t now = time( NULL ); - fprintf( stdout, "[%08ld,%03d,%s:%s/] \t", now, level, file, function ); - vfprintf( stdout, format, args ); + return xkl_engine_priv(engine, backend_id); } -/** - * Gets the state from the window property - */ -Bool _XklGetAppState( Window appWin, XklState * state_return ) -{ - Atom type_ret; - int format_ret; - unsigned long nitems, rest; - CARD32 *prop = NULL; - Bool ret = False; - - int grp = -1; - unsigned inds = 0; - - if( ( XGetWindowProperty - ( _xklDpy, appWin, _xklAtoms[XKLAVIER_STATE], 0L, - XKLAVIER_STATE_PROP_LENGTH, False, - XA_INTEGER, &type_ret, &format_ret, &nitems, &rest, - ( unsigned char ** ) ( void * ) &prop ) == Success ) - && ( type_ret == XA_INTEGER ) && ( format_ret == 32 ) ) - { - grp = prop[0]; - if( grp >= XklGetNumGroups( ) || grp < 0 ) - grp = 0; - - inds = prop[1]; - - if( state_return != NULL ) - { - state_return->group = grp; - state_return->indicators = inds; - } - if( prop != NULL ) - XFree( prop ); - - ret = True; - } - - if( ret ) - XklDebug( 150, - "Appwin " WINID_FORMAT - ", '%s' has the group %d, indicators %X\n", appWin, - _XklGetDebugWindowTitle( appWin ), grp, inds ); - else - XklDebug( 150, "Appwin " WINID_FORMAT ", '%s' does not have state\n", - appWin, _XklGetDebugWindowTitle( appWin ) ); - - return ret; -} - -/** - * Deletes the state from the window properties - */ -void _XklDelAppState( Window appWin ) +guint +xkl_engine_get_features(XklEngine * engine) { - XDeleteProperty( _xklDpy, appWin, _xklAtoms[XKLAVIER_STATE] ); + return xkl_engine_priv(engine, features); } -/** - * Saves the state into the window properties - */ -void _XklSaveAppState( Window appWin, XklState * state ) +void +xkl_engine_reset_all_info(XklEngine * engine, const gchar reason[]) { - CARD32 prop[XKLAVIER_STATE_PROP_LENGTH]; - - prop[0] = state->group; - prop[1] = state->indicators; - - XChangeProperty( _xklDpy, appWin, _xklAtoms[XKLAVIER_STATE], XA_INTEGER, - 32, PropModeReplace, ( const unsigned char * ) prop, - XKLAVIER_STATE_PROP_LENGTH ); - - XklDebug( 160, - "Saved the group %d, indicators %X for appwin " WINID_FORMAT "\n", - state->group, state->indicators, appWin ); + xkl_debug(150, "Resetting all the cached info, reason: [%s]\n", + reason); + xkl_engine_ensure_vtable_inited(engine); + if (!xkl_engine_vcall(engine, if_cached_info_equals_actual) + (engine)) { + xkl_engine_vcall(engine, free_all_info) (engine); + xkl_engine_vcall(engine, load_all_info) (engine); + } else + xkl_debug(100, + "NOT Resetting the cache: same configuration\n"); } /** - * Just selects some events from the window. + * Calling through vtable */ -void _XklSelectInput( Window win, long mask ) +const gchar ** +xkl_engine_groups_get_names(XklEngine * engine) { - if( _xklRootWindow == win ) - XklDebug( 160, - "Someone is looking for %lx on root window ***\n", - mask ); - - XSelectInput( _xklDpy, win, mask ); + xkl_engine_ensure_vtable_inited(engine); + return xkl_engine_vcall(engine, get_groups_names) (engine); } -void _XklSelectInputMerging( Window win, long mask ) +guint +xkl_engine_get_num_groups(XklEngine * engine) { - XWindowAttributes attrs; - long oldmask = 0L, newmask; - memset( &attrs, 0, sizeof( attrs ) ); - if( XGetWindowAttributes( _xklDpy, win, &attrs ) ) - oldmask = attrs.your_event_mask; - - newmask = oldmask | mask; - if( newmask != oldmask ) - _XklSelectInput( win, newmask ); + xkl_engine_ensure_vtable_inited(engine); + return xkl_engine_vcall(engine, get_num_groups) (engine); } -void _XklTryCallStateCallback( XklStateChange changeType, - XklState * oldState ) +void +xkl_engine_lock_group(XklEngine * engine, int group) { - int group = _xklCurState.group; - Bool restore = oldState->group == group; - - XklDebug( 150, - "changeType: %d, group: %d, secondaryGroupMask: %X, allowsecondary: %d\n", - changeType, group, _xklSecondaryGroupsMask, - _XklIsOneSwitchToSecondaryGroupAllowed() ); - - if( changeType == GROUP_CHANGED ) - { - if( !restore ) - { - if( ( _xklSecondaryGroupsMask & ( 1 << group ) ) != 0 && - !_XklIsOneSwitchToSecondaryGroupAllowed() ) - { - XklDebug( 150, "secondary -> go next\n" ); - group = XklGetNextGroup( ); - XklLockGroup( group ); - return; /* we do not need to revalidate */ - } - } - _XklOneSwitchToSecondaryGroupPerformed(); - } - if( stateCallback != NULL ) - { - - ( *stateCallback ) ( changeType, _xklCurState.group, - restore, stateCallbackData ); - } + xkl_engine_ensure_vtable_inited(engine); + xkl_engine_vcall(engine, lock_group) (engine, group); } -Bool _XklIsTransparentAppWindow( Window appWin ) +gint +xkl_engine_pause_listen(XklEngine * engine) { - Atom type_ret; - int format_ret; - unsigned long nitems, rest; - CARD32 *prop = NULL; - if( ( XGetWindowProperty - ( _xklDpy, appWin, _xklAtoms[XKLAVIER_TRANSPARENT], 0L, 1, False, - XA_INTEGER, &type_ret, &format_ret, &nitems, &rest, - ( unsigned char ** ) ( void * ) &prop ) == Success ) - && ( type_ret == XA_INTEGER ) && ( format_ret == 32 ) ) - { - if( prop != NULL ) - XFree( prop ); - return True; - } - return False; + xkl_engine_ensure_vtable_inited(engine); + return xkl_engine_vcall(engine, pause_listen) (engine); } -void _XklEnsureVTableInited( void ) +gint +xkl_engine_resume_listen(XklEngine * engine) { - char *p; - if ( xklVTable == NULL ) - { - XklDebug( 0, "ERROR: XKL VTable is NOT initialized.\n" ); - /* force the crash! */ - p = NULL; *p = '\0'; - } -} + xkl_engine_ensure_vtable_inited(engine); + xkl_debug(150, "listenerType: %x\n", + xkl_engine_priv(engine, listener_type)); + if (xkl_engine_vcall(engine, resume_listen) (engine)) + return 1; -const char *XklGetBackendName( void ) -{ - return xklVTable->id; -} + xkl_engine_select_input_merging(engine, + xkl_engine_priv(engine, + root_window), + SubstructureNotifyMask | + PropertyChangeMask); -int XklGetBackendFeatures( void ) -{ - return xklVTable->features; + xkl_engine_vcall(engine, + get_server_state) (engine, + &xkl_engine_priv(engine, + curr_state)); + return 0; } -void _XklResetAllInfo( const char reason[] ) +guint +xkl_engine_get_max_num_groups(XklEngine * engine) { - XklDebug( 150, "Resetting all the cached info, reason: [%s]\n", reason ); - _XklEnsureVTableInited(); - if( !(*xklVTable->xklIfCachedInfoEqualsActualHandler)() ) - { - (*xklVTable->xklFreeAllInfoHandler)(); - (*xklVTable->xklLoadAllInfoHandler)(); - } else - XklDebug( 100, "NOT Resetting the cache: same configuration\n" ); + xkl_engine_ensure_vtable_inited(engine); + return xkl_engine_vcall(engine, get_max_num_groups) (engine); } -/** - * Calling through vtable - */ -const char **XklGetGroupNames( void ) +XklEngine * +xkl_get_the_engine() { - _XklEnsureVTableInited(); - return (*xklVTable->xklGetGroupNamesHandler)(); + return the_engine; } -unsigned XklGetNumGroups( void ) -{ - _XklEnsureVTableInited(); - return (*xklVTable->xklGetNumGroupsHandler)(); -} +G_DEFINE_TYPE(XklEngine, xkl_engine, G_TYPE_OBJECT) -void XklLockGroup( int group ) +static GObject * +xkl_engine_constructor(GType type, + guint n_construct_properties, + GObjectConstructParam * construct_properties) { - _XklEnsureVTableInited(); - (*xklVTable->xklLockGroupHandler)( group ); -} + GObject *obj; -int XklPauseListen( void ) -{ - _XklEnsureVTableInited(); - return (*xklVTable->xklPauseListenHandler)(); -} + { + /* Invoke parent constructor. */ + XklEngineClass *klass; + klass = + XKL_ENGINE_CLASS(g_type_class_peek(XKL_TYPE_ENGINE)); + obj = + parent_class->constructor(type, n_construct_properties, + construct_properties); + } -int XklResumeListen( void ) -{ - _XklEnsureVTableInited(); - XklDebug( 150, "listenerType: %x\n", _xklListenerType ); - if( (*xklVTable->xklResumeListenHandler)() ) - return 1; - - _XklSelectInputMerging( _xklRootWindow, - SubstructureNotifyMask | PropertyChangeMask ); - _XklEnsureVTableInited(); - (*xklVTable->xklGetRealStateHandler)( &_xklCurState ); - return 0; -} + XklEngine *engine = XKL_ENGINE(obj); -Bool _XklLoadAllInfo( void ) -{ - _XklEnsureVTableInited(); - return (*xklVTable->xklLoadAllInfoHandler)(); -} + Display *display = + (Display *) g_value_peek_pointer(construct_properties[0]. + value); -void _XklFreeAllInfo( void ) -{ - _XklEnsureVTableInited(); - (*xklVTable->xklFreeAllInfoHandler)(); -} + xkl_engine_priv(engine, display) = display; -unsigned XklGetMaxNumGroups( void ) -{ - _XklEnsureVTableInited(); - return (*xklVTable->xklGetMaxNumGroupsHandler)(); -} + int scr; + + xkl_engine_priv(engine, default_error_handler) = + XSetErrorHandler((XErrorHandler) xkl_process_error); + + scr = DefaultScreen(display); + xkl_engine_priv(engine, root_window) = RootWindow(display, scr); + + xkl_engine_priv(engine, skip_one_restore) = FALSE; + xkl_engine_priv(engine, default_group) = -1; + xkl_engine_priv(engine, secondary_groups_mask) = 0L; + xkl_engine_priv(engine, prev_toplvl_win) = 0; + xkl_engine_priv(engine, atoms)[WM_NAME] = + XInternAtom(display, "WM_NAME", False); + xkl_engine_priv(engine, atoms)[WM_STATE] = + XInternAtom(display, "WM_STATE", False); + xkl_engine_priv(engine, atoms)[XKLAVIER_STATE] = + XInternAtom(display, "XKLAVIER_STATE", False); + xkl_engine_priv(engine, atoms)[XKLAVIER_TRANSPARENT] = + XInternAtom(display, "XKLAVIER_TRANSPARENT", False); + xkl_engine_priv(engine, atoms)[XKLAVIER_ALLOW_SECONDARY] = + XInternAtom(display, "XKLAVIER_ALLOW_SECONDARY", False); + + xkl_engine_one_switch_to_secondary_group_performed(engine); + + gint rv = -1; + xkl_debug(150, "Trying all backends:\n"); +#ifdef ENABLE_XKB_SUPPORT + xkl_debug(150, "Trying XKB backend\n"); + rv = xkl_xkb_init(engine); +#endif +#ifdef ENABLE_XMM_SUPPORT + if (rv != 0) { + xkl_debug(150, "Trying XMM backend\n"); + rv = xkl_xmm_init(engine); + } +#endif + if (rv == 0) { + xkl_debug(150, "Actual backend: %s\n", + xkl_engine_get_backend_name(engine)); + } else { + xkl_debug(0, "All backends failed, last result: %d\n", rv); + xkl_engine_priv(engine, display) = NULL; + g_object_unref(G_OBJECT(engine)); + return NULL; + } + + xkl_engine_ensure_vtable_inited(engine); + if (!xkl_engine_vcall(engine, load_all_info) (engine)) { + g_object_unref(G_OBJECT(engine)); + return NULL; + } + + return obj; +} + +static void +xkl_engine_init(XklEngine * engine) +{ + engine->priv = g_new0(XklEnginePrivate, 1); +} + +static void +xkl_engine_set_property(GObject * object, + guint property_id, + const GValue * value, GParamSpec * pspec) +{ +} + +static void +xkl_engine_get_property(GObject * object, + guint property_id, + GValue * value, GParamSpec * pspec) +{ + XklEngine *engine = XKL_ENGINE(object); + + switch (property_id) { + case PROP_DISPLAY: + g_value_set_pointer(value, xkl_engine_get_display(engine)); + break; + case PROP_BACKEND_NAME: + g_value_set_string(value, + xkl_engine_priv(engine, backend_id)); + break; + case PROP_FEATURES: + g_value_set_flags(value, + xkl_engine_priv(engine, features)); + break; + case PROP_MAX_NUM_GROUPS: + g_value_set_uint(value, + xkl_engine_vcall(engine, + get_max_num_groups) + (engine)); + break; + case PROP_NUM_GROUPS: + g_value_set_uint(value, + xkl_engine_vcall(engine, get_num_groups) + (engine)); + break; + case PROP_DEFAULT_GROUP: + g_value_set_uint(value, + xkl_engine_priv(engine, default_group)); + break; + case PROP_SECONDARY_GROUPS_MASK: + g_value_set_uint(value, + xkl_engine_priv(engine, + secondary_groups_mask)); + break; + case PROP_INDICATORS_HANDLING: + g_value_set_boolean(value, + xkl_engine_priv(engine, + handle_indicators)); + break; + } +} + +static void +xkl_engine_finalize(GObject * obj) +{ + XklEngine *engine = (XklEngine *) obj; + + XSetErrorHandler((XErrorHandler) + xkl_engine_priv(engine, default_error_handler)); + + xkl_engine_ensure_vtable_inited(engine); + xkl_engine_vcall(engine, free_all_info) (engine); + + xkl_engine_vcall(engine, finalize) (engine); + + gpointer backend = xkl_engine_priv(engine, backend); + if (backend != NULL) + g_free(backend); + g_free(engine->priv); + + G_OBJECT_CLASS(parent_class)->finalize(obj); +} + +static void +xkl_engine_class_init(XklEngineClass * klass) +{ + static GFlagsValue feature_flags[] = { + {XKLF_CAN_TOGGLE_INDICATORS, "XKLF_CAN_TOGGLE_INDICATORS", + NULL}, + {XKLF_CAN_OUTPUT_CONFIG_AS_ASCII, + "XKLF_CAN_OUTPUT_CONFIG_AS_ASCII", NULL}, + {XKLF_CAN_OUTPUT_CONFIG_AS_BINARY, + "XKLF_CAN_OUTPUT_CONFIG_AS_BINARY", NULL}, + {XKLF_MULTIPLE_LAYOUTS_SUPPORTED, + "XKLF_MULTIPLE_LAYOUTS_SUPPORTED", NULL}, + {XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT, + "XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT", NULL}, + {0, NULL, NULL} + }; + static GEnumValue state_change_values[] = { + {GROUP_CHANGED, "GROUP_CHANGED", NULL}, + {INDICATORS_CHANGED, "INDICATORS_CHANGED", NULL}, + {0, NULL, NULL} + }; + + GObjectClass *object_class; + + object_class = (GObjectClass *) klass; + parent_class = g_type_class_peek_parent(object_class); + + object_class->constructor = xkl_engine_constructor; + object_class->finalize = xkl_engine_finalize; + object_class->set_property = xkl_engine_set_property; + object_class->get_property = xkl_engine_get_property; + + GParamSpec *display_param_spec = g_param_spec_pointer("display", + "Display", + "X Display pointer", + G_PARAM_CONSTRUCT_ONLY + | + G_PARAM_READWRITE); + + GParamSpec *backend_name_param_spec = + g_param_spec_string("backendName", + "backendName", + "Backend name", + NULL, + G_PARAM_READABLE); + + GType features_type = g_flags_register_static("XklEngineFeatures", + feature_flags); + + GType state_change_type = + g_enum_register_static("XklEngineStateChangeType", + state_change_values); + + GParamSpec *features_param_spec = g_param_spec_flags("features", + "Features", + "Backend features", + features_type, + 0, + G_PARAM_READABLE); + GParamSpec *max_num_groups_param_spec = + g_param_spec_uint("max-num-groups", + "maxNumGroups", + "Max number of groups", + 0, 0x100, 0, + G_PARAM_READABLE); + + GParamSpec *num_groups_param_spec = g_param_spec_uint("num-groups", + "numGroups", + "Current number of groups", + 0, 0x100, 0, + G_PARAM_READABLE); + + GParamSpec *default_group_param_spec = + g_param_spec_uint("default-group", + "defaultGroup", + "Default group", + 0, 0x100, 0, + G_PARAM_READABLE); + + GParamSpec *secondary_groups_mask_param_spec = + g_param_spec_uint("secondary-groups-mask", + "secondaryGroupsMask", + "Secondary groups mask", + 0, 0x100, 0, + G_PARAM_READABLE); + + GParamSpec *indicators_handling_param_spec = + g_param_spec_boolean("indicators-handling", + "indicatorsHandling", + "Whether engine should handle indicators", + FALSE, + G_PARAM_READABLE); + + g_object_class_install_property(object_class, + PROP_DISPLAY, display_param_spec); + g_object_class_install_property(object_class, + PROP_BACKEND_NAME, + backend_name_param_spec); + g_object_class_install_property(object_class, PROP_FEATURES, + features_param_spec); + g_object_class_install_property(object_class, PROP_MAX_NUM_GROUPS, + max_num_groups_param_spec); + g_object_class_install_property(object_class, PROP_NUM_GROUPS, + num_groups_param_spec); + g_object_class_install_property(object_class, PROP_DEFAULT_GROUP, + default_group_param_spec); + g_object_class_install_property(object_class, + PROP_SECONDARY_GROUPS_MASK, + secondary_groups_mask_param_spec); + g_object_class_install_property(object_class, + PROP_INDICATORS_HANDLING, + indicators_handling_param_spec); + + + g_signal_new("X-config-changed", XKL_TYPE_ENGINE, + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(XklEngineClass, + config_notify), + NULL, NULL, xkl_engine_VOID__VOID, G_TYPE_NONE, 0); + + g_signal_new("new-toplevel-window", XKL_TYPE_ENGINE, + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(XklEngineClass, + new_window_notify), + NULL, NULL, xkl_engine_INT__LONG_LONG, + G_TYPE_INT, 2, G_TYPE_LONG, G_TYPE_LONG); + + g_signal_new("X-state-changed", XKL_TYPE_ENGINE, + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(XklEngineClass, + state_notify), + NULL, NULL, + xkl_engine_VOID__FLAGS_INT_BOOLEAN, + G_TYPE_NONE, 3, state_change_type, G_TYPE_INT, + G_TYPE_BOOLEAN); + + /* 2 Windows passed */ + /* static stuff initialized */ + + const gchar *sdl = g_getenv("XKL_DEBUG"); + + if (sdl != NULL) { + xkl_set_debug_level(atoi(sdl)); + } +} diff --git a/libxklavier/xklavier.h b/libxklavier/xklavier.h index 000f523..5dcb8c5 100644 --- a/libxklavier/xklavier.h +++ b/libxklavier/xklavier.h @@ -1,7 +1,3 @@ -/** - * @file xklavier.h - */ - #ifndef __XKLAVIER_H__ #define __XKLAVIER_H__ @@ -9,542 +5,117 @@ #include <X11/Xlib.h> -#ifdef __cplusplus -extern "C" -{ -#endif - - typedef enum - { -/** - * Group was changed - */ - GROUP_CHANGED, -/** - * Indicators were changed - */ - INDICATORS_CHANGED - } - 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 - */ - typedef struct - { -/** selected group */ - int group; -/** set of active indicators */ - unsigned indicators; - } - XklState; - -/** - * @defgroup xklinitterm Library initialization and termination - * @{ - */ - -/** - * Initializes internal structures. Does not start actual listening though. - * Some apps can use Xklavier for information retrieval but not for actual - * processing. - * @param dpy is an open display, will be tested for XKB extension - * @return 0 if OK, otherwise last X error - * (special case: -1 if XKB extension is not present) - */ - extern int XklInit( Display * dpy ); - -/** - * Terminates everything... - */ - 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 ); - -/** - * Provides the information on maximum number of simultaneously supported - * groups (layouts) - * @return maximum number of the groups in configuration, - * 0 if no restrictions. - */ - extern unsigned XklGetMaxNumGroups( void ); -/** @} */ - -/** - * @defgroup xkbevents XKB event handling and management - * @{ - */ - -/** - * 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( int what ); - -/** - * Stops listening for XKB-related events - * @return 0 - */ - extern int XklStopListen( void ); - -/** - * Temporary pauses listening for XKB-related events - * @return 0 - */ - extern int XklPauseListen( void ); - -/** - * Resumes listening for XKB-related events - * @return 0 - */ - extern int XklResumeListen( void ); - -/** - * Grabs some key - * @param keycode is a keycode - * @param modifiers is a bitmask of modifiers - * @return True on success - */ - extern Bool XklGrabKey( int keycode, unsigned modifiers ); - -/** - * Ungrabs some key - * @param keycode is a keycode - * @param modifiers is a bitmask of modifiers - * @return True on success - */ - extern Bool XklUngrabKey( int keycode, unsigned modifiers ); - -/** - * Processes X events. Should be included into the main event cycle of an - * application. One of the most important functions. - * @param evt is delivered X event - * @return 0 if the event it processed - 1 otherwise - * @see XklStartListen - */ - extern int XklFilterEvents( XEvent * evt ); - -/** - * Allows to switch (once) to the secondary group - */ - extern void XklAllowOneSwitchToSecondaryGroup( void ); - -/** @} */ - -/** - * @defgroup currents Current state of the library - * @{ - */ - -/** - * @return currently focused window - */ - extern Window XklGetCurrentWindow( void ); - -/** - * @return current state of the keyboard (in XKB terms). - * Returned value is a statically allocated buffer, should not be freed. - */ - extern XklState *XklGetCurrentState( void ); - -/** @} */ - -/** - * @defgroup wininfo Per-window information - * @{ - */ - -/** - * @return the window title of some window or NULL. - * If not NULL, it should be freed with XFree - */ - extern unsigned char *XklGetWindowTitle( Window w ); - -/** - * Finds the state for a given window (for its "App window"). - * @param win is a target window - * @param state_return is a structure to store the state - * @return True on success, otherwise False - * (the error message can be obtained using XklGetLastError). - */ - extern Bool XklGetState( Window win, XklState * state_return ); - -/** - * Drops the state of a given window (of its "App window"). - * @param win is a target window - */ - extern void XklDelState( Window win ); - -/** - * Stores ths state for a given window - * @param win is a target window - * @param state is a new state of the window - */ - extern void XklSaveState( Window win, XklState * state ); - -/** - * Sets the "transparent" flag. It means focus switching onto - * this window will never change the state. - * @param win is the window do set the flag for. - * @param transparent - if true, the windows is transparent. - * @see XklIsTranspatent - */ - extern void XklSetTransparent( Window win, Bool transparent ); - -/** - * Returns "transparent" flag. - * @param win is the window to get the transparent flag from. - * @see XklSetTranspatent - */ - extern Bool XklIsTransparent( Window win ); - -/** - * Checks whether 2 windows have the same App Window - * @param win1 is first window - * @param win2 is second window - * @return True is windows are in the same application - */ - extern Bool XklIsSameApp( Window win1, Window win2 ); - -/** @} */ - -/** - * @defgroup xkbinfo Various XKB configuration info - * @{ - */ - -/** - * @return the total number of groups in the current XKB configuration - * (keyboard) - */ - extern unsigned XklGetNumGroups( void ); - -/** - * @return the array of group names for the current XKB configuration - * (keyboard). - * This array is static, should not be freed - */ - extern const char **XklGetGroupNames( void ); - -/** - * @return the array of indicator names for the current XKB configuration - * (keyboard). - * This array is static, should not be freed - */ - extern const char **XklGetIndicatorNames( void ); - -/** @} */ - -/** - * @defgroup xkbgroup XKB group calculation and change - * @{ - */ - -/** - * Calculates next group id. Does not change the state of anything. - * @return next group id - */ - extern int XklGetNextGroup( void ); - -/** - * Calculates prev group id. Does not change the state of anything. - * @return prev group id - */ - extern int XklGetPrevGroup( void ); - -/** - * @return saved group id of the current client. - * Does not change the state of anything. - */ - extern int XklGetRestoreGroup( void ); - -/** - * Locks the group. Can be used after XklGetXXXGroup functions - * @param group is a group number for locking - * @see XklGetNextGroup - * @see XklGetPrevGroup - * @see XklGetRestoreGroup - */ - extern void XklLockGroup( int group ); - -/** @} */ - -/** - * @defgroup callbacks Application callbacks support - * @{ - */ - -/** - * Used for notifying application of the XKB configuration change. - * @param userData is anything which can be stored into the pointer - * @see XklRegisterConfigCallback - */ - typedef void ( *XklConfigCallback ) ( void *userData ); - -/** - * Registers user callback. Only one callback can be registered at a time - * @param fun is the function to call - * @param userData is the data to pass - * @see XklConfigCallback - */ - extern int XklRegisterConfigCallback( XklConfigCallback fun, - void *userData ); - -/** - * Used for notifying application of new window creation (actually, - * registration). - * @param win is a new window - * @param parent is a new window's parent - * @param userData is anything which can be stored into the pointer - * @return the initial group id for the window (-1 to use the default value) - * @see XklRegisterConfigCallback - * @see XklSetDefaultGroup - * @see XklGetDefaultGroup - */ - typedef int ( *XklWinCallback ) ( Window win, Window parent, - void *userData ); - -/** - * Registers user callback. Only one callback can be registered at a time - * @param fun is the function to call - * @param userData is the data to pass - * @see XklWindowCallback - */ - extern int XklRegisterWindowCallback( XklWinCallback fun, void *userData ); - -/** - * Used for notifying application of the window state change. - * @param changeType is a mask of changes - * @param group is a new group - * @param restore is indicator of whether this state is restored from - * saved state of set as new. - * @param userData is anything which can be stored into the pointer - * @see XklRegisterConfigCallback - */ - typedef void ( *XklStateCallback ) ( XklStateChange changeType, int group, - Bool restore, void *userData ); - -/** - * Registers user callback. Only one callback can be registered at a time - * @param fun is the function to call - * @param userData is the data to pass - * @see XklStateCallback - */ - extern int XklRegisterStateCallback( XklStateCallback fun, void *userData ); - -/** @} */ +#include <glib-object.h> -/** - * @defgroup settings Settings for event processing - * @{ - */ - -/** - * Sets the configuration parameter: group per application - * @param isGlobal is a new parameter value - */ - extern void XklSetGroupPerApp( Bool isGlobal ); - -/** - * @return the value of the parameter: group per application - */ - extern Bool XklIsGroupPerApp( void ); - -/** - * Sets the configuration parameter: perform indicators handling - * @param whetherHandle is a new parameter value - */ - extern void XklSetIndicatorsHandling( Bool whetherHandle ); - -/** - * @return the value of the parameter: perform indicator handling - */ - extern Bool XklGetIndicatorsHandling( void ); +#include <libxklavier/xkl_engine.h> +#include <libxklavier/xkl_config_rec.h> +#include <libxklavier/xkl_config_item.h> +#include <libxklavier/xkl_config_registry.h> -/** - * Sets the secondary groups (one bit per group). - * Secondary groups require explicit "allowance" for switching - * @param mask is a new group mask - * @see XklAllowOneSwitchToSecondaryGroup - */ - extern void XklSetSecondaryGroupsMask( int mask ); - -/** - * @return the secondary group mask - */ - extern int XklGetSecondaryGroupsMask( void ); - -/** - * Configures the default group set on window creation. - * If -1, no default group is used - * @param group the default group - */ - extern void XklSetDefaultGroup( int group ); - -/** - * Returns the default group set on window creation - * If -1, no default group is used - * @return the default group - */ - extern int XklGetDefaultGroup( void ); - -/** @} */ - -/** - * @defgroup debugerr Debugging, error processing - * @{ - */ +#ifdef __cplusplus +extern "C" { +#endif /** - * @return the text message (statically allocated) of the last error + * xkl_get_last_error: + * + * Returns: the text message (statically allocated) of the last error */ - extern const char *XklGetLastError( void ); + extern const gchar *xkl_get_last_error(void); /** - * Output (optionally) some debug info - * @param file is the name of the source file. + * _xkl_debug: + * @file: the name of the source file. * Preprocessor symbol__FILE__ should be used here - * @param function is a name of the function + * @function: name of the function * Preprocessor symbol__func__ should be used here - * @param level is a level of the message - * @param format is a format (like in printf) - * @see XklDebug + * @level: level of the message + * @format: is a format (like in printf) + * + * Output (optionally) some debug info */ - extern void _XklDebug( const char file[], const char function[], int level, - const char format[], ... ); + extern void _xkl_debug(const gchar file[], const gchar function[], + gint level, const gchar format[], ...); /** - * Custom log output method for _XklDebug. This appender is NOT called if the - * level of the message is greater than currently set debug level. - * - * @param file is the name of the source file. + * XklLogAppender: + * @file: name of the source file. * Preprocessor symbol__FILE__ should be used here - * @param function is a name of the function + * @function: name of the function * Preprocessor symbol__func__ should be used here - * @param level is a level of the message - * @param format is a format (like in printf) - * @param args is the list of parameters - * @see _XklDebug - * @see XklSetDebugLevel + * @level: level of the message + * @format: format (like in printf) + * @args: list of parameters + * + * Custom log output method for _xkl_debug. This appender is NOT called if the + * level of the message is greater than currently set debug level. */ - typedef void ( *XklLogAppender ) ( const char file[], const char function[], - int level, const char format[], - va_list args ); + typedef void (*XklLogAppender) (const gchar file[], + const gchar function[], + gint level, + const gchar format[], + va_list args); /** - * Default log output method. Sends everything to stdout. - * - * @param file is the name of the source file. + * xkl_default_log_appender: + * @file: name of the source file. * Preprocessor symbol__FILE__ should be used here - * @param function is a name of the function + * @function: name of the function * Preprocessor symbol__func__ should be used here - * @param level is a level of the message - * @param format is a format (like in printf) - * @param args is the list of parameters + * @level: level of the message + * @format: format (like in printf) + * @args: list of parameters + * + * Default log output method. Sends everything to stdout. */ - extern void XklDefaultLogAppender( const char file[], const char function[], - int level, const char format[], - va_list args ); + extern void xkl_default_log_appender(const gchar file[], + const gchar function[], + gint level, + const gchar format[], + va_list args); /** + * xkl_set_log_appender: + * @fun: new log appender + * * Installs the custom log appender.function - * @param fun is the new log appender */ - extern void XklSetLogAppender( XklLogAppender fun ); + extern void xkl_set_log_appender(XklLogAppender fun); /** + * xkl_set_debug_level: + * @level: new debug level + * * Sets maximum debug level. * Message of the level more than the one set here - will be ignored - * @param level is a new debug level */ - extern void XklSetDebugLevel( int level ); + extern void xkl_set_debug_level(gint level); -/* Just to make doxygen happy - two block with/without @param format */ -#if defined(G_HAVE_GNUC_VARARGS) +#ifdef G_HAVE_ISO_VARARGS /** + * xkl_debug: + * @level: level of the message + * * Output (optionally) some debug info - * @param level is a level of the message - * @param format is a format (like in printf) - * @see _XklDebug */ -#else +#define xkl_debug( level, ... ) \ + _xkl_debug( __FILE__, __func__, level, __VA_ARGS__ ) +#elif defined(G_HAVE_GNUC_VARARGS) /** + * xkl_debug: + * @level: level of the message + * @format: format (like in printf) + * * 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__ ) -#elif defined(G_HAVE_GNUC_VARARGS) -#define XklDebug( level, format, args... ) \ - _XklDebug( __FILE__, __func__, level, format, ## args ) +#define xkl_debug( level, format, args... ) \ + _xkl_debug( __FILE__, __func__, level, format, ## args ) #else -#define XklDebug( level, ... ) \ - _XklDebug( __FILE__, __func__, level, __VA_ARGS__ ) +#define xkl_debug( level, ... ) \ + _xkl_debug( __FILE__, __func__, level, __VA_ARGS__ ) #endif -/** @} */ - #ifdef __cplusplus } -#endif /* __cplusplus */ - +#endif /* __cplusplus */ #endif diff --git a/libxklavier/xklavier_config.c b/libxklavier/xklavier_config.c index 6e8c0a4..84645ae 100644 --- a/libxklavier/xklavier_config.c +++ b/libxklavier/xklavier_config.c @@ -1,593 +1,721 @@ #include <errno.h> -#include <string.h> -#include <stdio.h> #include <locale.h> +#include <stdio.h> +#include <string.h> #include <sys/stat.h> -#include <libxml/xpath.h> - #include "config.h" #include "xklavier_private.h" -typedef struct _XklConfigRegistry -{ - xmlDocPtr doc; - xmlXPathContextPtr xpathContext; -} -XklConfigRegistry; - -static XklConfigRegistry theRegistry; - -static xmlXPathCompExprPtr modelsXPath; -static xmlXPathCompExprPtr layoutsXPath; -static xmlXPathCompExprPtr optionGroupsXPath; - -#define _XklConfigRegistryIsInitialized() \ - ( theRegistry.xpathContext != NULL ) - -static xmlChar *_XklNodeGetXmlLangAttr( xmlNodePtr nptr ) -{ - if( nptr->properties != NULL && - !strcmp( "lang", (char *)nptr->properties[0].name ) && - nptr->properties[0].ns != NULL && - !strcmp( "xml", (char *)nptr->properties[0].ns->prefix ) && - nptr->properties[0].children != NULL ) - return nptr->properties[0].children->content; - else - return NULL; -} - -static Bool _XklReadConfigItem( xmlNodePtr iptr, XklConfigItemPtr pci ) -{ - xmlNodePtr nameElement, descElement = NULL, ntDescElement = - NULL, nptr, ptr, shortDescElement = NULL, ntShortDescElement = NULL; - int maxDescPriority = -1; - int maxShortDescPriority = -1; - - *pci->name = 0; - *pci->shortDescription = 0; - *pci->description = 0; - if( iptr->type != XML_ELEMENT_NODE ) - return False; - ptr = iptr->children; - while( ptr != NULL ) - { - switch ( ptr->type ) - { - case XML_ELEMENT_NODE: - if( !strcmp( (char *)ptr->name, "configItem" ) ) - break; - return False; - case XML_TEXT_NODE: - case XML_COMMENT_NODE: - ptr = ptr->next; - continue; - default: - return False; - } - break; - } - if( ptr == NULL ) - return False; - - nptr = ptr->children; - - if( nptr->type == XML_TEXT_NODE ) - nptr = nptr->next; - nameElement = nptr; - nptr = nptr->next; - - while( nptr != NULL ) - { - if( nptr->type != XML_TEXT_NODE ) - { - xmlChar *lang = _XklNodeGetXmlLangAttr( nptr ); - - if( lang != NULL ) - { - int priority = _XklGetLanguagePriority( (char *)lang ); - if( !strcmp( (char *)nptr->name, "description" ) && ( priority > maxDescPriority ) ) /* higher priority */ - { - descElement = nptr; - maxDescPriority = priority; - } else if( !strcmp( (char *)nptr->name, "shortDescription" ) && ( priority > maxShortDescPriority ) ) /* higher priority */ - { - shortDescElement = nptr; - maxShortDescPriority = priority; - } - } else - { - if( !strcmp( (char *)nptr->name, "description" ) ) - ntDescElement = nptr; - else if( !strcmp( (char *)nptr->name, "shortDescription" ) ) - ntShortDescElement = nptr; - } - } - nptr = nptr->next; - } - - /* 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... - */ - - if( nameElement != NULL && nameElement->children != NULL ) - strncat( pci->name, (char *)nameElement->children->content, - XKL_MAX_CI_NAME_LENGTH - 1 ); - - if( shortDescElement != NULL && shortDescElement->children != NULL ) - { - char * lsd = _XklLocaleFromUtf8( (const char *)shortDescElement->children->content ); - strncat( pci->shortDescription, - lsd, - XKL_MAX_CI_SHORT_DESC_LENGTH - 1 ); - free( lsd ); - } - - if( descElement != NULL && descElement->children != NULL ) - { - char * ld = _XklLocaleFromUtf8( (const char *)descElement->children->content ); - strncat( pci->description, - ld, - XKL_MAX_CI_DESC_LENGTH - 1 ); - free( ld ); - } - return True; -} - -static void _XklConfigEnumFromNodeSet( xmlNodeSetPtr nodes, - ConfigItemProcessFunc func, - void *userData ) +static GObjectClass *parent_class = NULL; + +static XklConfigRegistry *the_config = NULL; + +static xmlXPathCompExprPtr models_xpath; +static xmlXPathCompExprPtr layouts_xpath; +static xmlXPathCompExprPtr option_groups_xpath; + +enum { + PROP_0, + PROP_ENGINE, +}; + +#define xkl_config_registry_is_initialized(config) \ + ( xkl_config_registry_priv(config,xpath_context) != NULL ) + +static xmlChar * +xkl_node_get_xml_lang_attr(xmlNodePtr nptr) +{ + if (nptr->properties != NULL && + !g_ascii_strcasecmp("lang", (char *) nptr->properties[0].name) + && nptr->properties[0].ns != NULL + && !g_ascii_strcasecmp("xml", + (char *) nptr->properties[0].ns->prefix) + && nptr->properties[0].children != NULL) + return nptr->properties[0].children->content; + else + return NULL; +} + +static gboolean +xkl_read_config_item(xmlNodePtr iptr, XklConfigItem * item) +{ + xmlNodePtr name_element, nptr, ptr; + xmlNodePtr desc_element = NULL, short_desc_element = NULL; + xmlNodePtr nt_desc_element = NULL, nt_short_desc_element = NULL; + + gint max_desc_priority = -1; + gint max_short_desc_priority = -1; + + *item->name = 0; + *item->short_description = 0; + *item->description = 0; + if (iptr->type != XML_ELEMENT_NODE) + return FALSE; + ptr = iptr->children; + while (ptr != NULL) { + switch (ptr->type) { + case XML_ELEMENT_NODE: + if (!g_ascii_strcasecmp((char *) ptr->name, + "configItem")) + break; + return FALSE; + case XML_TEXT_NODE: + case XML_COMMENT_NODE: + ptr = ptr->next; + continue; + default: + return FALSE; + } + break; + } + if (ptr == NULL) + return FALSE; + + nptr = ptr->children; + + if (nptr->type == XML_TEXT_NODE) + nptr = nptr->next; + name_element = nptr; + nptr = nptr->next; + + while (nptr != NULL) { + char *node_name = (char *) nptr->name; + if (nptr->type != XML_TEXT_NODE) { + xmlChar *lang = xkl_node_get_xml_lang_attr(nptr); + + if (lang != NULL) { + gint priority = + xkl_get_language_priority((gchar *) + lang); + + /* + * Find desc/shortdesc with highest priority + */ + if (!g_ascii_strcasecmp(node_name, + "description") && + (priority > max_desc_priority)) { + desc_element = nptr; + max_desc_priority = priority; + } else if (!g_ascii_strcasecmp(node_name, + "shortDescription") + && (priority > + max_short_desc_priority)) { + short_desc_element = nptr; + max_short_desc_priority = priority; + } + } else // no language specified! + { + if (!g_ascii_strcasecmp(node_name, + "description")) + nt_desc_element = nptr; + else if (!g_ascii_strcasecmp(node_name, + "shortDescription")) + nt_short_desc_element = nptr; + } + } + nptr = nptr->next; + } + + /* if no language-specific description found - use the ones without lang */ + if (desc_element == NULL) + desc_element = nt_desc_element; + + if (short_desc_element == NULL) + short_desc_element = nt_short_desc_element; + + /* + * Actually, here we should have some code to find + * the correct localized description... + */ + + if (name_element != NULL && name_element->children != NULL) + strncat(item->name, + (char *) name_element->children->content, + XKL_MAX_CI_NAME_LENGTH - 1); + + if (short_desc_element != NULL && + short_desc_element->children != NULL) { + gchar *lmsg = xkl_locale_from_utf8((const gchar *) + short_desc_element-> + children->content); + strncat(item->short_description, lmsg, + XKL_MAX_CI_SHORT_DESC_LENGTH - 1); + g_free(lmsg); + } + + if (desc_element != NULL && desc_element->children != NULL) { + gchar *lmsg = + xkl_locale_from_utf8((const gchar *) desc_element-> + children->content); + strncat(item->description, lmsg, + XKL_MAX_CI_DESC_LENGTH - 1); + g_free(lmsg); + } + return TRUE; +} + +static void +xkl_config_registry_foreach_in_nodeset(XklConfigRegistry * config, + xmlNodeSetPtr nodes, + ConfigItemProcessFunc func, + gpointer data) +{ + gint i; + if (nodes != NULL) { + xmlNodePtr *pnode = nodes->nodeTab; + for (i = nodes->nodeNr; --i >= 0;) { + XklConfigItem ci; + if (xkl_read_config_item(*pnode, &ci)) + func(&ci, data); + + pnode++; + } + } +} + +static void +xkl_config_registry_foreach_in_xpath(XklConfigRegistry * config, + xmlXPathCompExprPtr xpath_comp_expr, + ConfigItemProcessFunc func, + gpointer data) +{ + xmlXPathObjectPtr xpath_obj; + + if (!xkl_config_registry_is_initialized(config)) + return; + xpath_obj = xmlXPathCompiledEval(xpath_comp_expr, + xkl_config_registry_priv(config, + xpath_context)); + if (xpath_obj != NULL) { + xkl_config_registry_foreach_in_nodeset(config, + xpath_obj-> + nodesetval, func, + data); + xmlXPathFreeObject(xpath_obj); + } +} + +static void +xkl_config_registry_foreach_in_xpath_with_param(XklConfigRegistry * config, + const gchar * format, + const gchar * value, + ConfigItemProcessFunc func, + gpointer data) { - int i; - if( nodes != NULL ) - { - xmlNodePtr *theNodePtr = nodes->nodeTab; - for( i = nodes->nodeNr; --i >= 0; ) - { - XklConfigItem ci; - if( _XklReadConfigItem( *theNodePtr, &ci ) ) - func( &ci, userData ); + char xpath_expr[1024]; + xmlXPathObjectPtr xpath_obj; - theNodePtr++; - } - } + if (!xkl_config_registry_is_initialized(config)) + return; + snprintf(xpath_expr, sizeof xpath_expr, format, value); + xpath_obj = xmlXPathEval((unsigned char *) xpath_expr, + xkl_config_registry_priv(config, + xpath_context)); + if (xpath_obj != NULL) { + xkl_config_registry_foreach_in_nodeset(config, + xpath_obj-> + nodesetval, func, + data); + xmlXPathFreeObject(xpath_obj); + } } -static void _XklConfigEnumSimple( xmlXPathCompExprPtr xpathCompExpr, - ConfigItemProcessFunc func, void *userData ) +static gboolean +xkl_config_registry_find_object(XklConfigRegistry * config, + const gchar * format, const gchar * arg1, + XklConfigItem * pitem /* in/out */ , + xmlNodePtr * pnode /* out */ ) { - xmlXPathObjectPtr xpathObj; + xmlXPathObjectPtr xpath_obj; + xmlNodeSetPtr nodes; + gboolean rv = FALSE; + gchar xpath_expr[1024]; - if( !_XklConfigRegistryIsInitialized( ) ) - return; - xpathObj = xmlXPathCompiledEval( xpathCompExpr, theRegistry.xpathContext ); - if( xpathObj != NULL ) - { - _XklConfigEnumFromNodeSet( xpathObj->nodesetval, func, userData ); - xmlXPathFreeObject( xpathObj ); - } -} + if (!xkl_config_registry_is_initialized(config)) + return FALSE; -static void _XklConfigEnumDirect( const char *format, - const char *value, - ConfigItemProcessFunc func, void *userData ) -{ - char xpathExpr[1024]; - xmlXPathObjectPtr xpathObj; + snprintf(xpath_expr, sizeof xpath_expr, format, arg1, pitem->name); + xpath_obj = xmlXPathEval((unsigned char *) xpath_expr, + xkl_config_registry_priv(config, + xpath_context)); + if (xpath_obj == NULL) + return FALSE; - if( !_XklConfigRegistryIsInitialized( ) ) - return; - snprintf( xpathExpr, sizeof xpathExpr, format, value ); - xpathObj = xmlXPathEval( (unsigned char *)xpathExpr, theRegistry.xpathContext ); - if( xpathObj != NULL ) - { - _XklConfigEnumFromNodeSet( xpathObj->nodesetval, func, userData ); - xmlXPathFreeObject( xpathObj ); - } -} - -static Bool _XklConfigFindObject( const char *format, - const char *arg1, - XklConfigItemPtr ptr /* in/out */ , - xmlNodePtr * nodePtr /* out */ ) -{ - xmlXPathObjectPtr xpathObj; - xmlNodeSetPtr nodes; - Bool rv = False; - char xpathExpr[1024]; - - if( !_XklConfigRegistryIsInitialized( ) ) - return False; - - snprintf( xpathExpr, sizeof xpathExpr, format, arg1, ptr->name ); - xpathObj = xmlXPathEval( (unsigned char *)xpathExpr, theRegistry.xpathContext ); - if( xpathObj == NULL ) - return False; - - nodes = xpathObj->nodesetval; - if( nodes != NULL && nodes->nodeTab != NULL ) - { - rv = _XklReadConfigItem( *nodes->nodeTab, ptr ); - if( nodePtr != NULL ) - { - *nodePtr = *nodes->nodeTab; - } - } + nodes = xpath_obj->nodesetval; + if (nodes != NULL && nodes->nodeTab != NULL) { + rv = xkl_read_config_item(*nodes->nodeTab, pitem); + if (pnode != NULL) { + *pnode = *nodes->nodeTab; + } + } - xmlXPathFreeObject( xpathObj ); - return rv; + xmlXPathFreeObject(xpath_obj); + return rv; } -char *_XklConfigRecMergeLayouts( const XklConfigRecPtr data ) +gchar * +xkl_config_rec_merge_layouts(const XklConfigRec * data) { - return _XklConfigRecMergeByComma( ( const char ** ) data->layouts, - data->numLayouts ); + return xkl_strings_concat_comma_separated(data->layouts); } -char *_XklConfigRecMergeVariants( const XklConfigRecPtr data ) +gchar * +xkl_config_rec_merge_variants(const XklConfigRec * data) { - return _XklConfigRecMergeByComma( ( const char ** ) data->variants, - data->numVariants ); + return xkl_strings_concat_comma_separated(data->variants); } -char *_XklConfigRecMergeOptions( const XklConfigRecPtr data ) +gchar * +xkl_config_rec_merge_options(const XklConfigRec * data) { - return _XklConfigRecMergeByComma( ( const char ** ) data->options, - data->numOptions ); + return xkl_strings_concat_comma_separated(data->options); } -char *_XklConfigRecMergeByComma( const char **array, const int arrayLength ) +gchar * +xkl_strings_concat_comma_separated(gchar ** array) { - int len = 0; - int i; - char *merged; - const char **theString; - - if( ( theString = array ) == NULL ) - return NULL; - - for( i = arrayLength; --i >= 0; theString++ ) - { - if( *theString != NULL ) - len += strlen( *theString ); - len++; - } - - if( len < 1 ) - return NULL; - - merged = ( char * ) malloc( len ); - merged[0] = '\0'; - - theString = array; - for( i = arrayLength; --i >= 0; theString++ ) - { - if( *theString != NULL ) - strcat( merged, *theString ); - if( i != 0 ) - strcat( merged, "," ); - } - return merged; + return g_strjoinv(",", array); } -void _XklConfigRecSplitLayouts( XklConfigRecPtr data, const char *merged ) +void +xkl_config_rec_split_layouts(XklConfigRec * data, const gchar * merged) { - _XklConfigRecSplitByComma( &data->layouts, &data->numLayouts, merged ); + xkl_strings_split_comma_separated(&data->layouts, merged); } -void _XklConfigRecSplitVariants( XklConfigRecPtr data, const char *merged ) +void +xkl_config_rec_split_variants(XklConfigRec * data, const gchar * merged) { - _XklConfigRecSplitByComma( &data->variants, &data->numVariants, merged ); + xkl_strings_split_comma_separated(&data->variants, merged); } -void _XklConfigRecSplitOptions( XklConfigRecPtr data, const char *merged ) +void +xkl_config_rec_split_options(XklConfigRec * data, const gchar * merged) { - _XklConfigRecSplitByComma( &data->options, &data->numOptions, merged ); + xkl_strings_split_comma_separated(&data->options, merged); } -void _XklConfigRecSplitByComma( char ***array, - int *arraySize, const char *merged ) +void +xkl_strings_split_comma_separated(gchar *** array, const gchar * merged) { - const char *pc = merged; - char **ppc, *npc; - *arraySize = 0; - *array = NULL; - - if( merged == NULL || merged[0] == '\0' ) - return; - - /* first count the elements */ - while( ( npc = strchr( pc, ',' ) ) != NULL ) - { - ( *arraySize )++; - pc = npc + 1; - } - ( *arraySize )++; - - if( ( *arraySize ) != 0 ) - { - int len; - *array = ( char ** ) malloc( ( sizeof( char * ) ) * ( *arraySize ) ); - - ppc = *array; - pc = merged; - while( ( npc = strchr( pc, ',' ) ) != NULL ) - { - int len = npc - pc; - /* *ppc = ( char * ) strndup( pc, len ); */ - *ppc = ( char * ) malloc( len + 1 ); - if ( *ppc != NULL ) - { - strncpy( *ppc, pc, len ); - (*ppc)[len] = '\0'; - } - - ppc++; - pc = npc + 1; - } - - /* len = npc - pc; */ - len = strlen( pc ); - /* *ppc = ( char * ) strndup( pc, len ); */ - *ppc = ( char * ) malloc( len + 1 ); - if ( *ppc != NULL ) - strcpy( *ppc, pc ); - } + *array = g_strsplit(merged, ",", 0); } -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; +gchar * +xkl_engine_get_ruleset_name(XklEngine * engine, + const gchar default_ruleset[]) +{ + static gchar rules_set_name[1024] = ""; + if (!rules_set_name[0]) { + /* first call */ + gchar *rf = NULL; + if (!xkl_config_rec_get_from_root_window_property + (NULL, xkl_engine_priv(engine, base_config_atom), &rf, + engine) + || (rf == NULL)) { + g_strlcpy(rules_set_name, default_ruleset, + sizeof rules_set_name); + xkl_debug(100, "Using default rules set: [%s]\n", + rules_set_name); + return rules_set_name; + } + g_strlcpy(rules_set_name, rf, sizeof rules_set_name); + g_free(rf); + } + xkl_debug(100, "Rules set: [%s]\n", rules_set_name); + return rules_set_name; } -void XklConfigInit( void ) +XklConfigRegistry * +xkl_config_registry_get_instance(XklEngine * engine) { - xmlXPathInit( ); - modelsXPath = xmlXPathCompile( (unsigned char *)"/xkbConfigRegistry/modelList/model" ); - layoutsXPath = xmlXPathCompile( (unsigned char *)"/xkbConfigRegistry/layoutList/layout" ); - optionGroupsXPath = - xmlXPathCompile( (unsigned char *)"/xkbConfigRegistry/optionList/group" ); - _XklI18NInit( ); + if (the_config != NULL) { + g_object_ref(G_OBJECT(the_config)); + return the_config; + } + + if (!engine) { + xkl_debug(10, + "xkl_config_registry_get_instance : engine is NULL ?\n"); + return NULL; + } - _XklEnsureVTableInited(); - (*xklVTable->xklConfigInitHandler)(); + the_config = + XKL_CONFIG_REGISTRY(g_object_new + (xkl_config_registry_get_type(), "engine", + engine, NULL)); + + return the_config; } -void XklConfigTerm( void ) +gboolean +xkl_config_registry_load_from_file(XklConfigRegistry * config, + const gchar * file_name) { - if( modelsXPath != NULL ) - { - xmlXPathFreeCompExpr( modelsXPath ); - modelsXPath = NULL; - } - if( layoutsXPath != NULL ) - { - xmlXPathFreeCompExpr( layoutsXPath ); - layoutsXPath = NULL; - } - if( optionGroupsXPath != NULL ) - { - xmlXPathFreeCompExpr( optionGroupsXPath ); - optionGroupsXPath = NULL; - } + xkl_config_registry_priv(config, doc) = xmlParseFile(file_name); + if (xkl_config_registry_priv(config, doc) == NULL) { + xkl_config_registry_priv(config, xpath_context) = NULL; + xkl_last_error_message = + "Could not parse XKB configuration registry"; + } else + xkl_config_registry_priv(config, xpath_context) = + xmlXPathNewContext(xkl_config_registry_priv + (config, doc)); + return xkl_config_registry_is_initialized(config); } -Bool XklConfigLoadRegistryFromFile( const char * fileName ) +void +xkl_config_registry_free(XklConfigRegistry * config) { - theRegistry.doc = xmlParseFile( fileName ); - if( theRegistry.doc == NULL ) - { - theRegistry.xpathContext = NULL; - _xklLastErrorMsg = "Could not parse XKB configuration registry"; - } else - theRegistry.xpathContext = xmlXPathNewContext( theRegistry.doc ); - return _XklConfigRegistryIsInitialized( ); + if (xkl_config_registry_is_initialized(config)) { + xmlXPathFreeContext(xkl_config_registry_priv + (config, xpath_context)); + xmlFreeDoc(xkl_config_registry_priv(config, doc)); + xkl_config_registry_priv(config, xpath_context) = NULL; + xkl_config_registry_priv(config, doc) = NULL; + } } -void XklConfigFreeRegistry( void ) -{ - if( _XklConfigRegistryIsInitialized( ) ) - { - xmlXPathFreeContext( theRegistry.xpathContext ); - xmlFreeDoc( theRegistry.doc ); - theRegistry.xpathContext = NULL; - theRegistry.doc = NULL; +void +xkl_config_registry_foreach_model(XklConfigRegistry * config, + ConfigItemProcessFunc func, + gpointer data) +{ + xkl_config_registry_foreach_in_xpath(config, models_xpath, func, + data); +} + +void +xkl_config_registry_foreach_layout(XklConfigRegistry * config, + ConfigItemProcessFunc func, + gpointer data) +{ + xkl_config_registry_foreach_in_xpath(config, layouts_xpath, func, + data); +} + +void +xkl_config_registry_foreach_layout_variant(XklConfigRegistry * config, + const gchar * layout_name, + ConfigItemProcessFunc func, + gpointer data) +{ + xkl_config_registry_foreach_in_xpath_with_param + (config, + "/xkbConfigRegistry/layoutList/layout/variantList/variant[../../configItem/name = '%s']", + layout_name, func, data); +} + +void +xkl_config_registry_foreach_option_group(XklConfigRegistry * config, + GroupProcessFunc func, + gpointer data) +{ + xmlXPathObjectPtr xpath_obj; + gint i; + + if (!xkl_config_registry_is_initialized(config)) + return; + xpath_obj = + xmlXPathCompiledEval(option_groups_xpath, + xkl_config_registry_priv(config, + xpath_context)); + if (xpath_obj != NULL) { + xmlNodeSetPtr nodes = xpath_obj->nodesetval; + xmlNodePtr *pnode = nodes->nodeTab; + for (i = nodes->nodeNr; --i >= 0;) { + XklConfigItem ci; + + if (xkl_read_config_item(*pnode, &ci)) { + gboolean allow_multisel = TRUE; + xmlChar *sallow_multisel = + xmlGetProp(*pnode, + (unsigned char *) + "allowMultipleSelection"); + if (sallow_multisel != NULL) { + allow_multisel = + !g_ascii_strcasecmp("true", + (char *) + sallow_multisel); + xmlFree(sallow_multisel); + } + + func(&ci, allow_multisel, data); + } + + pnode++; + } + xmlXPathFreeObject(xpath_obj); + } +} + +void +xkl_config_registry_foreach_option(XklConfigRegistry * config, + const gchar * option_group_name, + ConfigItemProcessFunc func, + gpointer data) +{ + xkl_config_registry_foreach_in_xpath_with_param + (config, + "/xkbConfigRegistry/optionList/group/option[../configItem/name = '%s']", + option_group_name, func, data); +} + +gboolean +xkl_config_registry_find_model(XklConfigRegistry * config, + XklConfigItem * pitem /* in/out */ ) +{ + return + xkl_config_registry_find_object + (config, + "/xkbConfigRegistry/modelList/model[configItem/name = '%s%s']", + "", pitem, NULL); +} + +gboolean +xkl_config_registry_find_layout(XklConfigRegistry * config, + XklConfigItem * pitem /* in/out */ ) +{ + return + xkl_config_registry_find_object + (config, + "/xkbConfigRegistry/layoutList/layout[configItem/name = '%s%s']", + "", pitem, NULL); +} + +gboolean +xkl_config_registry_find_variant(XklConfigRegistry * config, + const char *layout_name, + XklConfigItem * pitem /* in/out */ ) +{ + return + xkl_config_registry_find_object + (config, + "/xkbConfigRegistry/layoutList/layout/variantList/variant" + "[../../configItem/name = '%s' and configItem/name = '%s']", + layout_name, pitem, NULL); +} + +gboolean +xkl_config_registry_find_option_group(XklConfigRegistry * config, + XklConfigItem * pitem /* in/out */ , + gboolean * + allow_multiple_selection /* out */ ) +{ + xmlNodePtr node; + gboolean rv = xkl_config_registry_find_object(config, + "/xkbConfigRegistry/optionList/group[configItem/name = '%s%s']", + "", + pitem, &node); + + if (rv && allow_multiple_selection != NULL) { + xmlChar *val = xmlGetProp(node, + (unsigned char *) + "allowMultipleSelection"); + *allow_multiple_selection = FALSE; + if (val != NULL) { + *allow_multiple_selection = + !g_ascii_strcasecmp("true", (char *) val); + xmlFree(val); + } + } + return rv; +} + +gboolean +xkl_config_registry_find_option(XklConfigRegistry * config, + const char *option_group_name, + XklConfigItem * pitem /* in/out */ ) +{ + return + xkl_config_registry_find_object + (config, "/xkbConfigRegistry/optionList/group/option" + "[../configItem/name = '%s' and configItem/name = '%s']", + option_group_name, pitem, NULL); +} + +/* + * Calling through vtable + */ +gboolean +xkl_config_rec_activate(const XklConfigRec * data, XklEngine * engine) +{ + xkl_engine_ensure_vtable_inited(engine); + return xkl_engine_vcall(engine, activate_config_rec) (engine, + data); +} + +gboolean +xkl_config_registry_load(XklConfigRegistry * config) +{ + XklEngine *engine = xkl_config_registry_get_engine(config); + xkl_engine_ensure_vtable_inited(engine); + return xkl_engine_vcall(engine, load_config_registry) (config); +} + +gboolean +xkl_config_rec_write_to_file(XklEngine * engine, const gchar * file_name, + const XklConfigRec * data, + const gboolean binary) +{ + if ((!binary && + !(xkl_engine_priv(engine, features) & + XKLF_CAN_OUTPUT_CONFIG_AS_ASCII)) + || (binary + && !(xkl_engine_priv(engine, features) & + XKLF_CAN_OUTPUT_CONFIG_AS_BINARY))) { + xkl_last_error_message = + "Function not supported at backend"; + return FALSE; + } + xkl_engine_ensure_vtable_inited(engine); + return xkl_engine_vcall(engine, write_config_rec_to_file) (engine, + file_name, + data, + binary); +} + +void +xkl_config_rec_dump(FILE * file, XklConfigRec * data) +{ + int j; + fprintf(file, " model: [%s]\n", data->model); + + fprintf(file, " layouts:\n"); +#define OUTPUT_ARRZ(arrz) \ + { \ + fprintf( file, " " #arrz ":\n" ); \ + gchar **p = data->arrz; \ + if ( p != NULL ) \ + for( j = 0; *p != NULL; ) \ + fprintf( file, " %d: [%s]\n", j++, *p++ ); \ } -} + OUTPUT_ARRZ(layouts); + OUTPUT_ARRZ(variants); + OUTPUT_ARRZ(options); -void XklConfigEnumModels( ConfigItemProcessFunc func, void *userData ) -{ - _XklConfigEnumSimple( modelsXPath, func, userData ); } -void XklConfigEnumLayouts( ConfigItemProcessFunc func, void *userData ) -{ - _XklConfigEnumSimple( layoutsXPath, func, userData ); -} +G_DEFINE_TYPE(XklConfigRegistry, xkl_config_registry, G_TYPE_OBJECT) -void XklConfigEnumLayoutVariants( const char *layoutName, - ConfigItemProcessFunc func, void *userData ) +static GObject * +xkl_config_registry_constructor(GType type, + guint n_construct_properties, + GObjectConstructParam * + construct_properties) { - _XklConfigEnumDirect - ( "/xkbConfigRegistry/layoutList/layout/variantList/variant[../../configItem/name = '%s']", - layoutName, func, userData ); -} + GObject *obj; -void XklConfigEnumOptionGroups( GroupProcessFunc func, void *userData ) -{ - xmlXPathObjectPtr xpathObj; - int i; + { + /* Invoke parent constructor. */ + XklConfigRegistryClass *klass; + klass = + XKL_CONFIG_REGISTRY_CLASS(g_type_class_peek + (XKL_TYPE_CONFIG_REGISTRY)); + obj = + parent_class->constructor(type, n_construct_properties, + construct_properties); + } - if( !_XklConfigRegistryIsInitialized( ) ) - return; - xpathObj = - xmlXPathCompiledEval( optionGroupsXPath, theRegistry.xpathContext ); - if( xpathObj != NULL ) - { - xmlNodeSetPtr nodes = xpathObj->nodesetval; - xmlNodePtr *theNodePtr = nodes->nodeTab; - for( i = nodes->nodeNr; --i >= 0; ) - { - XklConfigItem ci; + XklConfigRegistry *config = XKL_CONFIG_REGISTRY(obj); - if( _XklReadConfigItem( *theNodePtr, &ci ) ) - { - Bool allowMC = True; - xmlChar *allowMCS = - xmlGetProp( *theNodePtr, (unsigned char *)"allowMultipleSelection" ); - if( allowMCS != NULL ) - { - allowMC = strcmp( "false", (char *)allowMCS ); - xmlFree( allowMCS ); - } + XklEngine *engine = + XKL_ENGINE(g_value_peek_pointer(construct_properties[0]. + value)); + xkl_config_registry_get_engine(config) = engine; - func( &ci, allowMC, userData ); - } + xkl_engine_ensure_vtable_inited(engine); + xkl_engine_vcall(engine, init_config_registry) (config); - theNodePtr++; - } - xmlXPathFreeObject( xpathObj ); - } + return obj; } -void XklConfigEnumOptions( const char *optionGroupName, - ConfigItemProcessFunc func, void *userData ) +static void +xkl_config_registry_init(XklConfigRegistry * config) { - _XklConfigEnumDirect - ( "/xkbConfigRegistry/optionList/group/option[../configItem/name = '%s']", - optionGroupName, func, userData ); + config->priv = g_new0(XklConfigRegistryPrivate, 1); } -Bool XklConfigFindModel( XklConfigItemPtr ptr /* in/out */ ) +static void +xkl_config_registry_set_property(GObject * object, + guint property_id, + const GValue * value, GParamSpec * pspec) { - return - _XklConfigFindObject - ( "/xkbConfigRegistry/modelList/model[configItem/name = '%s%s']", "", - ptr, NULL ); } -Bool XklConfigFindLayout( XklConfigItemPtr ptr /* in/out */ ) +static void +xkl_config_registry_get_property(GObject * object, + guint property_id, + GValue * value, GParamSpec * pspec) { - return - _XklConfigFindObject - ( "/xkbConfigRegistry/layoutList/layout[configItem/name = '%s%s']", "", - ptr, NULL ); -} + XklConfigRegistry *config = XKL_CONFIG_REGISTRY(object); + + switch (property_id) { + case PROP_ENGINE: + g_value_set_pointer(value, + xkl_config_registry_get_engine + (config)); + break; + } -Bool XklConfigFindVariant( const char *layoutName, - XklConfigItemPtr ptr /* in/out */ ) -{ - return - _XklConfigFindObject - ( "/xkbConfigRegistry/layoutList/layout/variantList/variant" - "[../../configItem/name = '%s' and configItem/name = '%s']", - layoutName, ptr, NULL ); } -Bool XklConfigFindOptionGroup( XklConfigItemPtr ptr /* in/out */ , - Bool * allowMultipleSelection /* out */ ) +static void +xkl_config_registry_finalize(GObject * obj) { - xmlNodePtr node; - Bool rv = - _XklConfigFindObject - ( "/xkbConfigRegistry/optionList/group[configItem/name = '%s%s']", "", - ptr, &node ); + XklConfigRegistry *config = (XklConfigRegistry *) obj; - if( rv && allowMultipleSelection != NULL ) - { - xmlChar *val = xmlGetProp( node, (unsigned char *)"allowMultipleSelection" ); - *allowMultipleSelection = False; - if( val != NULL ) - { - *allowMultipleSelection = !strcmp( (char *)val, "true" ); - xmlFree( val ); - } - } - return rv; -} + if (models_xpath != NULL) { + xmlXPathFreeCompExpr(models_xpath); + models_xpath = NULL; + } + if (layouts_xpath != NULL) { + xmlXPathFreeCompExpr(layouts_xpath); + layouts_xpath = NULL; + } + if (option_groups_xpath != NULL) { + xmlXPathFreeCompExpr(option_groups_xpath); + option_groups_xpath = NULL; + } -Bool XklConfigFindOption( const char *optionGroupName, - XklConfigItemPtr ptr /* in/out */ ) -{ - return - _XklConfigFindObject - ( "/xkbConfigRegistry/optionList/group/option" - "[../configItem/name = '%s' and configItem/name = '%s']", - optionGroupName, ptr, NULL ); -} + g_free(config->priv); -/** - * Calling through vtable - */ -Bool XklConfigActivate( const XklConfigRecPtr data ) -{ - _XklEnsureVTableInited(); - return (*xklVTable->xklConfigActivateHandler)( data ); + G_OBJECT_CLASS(parent_class)->finalize(obj); } -Bool XklConfigLoadRegistry( void ) +static void +xkl_config_registry_class_init(XklConfigRegistryClass * klass) { - _XklEnsureVTableInited(); - return (*xklVTable->xklConfigLoadRegistryHandler)(); -} + GObjectClass *object_class; -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 ); -} + object_class = (GObjectClass *) klass; + parent_class = g_type_class_peek_parent(object_class); + object_class->constructor = xkl_config_registry_constructor; + object_class->finalize = xkl_config_registry_finalize; + object_class->set_property = xkl_config_registry_set_property; + object_class->get_property = xkl_config_registry_get_property; -void XklConfigDump( FILE* file, - XklConfigRecPtr data ) -{ - int i,j; - char**p; - fprintf( file, " model: [%s]\n", data->model ); + GParamSpec *engine_param_spec = g_param_spec_object("engine", + "Engine", + "XklEngine", + XKL_TYPE_ENGINE, + G_PARAM_CONSTRUCT_ONLY + | + G_PARAM_READWRITE); - 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++ ); + g_object_class_install_property(object_class, + PROP_ENGINE, engine_param_spec); - 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++ ); + /* static stuff initialized */ - 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++ ); + xmlXPathInit(); + models_xpath = xmlXPathCompile((unsigned char *) + "/xkbConfigRegistry/modelList/model"); + layouts_xpath = xmlXPathCompile((unsigned char *) + "/xkbConfigRegistry/layoutList/layout"); + option_groups_xpath = xmlXPathCompile((unsigned char *) + "/xkbConfigRegistry/optionList/group"); + xkl_i18n_init(); } diff --git a/libxklavier/xklavier_config.h b/libxklavier/xklavier_config.h deleted file mode 100644 index 264f760..0000000 --- a/libxklavier/xklavier_config.h +++ /dev/null @@ -1,376 +0,0 @@ -/** - * @file xklavier_config.h - */ - -#ifndef __XKLAVIER_CONFIG_H__ -#define __XKLAVIER_CONFIG_H__ - -#include <libxklavier/xklavier.h> - -/** - * Maximum name length, including '\'0' character - */ -#define XKL_MAX_CI_NAME_LENGTH 32 - -/** - * Maximum short description length, including '\\0' character. - * Important: this length is in bytes, so for unicode (UTF-8 encoding in - * XML file) the actual maximum length can be smaller. - */ -#define XKL_MAX_CI_SHORT_DESC_LENGTH 10 - -/** - * Maximum description length, including '\\0' character. - * Important: this length is in bytes, so for unicode (UTF-8 encoding in - * XML file) the actual maximum length can be smaller. - */ -#define XKL_MAX_CI_DESC_LENGTH 192 - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -/** - * The configuration item. Corresponds to XML element "configItem". - */ - typedef struct _XklConfigItem - { -/** - * The configuration item name. Corresponds to XML element "name". - */ - char name[XKL_MAX_CI_NAME_LENGTH]; - -/** - * The configuration item short description. Corresponds to XML element "shortDescription". - */ - char shortDescription[XKL_MAX_CI_DESC_LENGTH]; - -/** - * The configuration item description. Corresponds to XML element "description". - */ - char description[XKL_MAX_CI_DESC_LENGTH]; - } - XklConfigItem, *XklConfigItemPtr; - -/** - * Basic configuration params - */ - typedef struct _XklConfigRec - { -/** - * The keyboard model - */ - char *model; -/** - * The number of keyboard layouts - */ - int numLayouts; -/** - * The array of keyboard layouts - */ - char **layouts; -/** - * The number of keyboard layout variants - */ - int numVariants; -/** - * The array of keyboard layout variants (if any) - */ - char **variants; -/** - * The number of keyboard layout options - */ - int numOptions; -/** - * The array of keyboard layout options - */ - char **options; - } - XklConfigRec, *XklConfigRecPtr; -/** - * @defgroup xklconfiginitterm XKB configuration handling initialization and termination - * @{ - */ - -/** - * Initializes XML configuration-related structures - */ - extern void XklConfigInit( void ); - -/** - * Cleans XML configuration-related structures - */ - extern void XklConfigTerm( void ); - -/** - * Loads XML configuration registry - * @param fileName file name to load - * @return true on success - */ - extern Bool XklConfigLoadRegistryFromFile( const char* fileName ); - -/** - * Loads XML configuration registry - * @return true on success - */ - extern Bool XklConfigLoadRegistry( void ); - -/** - * Frees XML configuration registry - */ - extern void XklConfigFreeRegistry( void ); -/** @} */ - -/** - * @defgroup enum XKB configuration elements enumeration functions - * @{ - */ - -/** - * Callback type used for enumerating keyboard models, layouts, variants, options - * @param configItem is the item from registry - * @param userData is anything which can be stored into the pointer - */ - typedef void ( *ConfigItemProcessFunc ) ( const XklConfigItemPtr configItem, - void *userData ); - -/** - * Callback type used for enumerating keyboard option groups - * @param configItem is the item from registry - * @param allowMultipleSelection is a flag whether this group allows multiple selection - * @param userData is anything which can be stored into the pointer - */ - typedef void ( *GroupProcessFunc ) ( const XklConfigItemPtr configItem, - Bool allowMultipleSelection, - void *userData ); -/** - * Enumerates keyboard models from the XML configuration registry - * @param func is a callback to call for every model - * @param userData is anything which can be stored into the pointer - */ - extern void XklConfigEnumModels( ConfigItemProcessFunc func, - void *userData ); - -/** - * Enumerates keyboard layouts from the XML configuration registry - * @param func is a callback to call for every layout - * @param userData is anything which can be stored into the pointer - */ - extern void XklConfigEnumLayouts( ConfigItemProcessFunc func, - void *userData ); - -/** - * Enumerates keyboard layout variants from the XML configuration registry - * @param layoutName is the layout name for which variants will be listed - * @param func is a callback to call for every layout variant - * @param userData is anything which can be stored into the pointer - */ - extern void XklConfigEnumLayoutVariants( const char *layoutName, - ConfigItemProcessFunc func, - void *userData ); - -/** - * Enumerates keyboard option groups from the XML configuration registry - * @param func is a callback to call for every option group - * @param userData is anything which can be stored into the pointer - */ - extern void XklConfigEnumOptionGroups( GroupProcessFunc func, - void *userData ); - -/** - * Enumerates keyboard options from the XML configuration registry - * @param optionGroupName is the option group name for which variants - * will be listed - * @param func is a callback to call for every option - * @param userData is anything which can be stored into the pointer - */ - extern void XklConfigEnumOptions( const char *optionGroupName, - ConfigItemProcessFunc func, - void *userData ); - -/** @} */ - -/** - * @defgroup lookup XKB configuration element lookup functions - * @{ - */ - -/** - * Loads a keyboard model information from the XML configuration registry. - * @param ptr is a pointer to a XklConfigItem containing the name of the - * keyboard model. On successfull return, the descriptions are filled. - * @return True if appropriate element was found and loaded - */ - extern Bool XklConfigFindModel( XklConfigItemPtr ptr ); - -/** - * Loads a keyboard layout information from the XML configuration registry. - * @param ptr is a pointer to a XklConfigItem containing the name of the - * keyboard layout. On successfull return, the descriptions are filled. - * @return True if appropriate element was found and loaded - */ - extern Bool XklConfigFindLayout( XklConfigItemPtr ptr ); - -/** - * Loads a keyboard layout variant information from the XML configuration - * registry. - * @param layoutName is a name of the parent layout - * @param ptr is a pointer to a XklConfigItem containing the name of the - * keyboard layout variant. On successfull return, the descriptions are filled. - * @return True if appropriate element was found and loaded - */ - extern Bool XklConfigFindVariant( const char *layoutName, - XklConfigItemPtr ptr ); - -/** - * Loads a keyboard option group information from the XML configuration - * registry. - * @param ptr is a pointer to a XklConfigItem containing the name of the - * keyboard option group. On successfull return, the descriptions are filled. - * @param allowMultipleSelection is a pointer to some Bool variable to fill - * the corresponding attribute of XML element "group". - * @return True if appropriate element was found and loaded - */ - extern Bool XklConfigFindOptionGroup( XklConfigItemPtr ptr, - Bool * allowMultipleSelection ); - -/** - * Loads a keyboard option information from the XML configuration - * registry. - * @param optionGroupName is a name of the option group - * @param ptr is a pointer to a XklConfigItem containing the name of the - * keyboard option. On successfull return, the descriptions are filled. - * @return True if appropriate element was found and loaded - */ - extern Bool XklConfigFindOption( const char *optionGroupName, - XklConfigItemPtr ptr ); -/** @} */ - -/** - * @defgroup activation XKB configuration activation - * @{ - */ - -/** - * Activates some XKB configuration - * @param data is a valid XKB configuration - * description. Can be NULL - * @return True on success - * @see XklSetKeyAsSwitcher - * At the moment, accepts only _ONE_ layout. Later probably I'll improve this.. - */ - extern Bool XklConfigActivate( const XklConfigRecPtr data ); - -/** - * Loads the current XKB configuration (from X server) - * @param data is a buffer for XKB configuration - * @return True on success - */ - extern Bool XklConfigGetFromServer( XklConfigRecPtr data ); - -/** - * Loads the current XKB configuration (from backup) - * @param data is a buffer for XKB configuration - * @return True on success - * @see XklBackupNamesProp - */ - extern Bool XklConfigGetFromBackup( XklConfigRecPtr data ); - -/** - * Writes some XKB configuration into XKM/XKB file - * @param fileName is a name of the file to create - * @param data is a valid XKB configuration - * description. Can be NULL - * @param binary is a flag indicating whether the output file should be binary - * @return True on success - */ - extern Bool XklConfigWriteFile( const char *fileName, - const XklConfigRecPtr data, - const Bool binary ); - -/** @} */ - -/** - * @defgroup props Saving and restoring XKB configuration into X root window properties - * Generalizes XkbRF_GetNamesProp and XkbRF_SetNamesProp. - * @{ - */ - -/** - * Gets the XKB configuration from any root window property - * @param rulesAtomName is an atom name of the root window property to read - * @param rulesFileOut is a pointer to hold the file name - * @param configOut is a buffer to hold the result - - * all records are allocated using standard malloc - * @return True on success - */ - extern Bool XklGetNamesProp( Atom rulesAtomName, - char **rulesFileOut, - XklConfigRecPtr configOut ); - -/** - * Saves the XKB configuration into any root window property - * @param rulesAtomName is an atom name of the root window property to write - * @param rulesFile is a rules file name - * @param config is a configuration to save - * @return True on success - */ - extern Bool XklSetNamesProp( Atom rulesAtomName, - char *rulesFile, XklConfigRecPtr config ); - -/** - * Backups current XKB configuration into some property - - * if this property is not defined yet. - * @return True on success - */ - extern Bool XklBackupNamesProp( ); - -/** - * Restores XKB from the property saved by XklBackupNamesProp - * @return True on success - * @see XklBackupNamesProp - */ - extern Bool XklRestoreNamesProp( ); - -/** @} */ - -/** - * @defgroup xklconfig XklConfigRec management utilities - * Little utilities for managing XklConfigRec. - * @{ - */ - -/** - * Initializes the record (actually, fills it with 0-s) - * @param data is a record to initialize - */ - extern void XklConfigRecInit( XklConfigRecPtr data ); - -/** - * Resets the record (equal to Destroy and Init) - * @param data is a record to reset - */ - extern void XklConfigRecReset( XklConfigRecPtr data ); - -/** - * Cleans the record (frees all the non-null members) - * @param data is a record to clean - */ - extern void XklConfigRecDestroy( XklConfigRecPtr data ); - -/** - * Compares the records - * @param data1 is a record to compare - * @param data2 is another record - * @return True if records are same - */ - extern Bool XklConfigRecEquals( XklConfigRecPtr data1, XklConfigRecPtr data2 ); - -/** @} */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif diff --git a/libxklavier/xklavier_config_i18n.c b/libxklavier/xklavier_config_i18n.c index 9a91577..4ff9a70 100644 --- a/libxklavier/xklavier_config_i18n.c +++ b/libxklavier/xklavier_config_i18n.c @@ -1,6 +1,6 @@ +#include <iconv.h> #include <stdlib.h> #include <string.h> -#include <iconv.h> #include "config.h" @@ -16,218 +16,220 @@ #define MAX_LOCALE_LEN 128 -static char localeSubStrings[3][MAX_LOCALE_LEN]; +static gchar locale_sub_strings[3][MAX_LOCALE_LEN]; /* * some bad guys create LC_ALL=LC_CTYPE=ru_RU.UTF-8;LC_NUMERIC=C;LC_TIME=ru_RU.UTF-8;LC_COLLATE=ru_RU.UTF-8;LC_MONETARY=ru_RU.UTF-8;LC_MESSAGES=ru_RU.UTF-8;LC_PAPER=ru_RU.UTF-8;LC_NAME=ru_RU.UTF-8;LC_ADDRESS=ru_RU.UTF-8;LC_TELEPHONE=ru_RU.UTF-8;LC_MEASUREMENT=ru_RU.UTF-8;LC_IDENTIFICATION=ru_RU.UTF-8 */ -static const char *_XklParseLC_ALL2LC_MESSAGES( const char *lcAll ) +static const gchar * +xkl_parse_LC_ALL_to_LC_MESSAGES(const gchar * lc_all) { - const char *lcMsgPos = strstr( lcAll, "LC_MESSAGES=" ); - const char *lcMsgEnd; - size_t len; - static char buf[128]; - if( lcMsgPos == NULL ) - return lcAll; - lcMsgPos += 12; - lcMsgEnd = strchr( lcMsgPos, ';' ); - if( lcMsgEnd == NULL ) /* LC_MESSAGES is the last piece of LC_ALL */ - { - return lcMsgPos; /* safe to return! */ - } - len = lcMsgEnd - lcMsgPos; - if( len > sizeof( buf ) ) - len = sizeof( buf ); - strncpy( buf, lcMsgPos, len ); - buf[sizeof( buf ) - 1] = '\0'; - return buf; + const gchar *lc_message_pos = + g_strstr_len(lc_all, -1, "LC_MESSAGES="); + const gchar *lc_message_end; + size_t len; + static gchar buf[128]; + if (lc_message_pos == NULL) + return lc_all; + lc_message_pos += 12; + lc_message_end = g_strstr_len(lc_message_pos, -1, ";"); + if (lc_message_end == NULL) { /* LC_MESSAGES is the last piece of LC_ALL */ + return lc_message_pos; /* safe to return! */ + } + len = lc_message_end - lc_message_pos; + if (len > sizeof(buf)) + len = sizeof(buf); + g_strlcpy(buf, lc_message_pos, len); + return buf; } /* Taken from gnome-vfs */ -static Bool _XklGetCharset( const char **a ) +static gboolean +xkl_get_charset(const gchar ** a) { - static const char *charset = NULL; + static const gchar *charset = NULL; - if( charset == NULL ) - { - charset = getenv( "CHARSET" ); + if (charset == NULL) { + charset = g_getenv("CHARSET"); - if( charset == NULL || charset[0] == '\0' ) - { -/* taken from gnome-vfs */ + if (charset == NULL || charset[0] == '\0') { #ifdef HAVE_LANGINFO_CODESET - charset = nl_langinfo( CODESET ); - if( charset == NULL || charset[0] == '\0' ) - { + charset = nl_langinfo(CODESET); + if (charset == NULL || charset[0] == '\0') { #endif #ifdef HAVE_SETLOCALE - charset = setlocale( LC_CTYPE, NULL ); - if( charset == NULL || charset[0] == '\0' ) - { + charset = setlocale(LC_CTYPE, NULL); + if (charset == NULL || charset[0] == '\0') { #endif - charset = getenv( "LC_ALL" ); - if( charset == NULL || charset[0] == '\0' ) - { - charset = getenv( "LC_CTYPE" ); - if( charset == NULL || charset[0] == '\0' ) - charset = getenv( "LANG" ); - } + charset = getenv("LC_ALL"); + if (charset == NULL + || charset[0] == '\0') { + charset = + getenv("LC_CTYPE"); + if (charset == NULL + || charset[0] == '\0') + charset = + getenv("LANG"); + } #ifdef HAVE_SETLOCALE - } else - { - XklDebug( 150, "Using charset from setlocale: [%s]\n", charset ); - } + } else { + xkl_debug(150, + "Using charset from setlocale: [%s]\n", + charset); + } #endif #ifdef HAVE_LANGINFO_CODESET - } else - { - XklDebug( 150, "Using charset from nl_langinfo: [%s]\n", charset ); - } + } else { + xkl_debug(150, + "Using charset from nl_langinfo: [%s]\n", + charset); + } #endif - } - } - - if( charset != NULL && *charset != '\0' ) - { - *a = charset; - return ( charset != NULL && strstr( charset, "UTF-8" ) != NULL ); - } - /* Assume this for compatibility at present. */ - *a = "US-ASCII"; - XklDebug( 150, "Using charset fallback: [%s]\n", *a ); - - return False; + } + } + + if (charset != NULL && *charset != '\0') { + *a = charset; + return (charset != NULL + && g_strstr_len(charset, -1, "UTF-8") != NULL); + } + /* Assume this for compatibility at present. */ + *a = "US-ASCII"; + xkl_debug(150, "Using charset fallback: [%s]\n", *a); + + return FALSE; } -char *_XklLocaleFromUtf8( const char *utf8string ) +gchar * +xkl_locale_from_utf8(const gchar * utf8string) { - size_t len; - - iconv_t converter; - char converted[XKL_MAX_CI_DESC_LENGTH]; - char *convertedStart = converted; - char *utfStart = ( char * ) utf8string; - size_t clen = XKL_MAX_CI_DESC_LENGTH - 1; - const char *charset; - - static Bool alreadyWarned = False; - - if( utf8string == NULL ) - return NULL; - - len = strlen( utf8string ); - - if( _XklGetCharset( &charset ) ) - return strdup( utf8string ); - - converter = iconv_open( charset, "UTF-8" ); - if( converter == ( iconv_t ) - 1 ) - { - if( !alreadyWarned ) - { - alreadyWarned = True; - XklDebug( 0, - "Unable to convert MIME info from UTF-8 to the current locale %s. MIME info will probably display wrong.", - charset ); - } - return strdup( utf8string ); - } - - if( iconv( converter, &utfStart, &len, &convertedStart, &clen ) == -1 ) - { - XklDebug( 0, - "Unable to convert %s from UTF-8 to %s, this string will probably display wrong.", - utf8string, charset ); - return strdup( utf8string ); - } - *convertedStart = '\0'; - - iconv_close( converter ); - - return strdup( converted ); + size_t len; + + iconv_t converter; + gchar converted[XKL_MAX_CI_DESC_LENGTH]; + gchar *converted_start = converted; + gchar *utf_start = (char *) utf8string; + size_t clen = XKL_MAX_CI_DESC_LENGTH - 1; + const gchar *charset; + + static gboolean already_warned = FALSE; + + if (utf8string == NULL) + return NULL; + + len = strlen(utf8string); + + if (xkl_get_charset(&charset)) + return g_strdup(utf8string); + + converter = iconv_open(charset, "UTF-8"); + if (converter == (iconv_t) - 1) { + if (!already_warned) { + already_warned = TRUE; + xkl_debug(0, + "Unable to convert MIME info from UTF-8 " + "to the current locale %s. " + "MIME info will probably display wrong.", + charset); + } + return g_strdup(utf8string); + } + + if (iconv(converter, &utf_start, &len, &converted_start, &clen) == + -1) { + xkl_debug(0, + "Unable to convert %s from UTF-8 to %s, " + "this string will probably display wrong.", + utf8string, charset); + return g_strdup(utf8string); + } + *converted_start = '\0'; + + iconv_close(converter); + + return g_strdup(converted); } /* * country[_LANG[.ENCODING]] - any other ideas? */ -void _XklI18NInit( void ) +void +xkl_i18n_init(void) { - char *dotPos; - char *underscorePos; - const char *locale = NULL; - char *curSubstring; + gchar *dot_pos; + gchar *underscore_pos; + const gchar *locale = NULL; + gchar *cur_substring; - localeSubStrings[0][0] = localeSubStrings[1][0] = - localeSubStrings[2][0] = '\0'; + locale_sub_strings[0][0] = locale_sub_strings[1][0] = + locale_sub_strings[2][0] = '\0'; #ifdef HAVE_SETLOCALE - locale = setlocale( LC_MESSAGES, NULL ); + locale = setlocale(LC_MESSAGES, NULL); #endif - if( locale == NULL || locale[0] == '\0' ) - { - locale = getenv( "LC_MESSAGES" ); - if( locale == NULL || locale[0] == '\0' ) - { - locale = getenv( "LC_ALL" ); - if( locale == NULL || locale[0] == '\0' ) - locale = getenv( "LANG" ); - else - locale = _XklParseLC_ALL2LC_MESSAGES( locale ); - } - } - - if( locale == NULL ) - { - XklDebug( 0, "Could not find locale - can be problems with i18n" ); - return; - } - - strncpy( localeSubStrings[0], locale, MAX_LOCALE_LEN ); - - curSubstring = localeSubStrings[1]; - - dotPos = strchr( locale, '.' ); - if( dotPos != NULL ) - { - int idx = dotPos - locale; - if( idx >= MAX_LOCALE_LEN ) - idx = MAX_LOCALE_LEN - 1; - strncpy( curSubstring, locale, idx ); - curSubstring[idx] = '\0'; - curSubstring += MAX_LOCALE_LEN; - } - - underscorePos = strchr( locale, '_' ); - if( underscorePos != NULL && ( dotPos == NULL || dotPos > underscorePos ) ) - { - int idx = underscorePos - locale; - if( idx >= MAX_LOCALE_LEN ) - idx = MAX_LOCALE_LEN - 1; - strncpy( curSubstring, locale, idx ); - curSubstring[idx] = '\0'; - } - - XklDebug( 150, "Locale search order:\n" ); - 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] ); + if (locale == NULL || locale[0] == '\0') { + locale = getenv("LC_MESSAGES"); + if (locale == NULL || locale[0] == '\0') { + locale = getenv("LC_ALL"); + if (locale == NULL || locale[0] == '\0') + locale = getenv("LANG"); + else + locale = + xkl_parse_LC_ALL_to_LC_MESSAGES + (locale); + } + } + + if (locale == NULL) { + xkl_debug(0, + "Could not find locale - can be problems with i18n"); + return; + } + + g_strlcpy(locale_sub_strings[0], locale, MAX_LOCALE_LEN); + + cur_substring = locale_sub_strings[1]; + + dot_pos = g_strstr_len(locale, -1, "."); + if (dot_pos != NULL) { + gint idx = dot_pos - locale; + if (idx >= MAX_LOCALE_LEN) + idx = MAX_LOCALE_LEN - 1; + g_strlcpy(cur_substring, locale, idx); + cur_substring += MAX_LOCALE_LEN; + } + + underscore_pos = strchr(locale, '_'); + if (underscore_pos != NULL && + (dot_pos == NULL || dot_pos > underscore_pos)) { + gint idx = underscore_pos - locale; + if (idx >= MAX_LOCALE_LEN) + idx = MAX_LOCALE_LEN - 1; + g_strlcpy(cur_substring, locale, idx); + } + + xkl_debug(150, "Locale search order:\n"); + /* full locale - highest priority */ + xkl_debug(150, " 0: %s\n", locale_sub_strings[0]); + xkl_debug(150, " 1: %s\n", locale_sub_strings[1]); + xkl_debug(150, " 2: %s\n", locale_sub_strings[2]); } -int _XklGetLanguagePriority( const char *lang ) +gint +xkl_get_language_priority(const gchar * lang) { - int i, priority = -1; - - for( i = sizeof( localeSubStrings ) / sizeof( localeSubStrings[0] ); - --i >= 0; ) - { - if( localeSubStrings[0][0] == '\0' ) - continue; - - if( !strcmp( lang, localeSubStrings[i] ) ) - { - priority = i; - break; - } - } - return priority; + gint i, priority = -1; + + for (i = + sizeof(locale_sub_strings) / sizeof(locale_sub_strings[0]); + --i >= 0;) { + if (locale_sub_strings[0][0] == '\0') + continue; + + if (!g_ascii_strcasecmp(lang, locale_sub_strings[i])) { + priority = i; + break; + } + } + return priority; } diff --git a/libxklavier/xklavier_config_xkb.c b/libxklavier/xklavier_config_xkb.c index 05843fe..39b74e8 100644 --- a/libxklavier/xklavier_config_xkb.c +++ b/libxklavier/xklavier_config_xkb.c @@ -1,6 +1,6 @@ #include <errno.h> -#include <string.h> #include <locale.h> +#include <string.h> #include <unistd.h> #include <sys/stat.h> #include <sys/param.h> @@ -30,415 +30,504 @@ #include <X11/keysymdef.h> #ifdef XKB_HEADERS_PRESENT -static XkbRF_RulesPtr _xklRules; +static XkbRF_RulesPtr xkl_rules; -static XkbRF_RulesPtr _XklLoadRulesSet( void ) +static XkbRF_RulesPtr +xkl_rules_set_load(XklEngine * engine) { - XkbRF_RulesPtr rulesSet = NULL; - char fileName[MAXPATHLEN] = ""; - char *rf = _XklGetRulesSetName( XKB_DEFAULT_RULESET ); - char *locale = NULL; - - if( rf == NULL ) - { - _xklLastErrorMsg = "Could not find the XKB rules set"; - return NULL; - } - - locale = setlocale( LC_ALL, NULL ); - - snprintf( fileName, sizeof fileName, XKB_BASE "/rules/%s", rf ); - XklDebug( 160, "Loading rules from [%s]\n", fileName ); - - rulesSet = XkbRF_Load( fileName, locale, True, True ); - - if( rulesSet == NULL ) - { - _xklLastErrorMsg = "Could not load rules"; - return NULL; - } - return rulesSet; + XkbRF_RulesPtr rules_set = NULL; + char file_name[MAXPATHLEN] = ""; + char *rf = + xkl_engine_get_ruleset_name(engine, XKB_DEFAULT_RULESET); + char *locale = NULL; + + if (rf == NULL) { + xkl_last_error_message = + "Could not find the XKB rules set"; + return NULL; + } + + locale = setlocale(LC_ALL, NULL); + + snprintf(file_name, sizeof file_name, XKB_BASE "/rules/%s", rf); + xkl_debug(160, "Loading rules from [%s]\n", file_name); + + rules_set = XkbRF_Load(file_name, locale, True, True); + + if (rules_set == NULL) { + xkl_last_error_message = "Could not load rules"; + return NULL; + } + return rules_set; } -static void _XklFreeRulesSet( void ) +static void +xkl_rules_set_free(void) { - if ( _xklRules ) - XkbRF_Free( _xklRules, True ); - _xklRules = NULL; + if (xkl_rules) + XkbRF_Free(xkl_rules, True); + xkl_rules = NULL; } #endif -void _XklXkbConfigInit( void ) +void +xkl_xkb_init_config_registry(XklConfigRegistry * config) { #ifdef XKB_HEADERS_PRESENT - XkbInitAtoms( NULL ); + XkbInitAtoms(NULL); #endif } -Bool _XklXkbConfigLoadRegistry( void ) +gboolean +xkl_xkb_load_config_registry(XklConfigRegistry * config) { - struct stat statBuf; - char fileName[MAXPATHLEN] = ""; - char* rf = _XklGetRulesSetName( XKB_DEFAULT_RULESET ); + struct stat stat_buf; + char file_name[MAXPATHLEN] = ""; + char *rf = + xkl_engine_get_ruleset_name(xkl_config_registry_get_engine + (config), + XKB_DEFAULT_RULESET); - if ( rf == NULL ) - return False; + if (rf == NULL) + return FALSE; - snprintf( fileName, sizeof fileName, XKB_BASE "/rules/%s.xml", rf ); + snprintf(file_name, sizeof file_name, XKB_BASE "/rules/%s.xml", + rf); - if( stat( fileName, &statBuf ) != 0 ) - { - strncpy( fileName, XML_CFG_FALLBACK_PATH, sizeof fileName ); - fileName[ MAXPATHLEN - 1 ] = '\0'; - } + if (stat(file_name, &stat_buf) != 0) { + g_strlcpy(file_name, XML_CFG_FALLBACK_PATH, + sizeof file_name); + } - return XklConfigLoadRegistryFromFile( fileName ); + return xkl_config_registry_load_from_file(config, file_name); } #ifdef XKB_HEADERS_PRESENT -Bool _XklXkbConfigPrepareNative( const XklConfigRecPtr data, XkbComponentNamesPtr componentNamesPtr ) +gboolean +xkl_xkb_config_native_prepare(XklEngine * engine, + const XklConfigRec * data, + XkbComponentNamesPtr component_names_ptr) { - XkbRF_VarDefsRec _xklVarDefs; - Bool gotComponents; - - memset( &_xklVarDefs, 0, sizeof( _xklVarDefs ) ); - - _xklRules = _XklLoadRulesSet(); - if( !_xklRules ) - { - return False; - } - - _xklVarDefs.model = ( char * ) data->model; - - if( data->layouts != NULL ) - _xklVarDefs.layout = _XklConfigRecMergeLayouts( data ); - - if( data->variants != NULL ) - _xklVarDefs.variant = _XklConfigRecMergeVariants( data ); - - if( data->options != NULL ) - _xklVarDefs.options = _XklConfigRecMergeOptions( data ); - - gotComponents = XkbRF_GetComponents( _xklRules, &_xklVarDefs, componentNamesPtr ); - - free( _xklVarDefs.layout ); - free( _xklVarDefs.variant ); - free( _xklVarDefs.options ); - - if( !gotComponents ) - { - _xklLastErrorMsg = "Could not translate rules into components"; - /* Just cleanup the stuff in case of failure */ - _XklXkbConfigCleanupNative( componentNamesPtr ); - - return False; - } - - if ( _xklDebugLevel >= 200 ) - { - XklDebug( 200, "keymap: %s\n", componentNamesPtr->keymap ); - XklDebug( 200, "keycodes: %s\n", componentNamesPtr->keycodes ); - XklDebug( 200, "compat: %s\n", componentNamesPtr->compat ); - XklDebug( 200, "types: %s\n", componentNamesPtr->types ); - XklDebug( 200, "symbols: %s\n", componentNamesPtr->symbols ); - XklDebug( 200, "geometry: %s\n", componentNamesPtr->geometry ); - } - return True; + XkbRF_VarDefsRec xkl_var_defs; + gboolean got_components; + + memset(&xkl_var_defs, 0, sizeof(xkl_var_defs)); + + xkl_rules = xkl_rules_set_load(engine); + if (!xkl_rules) { + return FALSE; + } + + xkl_var_defs.model = (char *) data->model; + + if (data->layouts != NULL) + xkl_var_defs.layout = xkl_config_rec_merge_layouts(data); + + if (data->variants != NULL) + xkl_var_defs.variant = xkl_config_rec_merge_variants(data); + + if (data->options != NULL) + xkl_var_defs.options = xkl_config_rec_merge_options(data); + + got_components = + XkbRF_GetComponents(xkl_rules, &xkl_var_defs, + component_names_ptr); + + g_free(xkl_var_defs.layout); + g_free(xkl_var_defs.variant); + g_free(xkl_var_defs.options); + + if (!got_components) { + xkl_last_error_message = + "Could not translate rules into components"; + /* Just cleanup the stuff in case of failure */ + xkl_xkb_config_native_cleanup(engine, component_names_ptr); + + return FALSE; + } + + if (xkl_debug_level >= 200) { + xkl_debug(200, "keymap: %s\n", + component_names_ptr->keymap); + xkl_debug(200, "keycodes: %s\n", + component_names_ptr->keycodes); + xkl_debug(200, "compat: %s\n", + component_names_ptr->compat); + xkl_debug(200, "types: %s\n", component_names_ptr->types); + xkl_debug(200, "symbols: %s\n", + component_names_ptr->symbols); + xkl_debug(200, "geometry: %s\n", + component_names_ptr->geometry); + } + return TRUE; } -void _XklXkbConfigCleanupNative( XkbComponentNamesPtr componentNamesPtr ) +void +xkl_xkb_config_native_cleanup(XklEngine * engine, + XkbComponentNamesPtr component_names_ptr) { - _XklFreeRulesSet(); - - free(componentNamesPtr->keymap); - free(componentNamesPtr->keycodes); - free(componentNamesPtr->compat); - free(componentNamesPtr->types); - free(componentNamesPtr->symbols); - free(componentNamesPtr->geometry); + xkl_rules_set_free(); + + g_free(component_names_ptr->keymap); + g_free(component_names_ptr->keycodes); + g_free(component_names_ptr->compat); + g_free(component_names_ptr->types); + g_free(component_names_ptr->symbols); + g_free(component_names_ptr->geometry); } -static XkbDescPtr _XklConfigGetKeyboard( XkbComponentNamesPtr componentNamesPtr, Bool activate ) +static XkbDescPtr +xkl_config_get_keyboard(XklEngine * engine, + XkbComponentNamesPtr component_names_ptr, + gboolean activate) { - XkbDescPtr xkb = NULL; + XkbDescPtr xkb = NULL; #if 0 - xkb = XkbGetKeyboardByName( _xklDpy, - XkbUseCoreKbd, - &componentNames, - XkbGBN_AllComponentsMask & - ( ~XkbGBN_GeometryMask ), - XkbGBN_AllComponentsMask & - ( ~XkbGBN_GeometryMask ), - activate ); + xkb = XkbGetKeyboardByName(_xklDpy, + XkbUseCoreKbd, + &componentNames, + XkbGBN_AllComponentsMask & + (~XkbGBN_GeometryMask), + XkbGBN_AllComponentsMask & + (~XkbGBN_GeometryMask), activate); #else - char xkmFN[L_tmpnam]; - char xkbFN[L_tmpnam]; - FILE* tmpxkm; - XkbFileInfo result; - int xkmloadres; - - if ( tmpnam( xkmFN ) != NULL && - tmpnam( xkbFN ) != NULL ) - { - pid_t cpid, pid; - int status = 0; - FILE *tmpxkb; - - XklDebug( 150, "tmp XKB/XKM file names: [%s]/[%s]\n", xkbFN, xkmFN ); - if( (tmpxkb = fopen( xkbFN, "w" )) != NULL ) - { - fprintf( tmpxkb, "xkb_keymap {\n" ); - fprintf( tmpxkb, " xkb_keycodes { include \"%s\" };\n", componentNamesPtr->keycodes ); - fprintf( tmpxkb, " xkb_types { include \"%s\" };\n", componentNamesPtr->types ); - fprintf( tmpxkb, " xkb_compat { include \"%s\" };\n", componentNamesPtr->compat ); - fprintf( tmpxkb, " xkb_symbols { include \"%s\" };\n", componentNamesPtr->symbols ); - fprintf( tmpxkb, " xkb_geometry { include \"%s\" };\n", componentNamesPtr->geometry ); - fprintf( tmpxkb, "};\n" ); - fclose( tmpxkb ); - - XklDebug( 150, "xkb_keymap {\n" - " xkb_keycodes { include \"%s\" };\n" - " xkb_types { include \"%s\" };\n" - " xkb_compat { include \"%s\" };\n" - " xkb_symbols { include \"%s\" };\n" - " xkb_geometry { include \"%s\" };\n};\n", - componentNamesPtr->keycodes, - componentNamesPtr->types, - componentNamesPtr->compat, - componentNamesPtr->symbols, - componentNamesPtr->geometry ); - - cpid=fork(); - switch( cpid ) - { - case -1: - XklDebug( 0, "Could not fork: %d\n", errno ); - break; - case 0: - /* child */ - XklDebug( 160, "Executing %s\n", XKBCOMP ); - XklDebug( 160, "%s %s %s %s %s %s %s\n", - XKBCOMP, XKBCOMP, "-I", "-I" XKB_BASE, "-xkm", xkbFN, xkmFN ); - execl( XKBCOMP, XKBCOMP, "-I", "-I" XKB_BASE, "-xkm", xkbFN, xkmFN, NULL ); - XklDebug( 0, "Could not exec %s: %d\n", XKBCOMP, errno ); - exit( 1 ); - default: - /* parent */ - pid = waitpid( cpid, &status, 0 ); - XklDebug( 150, "Return status of %d (well, started %d): %d\n", pid, cpid, status ); - memset( (char *)&result, 0, sizeof(result) ); - result.xkb = XkbAllocKeyboard(); - - if( Success == XkbChangeKbdDisplay( _xklDpy, &result ) ) - { - XklDebug( 150, "Hacked the kbddesc - set the display...\n" ); - if( (tmpxkm = fopen( xkmFN, "r" )) != NULL ) - { - xkmloadres = XkmReadFile( tmpxkm, XkmKeymapLegal, XkmKeymapLegal, &result); - XklDebug( 150, "Loaded %s output as XKM file, got %d (comparing to %d)\n", - XKBCOMP, (int)xkmloadres, (int)XkmKeymapLegal ); - if ( (int)xkmloadres != (int)XkmKeymapLegal ) - { - XklDebug( 150, "Loaded legal keymap\n" ); - if( activate ) - { - XklDebug( 150, "Activating it...\n" ); - if( XkbWriteToServer(&result) ) - { - XklDebug( 150, "Updating the keyboard...\n" ); - xkb = result.xkb; - } else - { - XklDebug( 0, "Could not write keyboard description to the server\n" ); - } - } else /* no activate, just load */ - xkb = result.xkb; - } else /* could not load properly */ - { - XklDebug( 0, "Could not load %s output as XKM file, got %d (asked %d)\n", - XKBCOMP, (int)xkmloadres, (int)XkmKeymapLegal ); - } - fclose( tmpxkm ); - XklDebug( 160, "Unlinking the temporary xkm file %s\n", xkmFN ); - if ( _xklDebugLevel < 500 ) /* don't remove on high debug levels! */ - { - if ( remove( xkmFN ) == -1 ) - XklDebug( 0, "Could not unlink the temporary xkm file %s: %d\n", - xkmFN, errno ); - } else - XklDebug( 500, "Well, not really - the debug level is too high: %d\n", _xklDebugLevel ); - } else /* could not open the file */ - { - XklDebug( 0, "Could not open the temporary xkm file %s\n", xkmFN ); - } - } else /* could not assign to display */ - { - XklDebug( 0, "Could not change the keyboard description to display\n" ); - } - if ( xkb == NULL ) - XkbFreeKeyboard( result.xkb, XkbAllComponentsMask, True ); - break; - } - XklDebug( 160, "Unlinking the temporary xkb file %s\n", xkbFN ); - if ( _xklDebugLevel < 500 ) /* don't remove on high debug levels! */ - { - if ( remove( xkbFN ) == -1 ) - XklDebug( 0, "Could not unlink the temporary xkb file %s: %d\n", - xkbFN, errno ); - } else - XklDebug( 500, "Well, not really - the debug level is too high: %d\n", _xklDebugLevel ); - } else /* could not open input tmp file */ - { - XklDebug( 0, "Could not open tmp XKB file [%s]: %d\n", xkbFN, errno ); - } - } else - { - XklDebug( 0, "Could not get tmp names\n" ); - } + char xkm_fn[L_tmpnam]; + char xkb_fn[L_tmpnam]; + FILE *tmpxkm; + XkbFileInfo result; + int xkmloadres; + + Display *display = xkl_engine_get_display(engine); + + if (tmpnam(xkm_fn) != NULL && tmpnam(xkb_fn) != NULL) { + pid_t cpid, pid; + int status = 0; + FILE *tmpxkb; + + xkl_debug(150, "tmp XKB/XKM file names: [%s]/[%s]\n", + xkb_fn, xkm_fn); + if ((tmpxkb = fopen(xkb_fn, "w")) != NULL) { + fprintf(tmpxkb, "xkb_keymap {\n"); + fprintf(tmpxkb, + " xkb_keycodes { include \"%s\" };\n", + component_names_ptr->keycodes); + fprintf(tmpxkb, + " xkb_types { include \"%s\" };\n", + component_names_ptr->types); + fprintf(tmpxkb, + " xkb_compat { include \"%s\" };\n", + component_names_ptr->compat); + fprintf(tmpxkb, + " xkb_symbols { include \"%s\" };\n", + component_names_ptr->symbols); + fprintf(tmpxkb, + " xkb_geometry { include \"%s\" };\n", + component_names_ptr->geometry); + fprintf(tmpxkb, "};\n"); + fclose(tmpxkb); + + xkl_debug(150, "xkb_keymap {\n" + " xkb_keycodes { include \"%s\" };\n" + " xkb_types { include \"%s\" };\n" + " xkb_compat { include \"%s\" };\n" + " xkb_symbols { include \"%s\" };\n" + " xkb_geometry { include \"%s\" };\n};\n", + component_names_ptr->keycodes, + component_names_ptr->types, + component_names_ptr->compat, + component_names_ptr->symbols, + component_names_ptr->geometry); + + cpid = fork(); + switch (cpid) { + case -1: + xkl_debug(0, "Could not fork: %d\n", + errno); + break; + case 0: + /* child */ + xkl_debug(160, "Executing %s\n", XKBCOMP); + xkl_debug(160, "%s %s %s %s %s %s %s\n", + XKBCOMP, XKBCOMP, "-I", + "-I" XKB_BASE, "-xkm", xkb_fn, + xkm_fn); + execl(XKBCOMP, XKBCOMP, "-I", + "-I" XKB_BASE, "-xkm", xkb_fn, + xkm_fn, NULL); + xkl_debug(0, "Could not exec %s: %d\n", + XKBCOMP, errno); + exit(1); + default: + /* parent */ + pid = waitpid(cpid, &status, 0); + xkl_debug(150, + "Return status of %d (well, started %d): %d\n", + pid, cpid, status); + memset((char *) &result, 0, + sizeof(result)); + result.xkb = XkbAllocKeyboard(); + + if (Success == + XkbChangeKbdDisplay(display, + &result)) { + xkl_debug(150, + "Hacked the kbddesc - set the display...\n"); + if ((tmpxkm = + fopen(xkm_fn, "r")) != NULL) { + xkmloadres = + XkmReadFile(tmpxkm, + XkmKeymapLegal, + XkmKeymapLegal, + &result); + xkl_debug(150, + "Loaded %s output as XKM file, got %d (comparing to %d)\n", + XKBCOMP, + (int) xkmloadres, + (int) + XkmKeymapLegal); + if ((int) xkmloadres != + (int) XkmKeymapLegal) { + xkl_debug(150, + "Loaded legal keymap\n"); + if (activate) { + xkl_debug + (150, + "Activating it...\n"); + if (XkbWriteToServer(&result)) { + xkl_debug + (150, + "Updating the keyboard...\n"); + xkb = result.xkb; + } else { + xkl_debug + (0, + "Could not write keyboard description to the server\n"); + } + } else /* no activate, just load */ + xkb = + result. + xkb; + } else { /* could not load properly */ + + xkl_debug(0, + "Could not load %s output as XKM file, got %d (asked %d)\n", + XKBCOMP, + (int) + xkmloadres, + (int) + XkmKeymapLegal); + } + fclose(tmpxkm); + xkl_debug(160, + "Unlinking the temporary xkm file %s\n", + xkm_fn); + if (xkl_debug_level < 500) { /* don't remove on high debug levels! */ + if (remove(xkm_fn) + == -1) + xkl_debug + (0, + "Could not unlink the temporary xkm file %s: %d\n", + xkm_fn, + errno); + } else + xkl_debug(500, + "Well, not really - the debug level is too high: %d\n", + xkl_debug_level); + } else { /* could not open the file */ + + xkl_debug(0, + "Could not open the temporary xkm file %s\n", + xkm_fn); + } + } else { /* could not assign to display */ + + xkl_debug(0, + "Could not change the keyboard description to display\n"); + } + if (xkb == NULL) + XkbFreeKeyboard(result.xkb, + XkbAllComponentsMask, + True); + break; + } + xkl_debug(160, + "Unlinking the temporary xkb file %s\n", + xkb_fn); + if (xkl_debug_level < 500) { /* don't remove on high debug levels! */ + if (remove(xkb_fn) == -1) + xkl_debug(0, + "Could not unlink the temporary xkb file %s: %d\n", + xkb_fn, errno); + } else + xkl_debug(500, + "Well, not really - the debug level is too high: %d\n", + xkl_debug_level); + } else { /* could not open input tmp file */ + + xkl_debug(0, + "Could not open tmp XKB file [%s]: %d\n", + xkb_fn, errno); + } + } else { + xkl_debug(0, "Could not get tmp names\n"); + } #endif - return xkb; + return xkb; } -#else /* no XKB headers */ -Bool _XklXkbConfigPrepareNative( const XklConfigRecPtr data, void * componentNamesPtr ) +#else /* no XKB headers */ +gboolean +xkl_xkb_config_native_prepare(const XklConfigRec * data, + gpointer componentNamesPtr) { - return False; + return FALSE; } -void _XklXkbConfigCleanupNative( void * componentNamesPtr ) +void +_XklXkbConfigCleanupNative(gpointer componentNamesPtr) { } #endif /* check only client side support */ -Bool _XklXkbConfigMultipleLayoutsSupported( void ) +gboolean +xkl_xkb_multiple_layouts_supported(XklEngine * engine) { - enum { NON_SUPPORTED, SUPPORTED, UNCHECKED }; + enum { NON_SUPPORTED, SUPPORTED, UNCHECKED }; - static int supportState = UNCHECKED; + static int support_state = UNCHECKED; - if( supportState == UNCHECKED ) - { - XklConfigRec data; - char *layouts[] = { "us", "de" }; - char *variants[] = { NULL, NULL }; + if (support_state == UNCHECKED) { + XklConfigRec data; + char *layouts[] = { "us", "de", NULL }; + char *variants[] = { NULL, NULL, NULL }; #ifdef XKB_HEADERS_PRESENT - XkbComponentNamesRec componentNames; - memset( &componentNames, 0, sizeof( componentNames ) ); + XkbComponentNamesRec component_names; + memset(&component_names, 0, sizeof(component_names)); #endif - data.model = "pc105"; - data.numVariants = - data.numLayouts = 2; - data.numOptions = 0; - data.layouts = layouts; - data.variants = variants; - data.options = NULL; + data.model = "pc105"; + data.layouts = layouts; + data.variants = variants; + data.options = NULL; - XklDebug( 100, "!!! Checking multiple layouts support\n" ); - supportState = NON_SUPPORTED; + xkl_debug(100, "!!! Checking multiple layouts support\n"); + support_state = NON_SUPPORTED; #ifdef XKB_HEADERS_PRESENT - if( _XklXkbConfigPrepareNative( &data, &componentNames ) ) - { - XklDebug( 100, "!!! Multiple layouts ARE supported\n" ); - supportState = SUPPORTED; - _XklXkbConfigCleanupNative( &componentNames ); - } else - { - XklDebug( 100, "!!! Multiple layouts ARE NOT supported\n" ); - } + if (xkl_xkb_config_native_prepare + (engine, &data, &component_names)) { + xkl_debug(100, + "!!! Multiple layouts ARE supported\n"); + support_state = SUPPORTED; + xkl_xkb_config_native_cleanup(engine, + &component_names); + } else { + xkl_debug(100, + "!!! Multiple layouts ARE NOT supported\n"); + } #endif - } - return supportState == SUPPORTED; + } + return support_state == SUPPORTED; } -Bool _XklXkbConfigActivate( const XklConfigRecPtr data ) +gboolean +xkl_xkb_activate_config_rec(XklEngine * engine, const XklConfigRec * data) { - Bool rv = False; + gboolean rv = FALSE; #if 0 - { - int i; - XklDebug( 150, "New model: [%s]\n", data->model ); - XklDebug( 150, "New layouts: %p\n", data->layouts ); - for( i = data->numLayouts; --i >= 0; ) - XklDebug( 150, "New layout[%d]: [%s]\n", i, data->layouts[i] ); - XklDebug( 150, "New variants: %p\n", data->variants ); - for( i = data->numVariants; --i >= 0; ) - XklDebug( 150, "New variant[%d]: [%s]\n", i, data->variants[i] ); - XklDebug( 150, "New options: %p\n", data->options ); - for( i = data->numOptions; --i >= 0; ) - XklDebug( 150, "New option[%d]: [%s]\n", i, data->options[i] ); - } + { + int i; + XklDebug(150, "New model: [%s]\n", data->model); + XklDebug(150, "New layouts: %p\n", data->layouts); + for (i = data->numLayouts; --i >= 0;) + XklDebug(150, "New layout[%d]: [%s]\n", i, + data->layouts[i]); + XklDebug(150, "New variants: %p\n", data->variants); + for (i = data->numVariants; --i >= 0;) + XklDebug(150, "New variant[%d]: [%s]\n", i, + data->variants[i]); + XklDebug(150, "New options: %p\n", data->options); + for (i = data->numOptions; --i >= 0;) + XklDebug(150, "New option[%d]: [%s]\n", i, + data->options[i]); + } #endif #ifdef XKB_HEADERS_PRESENT - XkbComponentNamesRec componentNames; - memset( &componentNames, 0, sizeof( componentNames ) ); - - if( _XklXkbConfigPrepareNative( data, &componentNames ) ) - { - XkbDescPtr xkb; - xkb = _XklConfigGetKeyboard( &componentNames, True ); - if( xkb != NULL ) - { - if( XklSetNamesProp - ( 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"; - XkbFreeKeyboard( xkb, XkbAllComponentsMask, True ); - } else - { - _xklLastErrorMsg = "Could not load keyboard description"; - } - _XklXkbConfigCleanupNative( &componentNames ); - } + XkbComponentNamesRec component_names; + memset(&component_names, 0, sizeof(component_names)); + + if (xkl_xkb_config_native_prepare(engine, data, &component_names)) { + XkbDescPtr xkb; + xkb = + xkl_config_get_keyboard(engine, &component_names, + TRUE); + if (xkb != NULL) { + if (xkl_config_rec_set_to_root_window_property + (data, + xkl_engine_priv(engine, base_config_atom), + xkl_engine_get_ruleset_name(engine, + XKB_DEFAULT_RULESET), + engine)) + /* We do not need to check the result of _XklGetRulesSetName - + because PrepareBeforeKbd did it for us */ + rv = TRUE; + else + xkl_last_error_message = + "Could not set names property"; + XkbFreeKeyboard(xkb, XkbAllComponentsMask, True); + } else { + xkl_last_error_message = + "Could not load keyboard description"; + } + xkl_xkb_config_native_cleanup(engine, &component_names); + } #endif - return rv; + return rv; } -Bool _XklXkbConfigWriteFile( const char *fileName, - const XklConfigRecPtr data, - const Bool binary ) +gboolean +xkl_xkb_write_config_rec_to_file(XklEngine * engine, const char *file_name, + const XklConfigRec * data, + const gboolean binary) { - Bool rv = False; + gboolean rv = FALSE; #ifdef XKB_HEADERS_PRESENT - XkbComponentNamesRec componentNames; - FILE *output = fopen( fileName, "w" ); - XkbFileInfo dumpInfo; - - if( output == NULL ) - { - _xklLastErrorMsg = "Could not open the XKB file"; - return False; - } - - memset( &componentNames, 0, sizeof( componentNames ) ); - - if( _XklXkbConfigPrepareNative( data, &componentNames ) ) - { - XkbDescPtr xkb; - xkb = _XklConfigGetKeyboard( &componentNames, False ); - if( xkb != NULL ) - { - dumpInfo.defined = 0; - dumpInfo.xkb = xkb; - dumpInfo.type = XkmKeymapFile; - if( binary ) - rv = XkbWriteXKMFile( output, &dumpInfo ); - else - rv = XkbWriteXKBFile( output, &dumpInfo, True, NULL, NULL ); - - XkbFreeKeyboard( xkb, XkbGBN_AllComponentsMask, True ); - } else - _xklLastErrorMsg = "Could not load keyboard description"; - _XklXkbConfigCleanupNative( &componentNames ); - } - fclose( output ); + XkbComponentNamesRec component_names; + FILE *output = fopen(file_name, "w"); + XkbFileInfo dump_info; + + if (output == NULL) { + xkl_last_error_message = "Could not open the XKB file"; + return FALSE; + } + + memset(&component_names, 0, sizeof(component_names)); + + if (xkl_xkb_config_native_prepare(engine, data, &component_names)) { + XkbDescPtr xkb; + xkb = + xkl_config_get_keyboard(engine, &component_names, + FALSE); + if (xkb != NULL) { + dump_info.defined = 0; + dump_info.xkb = xkb; + dump_info.type = XkmKeymapFile; + if (binary) + rv = XkbWriteXKMFile(output, &dump_info); + else + rv = XkbWriteXKBFile(output, &dump_info, + True, NULL, NULL); + + XkbFreeKeyboard(xkb, XkbGBN_AllComponentsMask, + True); + } else + xkl_last_error_message = + "Could not load keyboard description"; + xkl_xkb_config_native_cleanup(engine, &component_names); + } + fclose(output); #endif - return rv; + return rv; } diff --git a/libxklavier/xklavier_config_xmm.c b/libxklavier/xklavier_config_xmm.c index abceec0..b18f851 100644 --- a/libxklavier/xklavier_config_xmm.c +++ b/libxklavier/xklavier_config_xmm.c @@ -1,6 +1,6 @@ #include <errno.h> -#include <string.h> #include <locale.h> +#include <string.h> #include <unistd.h> #include <sys/stat.h> #include <sys/param.h> @@ -19,37 +19,46 @@ #define XK_XKB_KEYS #include <X11/keysymdef.h> -void _XklXmmConfigInit( void ) +void +xkl_xmm_init_config_registry(XklConfigRegistry * config) { } -Bool _XklXmmConfigLoadRegistry( void ) +gboolean +xkl_xmm_load_config_registry(XklConfigRegistry * config) { - struct stat statBuf; - char fileName[MAXPATHLEN] = ""; - char* rf = _XklGetRulesSetName( "" ); + struct stat stat_buf; + gchar file_name[MAXPATHLEN] = ""; + XklEngine *engine = xkl_config_registry_get_engine(config); + gchar *rf = xkl_engine_get_ruleset_name(engine, ""); - if ( rf == NULL || rf[0] == '\0' ) - return False; + if (rf == NULL || rf[0] == '\0') + return FALSE; - snprintf( fileName, sizeof fileName, XMODMAP_BASE "/%s.xml", rf ); + g_snprintf(file_name, sizeof file_name, XMODMAP_BASE "/%s.xml", + rf); - if( stat( fileName, &statBuf ) != 0 ) - { - _xklLastErrorMsg = "No rules file found"; - return False; - } + if (stat(file_name, &stat_buf) != 0) { + xkl_last_error_message = "No rules file found"; + return FALSE; + } - return XklConfigLoadRegistryFromFile( fileName ); + return xkl_config_registry_load_from_file(config, file_name); } -Bool _XklXmmConfigActivate( const XklConfigRecPtr data ) +gboolean +xkl_xmm_activate_config_rec(XklEngine * engine, const XklConfigRec * data) { - Bool rv; - rv = XklSetNamesProp( xklVTable->baseConfigAtom, - currentXmmRules, - data ); - if( rv ) - _XklXmmLockGroup( 0 ); - return rv; + gboolean rv; + rv = xkl_config_rec_set_to_root_window_property(data, + xkl_engine_priv + (engine, + base_config_atom), + xkl_engine_backend + (engine, XklXmm, + current_rules), + engine); + if (rv) + xkl_xmm_lock_group(engine, 0); + return rv; } diff --git a/libxklavier/xklavier_dump.c b/libxklavier/xklavier_dump.c index b013584..1681151 100644 --- a/libxklavier/xklavier_dump.c +++ b/libxklavier/xklavier_dump.c @@ -21,261 +21,264 @@ #ifdef XKB_HEADERS_PRESENT #if 0 -static void _XkbModsRecDump( FILE * fs, XkbModsRec * mods ) +static void +_XkbModsRecDump(FILE * fs, XkbModsRec * mods) { - fprintf( fs, "flags: 0x%X\n", mods->mask ); - fprintf( fs, "real_mods: 0x%X\n", mods->real_mods ); - fprintf( fs, "vmods: 0x%X\n", mods->vmods ); + fprintf(fs, "flags: 0x%X\n", mods->mask); + fprintf(fs, "real_mods: 0x%X\n", mods->real_mods); + fprintf(fs, "vmods: 0x%X\n", mods->vmods); } -static void _XkbControlsDump( FILE * fs, XkbControlsPtr ctrls ) +static void +_XkbControlsDump(FILE * fs, XkbControlsPtr ctrls) { - int i; - char buf[1024]; - fprintf( fs, "mk_dflt_btn: %d\n", ctrls->mk_dflt_btn ); - fprintf( fs, "num_groups: %d\n", ctrls->num_groups ); - fprintf( fs, "groups_wrap: %d\n", ctrls->groups_wrap ); - fprintf( fs, "internal: \n" ); - _XkbModsRecDump( fs, &ctrls->internal ); - fprintf( fs, "ignore_lock: \n" ); - _XkbModsRecDump( fs, &ctrls->ignore_lock ); - fprintf( fs, "enabled_ctrls: 0x%X\n", ctrls->enabled_ctrls ); - fprintf( fs, "repeat_delay: %d\n", ctrls->repeat_delay ); - fprintf( fs, "repeat_interval: %d\n", ctrls->repeat_interval ); - fprintf( fs, "slow_keys_delay: %d\n", ctrls->slow_keys_delay ); - fprintf( fs, "debounce_delay: %d\n", ctrls->debounce_delay ); - fprintf( fs, "mk_delay: %d\n", ctrls->mk_delay ); - fprintf( fs, "mk_interval: %d\n", ctrls->mk_interval ); - fprintf( fs, "mk_time_to_max: %d\n", ctrls->mk_time_to_max ); - fprintf( fs, "mk_max_speed: %d\n", ctrls->mk_max_speed ); - fprintf( fs, "mk_curve: %d\n", ctrls->mk_curve ); - fprintf( fs, "ax_options: %d\n", ctrls->ax_options ); - fprintf( fs, "ax_timeout: %d\n", ctrls->ax_timeout ); - fprintf( fs, "axt_opts_mask: 0x%X\n", ctrls->axt_opts_mask ); - fprintf( fs, "axt_opts_values: 0x%X\n", ctrls->axt_opts_values ); - fprintf( fs, "axt_ctrls_mask: 0x%X\n", ctrls->axt_ctrls_mask ); - fprintf( fs, "axt_ctrls_values: 0x%X\n", ctrls->axt_ctrls_values ); - fprintf( fs, "axt_ctrls_values: 0x%X\n", ctrls->axt_ctrls_values ); - fprintf( fs, "per_key_repeat:\n" ); - buf[0] = 0; - for( i = 0; i < XkbPerKeyBitArraySize; i++ ) - { - char b[5]; - snprintf( b, sizeof( b ), "%d ", ctrls->per_key_repeat[i] ); - strcat( buf, b ); - } - fprintf( fs, " %s\n", buf ); + gint i; + gchar buf[1024]; + fprintf(fs, "mk_dflt_btn: %d\n", ctrls->mk_dflt_btn); + fprintf(fs, "num_groups: %d\n", ctrls->num_groups); + fprintf(fs, "groups_wrap: %d\n", ctrls->groups_wrap); + fprintf(fs, "internal: \n"); + _XkbModsRecDump(fs, &ctrls->internal); + fprintf(fs, "ignore_lock: \n"); + _XkbModsRecDump(fs, &ctrls->ignore_lock); + fprintf(fs, "enabled_ctrls: 0x%X\n", ctrls->enabled_ctrls); + fprintf(fs, "repeat_delay: %d\n", ctrls->repeat_delay); + fprintf(fs, "repeat_interval: %d\n", ctrls->repeat_interval); + fprintf(fs, "slow_keys_delay: %d\n", ctrls->slow_keys_delay); + fprintf(fs, "debounce_delay: %d\n", ctrls->debounce_delay); + fprintf(fs, "mk_delay: %d\n", ctrls->mk_delay); + fprintf(fs, "mk_interval: %d\n", ctrls->mk_interval); + fprintf(fs, "mk_time_to_max: %d\n", ctrls->mk_time_to_max); + fprintf(fs, "mk_max_speed: %d\n", ctrls->mk_max_speed); + fprintf(fs, "mk_curve: %d\n", ctrls->mk_curve); + fprintf(fs, "ax_options: %d\n", ctrls->ax_options); + fprintf(fs, "ax_timeout: %d\n", ctrls->ax_timeout); + fprintf(fs, "axt_opts_mask: 0x%X\n", ctrls->axt_opts_mask); + fprintf(fs, "axt_opts_values: 0x%X\n", ctrls->axt_opts_values); + fprintf(fs, "axt_ctrls_mask: 0x%X\n", ctrls->axt_ctrls_mask); + fprintf(fs, "axt_ctrls_values: 0x%X\n", ctrls->axt_ctrls_values); + fprintf(fs, "axt_ctrls_values: 0x%X\n", ctrls->axt_ctrls_values); + fprintf(fs, "per_key_repeat:\n"); + buf[0] = 0; + for (i = 0; i < XkbPerKeyBitArraySize; i++) { + gchar b[5]; + snprintf(b, sizeof(b), "%d ", ctrls->per_key_repeat[i]); + strcat(buf, b); + } + fprintf(fs, " %s\n", buf); } #endif -static const char *actionTypeNames[] = { - "XkbSA_NoAction", - "XkbSA_SetMods", - "XkbSA_LatchMods", - "XkbSA_LockMods", - "XkbSA_SetGroup", - "XkbSA_LatchGroup", - "XkbSA_LockGroup", - "XkbSA_MovePtr", - "XkbSA_PtrBtn", - "XkbSA_LockPtrBtn", - "XkbSA_SetPtrDflt", - "XkbSA_ISOLock", - "XkbSA_Terminate", - "XkbSA_SwitchScreen", - "XkbSA_SetControls", - "XkbSA_LockControls", - "XkbSA_ActionMessage", - "XkbSA_RedirectKey", - "XkbSA_DeviceBtn", - "XkbSA_LockDeviceBtn", - "XkbSA_DeviceValuator" +static const gchar *action_type_names[] = { + "XkbSA_NoAction", + "XkbSA_SetMods", + "XkbSA_LatchMods", + "XkbSA_LockMods", + "XkbSA_SetGroup", + "XkbSA_LatchGroup", + "XkbSA_LockGroup", + "XkbSA_MovePtr", + "XkbSA_PtrBtn", + "XkbSA_LockPtrBtn", + "XkbSA_SetPtrDflt", + "XkbSA_ISOLock", + "XkbSA_Terminate", + "XkbSA_SwitchScreen", + "XkbSA_SetControls", + "XkbSA_LockControls", + "XkbSA_ActionMessage", + "XkbSA_RedirectKey", + "XkbSA_DeviceBtn", + "XkbSA_LockDeviceBtn", + "XkbSA_DeviceValuator" }; -static void _XkbActionDump( FILE * fs, int level, XkbAction * act ) +static void +xkb_action_dump(FILE * fs, gint level, XkbAction * act) { - XkbGroupAction *ga; - fprintf( fs, "%*stype: %d(%s)\n", level, "", act->type, - actionTypeNames[act->type] ); - switch ( act->type ) - { - case XkbSA_SetGroup: - case XkbSA_LatchGroup: - case XkbSA_LockGroup: - ga = ( XkbGroupAction * ) act; - fprintf( fs, "%*sXkbGroupAction: \n", level, "" ); - fprintf( fs, "%*sflags: %d\n", level, "", ga->flags ); - fprintf( fs, "%*sgroup_XXX: %d\n", level, "", ga->group_XXX ); - break; - } + XkbGroupAction *ga; + fprintf(fs, "%*stype: %d(%s)\n", level, "", act->type, + action_type_names[act->type]); + switch (act->type) { + case XkbSA_SetGroup: + case XkbSA_LatchGroup: + case XkbSA_LockGroup: + ga = (XkbGroupAction *) act; + fprintf(fs, "%*sXkbGroupAction: \n", level, ""); + fprintf(fs, "%*sflags: %d\n", level, "", ga->flags); + fprintf(fs, "%*sgroup_XXX: %d\n", level, "", + ga->group_XXX); + break; + } } -static void _XkbBehaviorDump( FILE * fs, int level, XkbBehavior * b ) +static void +xkb_behavior_dump(FILE * fs, gint level, XkbBehavior * b) { - fprintf( fs, "%*stype: %d\n", level, "", b->type ); - fprintf( fs, "%*sdata: %d\n", level, "", b->data ); + fprintf(fs, "%*stype: %d\n", level, "", b->type); + fprintf(fs, "%*sdata: %d\n", level, "", b->data); } -static void _XkbServerMapDump( FILE * fs, int level, XkbServerMapPtr server, - XkbDescPtr kbd ) +static void +xkb_server_map_dump(FILE * fs, gint level, XkbServerMapPtr server, + XkbDescPtr kbd) { - int i; - XkbAction *pa = server->acts; - XkbBehavior *pb = server->behaviors; - fprintf( fs, "%*snum_acts: %d\n", level, "", server->num_acts ); - fprintf( fs, "%*ssize_acts: %d\n", level, "", server->size_acts ); - if( server->acts != NULL ) - { - for( i = 0; i < server->num_acts; i++ ) - { - fprintf( fs, "%*sacts[%d]:\n", level, "", i ); - _XkbActionDump( fs, level + 2, pa++ ); - } - } else - fprintf( fs, "%*sNO acts\n", level, "" ); + gint i; + XkbAction *pa = server->acts; + XkbBehavior *pb = server->behaviors; + fprintf(fs, "%*snum_acts: %d\n", level, "", server->num_acts); + fprintf(fs, "%*ssize_acts: %d\n", level, "", server->size_acts); + if (server->acts != NULL) { + for (i = 0; i < server->num_acts; i++) { + fprintf(fs, "%*sacts[%d]:\n", level, "", i); + xkb_action_dump(fs, level + 2, pa++); + } + } else + fprintf(fs, "%*sNO acts\n", level, ""); - if( server->key_acts != NULL ) - { - for( i = 0; i <= kbd->max_key_code; i++ ) - { - fprintf( fs, "%*skey_acts[%d]: offset %d, total %d\n", level, "", i, - server->key_acts[i], XkbKeyNumSyms(kbd,i) ); - } - } else - fprintf( fs, "%*sNO key_acts\n", level, "" ); + if (server->key_acts != NULL) { + for (i = 0; i <= kbd->max_key_code; i++) { + fprintf(fs, + "%*skey_acts[%d]: offset %d, total %d\n", + level, "", i, server->key_acts[i], + XkbKeyNumSyms(kbd, i)); + } + } else + fprintf(fs, "%*sNO key_acts\n", level, ""); - for( i = 0; i < XkbNumVirtualMods; i++ ) - { - fprintf( fs, "%*svmod[%d]: %X\n", level, "", i, server->vmods[i] ); - } + for (i = 0; i < XkbNumVirtualMods; i++) { + fprintf(fs, "%*svmod[%d]: %X\n", level, "", i, + server->vmods[i]); + } - if( server->behaviors != NULL ) - { - for( i = 0; i <= kbd->max_key_code; i++ ) - { - fprintf( fs, "%*sbehaviors[%d]:\n", level, "", i ); - _XkbBehaviorDump( fs, level + 2, pb++ ); - } - } else - fprintf( fs, "%*sNO behaviors\n", level, "" ); + if (server->behaviors != NULL) { + for (i = 0; i <= kbd->max_key_code; i++) { + fprintf(fs, "%*sbehaviors[%d]:\n", level, "", i); + xkb_behavior_dump(fs, level + 2, pb++); + } + } else + fprintf(fs, "%*sNO behaviors\n", level, ""); - if( server->explicit != NULL ) - { - for( i = 0; i <= kbd->max_key_code; i++ ) - { - fprintf( fs, "%*sexplicit[%d]: %d\n", level, "", i, - server->explicit[i] ); - } - } else - fprintf( fs, "%*sNO explicit\n", level, "" ); + if (server->explicit != NULL) { + for (i = 0; i <= kbd->max_key_code; i++) { + fprintf(fs, "%*sexplicit[%d]: %d\n", level, "", i, + server->explicit[i]); + } + } else + fprintf(fs, "%*sNO explicit\n", level, ""); - if( server->vmodmap != NULL ) - { - for( i = 0; i <= kbd->max_key_code; i++ ) - { - fprintf( fs, "%*svmodmap[%d]: %d\n", level, "", i, server->vmodmap[i] ); - } - } else - fprintf( fs, "%*sNO vmodmap\n", level, "" ); + if (server->vmodmap != NULL) { + for (i = 0; i <= kbd->max_key_code; i++) { + fprintf(fs, "%*svmodmap[%d]: %d\n", level, "", i, + server->vmodmap[i]); + } + } else + fprintf(fs, "%*sNO vmodmap\n", level, ""); } -static void _XkbKeyTypeDump( FILE * fs, int level, XkbKeyTypePtr type ) +static void +xkb_key_type_dump(FILE * fs, gint level, XkbKeyTypePtr type, + XklEngine * engine) { - char *z = type->name == None ? NULL : XGetAtomName( _xklDpy, type->name ); - fprintf( fs, "%*sname: 0x%X(%s)\n", level, "", (int)type->name, z ); - if( z != NULL ) - XFree( z ); + gchar *z = + type->name == + None ? NULL : XGetAtomName(xkl_engine_get_display(engine), + type->name); + fprintf(fs, "%*sname: 0x%X(%s)\n", level, "", (gint) type->name, + z); + if (z != NULL) + XFree(z); } -static void _XkbSymMapDump( FILE * fs, int level, XkbSymMapPtr ksm ) +static void +xkb_sym_map_dump(FILE * fs, gint level, XkbSymMapPtr ksm) { - int i; - fprintf( fs, "%*skt_index: ", level, "" ); - for( i = 0; i < XkbNumKbdGroups; i++ ) - { - fprintf( fs, "%d ", ksm->kt_index[i] ); - } - fprintf( fs, "\n%*sgroup_info: %d\n", level, "", ksm->group_info ); - fprintf( fs, "%*swidth: %d\n", level, "", ksm->width ); - fprintf( fs, "%*soffset: %d\n", level, "", ksm->offset ); + gint i; + fprintf(fs, "%*skt_index: ", level, ""); + for (i = 0; i < XkbNumKbdGroups; i++) { + fprintf(fs, "%d ", ksm->kt_index[i]); + } + fprintf(fs, "\n%*sgroup_info: %d\n", level, "", ksm->group_info); + fprintf(fs, "%*swidth: %d\n", level, "", ksm->width); + fprintf(fs, "%*soffset: %d\n", level, "", ksm->offset); } -static void _XkbClientMapDump( FILE * fs, int level, XkbClientMapPtr map, - XkbDescPtr kbd ) +static void +xkb_client_map_dump(FILE * fs, gint level, XkbClientMapPtr map, + XkbDescPtr kbd, XklEngine * engine) { - int i; - fprintf( fs, "%*ssize_types: %d\n", level, "", map->size_types ); - fprintf( fs, "%*snum_types: %d\n", level, "", map->num_types ); - if( map->types != NULL ) - { - XkbKeyTypePtr type = map->types; - for( i = 0; i < map->num_types; i++ ) - { - fprintf( fs, "%*stypes[%d]:\n", level, "", i ); - _XkbKeyTypeDump( fs, level + 2, type++ ); - } - } else - fprintf( fs, "%*sNO types\n", level, "" ); + gint i; + fprintf(fs, "%*ssize_types: %d\n", level, "", map->size_types); + fprintf(fs, "%*snum_types: %d\n", level, "", map->num_types); + if (map->types != NULL) { + XkbKeyTypePtr type = map->types; + for (i = 0; i < map->num_types; i++) { + fprintf(fs, "%*stypes[%d]:\n", level, "", i); + xkb_key_type_dump(fs, level + 2, type++, engine); + } + } else + fprintf(fs, "%*sNO types\n", level, ""); - fprintf( fs, "%*ssize_syms: %d\n", level, "", map->size_syms ); - fprintf( fs, "%*snum_syms: %d\n", level, "", map->num_syms ); - if( map->syms != NULL ) - { - for( i = 0; i < map->num_syms; i++ ) - fprintf( fs, "%*ssyms[%d]:0x%lX(%s)\n", level, "", i, map->syms[i], - XKeysymToString( map->syms[i] ) ); - } else - fprintf( fs, "%*sNO syms\n", level, "" ); - if( map->key_sym_map != NULL ) - { - XkbSymMapPtr ksm = map->key_sym_map; - for( i = 0; i <= kbd->max_key_code; i++ ) - { - fprintf( fs, "%*skey_sym_map[%d]:\n", level, "", i ); - _XkbSymMapDump( fs, level + 2, ksm++ ); - } - } else - fprintf( fs, "%*sNO key_sym_map\n", level, "" ); + fprintf(fs, "%*ssize_syms: %d\n", level, "", map->size_syms); + fprintf(fs, "%*snum_syms: %d\n", level, "", map->num_syms); + if (map->syms != NULL) { + for (i = 0; i < map->num_syms; i++) + fprintf(fs, "%*ssyms[%d]:0x%lX(%s)\n", level, "", + i, map->syms[i], + XKeysymToString(map->syms[i])); + } else + fprintf(fs, "%*sNO syms\n", level, ""); + if (map->key_sym_map != NULL) { + XkbSymMapPtr ksm = map->key_sym_map; + for (i = 0; i <= kbd->max_key_code; i++) { + fprintf(fs, "%*skey_sym_map[%d]:\n", level, "", i); + xkb_sym_map_dump(fs, level + 2, ksm++); + } + } else + fprintf(fs, "%*sNO key_sym_map\n", level, ""); } -static void _XkbDescDump( FILE * fs, int level, XkbDescPtr kbd ) +static void +xkb_desc_dump(FILE * fs, gint level, XkbDescPtr kbd, XklEngine * engine) { - fprintf( fs, "%*sflags: 0x%X\n", level, "", kbd->flags ); - fprintf( fs, "%*sdevice_spec: %d\n", level, "", kbd->device_spec ); - fprintf( fs, "%*smin_key_code: %d\n", level, "", kbd->min_key_code ); - fprintf( fs, "%*smax_key_code: %d\n", level, "", kbd->max_key_code ); + fprintf(fs, "%*sflags: 0x%X\n", level, "", kbd->flags); + fprintf(fs, "%*sdevice_spec: %d\n", level, "", kbd->device_spec); + fprintf(fs, "%*smin_key_code: %d\n", level, "", kbd->min_key_code); + fprintf(fs, "%*smax_key_code: %d\n", level, "", kbd->max_key_code); #if 0 - if( kbd->ctrls != NULL ) - { - fprintf( fs, "ctrls:\n" ); - _XkbControlsDump( fs, kbd->ctrls ); - } else - fprintf( fs, "NO server\n" ); + if (kbd->ctrls != NULL) { + fprintf(fs, "ctrls:\n"); + _XkbControlsDump(fs, kbd->ctrls); + } else + fprintf(fs, "NO server\n"); #endif - if( kbd->server != NULL ) - { - fprintf( fs, "%*sserver:\n", level, "" ); - _XkbServerMapDump( fs, level + 2, kbd->server, kbd ); - } else - fprintf( fs, "%*sNO server\n", level, "" ); + if (kbd->server != NULL) { + fprintf(fs, "%*sserver:\n", level, ""); + xkb_server_map_dump(fs, level + 2, kbd->server, kbd); + } else + fprintf(fs, "%*sNO server\n", level, ""); - if( kbd->map != NULL ) - { - fprintf( fs, "%*smap:\n", level, "" ); - _XkbClientMapDump( fs, level + 2, kbd->map, kbd ); - } else - fprintf( fs, "%*sNO map\n", level, "" ); - fprintf( fs, "XKB libraries not present\n" ); + if (kbd->map != NULL) { + fprintf(fs, "%*smap:\n", level, ""); + xkb_client_map_dump(fs, level + 2, kbd->map, kbd, engine); + } else + fprintf(fs, "%*sNO map\n", level, ""); + fprintf(fs, "XKB libraries not present\n"); } -void XklDumpXkbDesc( const char *filename, XkbDescPtr kbd ) +void +xkl_engine_dump_xkb_desc(XklEngine * engine, const gchar * file_name, + XkbDescPtr kbd) { - FILE *fs = fopen( filename, "w+" ); - if( fs != NULL ) - { - _XkbDescDump( fs, 0, kbd == NULL ? _xklXkb : kbd ); - fclose( fs ); - } + FILE *fs = fopen(file_name, "w+"); + if (fs != NULL) { + xkb_desc_dump(fs, 0, + kbd == NULL ? xkl_engine_backend(engine, + XklXkb, + cached_desc) + : kbd, engine); + fclose(fs); + } } #endif diff --git a/libxklavier/xklavier_evt.c b/libxklavier/xklavier_evt.c index 1540841..40dd41a 100644 --- a/libxklavier/xklavier_evt.c +++ b/libxklavier/xklavier_evt.c @@ -1,327 +1,433 @@ +#include <string.h> #include <time.h> #include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#include <X11/Xlibint.h> #include "xklavier_private.h" -int XklFilterEvents( XEvent * xev ) +gint +xkl_engine_filter_events(XklEngine * engine, XEvent * xev) { - XAnyEvent *pe = ( XAnyEvent * ) xev; - XklDebug( 400, "**> Filtering event %d of type %d from window %d\n", - pe->serial, pe->type, pe->window ); - _XklEnsureVTableInited(); - if ( !xklVTable->xklEventHandler( xev ) ) - switch ( xev->type ) - { /* core events */ - case FocusIn: - _XklFocusInEvHandler( &xev->xfocus ); - break; - case FocusOut: - _XklFocusOutEvHandler( &xev->xfocus ); - break; - case PropertyNotify: - _XklPropertyEvHandler( &xev->xproperty ); - break; - case CreateNotify: - _XklCreateEvHandler( &xev->xcreatewindow ); - break; - case DestroyNotify: - XklDebug( 150, "Window " WINID_FORMAT " destroyed\n", - xev->xdestroywindow.window ); - break; - case UnmapNotify: - XklDebug( 200, "Window " WINID_FORMAT " unmapped\n", - xev->xunmap.window ); - break; - case MapNotify: - XklDebug( 200, "%s\n", _XklGetEventName( xev->type ) ); - break; - case MappingNotify: - XklDebug( 200, "%s\n", _XklGetEventName( xev->type ) ); - _XklResetAllInfo( "X event: MappingNotify" ); - break; - case GravityNotify: - XklDebug( 200, "%s\n", _XklGetEventName( xev->type ) ); - break; - case ReparentNotify: - XklDebug( 200, "Window " WINID_FORMAT " reparented to " WINID_FORMAT "\n", - xev->xreparent.window, xev->xreparent.parent ); - break; - default: - { - XklDebug( 200, "Unknown event %d [%s]\n", - xev->type, _XklGetEventName( xev->type ) ); - return 1; - } - } - XklDebug( 400, "Filtered event %d of type %d from window %d **>\n", - pe->serial, pe->type, pe->window ); - return 1; + XAnyEvent *pe = (XAnyEvent *) xev; + xkl_debug(400, + "**> Filtering event %d of type %d from window %d\n", + pe->serial, pe->type, pe->window); + xkl_engine_ensure_vtable_inited(engine); + if (!xkl_engine_vcall(engine, process_x_event) (engine, xev)) + switch (xev->type) { /* core events */ + case FocusIn: + xkl_engine_process_focus_in_evt(engine, + &xev->xfocus); + break; + case FocusOut: + xkl_engine_process_focus_out_evt(engine, + &xev->xfocus); + break; + case PropertyNotify: + xkl_engine_process_property_evt(engine, + &xev->xproperty); + break; + case CreateNotify: + xkl_engine_process_create_window_evt(engine, + &xev-> + xcreatewindow); + break; + case DestroyNotify: + xkl_debug(150, + "Window " WINID_FORMAT " destroyed\n", + xev->xdestroywindow.window); + break; + case UnmapNotify: + xkl_debug(200, + "Window " WINID_FORMAT " unmapped\n", + xev->xunmap.window); + break; + case MapNotify: + case GravityNotify: + xkl_debug(200, "%s\n", + xkl_event_get_name(xev->type)); + break; /* Ignore these events */ + case ReparentNotify: + xkl_debug(200, + "Window " WINID_FORMAT " reparented to " + WINID_FORMAT "\n", xev->xreparent.window, + xev->xreparent.parent); + break; /* Ignore these events */ + case MappingNotify: + xkl_debug(200, "%s\n", + xkl_event_get_name(xev->type)); + xkl_engine_reset_all_info(engine, + "X event: MappingNotify"); + break; + default: + { + xkl_debug(200, "Unknown event %d [%s]\n", + xev->type, + xkl_event_get_name(xev->type)); + return 1; + } + } + xkl_debug(400, "Filtered event %d of type %d from window %d **>\n", + pe->serial, pe->type, pe->window); + return 1; } -/** +/* * FocusIn handler */ -void _XklFocusInEvHandler( XFocusChangeEvent * fev ) +void +xkl_engine_process_focus_in_evt(XklEngine * engine, + XFocusChangeEvent * fev) { - Window win; - Window appWin; - XklState selectedWindowState; - - if( !( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) ) - return; - - win = fev->window; - - switch ( fev->mode ) - { - case NotifyNormal: - case NotifyWhileGrabbed: - break; - default: - XklDebug( 160, - "Window " WINID_FORMAT - " has got focus during special action %d\n", win, fev->mode ); - return; - } - - XklDebug( 150, "Window " WINID_FORMAT ", '%s' has got focus\n", win, - _XklGetDebugWindowTitle( win ) ); - - if( !_XklGetAppWindow( win, &appWin ) ) - { - return; - } - - XklDebug( 150, "Appwin " WINID_FORMAT ", '%s' has got focus\n", appWin, - _XklGetDebugWindowTitle( appWin ) ); - - if( XklGetState( appWin, &selectedWindowState ) ) - { - if( _xklCurClient != appWin ) - { - Bool oldWinTransparent, newWinTransparent; - XklState tmpState; - - oldWinTransparent = _XklIsTransparentAppWindow( _xklCurClient ); - if( oldWinTransparent ) - XklDebug( 150, "Leaving transparent window\n" ); - - /** - * Reload the current state from the current window. - * Do not do it for transparent window - we keep the state from - * the _previous_ window. - */ - if ( !oldWinTransparent && XklGetState ( _xklCurClient, &tmpState ) ) - { - _XklUpdateCurState( tmpState.group, - tmpState.indicators, - "Loading current (previous) state from the current (previous) window" ); - } - - _xklCurClient = appWin; - XklDebug( 150, "CurClient:changed to " WINID_FORMAT ", '%s'\n", - _xklCurClient, _XklGetDebugWindowTitle( _xklCurClient ) ); - - newWinTransparent = _XklIsTransparentAppWindow( appWin ); - if( newWinTransparent ) - XklDebug( 150, "Entering transparent window\n" ); - - if( XklIsGroupPerApp() == !newWinTransparent ) - { - /* We skip restoration only if we return to the same app window */ - Bool doSkip = False; - if( _xklSkipOneRestore ) - { - _xklSkipOneRestore = False; - if( appWin == _xklPrevAppWindow ) - doSkip = True; - } - - if( doSkip ) - { - XklDebug( 150, - "Skipping one restore as requested - instead, saving the current group into the window state\n" ); - _XklSaveAppState( appWin, &_xklCurState ); - } else - { - if( _xklCurState.group != selectedWindowState.group ) - { - XklDebug( 150, - "Restoring the group from %d to %d after gaining focus\n", - _xklCurState.group, selectedWindowState.group ); - /** - * For fast mouse movements - the state is probably not updated yet - * (because of the group change notification being late). - * so we'll enforce the update. But this should only happen in GPA mode - */ - _XklUpdateCurState( selectedWindowState.group, - selectedWindowState.indicators, - "Enforcing fast update of the current state" ); - XklLockGroup( selectedWindowState.group ); - } else - { - XklDebug( 150, - "Both old and new focused window have group %d so no point restoring it\n", - selectedWindowState.group ); - _XklOneSwitchToSecondaryGroupPerformed(); - } - } - - if( ( xklVTable->features & XKLF_CAN_TOGGLE_INDICATORS ) && - XklGetIndicatorsHandling( ) ) - { - XklDebug( 150, - "Restoring the indicators from %X to %X after gaining focus\n", - _xklCurState.indicators, selectedWindowState.indicators ); - _XklEnsureVTableInited(); - (*xklVTable->xklSetIndicatorsHandler)( &selectedWindowState ); - } else - XklDebug( 150, - "Not restoring the indicators %X after gaining focus: indicator handling is not enabled\n", - _xklCurState.indicators ); - } else - XklDebug( 150, - "Not restoring the group %d after gaining focus: global layout (xor transparent window)\n", - _xklCurState.group ); - } else - XklDebug( 150, "Same app window - just do nothing\n" ); - } else - { - XklDebug( 150, "But it does not have xklavier_state\n" ); - if( _XklHasWmState( win ) ) - { - XklDebug( 150, "But it does have wm_state so we'll add it\n" ); - _xklCurClient = appWin; - XklDebug( 150, "CurClient:changed to " WINID_FORMAT ", '%s'\n", - _xklCurClient, _XklGetDebugWindowTitle( _xklCurClient ) ); - _XklAddAppWindow( _xklCurClient, ( Window ) NULL, False, - &_xklCurState ); - } else - XklDebug( 150, "And it does have wm_state either\n" ); - } + Window win; + Window toplevel_win; + XklState selected_window_state; + + if (! + (xkl_engine_priv(engine, listener_type) & + XKLL_MANAGE_WINDOW_STATES)) + return; + + win = fev->window; + + switch (fev->mode) { + case NotifyNormal: + case NotifyWhileGrabbed: + break; + default: + xkl_debug(160, + "Window " WINID_FORMAT + " has got focus during special action %d\n", win, + fev->mode); + return; + } + + xkl_debug(150, "Window " WINID_FORMAT ", '%s' has got focus\n", + win, xkl_get_debug_window_title(engine, win)); + + if (!xkl_engine_find_toplevel_window(engine, win, &toplevel_win)) { + return; + } + + xkl_debug(150, "Appwin " WINID_FORMAT ", '%s' has got focus\n", + toplevel_win, xkl_get_debug_window_title(engine, + toplevel_win)); + + if (xkl_engine_get_toplevel_window_state + (engine, toplevel_win, &selected_window_state)) { + if (xkl_engine_priv(engine, curr_toplvl_win) != + toplevel_win) { + gboolean old_win_transparent, new_win_transparent; + XklState tmp_state; + + old_win_transparent = + xkl_engine_is_toplevel_window_transparent + (engine, + xkl_engine_priv(engine, curr_toplvl_win)); + if (old_win_transparent) + xkl_debug(150, + "Leaving transparent window\n"); + + /* + * Reload the current state from the current window. + * Do not do it for transparent window - we keep the state from + * the _previous_ window. + */ + if (!old_win_transparent && + xkl_engine_get_toplevel_window_state(engine, + xkl_engine_priv + (engine, + curr_toplvl_win), + &tmp_state)) + { + xkl_engine_update_current_state(engine, + tmp_state. + group, + tmp_state. + indicators, + "Loading current (previous) state from the current (previous) window"); + } + + xkl_engine_priv(engine, curr_toplvl_win) = + toplevel_win; + xkl_debug(150, + "CurClient:changed to " WINID_FORMAT + ", '%s'\n", xkl_engine_priv(engine, + curr_toplvl_win), + xkl_get_debug_window_title(engine, + xkl_engine_priv + (engine, + curr_toplvl_win))); + + new_win_transparent = + xkl_engine_is_toplevel_window_transparent + (engine, toplevel_win); + if (new_win_transparent) + xkl_debug(150, + "Entering transparent window\n"); + + if (xkl_engine_is_group_per_toplevel_window(engine) + == !new_win_transparent) { + /* We skip restoration only if we return to the same app window */ + gboolean do_skip = FALSE; + if (xkl_engine_priv + (engine, skip_one_restore)) { + xkl_engine_priv(engine, + skip_one_restore) = + FALSE; + if (toplevel_win == + xkl_engine_priv(engine, + prev_toplvl_win)) + do_skip = TRUE; + } + + if (do_skip) { + xkl_debug(150, + "Skipping one restore as requested - instead, " + "saving the current group into the window state\n"); + xkl_engine_save_toplevel_window_state + (engine, toplevel_win, + &xkl_engine_priv(engine, + curr_state)); + } else { + if (xkl_engine_priv + (engine, + curr_state).group != + selected_window_state.group) { + xkl_debug(150, + "Restoring the group from %d to %d after gaining focus\n", + xkl_engine_priv + (engine, + curr_state). + group, + selected_window_state. + group); + /* + * For fast mouse movements - the state is probably not updated yet + * (because of the group change notification being late). + * so we'll enforce the update. But this should only happen in GPA mode + */ + xkl_engine_update_current_state + (engine, + selected_window_state. + group, + selected_window_state. + indicators, + "Enforcing fast update of the current state"); + xkl_engine_lock_group + (engine, + selected_window_state. + group); + } else { + xkl_debug(150, + "Both old and new focused window " + "have group %d so no point restoring it\n", + selected_window_state. + group); + xkl_engine_one_switch_to_secondary_group_performed + (engine); + } + } + + if ((xkl_engine_priv(engine, features) & + XKLF_CAN_TOGGLE_INDICATORS) + && + xkl_engine_get_indicators_handling + (engine)) { + xkl_debug(150, + "Restoring the indicators from %X to %X after gaining focus\n", + xkl_engine_priv(engine, + curr_state). + indicators, + selected_window_state. + indicators); + xkl_engine_ensure_vtable_inited + (engine); + xkl_engine_vcall(engine, + set_indicators) + (engine, + &selected_window_state); + } else + xkl_debug(150, + "Not restoring the indicators %X after gaining focus: indicator handling is not enabled\n", + xkl_engine_priv(engine, + curr_state). + indicators); + } else + xkl_debug(150, + "Not restoring the group %d after gaining focus: global layout (xor transparent window)\n", + xkl_engine_priv(engine, + curr_state). + group); + } else + xkl_debug(150, + "Same app window - just do nothing\n"); + } else { + xkl_debug(150, "But it does not have xklavier_state\n"); + if (xkl_engine_if_window_has_wm_state(engine, win)) { + xkl_debug(150, + "But it does have wm_state so we'll add it\n"); + xkl_engine_priv(engine, curr_toplvl_win) = + toplevel_win; + xkl_debug(150, + "CurClient:changed to " WINID_FORMAT + ", '%s'\n", xkl_engine_priv(engine, + curr_toplvl_win), + xkl_get_debug_window_title(engine, + xkl_engine_priv + (engine, + curr_toplvl_win))); + xkl_engine_add_toplevel_window(engine, + xkl_engine_priv + (engine, + curr_toplvl_win), + (Window) NULL, + FALSE, + &xkl_engine_priv + (engine, + curr_state)); + } else + xkl_debug(150, + "And it does have wm_state either\n"); + } } -/** +/* * FocusOut handler */ -void _XklFocusOutEvHandler( XFocusChangeEvent * fev ) +void +xkl_engine_process_focus_out_evt(XklEngine * engine, + XFocusChangeEvent * fev) { - if( !( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) ) - return; - - if( fev->mode != NotifyNormal ) - { - XklDebug( 200, - "Window " WINID_FORMAT - " has lost focus during special action %d\n", fev->window, - fev->mode ); - return; - } - - XklDebug( 160, "Window " WINID_FORMAT ", '%s' has lost focus\n", - fev->window, _XklGetDebugWindowTitle( fev->window ) ); - - if( XklIsTransparent( fev->window ) ) - { - - XklDebug( 150, "Leaving transparent window!\n" ); -/** + if (! + (xkl_engine_priv(engine, listener_type) & + XKLL_MANAGE_WINDOW_STATES)) + return; + + if (fev->mode != NotifyNormal) { + xkl_debug(200, + "Window " WINID_FORMAT + " has lost focus during special action %d\n", + fev->window, fev->mode); + return; + } + + xkl_debug(160, "Window " WINID_FORMAT ", '%s' has lost focus\n", + fev->window, xkl_get_debug_window_title(engine, + fev->window)); + + if (xkl_engine_is_window_transparent(engine, fev->window)) { + xkl_debug(150, "Leaving transparent window!\n"); +/* * If we are leaving the transparent window - we skip the restore operation. * This is useful for secondary groups switching from the transparent control * window. */ - _xklSkipOneRestore = True; - } else - { - Window p; - if( _XklGetAppWindow( fev->window, &p ) ) - _xklPrevAppWindow = p; - } + xkl_engine_priv(engine, skip_one_restore) = TRUE; + } else { + Window p; + if (xkl_engine_find_toplevel_window + (engine, fev->window, &p)) + xkl_engine_priv(engine, prev_toplvl_win) = p; + } } -/** +/* * PropertyChange handler * Interested in : * + for XKLL_MANAGE_WINDOW_STATES * - WM_STATE property for all windows * - Configuration property of the root window */ -void _XklPropertyEvHandler( XPropertyEvent * pev ) +void +xkl_engine_process_property_evt(XklEngine * engine, XPropertyEvent * pev) { - if( 400 <= _xklDebugLevel ) - { - char *atomName = XGetAtomName( _xklDpy, pev->atom ); - if( atomName != NULL ) - { - XklDebug( 400, "The property '%s' changed for " WINID_FORMAT "\n", - atomName, pev->window ); - XFree( atomName ); - } else - { - XklDebug( 200, "Some magic property changed for " WINID_FORMAT "\n", - pev->window ); - } - } - - if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) - { - if( pev->atom == _xklAtoms[WM_STATE] ) - { - Bool hasXklState = XklGetState( pev->window, NULL ); - - if( pev->state == PropertyNewValue ) - { - 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 - if( pev->atom == xklVTable->baseConfigAtom - && pev->window == _xklRootWindow ) - { - if( pev->state == PropertyNewValue ) - { - /* If root window got new *_NAMES_PROP_ATOM - - it most probably means new keyboard config is loaded by somebody */ - _XklResetAllInfo( "New value of *_NAMES_PROP_ATOM on root window" ); - } - } - } /* XKLL_MANAGE_WINDOW_STATES */ + if (400 <= xkl_debug_level) { + char *atom_name = + XGetAtomName(xkl_engine_get_display(engine), + pev->atom); + if (atom_name != NULL) { + xkl_debug(400, + "The property '%s' changed for " + WINID_FORMAT "\n", atom_name, + pev->window); + XFree(atom_name); + } else { + xkl_debug(200, + "Some magic property changed for " + WINID_FORMAT "\n", pev->window); + } + } + + if (xkl_engine_priv(engine, listener_type) & + XKLL_MANAGE_WINDOW_STATES) { + if (pev->atom == xkl_engine_priv(engine, atoms)[WM_STATE]) { + gboolean has_xkl_state = + xkl_engine_get_state(engine, pev->window, + NULL); + + if (pev->state == PropertyNewValue) { + xkl_debug(160, + "New value of WM_STATE on window " + WINID_FORMAT "\n", pev->window); + if (!has_xkl_state) { /* Is this event the first or not? */ + xkl_engine_add_toplevel_window + (engine, pev->window, (Window) + NULL, FALSE, + &xkl_engine_priv(engine, + curr_state)); + } + } else { /* ev->xproperty.state == PropertyDelete, either client or WM can remove it, ICCCM 4.1.3.1 */ + xkl_debug(160, + "Something (%d) happened to WM_STATE of window 0x%x\n", + pev->state, pev->window); + xkl_engine_select_input_merging(engine, + pev-> + window, + PropertyChangeMask); + if (has_xkl_state) { + xkl_engine_delete_state(engine, + pev-> + window); + } + } + } else + if (pev->atom == + xkl_engine_priv(engine, base_config_atom) + && pev->window == xkl_engine_priv(engine, + root_window)) { + if (pev->state == PropertyNewValue) { + /* If root window got new *_NAMES_PROP_ATOM - + it most probably means new keyboard config is loaded by somebody */ + xkl_engine_reset_all_info + (engine, + "New value of *_NAMES_PROP_ATOM on root window"); + } + } + } /* XKLL_MANAGE_WINDOW_STATES */ } -/** +/* * CreateNotify handler. Just interested in properties and focus events... */ -void _XklCreateEvHandler( XCreateWindowEvent * cev ) +void +xkl_engine_process_create_window_evt(XklEngine * engine, + 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, - _XklGetDebugWindowTitle( cev->window ), cev->x, cev->y, - cev->width, cev->height ); - - if( !cev->override_redirect ) - { + if (! + (xkl_engine_priv(engine, listener_type) & + XKLL_MANAGE_WINDOW_STATES)) + return; + + xkl_debug(200, + "Under-root window " WINID_FORMAT + "/%s (%d,%d,%d x %d) is created\n", cev->window, + xkl_get_debug_window_title(engine, cev->window), cev->x, + cev->y, cev->width, cev->height); + + if (!cev->override_redirect) { /* ICCCM 4.1.6: override-redirect is NOT private to * client (and must not be changed - am I right?) * We really need only PropertyChangeMask on this window but even in the case of @@ -329,126 +435,173 @@ void _XklCreateEvHandler( XCreateWindowEvent * cev ) * event + SelectInput request is not zero) and we definitely will (my system DO) * lose FocusIn/Out events after the following call of PropertyNotifyHandler. * So I just decided to purify this extra FocusChangeMask in the FocusIn/OutHandler. */ - _XklSelectInputMerging( cev->window, - PropertyChangeMask | FocusChangeMask ); - - if( _XklHasWmState( cev->window ) ) - { - XklDebug( 200, - "Just created window already has WM_STATE - so I'll add it" ); - _XklAddAppWindow( cev->window, ( Window ) NULL, False, &_xklCurState ); - } - } + xkl_engine_select_input_merging(engine, cev->window, + PropertyChangeMask | + FocusChangeMask); + + if (xkl_engine_if_window_has_wm_state(engine, cev->window)) { + xkl_debug(200, + "Just created window already has WM_STATE - so I'll add it"); + xkl_engine_add_toplevel_window(engine, cev->window, + (Window) NULL, + FALSE, + &xkl_engine_priv + (engine, + curr_state)); + } + } } -/** +/* * Just error handler - sometimes we get BadWindow error for already gone * windows, so we'll just ignore */ -void _XklErrHandler( Display * dpy, XErrorEvent * evt ) +void +xkl_process_error(Display * dpy, XErrorEvent * evt) { - char buf[128] = ""; - _xklLastErrorCode = evt->error_code; - switch ( _xklLastErrorCode ) - { - case BadWindow: - case BadAccess: - { - XGetErrorText( dpy, _xklLastErrorCode, buf, sizeof(buf) ); - /* in most cases this means we are late:) */ - XklDebug( 200, "ERROR: %p, " WINID_FORMAT ", %d [%s], " - "X11 request: %d, minor code: %d\n", - dpy, - ( unsigned long ) evt->resourceid, - ( int ) evt->error_code, buf, - ( int ) evt->request_code, - ( int ) evt->minor_code ); - break; - } - default: - ( *_xklDefaultErrHandler ) ( dpy, evt ); - } + char buf[128] = ""; + XklEngine *engine = xkl_get_the_engine(); + + xkl_engine_priv(engine, last_error_code) = evt->error_code; + switch (xkl_engine_priv(engine, last_error_code)) { + case BadWindow: + case BadAccess: + { + XGetErrorText(xkl_engine_get_display(engine), + evt->error_code, buf, + sizeof(buf)); + /* in most cases this means we are late:) */ + xkl_debug(200, + "ERROR: %p, " WINID_FORMAT ", %d [%s], " + "X11 request: %d, minor code: %d\n", dpy, + (unsigned long) evt->resourceid, + (int) evt->error_code, buf, + (int) evt->request_code, + (int) evt->minor_code); + break; + } + default: + (*xkl_engine_priv(engine, default_error_handler)) (dpy, + evt); + } } -/** +/* * Some common functionality for Xkb handler */ -void _XklStateModificationHandler( XklStateChange changeType, - int grp, - unsigned inds, - Bool setInds ) +void +xkl_engine_process_state_modification(XklEngine * engine, + XklEngineStateChange change_type, + gint grp, guint inds, + gboolean set_inds) { - Window focused, focusedApp; - XklState oldState; - int revert; - Bool haveOldState = True; - Bool setGroup = changeType == GROUP_CHANGED; - - XGetInputFocus( _xklDpy, &focused, &revert ); - - if( ( focused == None ) || ( focused == PointerRoot ) ) - { - XklDebug( 160, "Something with focus: " WINID_FORMAT "\n", focused ); - return; - } - - /** - * Only if we manage states - otherwise _xklCurClient does not make sense - */ - if( !_XklGetAppWindow( focused, &focusedApp ) && - _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) - focusedApp = _xklCurClient; /* what else can I do */ - - XklDebug( 150, "Focused window: " WINID_FORMAT ", '%s'\n", focusedApp, - _XklGetDebugWindowTitle( focusedApp ) ); - if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) - { - XklDebug( 150, "CurClient: " WINID_FORMAT ", '%s'\n", _xklCurClient, - _XklGetDebugWindowTitle( _xklCurClient ) ); - - if( focusedApp != _xklCurClient ) - { - /** - * If not state - we got the new window - */ - if ( !_XklGetAppState( focusedApp, &oldState ) ) - { - _XklUpdateCurState( grp, inds, - "Updating the state from new focused window" ); - if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) - _XklAddAppWindow( focusedApp, ( Window ) NULL, False, &_xklCurState ); - } - /** - * There is state - just get the state from the window - */ - else - { - grp = oldState.group; - inds = oldState.indicators; - } - _xklCurClient = focusedApp; - 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 */ - haveOldState = _XklGetAppState( _xklCurClient, &oldState ); - } else /* just tracking the stuff, no smart things */ - { - XklDebug( 160, "Just updating the current state in the tracking mode\n" ); - memcpy( &oldState, &_xklCurState, sizeof( XklState ) ); - } - - if( setGroup || haveOldState ) - { - _XklUpdateCurState( setGroup ? grp : oldState.group, - setInds ? inds : oldState.indicators, - "Restoring the state from the window" ); - } - - if( haveOldState ) - _XklTryCallStateCallback( changeType, &oldState ); - - if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) - _XklSaveAppState( _xklCurClient, &_xklCurState ); + Window focused, focused_toplevel; + XklState old_state; + gint revert; + gboolean have_old_state = TRUE; + gboolean set_group = change_type == GROUP_CHANGED; + + XGetInputFocus(xkl_engine_get_display(engine), &focused, &revert); + + if ((focused == None) || (focused == PointerRoot)) { + xkl_debug(160, "Something with focus: " WINID_FORMAT "\n", + focused); + return; + } + + /* + * Only if we manage states - otherwise xkl_engine_priv(engine,curr_toplvl_win) does not make sense + */ + if (!xkl_engine_find_toplevel_window + (engine, focused, &focused_toplevel) + && xkl_engine_priv(engine, + listener_type) & XKLL_MANAGE_WINDOW_STATES) + focused_toplevel = xkl_engine_priv(engine, curr_toplvl_win); /* what else can I do */ + + xkl_debug(150, "Focused window: " WINID_FORMAT ", '%s'\n", + focused_toplevel, + xkl_get_debug_window_title(engine, focused_toplevel)); + if (xkl_engine_priv(engine, listener_type) & + XKLL_MANAGE_WINDOW_STATES) { + xkl_debug(150, "CurClient: " WINID_FORMAT ", '%s'\n", + xkl_engine_priv(engine, curr_toplvl_win), + xkl_get_debug_window_title(engine, + xkl_engine_priv + (engine, + curr_toplvl_win))); + + if (focused_toplevel != + xkl_engine_priv(engine, curr_toplvl_win)) { + /* + * If not state - we got the new window + */ + if (!xkl_engine_get_toplevel_window_state + (engine, focused_toplevel, &old_state)) { + xkl_engine_update_current_state(engine, + grp, inds, + "Updating the state from new focused window"); + if (xkl_engine_priv(engine, listener_type) + & XKLL_MANAGE_WINDOW_STATES) + xkl_engine_add_toplevel_window + (engine, focused_toplevel, + (Window) NULL, FALSE, + &xkl_engine_priv(engine, + curr_state)); + } + /* + * There is state - just get the state from the window + */ + else { + grp = old_state.group; + inds = old_state.indicators; + } + xkl_engine_priv(engine, curr_toplvl_win) = + focused_toplevel; + xkl_debug(160, + "CurClient:changed to " WINID_FORMAT + ", '%s'\n", xkl_engine_priv(engine, + curr_toplvl_win), + xkl_get_debug_window_title(engine, + xkl_engine_priv + (engine, + curr_toplvl_win))); + } + /* If the window already has this this state - we are just restoring it! + (see the second parameter of stateCallback */ + have_old_state = + xkl_engine_get_toplevel_window_state(engine, + xkl_engine_priv + (engine, + curr_toplvl_win), + &old_state); + } else { /* just tracking the stuff, no smart things */ + + xkl_debug(160, + "Just updating the current state in the tracking mode\n"); + memcpy(&old_state, &xkl_engine_priv(engine, curr_state), + sizeof(XklState)); + } + + if (set_group || have_old_state) { + xkl_engine_update_current_state(engine, + set_group ? grp : + old_state.group, + set_inds ? inds : + old_state.indicators, + "Restoring the state from the window"); + } + + if (have_old_state) + xkl_engine_try_call_state_func(engine, change_type, + &old_state); + + if (xkl_engine_priv(engine, listener_type) & + XKLL_MANAGE_WINDOW_STATES) + xkl_engine_save_toplevel_window_state(engine, + xkl_engine_priv + (engine, + curr_toplvl_win), + &xkl_engine_priv + (engine, + curr_state)); } diff --git a/libxklavier/xklavier_evt_xkb.c b/libxklavier/xklavier_evt_xkb.c index d70a3a3..19da8e3 100644 --- a/libxklavier/xklavier_evt_xkb.c +++ b/libxklavier/xklavier_evt_xkb.c @@ -3,135 +3,141 @@ #include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#include <X11/Xlibint.h> #include "xklavier_private.h" #include "xklavier_private_xkb.h" -/** +/* * XKB event handler */ -int _XklXkbEventHandler( XEvent *xev ) +gint +xkl_xkb_process_x_event(XklEngine * engine, XEvent * xev) { #ifdef XKB_HEADERS_PRESENT - int i; - unsigned bit; - unsigned inds; - XkbEvent *kev = (XkbEvent*)xev; - - if( xev->type != _xklXkbEventType ) - return 0; - - if( !( _xklListenerType & - ( XKLL_MANAGE_WINDOW_STATES | XKLL_TRACK_KEYBOARD_STATE ) ) ) - return 0; - - XklDebug( 150, "Xkb event detected\n" ); - - switch ( kev->any.xkb_type ) - { - /** - * Group is changed! - */ - case XkbStateNotify: + gint i; + guint bit; + guint inds; + XkbEvent *kev = (XkbEvent *) xev; + + if (xev->type != xkl_engine_backend(engine, XklXkb, event_type)) + return 0; + + if (!(xkl_engine_priv(engine, listener_type) & + (XKLL_MANAGE_WINDOW_STATES | XKLL_TRACK_KEYBOARD_STATE))) + return 0; + + xkl_debug(150, "Xkb event detected\n"); + + switch (kev->any.xkb_type) { + /* + * Group is changed! + */ + case XkbStateNotify: #define GROUP_CHANGE_MASK \ ( XkbGroupStateMask | XkbGroupBaseMask | XkbGroupLatchMask | XkbGroupLockMask ) - XklDebug( 150, - "XkbStateNotify detected, changes: %X/(mask %X), new group %d\n", - kev->state.changed, GROUP_CHANGE_MASK, - kev->state.locked_group ); - - if( kev->state.changed & GROUP_CHANGE_MASK ) - _XklStateModificationHandler( GROUP_CHANGED, - kev->state.locked_group, - 0, - False ); - else /* ...not interested... */ - { - XklDebug( 200, - "This type of state notification is not regarding groups\n" ); - if ( kev->state.locked_group != _xklCurState.group ) - XklDebug( 0, - "ATTENTION! Currently cached group %d is not equal to the current group from the event: %d\n!", - _xklCurState.group, - kev->state.locked_group ); - } - - break; - - /** - * Indicators are changed! - */ - case XkbIndicatorStateNotify: - - XklDebug( 150, "XkbIndicatorStateNotify\n" ); - - inds = _xklCurState.indicators; - - ForPhysIndicators( i, bit ) if( kev->indicators.changed & bit ) - { - if( kev->indicators.state & bit ) - inds |= bit; - else - inds &= ~bit; - } - - _XklStateModificationHandler( INDICATORS_CHANGED, - 0, - inds, - True ); - break; - - /** - * The configuration is changed! - */ - case XkbIndicatorMapNotify: - case XkbControlsNotify: - case XkbNamesNotify: + xkl_debug(150, + "XkbStateNotify detected, changes: %X/(mask %X), new group %d\n", + kev->state.changed, GROUP_CHANGE_MASK, + kev->state.locked_group); + + if (kev->state.changed & GROUP_CHANGE_MASK) + xkl_engine_process_state_modification(engine, + GROUP_CHANGED, + kev->state. + locked_group, + 0, FALSE); + else { /* ...not interested... */ + + xkl_debug(200, + "This type of state notification is not regarding groups\n"); + if (kev->state.locked_group != + xkl_engine_priv(engine, curr_state).group) + xkl_debug(0, + "ATTENTION! Currently cached group %d is not equal to the current group from the event: %d\n!", + xkl_engine_priv(engine, + curr_state). + group, kev->state.locked_group); + } + + break; + + /* + * Indicators are changed! + */ + case XkbIndicatorStateNotify: + + xkl_debug(150, "XkbIndicatorStateNotify\n"); + + inds = xkl_engine_priv(engine, curr_state).indicators; + + ForPhysIndicators(i, + bit) if (kev->indicators.changed & bit) { + if (kev->indicators.state & bit) + inds |= bit; + else + inds &= ~bit; + } + + xkl_engine_process_state_modification(engine, + INDICATORS_CHANGED, + 0, inds, TRUE); + break; + + /* + * The configuration is changed! + */ + case XkbIndicatorMapNotify: + case XkbControlsNotify: + case XkbNamesNotify: #if 0 - /* not really fair - but still better than flooding... */ - XklDebug( 200, "warning: configuration event %s is not actually processed\n", - _XklXkbGetXkbEventName( kev->any.xkb_type ) ); - break; + /* not really fair - but still better than flooding... */ + XklDebug(200, + "warning: configuration event %s is not actually processed\n", + _XklXkbGetXkbEventName(kev->any.xkb_type)); + break; #endif - case XkbNewKeyboardNotify: - XklDebug( 150, "%s\n", - _XklXkbGetXkbEventName( kev->any.xkb_type ) ); - _XklResetAllInfo( "XKB event: XkbNewKeyboardNotify" ); - break; - - /** - * ...Not interested... - */ - default: - XklDebug( 150, "Unknown XKB event %d [%s]\n", - kev->any.xkb_type, _XklXkbGetXkbEventName( kev->any.xkb_type ) ); - return 0; - } - return 1; + case XkbNewKeyboardNotify: + xkl_debug(150, "%s\n", + xkl_xkb_event_get_name(kev->any.xkb_type)); + xkl_engine_reset_all_info(engine, + "XKB event: XkbNewKeyboardNotify"); + break; + + /* + * ...Not interested... + */ + default: + xkl_debug(150, "Unknown XKB event %d [%s]\n", + kev->any.xkb_type, + xkl_xkb_event_get_name(kev->any.xkb_type)); + return 0; + } + return 1; #else - return 0; + return 0; #endif } -void _XklXkbSetIndicators( const XklState *windowState ) +void +xkl_xkb_set_indicators(XklEngine * engine, const XklState * window_state) { #ifdef XKB_HEADERS_PRESENT - int i; - unsigned bit; - - ForPhysIndicators( i, - bit ) if( _xklXkb->names->indicators[i] != None ) - { - Bool status; - status = _XklSetIndicator( i, - ( windowState->indicators & bit ) != 0 ); - XklDebug( 150, "Set indicator \"%s\"/%d to %d: %d\n", - _xklIndicatorNames[i], - _xklXkb->names->indicators[i], - windowState->indicators & bit, - status ); - } + int i; + unsigned bit; + + XkbDescPtr cached = + xkl_engine_backend(engine, XklXkb, cached_desc); + ForPhysIndicators(i, bit) if (cached->names->indicators[i] != None) { + gboolean status; + status = xkl_xkb_set_indicator(engine, i, + (window_state-> + indicators & bit) != 0); + xkl_debug(150, "Set indicator \"%s\"/%d to %d: %d\n", + xkl_engine_backend(engine, XklXkb, + indicator_names)[i], + cached->names->indicators[i], + window_state->indicators & bit, status); + } #endif } diff --git a/libxklavier/xklavier_evt_xmm.c b/libxklavier/xklavier_evt_xmm.c index 7574f3e..91d3699 100644 --- a/libxklavier/xklavier_evt_xmm.c +++ b/libxklavier/xklavier_evt_xmm.c @@ -3,170 +3,190 @@ #include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#include <X11/Xlibint.h> #include <X11/keysym.h> #include "xklavier_private.h" #include "xklavier_private_xmm.h" -static int _XklXmmKeypressEventHandler( XKeyPressedEvent* kpe ) +static gint +xkl_xmm_process_keypress_event(XklEngine * engine, 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; + if (xkl_engine_priv(engine, listener_type) & XKLL_MANAGE_LAYOUTS) { + xkl_debug(200, "Processing the KeyPress event\n"); + gint current_shortcut = 0; + const XmmSwitchOption *sop = + xkl_xmm_find_switch_option(engine, kpe->keycode, + kpe->state, + ¤t_shortcut); + if (sop != NULL) { + xkl_debug(150, "It is THE shortcut\n"); + XklState state; + xkl_xmm_get_server_state(engine, &state); + if (state.group != -1) { + gint new_group = + (state.group + + sop-> + shortcut_steps[current_shortcut]) % + g_strv_length(xkl_engine_backend + (engine, XklXmm, + current_config). + layouts); + xkl_debug(150, + "Setting new xmm group %d\n", + new_group); + xkl_xmm_lock_group(engine, new_group); + return 1; + } + } + } + return 0; } -static int _XklXmmPropertyEventHandler( XPropertyEvent* kpe ) +static gint +xkl_xmm_process_property_event(XklEngine * engine, XPropertyEvent * kpe) { - XklDebug( 200, "Processing the PropertyNotify event: %d/%d\n", - kpe->atom, xmmStateAtom ); - /** + Atom state_atom = xkl_engine_backend(engine, XklXmm, state_atom); + xkl_debug(200, "Processing the PropertyNotify event: %d/%d\n", + kpe->atom, state_atom); + /* * Group is changed! */ - if( kpe->atom == xmmStateAtom ) - { - XklState state; - _XklXmmGetRealState( &state ); - - if( _xklListenerType & XKLL_MANAGE_LAYOUTS ) - { - XklDebug( 150, "Current group from the root window property %d\n", state.group ); - _XklXmmUngrabShortcuts(); - _XklXmmActualizeGroup( state.group ); - _XklXmmGrabShortcuts(); - return 1; - } - - if( _xklListenerType & - ( XKLL_MANAGE_WINDOW_STATES | XKLL_TRACK_KEYBOARD_STATE ) ) - { - XklDebug( 150, - "XMM state changed, new 'group' %d\n", - state.group ); - - _XklStateModificationHandler( GROUP_CHANGED, - state.group, - 0, - False ); - } - } else - /** + if (kpe->atom == state_atom) { + XklState state; + xkl_xmm_get_server_state(engine, &state); + + if (xkl_engine_priv(engine, listener_type) & + XKLL_MANAGE_LAYOUTS) { + xkl_debug(150, + "Current group from the root window property %d\n", + state.group); + xkl_xmm_shortcuts_ungrab(engine); + xkl_xmm_actualize_group(engine, state.group); + xkl_xmm_shortcuts_grab(engine); + return 1; + } + + if (xkl_engine_priv(engine, listener_type) & + (XKLL_MANAGE_WINDOW_STATES | + XKLL_TRACK_KEYBOARD_STATE)) { + xkl_debug(150, + "XMM state changed, new 'group' %d\n", + state.group); + + xkl_engine_process_state_modification(engine, + GROUP_CHANGED, + state.group, + 0, False); + } + } else + /* * Configuration is changed! */ - if( kpe->atom == xklVTable->baseConfigAtom ) - { - _XklResetAllInfo( "base config atom changed" ); - } - - return 0; + if (kpe->atom == xkl_engine_priv(engine, base_config_atom)) { + xkl_engine_reset_all_info(engine, + "base config atom changed"); + } + + return 0; } -/** +/* * XMM event handler */ -int _XklXmmEventHandler( XEvent *xev ) +gint +xkl_xmm_process_x_event(XklEngine * engine, XEvent * xev) { - switch( xev->type ) - { - case KeyPress: - return _XklXmmKeypressEventHandler( (XKeyPressedEvent*)xev ); - case PropertyNotify: - return _XklXmmPropertyEventHandler( (XPropertyEvent*)xev ); - } - return 0; + switch (xev->type) { + case KeyPress: + return xkl_xmm_process_keypress_event(engine, + (XKeyPressedEvent *) + xev); + case PropertyNotify: + return xkl_xmm_process_property_event(engine, + (XPropertyEvent *) + xev); + } + return 0; } -/** +/* * 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 ) +static void +xkl_xmm_init_xmm_indicators_map(XklEngine * engine, + guint * p_caps_lock_mask, + guint * p_num_lock_mask, + guint * p_scroll_lock_mask) { - 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 ); - } + XModifierKeymap *xmkm = NULL; + KeyCode *kcmap, nlkc, clkc, slkc; + int m, k, mask; + + Display *display = xkl_engine_get_display(engine); + xmkm = XGetModifierMapping(display); + if (xmkm) { + clkc = XKeysymToKeycode(display, XK_Num_Lock); + nlkc = XKeysymToKeycode(display, XK_Caps_Lock); + slkc = XKeysymToKeycode(display, 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) + *p_caps_lock_mask = mask; + if (*kcmap == slkc) + *p_scroll_lock_mask = mask; + if (*kcmap == nlkc) + *p_num_lock_mask = mask; + } + XFreeModifiermap(xmkm); + } } -void _XklXmmGrabIgnoringIndicators( int keycode, int modifiers ) +void +xkl_xmm_grab_ignoring_indicators(XklEngine * engine, gint keycode, + guint modifiers) { - int CapsLockMask = 0, NumLockMask = 0, ScrollLockMask = 0; - - _XklXmmInitXmmIndicatorsMap( &CapsLockMask, &NumLockMask, &ScrollLockMask ); + guint caps_lock_mask = 0, num_lock_mask = 0, scroll_lock_mask = 0; + + xkl_xmm_init_xmm_indicators_map(engine, &caps_lock_mask, + &num_lock_mask, &scroll_lock_mask); #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 ); + xkl_engine_grab_key(engine, keycode, modifiers|(mods)) + + GRAB(0); + GRAB(caps_lock_mask); + GRAB(num_lock_mask); + GRAB(scroll_lock_mask); + GRAB(caps_lock_mask | num_lock_mask); + GRAB(caps_lock_mask | scroll_lock_mask); + GRAB(num_lock_mask | scroll_lock_mask); + GRAB(caps_lock_mask | num_lock_mask | scroll_lock_mask); #undef GRAB } -void _XklXmmUngrabIgnoringIndicators( int keycode, int modifiers ) +void +xkl_xmm_ungrab_ignoring_indicators(XklEngine * engine, gint keycode, + guint modifiers) { - int CapsLockMask = 0, NumLockMask = 0, ScrollLockMask = 0; + guint caps_lock_mask = 0, num_lock_mask = 0, scroll_lock_mask = 0; + + xkl_xmm_init_xmm_indicators_map(engine, &caps_lock_mask, + &num_lock_mask, &scroll_lock_mask); - _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 ); + xkl_engine_ungrab_key(engine, keycode, modifiers|(mods)) + + UNGRAB(0); + UNGRAB(caps_lock_mask); + UNGRAB(num_lock_mask); + UNGRAB(scroll_lock_mask); + UNGRAB(caps_lock_mask | num_lock_mask); + UNGRAB(caps_lock_mask | scroll_lock_mask); + UNGRAB(num_lock_mask | scroll_lock_mask); + UNGRAB(caps_lock_mask | num_lock_mask | scroll_lock_mask); #undef UNGRAB } diff --git a/libxklavier/xklavier_private.h b/libxklavier/xklavier_private.h index 0dfecc0..30aef9e 100644 --- a/libxklavier/xklavier_private.h +++ b/libxklavier/xklavier_private.h @@ -3,350 +3,384 @@ #include <stdio.h> -#include <libxklavier/xklavier_config.h> +#include <libxml/xpath.h> -typedef Bool ( *XklConfigActivateHandler )( const XklConfigRecPtr data ); +#include <libxklavier/xklavier.h> -typedef void ( *XklConfigInitHandler )( void ); - -typedef Bool ( *XklConfigLoadRegistryHandler )( void ); - -typedef Bool ( *XklConfigWriteFileHandler )( const char *fileName, - const XklConfigRecPtr data, - const Bool binary ); - -typedef int ( *XklEventHandler )( XEvent *xev ); - -typedef void ( *XklFreeAllInfoHandler )( void ); - -typedef const char **( *XklGetGroupNamesHandler )( void ); - -typedef unsigned ( *XklGetMaxNumGroupsHandler )( void ); - -typedef unsigned ( *XklGetNumGroupsHandler )( void ); - -typedef void ( *XklGetRealStateHandler)( XklState * curState_return ); - -typedef Bool ( *XklIfCachedInfoEqualsActualHandler) ( void ); - -typedef Bool ( *XklLoadAllInfoHandler )( void ); - -typedef void ( *XklLockGroupHandler )( int group ); - -typedef int ( *XklPauseResumeListenHandler )( void ); - -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 - * xmodmap: save the property, init layout #1 - */ - XklConfigActivateHandler xklConfigActivateHandler; - - /** - * Background-specific initialization. - * xkb: XkbInitAtoms - init internal xkb atoms table - * 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" - * xmodmap: loads xml from XMODMAP_BASE+"/"+ruleset+".xml" - */ - XklConfigLoadRegistryHandler xklConfigLoadRegistryHandler; - - /** - * Write the configuration into the file (binary/textual) - * xkb: write xkb or xkm file - * 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 - * xmodmap: keep track on the root window properties. What else can we do? - */ - XklEventHandler xklEventHandler; - - /** - * Flushes the cached server config info. - * xkb: frees XkbDesc - * xmodmap: frees internal XklConfigRec - */ - XklFreeAllInfoHandler xklFreeAllInfoHandler; /* private */ - - /** - * Get the list of the group names - * xkb: return cached list of the group names - * xmodmap: return the list of layouts from the internal XklConfigRec - */ - XklGetGroupNamesHandler xklGetGroupNamesHandler; - - /** - * Get the maximum number of loaded groups - * xkb: returns 1 or XkbNumKbdGroups - * xmodmap: return 0 - */ - XklGetMaxNumGroupsHandler xklGetMaxNumGroupsHandler; - - /** - * Get the number of loaded groups - * xkb: return from the cached XkbDesc - * 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; - - /** - * Compares the cached info with the actual one, from the server - * xkb: Compares some parts of XkbDescPtr - * xmodmap: returns False - */ - XklIfCachedInfoEqualsActualHandler xklIfCachedInfoEqualsActualHandler; - - /** - * Loads the configuration info from the server - * xkb: loads XkbDesc, names, indicators - * 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 - * xmodmap: changes the root window property - * (listener invokes xmodmap with appropriate config file). - */ - XklLockGroupHandler xklLockGroupHandler; - - /** - * Stop tracking the keyboard-related events - * xkb: XkbSelectEvents(..., 0) - * xmodmap: Ungrab the switching shortcut. - */ - XklPauseResumeListenHandler xklPauseListenHandler; - - /** - * Start tracking the keyboard-related events - * xkb: XkbSelectEvents + XkbSelectEventDetails - * xmodmap: Grab the switching shortcut. - */ - XklPauseResumeListenHandler xklResumeListenHandler; - - /** - * Set the indicators state from the XklState - * xkb: _XklSetIndicator for all indicators - * 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 _XklAddAppWindow( Window win, Window parent, Bool force, - XklState * initState ); -extern Bool _XklGetAppWindowBottomToTop( Window win, Window * appWin_return ); -extern Bool _XklGetAppWindow( Window win, Window * appWin_return ); - -extern void _XklFocusInEvHandler( XFocusChangeEvent * fev ); -extern void _XklFocusOutEvHandler( XFocusChangeEvent * fev ); -extern void _XklPropertyEvHandler( XPropertyEvent * rev ); -extern void _XklCreateEvHandler( XCreateWindowEvent * cev ); - -extern void _XklErrHandler( Display * dpy, XErrorEvent * evt ); - -extern Window _XklGetRegisteredParent( Window win ); -extern Bool _XklLoadAllInfo( void ); -extern void _XklFreeAllInfo( void ); -extern void _XklResetAllInfo( const char reason[] ); -extern Bool _XklLoadWindowTree( void ); -extern Bool _XklLoadSubtree( Window window, int level, XklState * initState ); - -extern Bool _XklHasWmState( Window win ); - -extern Bool _XklGetAppState( Window appWin, XklState * state_return ); -extern void _XklDelAppState( Window appWin ); -extern void _XklSaveAppState( Window appWin, XklState * state ); - -extern void _XklSelectInputMerging( Window win, long mask ); - -extern char *_XklGetDebugWindowTitle( Window win ); - -extern Status _XklStatusQueryTree( Display * display, - Window w, - Window * root_return, - Window * parent_return, - Window ** children_return, - unsigned int *nchildren_return ); - -extern Bool _XklSetIndicator( int indicatorNum, Bool set ); - -extern void _XklTryCallStateCallback( XklStateChange changeType, - XklState * oldState ); - -extern void _XklI18NInit( ); +enum { WM_NAME, + WM_STATE, + XKLAVIER_STATE, + XKLAVIER_TRANSPARENT, + XKLAVIER_ALLOW_SECONDARY, + TOTAL_ATOMS +}; + +struct _XklEnginePrivate { + + gboolean group_per_toplevel_window; + + gboolean handle_indicators; + + gboolean skip_one_restore; + + gint default_group; + + guint listener_type; + + guint secondary_groups_mask; + + Window root_window; + + Window prev_toplvl_win; + + Window curr_toplvl_win; + + XErrorHandler default_error_handler; + + Status last_error_code; + + XklState curr_state; + + Atom atoms[TOTAL_ATOMS]; + + Display *display; + + /* + * Backend name + */ + const gchar *backend_id; + + /* + * Functions supported by the backend, combination of XKLF_* constants + */ + guint8 features; + + /* + * Activates the configuration. + * xkb: create proper the XkbDescRec and send it to the server + * xmodmap: save the property, init layout #1 + */ + gboolean(*activate_config_rec) (XklEngine * engine, + const XklConfigRec * data); + + /* + * Background-specific initialization. + * xkb: XkbInitAtoms - init internal xkb atoms table + * xmodmap: void. + */ + void (*init_config_registry) (XklConfigRegistry * config); + + /* + * Loads the registry tree into DOM (using whatever path(s)) + * The XklVTConfigFreeRegistry is static - no virtualization necessary. + * xkb: loads xml from XKB_BASE+"/rules/"+ruleset+".xml" + * xmodmap: loads xml from XMODMAP_BASE+"/"+ruleset+".xml" + */ + gboolean(*load_config_registry) (XklConfigRegistry * config); + + /* + * Write the configuration into the file (binary/textual) + * xkb: write xkb or xkm file + * xmodmap: if text requested, just dump XklConfigRec to the + * file - not really useful. If binary - fail (not supported) + */ + gboolean(*write_config_rec_to_file) (XklEngine * engine, + const gchar * file_name, + const XklConfigRec * data, + const gboolean binary); + + /* + * Get the list of the group names + * xkb: return cached list of the group names + * xmodmap: return the list of layouts from the internal XklConfigRec + */ + const gchar **(*get_groups_names) (XklEngine * engine); + + /* + * Get the maximum number of loaded groups + * xkb: returns 1 or XkbNumKbdGroups + * xmodmap: return 0 + */ + guint(*get_max_num_groups) (XklEngine * engine); + + /* + * Get the number of loaded groups + * xkb: return from the cached XkbDesc + * xmodmap: return number of layouts from internal XklConfigRec + */ + guint(*get_num_groups) (XklEngine * engine); + + /* + * Switches the keyboard to the group N + * xkb: simple one-liner to call the XKB function + * xmodmap: changes the root window property + * (listener invokes xmodmap with appropriate config file). + */ + void (*lock_group) (XklEngine * engine, gint group); + + /* + * Handles X events. + * xkb: XkbEvent handling + * xmodmap: keep track on the root window properties. What else can we do? + */ + gint(*process_x_event) (XklEngine * engine, XEvent * xev); + + /* + * Flushes the cached server config info. + * xkb: frees XkbDesc + * xmodmap: frees internal XklConfigRec + */ + void (*free_all_info) (XklEngine * engine); + + /* + * Compares the cached info with the actual one, from the server + * xkb: Compares some parts of XkbDescPtr + * xmodmap: returns False + */ + gboolean(*if_cached_info_equals_actual) (XklEngine * engine); + + /* + * Loads the configuration info from the server + * xkb: loads XkbDesc, names, indicators + * xmodmap: loads internal XklConfigRec from server + */ + gboolean(*load_all_info) (XklEngine * engine); + + /* + * Gets the current state + * xkb: XkbGetState and XkbGetIndicatorState + * xmodmap: check the root window property (regarding the group) + */ + void (*get_server_state) (XklEngine * engine, + XklState * current_state_out); + + /* + * Stop tracking the keyboard-related events + * xkb: XkbSelectEvents(..., 0) + * xmodmap: Ungrab the switching shortcut. + */ + gint(*pause_listen) (XklEngine * engine); + + /* + * Start tracking the keyboard-related events + * xkb: XkbSelectEvents + XkbSelectEventDetails + * xmodmap: Grab the switching shortcut. + */ + gint(*resume_listen) (XklEngine * engine); + + /* + * Set the indicators state from the XklState + * xkb: XklSetIndicator for all indicators + * xmodmap: NULL. Not supported + */ + void (*set_indicators) (XklEngine * engine, + const XklState * window_state); + + /* + * Perform the cleanup + */ + void (*finalize) (XklEngine * engine); + + /* all data is private - no direct access */ + /* + * The base configuration atom. + * xkb: _XKB_RF_NAMES_PROP_ATOM + * xmodmap: "_XMM_NAMES" + */ + Atom base_config_atom; + + /* + * The configuration backup atom + * xkb: "_XKB_RULES_NAMES_BACKUP" + * xmodmap: "_XMM_NAMES_BACKUP" + */ + Atom backup_config_atom; + + /* + * Fallback for missing model + */ + const gchar *default_model; + + /* + * Fallback for missing layout + */ + const gchar *default_layout; + + /* + * Any stuff backend might need to put in here + */ + gpointer backend; +}; + +extern XklEngine *xkl_get_the_engine(void); + +struct _XklConfigRegistryPrivate { + XklEngine *engine; + + xmlDocPtr doc; + + xmlXPathContextPtr xpath_context; +}; + +extern void xkl_engine_ensure_vtable_inited(XklEngine * engine); + +extern void xkl_engine_process_focus_in_evt(XklEngine * engine, + XFocusChangeEvent * fev); +extern void xkl_engine_process_focus_out_evt(XklEngine * engine, + XFocusChangeEvent * fev); +extern void xkl_engine_process_property_evt(XklEngine * engine, + XPropertyEvent * rev); +extern void xkl_engine_process_create_window_evt(XklEngine * engine, + XCreateWindowEvent * cev); + +extern void xkl_process_error(Display * dpy, XErrorEvent * evt); + +extern void xkl_engine_process_state_modification(XklEngine * engine, + XklEngineStateChange + change_type, gint group, + unsigned inds, + gboolean set_indicators); + +extern Window xkl_engine_get_registered_parent(XklEngine * engine, + Window win); +extern void xkl_engine_reset_all_info(XklEngine * engine, + const gchar reason[]); +extern gboolean xkl_engine_load_window_tree(XklEngine * engine); +extern gboolean xkl_engine_load_subtree(XklEngine * engine, Window window, + gint level, XklState * init_state); + +extern gboolean xkl_engine_if_window_has_wm_state(XklEngine * engine, + Window win); + + +/** + * Toplevel window stuff + */ +extern void xkl_engine_add_toplevel_window(XklEngine * engine, Window win, + Window parent, gboolean force, + XklState * init_state); + +extern gboolean xkl_engine_find_toplevel_window_bottom_to_top(XklEngine * + engine, + Window win, + Window * + toplevel_win_out); -extern char *_XklLocaleFromUtf8( const char *utf8string ); +extern gboolean xkl_engine_find_toplevel_window(XklEngine * engine, + Window win, + Window * toplevel_win_out); -extern int _XklGetLanguagePriority( const char *language ); +extern gboolean xkl_engine_is_toplevel_window_transparent(XklEngine * + engine, + Window + toplevel_win); -extern char* _XklGetRulesSetName( const char defaultRuleset[] ); +extern void xkl_engine_set_toplevel_window_transparent(XklEngine * engine, + Window toplevel_win, + gboolean + transparent); -extern Bool _XklConfigGetFullFromServer( char **rulesFileOut, - XklConfigRecPtr data ); +extern gboolean xkl_engine_get_toplevel_window_state(XklEngine * engine, + Window toplevel_win, + XklState * state_out); -extern char *_XklConfigRecMergeByComma( const char **array, - const int arrayLength ); +extern void xkl_engine_remove_toplevel_window_state(XklEngine * engine, + Window toplevel_win); +extern void xkl_engine_save_toplevel_window_state(XklEngine * engine, + Window toplevel_win, + XklState * state); +/***/ -extern char *_XklConfigRecMergeLayouts( const XklConfigRecPtr data ); +extern void xkl_engine_select_input_merging(XklEngine * engine, Window win, + gulong mask); -extern char *_XklConfigRecMergeVariants( const XklConfigRecPtr data ); +extern gchar *xkl_get_debug_window_title(XklEngine * engine, Window win); -extern char *_XklConfigRecMergeOptions( const XklConfigRecPtr data ); +extern Status xkl_engine_query_tree(XklEngine * engine, + Window w, + Window * root_out, + Window * parent_out, + Window ** children_out, + guint * nchildren_out); -extern void _XklConfigRecSplitByComma( char ***array, - int *arraySize, const char *merged ); +extern void xkl_engine_try_call_state_func(XklEngine * engine, + XklEngineStateChange + change_type, + XklState * old_state); -extern void _XklConfigRecSplitLayouts( XklConfigRecPtr data, - const char *merged ); +extern void xkl_i18n_init(void); -extern void _XklConfigRecSplitVariants( XklConfigRecPtr data, - const char *merged ); +extern gchar *xkl_locale_from_utf8(const gchar * utf8string); -extern void _XklConfigRecSplitOptions( XklConfigRecPtr data, - const char *merged ); +extern gint xkl_get_language_priority(const gchar * language); -extern void XklConfigDump( FILE* file, - XklConfigRecPtr data ); - -extern const char *_XklGetEventName( int requestId ); +extern gchar *xkl_engine_get_ruleset_name(XklEngine * engine, + const gchar default_ruleset[]); -extern Bool _XklIsTransparentAppWindow( Window appWin ); +extern gboolean xkl_config_rec_get_full_from_server(gchar ** + rules_file_out, + XklConfigRec * data, + XklEngine * engine); -extern void _XklUpdateCurState( int group, unsigned indicators, const char reason[] ); +extern gchar *xkl_strings_concat_comma_separated(gchar ** array); -extern void _XklStateModificationHandler( XklStateChange changeType, - int grp, - unsigned inds, - Bool setInds ); +extern void xkl_strings_split_comma_separated(gchar *** array, + const gchar * merged); -extern int _XklXkbInit( void ); +/** + * XConfigRec + */ +extern gchar *xkl_config_rec_merge_layouts(const XklConfigRec * data); -extern int _XklXmmInit( void ); +extern gchar *xkl_config_rec_merge_variants(const XklConfigRec * data); -extern Bool _XklIsOneSwitchToSecondaryGroupAllowed( void ); +extern gchar *xkl_config_rec_merge_options(const XklConfigRec * data); -extern void _XklOneSwitchToSecondaryGroupPerformed( void ); +extern void xkl_config_rec_split_layouts(XklConfigRec * data, + const gchar * merged); -extern Display *_xklDpy; +extern void xkl_config_rec_split_variants(XklConfigRec * data, + const gchar * merged); -extern Window _xklRootWindow; +extern void xkl_config_rec_split_options(XklConfigRec * data, + const gchar * merged); +/***/ -extern XklState _xklCurState; +extern void xkl_config_rec_dump(FILE * file, XklConfigRec * data); -extern Window _xklCurClient; +extern const gchar *xkl_event_get_name(gint type); -extern Status _xklLastErrorCode; +extern void xkl_engine_update_current_state(XklEngine * engine, gint group, + unsigned indicators, + const gchar reason[]); -extern const char *_xklLastErrorMsg; +extern gint xkl_xkb_init(XklEngine * engine); -extern XErrorHandler _xklDefaultErrHandler; +extern gint xkl_xmm_init(XklEngine * engine); -extern char *_xklIndicatorNames[]; +extern gboolean +xkl_engine_is_one_switch_to_secondary_group_allowed(XklEngine * engine); -enum { WM_NAME, - WM_STATE, - XKLAVIER_STATE, - XKLAVIER_TRANSPARENT, - XKLAVIER_ALLOW_SECONDARY, - TOTAL_ATOMS }; +extern void xkl_engine_one_switch_to_secondary_group_performed(XklEngine * + engine); #define XKLAVIER_STATE_PROP_LENGTH 2 /* taken from XFree86 maprules.c */ -#define _XKB_RF_NAMES_PROP_MAXLEN 1024 - -extern Atom _xklAtoms[]; - -extern Bool _xklAllowSecondaryGroupOnce; - -extern int _xklDefaultGroup; - -extern Bool _xklSkipOneRestore; - -extern int _xklSecondaryGroupsMask; - -extern int _xklDebugLevel; - -extern int _xklListenerType; - -extern Window _xklPrevAppWindow; +#define XKB_RF_NAMES_PROP_MAXLEN 1024 #define WINID_FORMAT "%lx" -extern XklConfigCallback _xklConfigCallback; +#define xkl_engine_priv(engine,member) (engine)->priv->member +#define xkl_engine_backend(engine,type,member) ((type*)((engine)->priv->backend))->member +#define xkl_engine_get_display(engine) (xkl_engine_priv(engine,display)) +#define xkl_engine_vcall(engine,func) (*(engine)->priv->func) -extern void *_xklConfigCallbackData; +#define xkl_config_registry_priv(config,member) (config)->priv->member +#define xkl_config_registry_get_engine(config) ((config)->priv->engine) -extern XklVTable *xklVTable; +extern gint xkl_debug_level; -#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 +extern const gchar *xkl_last_error_message; #endif diff --git a/libxklavier/xklavier_private_xkb.h b/libxklavier/xklavier_private_xkb.h index ce71002..0fa7d15 100644 --- a/libxklavier/xklavier_private_xkb.h +++ b/libxklavier/xklavier_private_xkb.h @@ -8,74 +8,99 @@ #define ForPhysIndicators( i, bit ) \ for ( i=0, bit=1; i<XkbNumIndicators; i++, bit<<=1 ) \ - if ( _xklXkb->indicators->phys_indicators & bit ) + if ( xkl_engine_backend(engine,XklXkb,cached_desc)->indicators->phys_indicators & bit ) -extern int _xklXkbEventType, _xklXkbError; +typedef struct _XklXkb { -extern XkbRF_VarDefsRec _xklVarDefs; + gint event_type; -extern XkbDescPtr _xklXkb; + gint error_code; -extern void XklDumpXkbDesc( const char *filename, XkbDescPtr kbd ); + XkbDescPtr cached_desc; -extern Bool _XklXkbConfigMultipleLayoutsSupported( void ); + gchar *indicator_names[XkbNumIndicators]; -extern const char *_XklXkbGetXkbEventName( int xkb_type ); + XkbDescPtr actual_desc; -extern Bool _XklXkbConfigPrepareNative( const XklConfigRecPtr data, XkbComponentNamesPtr componentNamesPtr ); + gchar *group_names[XkbNumKbdGroups]; -extern void _XklXkbConfigCleanupNative( XkbComponentNamesPtr componentNamesPtr ); +} XklXkb; + +extern void xkl_engine_dump_xkb_desc(XklEngine * engine, + const char *file_name, + XkbDescPtr kbd); + +extern gboolean xkl_xkb_multiple_layouts_supported(XklEngine * engine); + +extern const gchar *xkl_xkb_event_get_name(gint xkb_type); + +extern gboolean xkl_xkb_config_native_prepare(XklEngine * engine, + const XklConfigRec * data, + XkbComponentNamesPtr + component_names); + +extern void xkl_xkb_config_native_cleanup(XklEngine * engine, + XkbComponentNamesPtr + component_names); + +extern gboolean xkl_xkb_set_indicator(XklEngine * engine, + gint indicator_num, gboolean set); /* Start VTable methods */ -extern Bool _XklXkbConfigActivate( const XklConfigRecPtr data ); +extern gboolean xkl_xkb_activate_config_rec(XklEngine * engine, + const XklConfigRec * data); -extern void _XklXkbConfigInit( void ); +extern void xkl_xkb_init_config_registry(XklConfigRegistry * config); -extern Bool _XklXkbConfigLoadRegistry( void ); +extern gboolean xkl_xkb_load_config_registry(XklConfigRegistry * config); -extern Bool _XklXkbConfigWriteFile( const char *fileName, - const XklConfigRecPtr data, - const Bool binary ); +extern gboolean xkl_xkb_write_config_rec_to_file(XklEngine * engine, + const char *file_name, + const XklConfigRec * data, + const gboolean binary); -extern int _XklXkbEventHandler( XEvent * kev ); +extern gint xkl_xkb_process_x_event(XklEngine * engine, XEvent * kev); -extern void _XklXkbFreeAllInfo( void ); +extern void xkl_xkb_free_all_info(XklEngine * engine); -extern const char **_XklXkbGetGroupNames( void ); +extern const gchar **xkl_xkb_get_groups_names(XklEngine * engine); -extern unsigned _XklXkbGetMaxNumGroups( void ); +extern guint xkl_xkb_get_max_num_groups(XklEngine * engine); -extern unsigned _XklXkbGetNumGroups( void ); +extern guint xkl_xkb_get_num_groups(XklEngine * engine); -extern void _XklXkbGetRealState( XklState * curState_return ); +extern void xkl_xkb_get_server_state(XklEngine * engine, + XklState * current_state_out); -extern Bool _XklXkbIfCachedInfoEqualsActual( void ); +extern gboolean xkl_xkb_if_cached_info_equals_actual(XklEngine * engine); -extern Bool _XklXkbLoadAllInfo( void ); +extern gboolean xkl_xkb_load_all_info(XklEngine * engine); -extern void _XklXkbLockGroup( int group ); +extern void xkl_xkb_lock_group(XklEngine * engine, gint group); -extern int _XklXkbPauseListen( void ); +extern gint xkl_xkb_pause_listen(XklEngine * engine); -extern int _XklXkbResumeListen( void ); +extern gint xkl_xkb_resume_listen(XklEngine * engine); -extern void _XklXkbSetIndicators( const XklState *windowState ); +extern void xkl_xkb_set_indicators(XklEngine * engine, + const XklState * window_state); + +extern void xkl_xkb_term(XklEngine * engine); /* End of VTable methods */ #else -/** +/* * VERY VERY BAD STYLE, some kind of 'protected' methods - * but some programs may want to hook into them. */ -extern Bool _XklXkbConfigPrepareNative( const XklConfigRecPtr data, void * componentNamesPtr ); +extern gboolean xkl_xkb_config_prepare_native(const XklConfigRec * data, + gpointer component_names); -extern void _XklXkbConfigCleanupNative( void * componentNamesPtr ); +extern void xkl_xkb_config_cleanup_native(gpointer component_names); #endif -extern Bool _xklXkbExtPresent; - #endif diff --git a/libxklavier/xklavier_private_xmm.h b/libxklavier/xklavier_private_xmm.h index f83cd07..178e7d2 100644 --- a/libxklavier/xklavier_private_xmm.h +++ b/libxklavier/xklavier_private_xmm.h @@ -1,77 +1,92 @@ #ifndef __XKLAVIER_PRIVATE_XMM_H__ #define __XKLAVIER_PRIVATE_XMM_H__ -typedef struct _XmmShortcut -{ - int keysym; - int modifiers; -} XmmShortcut, *XmmShortcutPtr; +typedef struct _XmmShortcut { + guint keysym; + guint modifiers; +} XmmShortcut; #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; +typedef struct _XmmSwitchOption { + XmmShortcut shortcuts[MAX_SHORTCUTS_PER_OPTION + 1]; + gint shortcut_steps[MAX_SHORTCUTS_PER_OPTION + 1]; +} XmmSwitchOption; -extern char* currentXmmRules; +typedef struct _XklXmm { + gchar *current_rules; -extern XklConfigRec currentXmmConfig; + XklConfigRec current_config; -extern Atom xmmStateAtom; + Atom state_atom; + + GHashTable *switch_options; +} XklXmm; /* in the ideal world this should be a hashmap */ -extern XmmSwitchOption allSwitchOptions[]; +extern void xkl_xmm_grab_ignoring_indicators(XklEngine * engine, + gint keycode, + guint modifiers); -extern void _XklXmmGrabIgnoringIndicators( int keycode, int modifiers ); +extern void xkl_xmm_ungrab_ignoring_indicators(XklEngine * engine, + gint keycode, + guint modifiers); -extern void _XklXmmUngrabIgnoringIndicators( int keycode, int modifiers ); +extern void xkl_xmm_shortcuts_grab(XklEngine * engine); -extern void _XklXmmGrabShortcuts( void ); +extern void xkl_xmm_shortcuts_ungrab(XklEngine * engine); -extern void _XklXmmUngrabShortcuts( void ); +extern const gchar *xkl_xmm_shortcut_get_current_option_name(XklEngine * + engine); -extern const char* _XklXmmGetCurrentShortcutOptionName( void ); +XmmSwitchOption *xkl_xmm_shortcut_get_current(XklEngine * engine); -XmmSwitchOptionPtr _XklXmmGetCurrentShortcut( void ); +extern void xkl_xmm_actualize_group(XklEngine * engine, gint group); -extern void _XklXmmActualizeGroup( int group ); +const XmmSwitchOption *xkl_xmm_find_switch_option(XklEngine * engine, + gint keycode, + guint state, + gint * + current_shortcut_out); -XmmSwitchOptionPtr _XklXmmFindSwitchOption( unsigned keycode, - unsigned state, - int * currentShortcut_rv ); +extern void xkl_xmm_init_switch_options(XklXmm * xmm); +extern void xkl_xmm_term_switch_options(XklXmm * xmm); /* Start VTable methods */ -extern Bool _XklXmmConfigActivate( const XklConfigRecPtr data ); +extern gboolean xkl_xmm_activate_config_rec(XklEngine * engine, + const XklConfigRec * data); + +extern void xkl_xmm_init_config_registry(XklConfigRegistry * config); + +extern gboolean xkl_xmm_load_config_registry(XklConfigRegistry * config); -extern void _XklXmmConfigInit( void ); +extern gint xkl_xmm_process_x_event(XklEngine * engine, XEvent * kev); -extern Bool _XklXmmConfigLoadRegistry( void ); +extern void xkl_xmm_free_all_info(XklEngine * engine); -extern int _XklXmmEventHandler( XEvent * kev ); +extern const gchar **xkl_xmm_get_groups_names(XklEngine * engine); -extern void _XklXmmFreeAllInfo( void ); +extern guint xkl_xmm_get_max_num_groups(XklEngine * engine); -extern const char **_XklXmmGetGroupNames( void ); +extern guint xkl_xmm_get_num_groups(XklEngine * engine); -extern unsigned _XklXmmGetMaxNumGroups( void ); +extern void xkl_xmm_lock_group(XklEngine * engine, gint group); -extern unsigned _XklXmmGetNumGroups( void ); +extern void xkl_xmm_get_server_state(XklEngine * engine, + XklState * current_state_out); -extern void _XklXmmGetRealState( XklState * curState_return ); +extern gboolean xkl_xmm_if_cached_info_equals_actual(XklEngine * engine); -extern Bool _XklXmmIfCachedInfoEqualsActual( void ); +extern gboolean xkl_xmm_load_all_info(XklEngine * engine); -extern Bool _XklXmmLoadAllInfo( void ); +extern gint xkl_xmm_listen_pause(XklEngine * engine); -extern void _XklXmmLockGroup( int group ); +extern gint xkl_xmm_listen_resume(XklEngine * engine); -extern int _XklXmmPauseListen( void ); +extern void xkl_xmm_set_indicators(XklEngine * engine, + const XklState * window_state); -extern int _XklXmmResumeListen( void ); +extern void xkl_xmm_term(XklEngine * engine); /* End of VTable methods */ diff --git a/libxklavier/xklavier_props.c b/libxklavier/xklavier_props.c index 52a98fe..b18d142 100644 --- a/libxklavier/xklavier_props.c +++ b/libxklavier/xklavier_props.c @@ -1,6 +1,6 @@ #include <errno.h> -#include <string.h> #include <locale.h> +#include <string.h> #include <X11/Xlib.h> #include <X11/Xatom.h> @@ -9,417 +9,465 @@ #include "config.h" -#include "xklavier.h" -#include "xklavier_config.h" #include "xklavier_private.h" -void XklConfigRecInit( XklConfigRecPtr data ) +static GObjectClass *parent_class = NULL; + +static void xkl_config_rec_destroy(XklConfigRec * data); + +G_DEFINE_TYPE(XklConfigItem, xkl_config_item, G_TYPE_OBJECT) + +static void +xkl_config_item_init(XklConfigItem * this) { - /* clear the structure VarDefsPtr... */ - memset( ( void * ) data, 0, sizeof( XklConfigRec ) ); } -static Bool PtrsEqual( char* p1, char* p2 ) +static void +xkl_config_item_class_init(XklConfigItemClass * klass) { - if ( p1 == p2 ) - return True; - if ( ( p1 == NULL && p2 != NULL ) || - ( p1 != NULL && p2 == NULL ) ) - return False; - return !strcmp( p1, p2 ); } -static Bool ListsEqual( int numItems1, char** items1, - int numItems2, char** items2 ) +XklConfigItem * +xkl_config_item_new(void) { - int i; - if ( numItems1 != numItems2 ) - return False; - if ( items1 == items2 ) - return True; - for( i = numItems1; --i >= 0; ) - if ( !PtrsEqual( *items1++ , *items2++ ) ) - return False; - return True; + return + XKL_CONFIG_ITEM(g_object_new + (xkl_config_item_get_type(), NULL)); } -static Bool _XklGetDefaultNamesProp( char **rulesFileOut, XklConfigRecPtr data ) +G_DEFINE_TYPE(XklConfigRec, xkl_config_rec, G_TYPE_OBJECT) + +static void +xkl_config_rec_finalize(GObject * obj) { - if ( rulesFileOut != NULL ) - *rulesFileOut = strdup( XKB_DEFAULT_RULESET ); - data->model = strdup( xklVTable->defaultModel ); -/* keeping Nvariants = Nlayouts */ - data->numLayouts = data->numVariants = 1; - data->layouts = malloc( sizeof( char * ) ); - data->layouts[0] = strdup( xklVTable->defaultLayout ); - data->variants = malloc( sizeof( char * ) ); - data->variants[0] = strdup( "" ); - data->numOptions = 0; - data->options = NULL; - return True; + XklConfigRec *this = (XklConfigRec *) obj; + xkl_config_rec_destroy(this); + G_OBJECT_CLASS(parent_class)->finalize(obj); } -Bool _XklConfigGetFullFromServer( char **rulesFileOut, XklConfigRecPtr data ) +static void +xkl_config_rec_class_init(XklConfigRecClass * klass) { - Bool rv = - XklGetNamesProp( xklVTable->baseConfigAtom, rulesFileOut, data ); + GObjectClass *object_class; - if( !rv ) - rv = _XklGetDefaultNamesProp( rulesFileOut, data ); + object_class = (GObjectClass *) klass; + parent_class = g_type_class_peek_parent(object_class); + object_class->finalize = xkl_config_rec_finalize; +} - return rv; +XklConfigRec * +xkl_config_rec_new(void) +{ + return + XKL_CONFIG_REC(g_object_new(xkl_config_rec_get_type(), NULL)); } -Bool XklConfigRecEquals( XklConfigRecPtr data1, XklConfigRecPtr data2 ) +static gboolean +xkl_strings_equal(gchar * p1, gchar * p2) { - if ( data1 == data2 ) - return True; - if ( !PtrsEqual( data1->model, data2->model ) ) - return False; - if ( !ListsEqual( data1->numLayouts, data1->layouts, - data2->numLayouts, data2->layouts ) ) - return False; - if ( !ListsEqual( data1->numVariants, data1->variants, - data2->numVariants, data2->variants ) ) - return False; - return ListsEqual( data1->numOptions, data1->options, - data2->numOptions, data2->options ); + if (p1 == p2) + return TRUE; + if ((p1 == NULL && p2 != NULL) || (p1 != NULL && p2 == NULL)) + return FALSE; + return !g_ascii_strcasecmp(p1, p2); } -void XklConfigRecDestroy( XklConfigRecPtr data ) +static gboolean +xkl_lists_equal(gchar ** items1, gchar ** items2) { - int i; - char **p; - - if( data->model != NULL ) - free( data->model ); - - if( ( p = data->layouts ) != NULL ) - { - for( i = data->numLayouts; --i >= 0; ) - free( *p++ ); - free( data->layouts ); - } - - if( ( p = data->variants ) != NULL ) - { - for( i = data->numVariants; --i >= 0; ) - free( *p++ ); - free( data->variants ); - } - - if( ( p = data->options ) != NULL ) - { - for( i = data->numOptions; --i >= 0; ) - free( *p++ ); - free( data->options ); - } + if (items1 == items2) + return TRUE; + + if ((items1 == NULL && items2 != NULL) || + (items1 != NULL && items2 == NULL)) + return FALSE; + + while (*items1 != NULL && *items2 != NULL) + if (!xkl_strings_equal(*items1++, *items2++)) + return FALSE; + + return (*items1 == NULL && *items2 == NULL); } -void XklConfigRecReset( XklConfigRecPtr data ) +static gboolean +xkl_engine_get_default_names_prop(XklEngine * engine, + char **rules_file_out, + XklConfigRec * data) { - XklConfigRecDestroy( data ); - XklConfigRecInit( data ); + if (rules_file_out != NULL) + *rules_file_out = g_strdup(XKB_DEFAULT_RULESET); + data->model = g_strdup(xkl_engine_priv(engine, default_model)); +/* keeping Nvariants = Nlayouts */ + data->layouts = g_new0(char *, 2); + data->layouts[0] = + g_strdup(xkl_engine_priv(engine, default_layout)); + data->variants = g_new0(char *, 2); + data->variants[0] = g_strdup(""); + data->options = NULL; + return TRUE; } -Bool XklConfigGetFromServer( XklConfigRecPtr data ) +gboolean +xkl_config_rec_get_full_from_server(char **rules_file_out, + XklConfigRec * data, + XklEngine * engine) { - return _XklConfigGetFullFromServer( NULL, data ); + gboolean rv = xkl_config_rec_get_from_root_window_property(data, + xkl_engine_priv + (engine, + base_config_atom), + rules_file_out, + engine); + + if (!rv) + rv = xkl_engine_get_default_names_prop(engine, + rules_file_out, + data); + + return rv; } -Bool XklConfigGetFromBackup( XklConfigRecPtr data ) +gboolean +xkl_config_rec_equals(XklConfigRec * data1, XklConfigRec * data2) { - Bool rv = - XklGetNamesProp( xklVTable->backupConfigAtom, NULL, data ); + if (data1 == data2) + return TRUE; + if (!xkl_strings_equal(data1->model, data2->model)) + return FALSE; + if (!xkl_lists_equal(data1->layouts, data2->layouts)) + return FALSE; + if (!xkl_lists_equal(data1->variants, data2->variants)) + return FALSE; + return xkl_lists_equal(data1->options, data2->options); +} - return rv; +void +xkl_config_rec_init(XklConfigRec * data) +{ + /* clear the structure VarDefsPtr... */ + data->model = NULL; + data->layouts = data->variants = data->options = NULL; } -Bool XklBackupNamesProp( void ) +void +xkl_config_rec_destroy(XklConfigRec * data) { - Bool rv = True; - char *rf = NULL; - XklConfigRec data; - Bool cgp = False; - - XklConfigRecInit( &data ); - if( XklGetNamesProp - ( xklVTable->backupConfigAtom, NULL, &data ) ) - { - XklConfigRecDestroy( &data ); - return True; - } - /* "backup" property is not defined */ - XklConfigRecReset( &data ); - cgp = _XklConfigGetFullFromServer( &rf, &data ); - - if ( cgp ) - { -#if 0 - int i; - XklDebug( 150, "Original model: [%s]\n", data.model ); + if (data->model != NULL) + g_free(data->model); - XklDebug( 150, "Original layouts(%d):\n", data.numLayouts ); - for( i = data.numLayouts; --i >= 0; ) - XklDebug( 150, "%d: [%s]\n", i, data.layouts[i] ); + g_strfreev(data->layouts); + g_strfreev(data->variants); + g_strfreev(data->options); + data->layouts = data->variants = data->options = NULL; +} - XklDebug( 150, "Original variants(%d):\n", data.numVariants ); - for( i = data.numVariants; --i >= 0; ) - XklDebug( 150, "%d: [%s]\n", i, data.variants[i] ); +void +xkl_config_rec_reset(XklConfigRec * data) +{ + xkl_config_rec_destroy(data); + xkl_config_rec_init(data); +} - XklDebug( 150, "Original options(%d):\n", data.numOptions ); - for( i = data.numOptions; --i >= 0; ) - XklDebug( 150, "%d: [%s]\n", i, data.options[i] ); -#endif - if( !XklSetNamesProp( xklVTable->backupConfigAtom, rf, &data ) ) - { - XklDebug( 150, "Could not backup the configuration" ); - rv = False; - } - if( rf != NULL ) - free( rf ); - } else - { - XklDebug( 150, "Could not get the configuration for backup" ); - rv = False; - } - XklConfigRecDestroy( &data ); - return rv; +gboolean +xkl_config_rec_get_from_server(XklConfigRec * data, XklEngine * engine) +{ + return xkl_config_rec_get_full_from_server(NULL, data, engine); +} + +gboolean +xkl_config_rec_get_from_backup(XklConfigRec * data, XklEngine * engine) +{ + return xkl_config_rec_get_from_root_window_property(data, + xkl_engine_priv + (engine, + backup_config_atom), + NULL, engine); +} + +gboolean +xkl_backup_names_prop(XklEngine * engine) +{ + gboolean rv = TRUE; + gchar *rf = NULL; + XklConfigRec data; + gboolean cgp = FALSE; + + xkl_config_rec_init(&data); + if (xkl_config_rec_get_from_root_window_property + (&data, xkl_engine_priv(engine, backup_config_atom), NULL, + engine)) { + xkl_config_rec_destroy(&data); + return TRUE; + } + /* "backup" property is not defined */ + xkl_config_rec_reset(&data); + cgp = xkl_config_rec_get_full_from_server(&rf, &data, engine); + + if (cgp) { + if (!xkl_config_rec_set_to_root_window_property + (&data, xkl_engine_priv(engine, backup_config_atom), + rf, engine)) { + xkl_debug(150, + "Could not backup the configuration"); + rv = FALSE; + } + if (rf != NULL) + g_free(rf); + } else { + xkl_debug(150, + "Could not get the configuration for backup"); + rv = FALSE; + } + xkl_config_rec_destroy(&data); + return rv; } -Bool XklRestoreNamesProp( void ) +gboolean +xkl_restore_names_prop(XklEngine * engine) { - Bool rv = True; - char *rf = NULL; - XklConfigRec data; - - XklConfigRecInit( &data ); - if( !XklGetNamesProp( xklVTable->backupConfigAtom, NULL, &data ) ) - { - XklConfigRecDestroy( &data ); - return False; - } - - if( !XklSetNamesProp( xklVTable->baseConfigAtom, rf, &data ) ) - { - XklDebug( 150, "Could not backup the configuration" ); - rv = False; - } - XklConfigRecDestroy( &data ); - return rv; + gboolean rv = TRUE; + gchar *rf = NULL; + XklConfigRec data; + + xkl_config_rec_init(&data); + if (!xkl_config_rec_get_from_root_window_property + (&data, xkl_engine_priv(engine, backup_config_atom), NULL, + engine)) { + xkl_config_rec_destroy(&data); + return FALSE; + } + + if (!xkl_config_rec_set_to_root_window_property + (&data, xkl_engine_priv(engine, base_config_atom), rf, + engine)) { + xkl_debug(150, "Could not backup the configuration"); + rv = FALSE; + } + xkl_config_rec_destroy(&data); + return rv; } -Bool XklGetNamesProp( Atom rulesAtom, - char **rulesFileOut, XklConfigRecPtr data ) +gboolean +xkl_config_rec_get_from_root_window_property(XklConfigRec * data, + Atom rules_atom, + gchar ** rules_file_out, + XklEngine * engine) { - Atom realPropType; - int fmt; - unsigned long nitems, extraBytes; - char *propData = NULL, *out; - Status rtrn; - - /* no such atom! */ - if( rulesAtom == None ) /* property cannot exist */ - { - _xklLastErrorMsg = "Could not find the atom"; - return False; - } - - rtrn = - XGetWindowProperty( _xklDpy, _xklRootWindow, rulesAtom, 0L, - _XKB_RF_NAMES_PROP_MAXLEN, False, XA_STRING, - &realPropType, &fmt, &nitems, &extraBytes, - ( unsigned char ** ) ( void * ) &propData ); - /* property not found! */ - if( rtrn != Success ) - { - _xklLastErrorMsg = "Could not get the property"; - return False; - } - /* set rules file to "" */ - if( rulesFileOut ) - *rulesFileOut = NULL; - - /* has to be array of strings */ - if( ( extraBytes > 0 ) || ( realPropType != XA_STRING ) || ( fmt != 8 ) ) - { - if( propData ) - XFree( propData ); - _xklLastErrorMsg = "Wrong property format"; - return False; - } - - if( !propData ) - { - _xklLastErrorMsg = "No properties returned"; - return False; - } - - /* 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( !data ) - { - XFree( propData ); - return True; - } - - if( ( out - propData ) < nitems ) - { - if( *out ) - data->model = strdup( out ); - out += strlen( out ) + 1; - } - - if( ( out - propData ) < nitems ) - { - _XklConfigRecSplitLayouts( data, out ); - out += strlen( out ) + 1; - } - - if( ( out - propData ) < nitems ) - { - int i; - char **theLayout, **theVariant; - _XklConfigRecSplitVariants( data, out ); - /* - Now have to ensure that number of variants matches the number of layouts - The 'remainder' is filled with NULLs (not ""s!) - */ - if( data->numVariants < data->numLayouts ) - { - data->variants = - realloc( data->variants, data->numLayouts * sizeof( char * ) ); - memset( data->variants + data->numVariants, 0, - ( data->numLayouts - data->numVariants ) * sizeof( char * ) ); - data->numVariants = data->numLayouts; - } - /* take variants from layouts like ru(winkeys) */ - theLayout = data->layouts; - theVariant = data->variants; - for( i = data->numLayouts; --i >= 0; theLayout++, theVariant++ ) - { - if( *theLayout != NULL ) - { - char *varstart = strchr( *theLayout, '(' ); - if( varstart != NULL ) - { - char *varend = strchr( varstart, ')' ); - if( varend != NULL ) - { - int varlen = varend - varstart; - int laylen = varstart - *theLayout; - /* 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 ); - var[varlen] = '\0'; - - ( (char*)realloc( *theLayout, laylen + 1 ) )[laylen] = '\0'; - } - } - } - } - out += strlen( out ) + 1; - } - - if( ( out - propData ) < nitems ) - { - _XklConfigRecSplitOptions( data, out ); -/* out += strlen( out ) + 1; */ - } - XFree( propData ); - return True; + Atom real_prop_type; + int fmt; + unsigned long nitems, extra_bytes; + char *prop_data = NULL, *out; + Status rtrn; + + /* no such atom! */ + if (rules_atom == None) { /* property cannot exist */ + xkl_last_error_message = "Could not find the atom"; + return FALSE; + } + + rtrn = + XGetWindowProperty(xkl_engine_get_display(engine), + xkl_engine_priv(engine, root_window), + rules_atom, 0L, XKB_RF_NAMES_PROP_MAXLEN, + False, XA_STRING, &real_prop_type, &fmt, + &nitems, &extra_bytes, + (unsigned char **) (void *) &prop_data); + /* property not found! */ + if (rtrn != Success) { + xkl_last_error_message = "Could not get the property"; + return FALSE; + } + /* set rules file to "" */ + if (rules_file_out) + *rules_file_out = NULL; + + /* has to be array of strings */ + if ((extra_bytes > 0) || (real_prop_type != XA_STRING) + || (fmt != 8)) { + if (prop_data) + XFree(prop_data); + xkl_last_error_message = "Wrong property format"; + return FALSE; + } + + if (!prop_data) { + xkl_last_error_message = "No properties returned"; + return FALSE; + } + + /* rules file */ + out = prop_data; + if (out && (*out) && rules_file_out) + *rules_file_out = g_strdup(out); + out += strlen(out) + 1; + + /* if user is interested in rules only - don't waste the time */ + if (!data) { + XFree(prop_data); + return TRUE; + } + + if ((out - prop_data) < nitems) { + if (*out) + data->model = g_strdup(out); + out += strlen(out) + 1; + } + + if ((out - prop_data) < nitems) { + xkl_config_rec_split_layouts(data, out); + out += strlen(out) + 1; + } + + if ((out - prop_data) < nitems) { + gint nv, nl; + gchar **layout, **variant; + xkl_config_rec_split_variants(data, out); + /* + Now have to ensure that number of variants matches the number of layouts + The 'remainder' is filled with NULLs (not ""s!) + */ + + nv = g_strv_length(data->variants); + nl = g_strv_length(data->layouts); + if (nv < nl) { + data->variants = g_realloc(data->variants, + (nl + + 1) * sizeof(char *)); + memset(data->variants + nv + 1, 0, + (nl - nv) * sizeof(char *)); + } + /* take variants from layouts like ru(winkeys) */ + layout = data->layouts; + variant = data->variants; + while (*layout != NULL && *variant != NULL) { + gchar *varstart = g_strstr_len(*layout, -1, "("); + if (varstart != NULL) { + gchar *varend = + g_strstr_len(varstart, -1, ")"); + if (varend != NULL) { + gint varlen = varend - varstart; + gint laylen = varstart - *layout; + /* I am not sure - but I assume variants in layout have priority */ + gchar *var = *variant = + (*variant != + NULL) ? g_realloc(*variant, + varlen) : + g_new(gchar, varlen); + memcpy(var, varstart + 1, + --varlen); + var[varlen] = '\0'; + /* Resize the original layout */ + ((char *) + g_realloc(*layout, + laylen + 1))[laylen] = + '\0'; + } + } + layout++; + variant++; + } + out += strlen(out) + 1; + } + + if ((out - prop_data) < nitems) { + xkl_config_rec_split_options(data, out); + } + XFree(prop_data); + return TRUE; } /* taken from XFree86 maprules.c */ -Bool XklSetNamesProp( Atom rulesAtom, - char *rulesFile, const XklConfigRecPtr data ) +gboolean +xkl_config_rec_set_to_root_window_property(const XklConfigRec * data, + Atom rules_atom, + gchar * rules_file, + XklEngine * engine) { - int len, rv; - char *pval; - char *next; - char *allLayouts = _XklConfigRecMergeLayouts( data ); - char *allVariants = _XklConfigRecMergeVariants( data ); - char *allOptions = _XklConfigRecMergeOptions( data ); - - len = ( rulesFile ? strlen( rulesFile ) : 0 ); - len += ( data->model ? strlen( data->model ) : 0 ); - len += ( allLayouts ? strlen( allLayouts ) : 0 ); - len += ( allVariants ? strlen( allVariants ) : 0 ); - len += ( allOptions ? strlen( allOptions ) : 0 ); - if( len < 1 ) - return True; - - len += 5; /* trailing NULs */ - - pval = next = ( char * ) malloc( len + 1 ); - if( !pval ) - { - _xklLastErrorMsg = "Could not allocate buffer"; - if ( allLayouts != NULL ) free( allLayouts ); - if ( allVariants != NULL ) free( allVariants ); - if ( allOptions != NULL ) free( allOptions ); - return False; - } - if( rulesFile ) - { - strcpy( next, rulesFile ); - next += strlen( rulesFile ); - } - *next++ = '\0'; - if( data->model ) - { - strcpy( next, data->model ); - next += strlen( data->model ); - } - *next++ = '\0'; - if( data->layouts ) - { - strcpy( next, allLayouts ); - next += strlen( allLayouts ); - } - *next++ = '\0'; - if( data->variants ) - { - strcpy( next, allVariants ); - next += strlen( allVariants ); - } - *next++ = '\0'; - if( data->options ) - { - strcpy( next, allOptions ); - next += strlen( allOptions ); - } - *next++ = '\0'; - if( ( next - pval ) != len ) - { - XklDebug( 150, "Illegal final position: %d/%d\n", ( next - pval ), len ); - if ( allLayouts != NULL ) free( allLayouts ); - if ( allVariants != NULL ) free( allVariants ); - if ( allOptions != NULL ) free( allOptions ); - free( pval ); - _xklLastErrorMsg = "Internal property parsing error"; - return False; - } - - rv = XChangeProperty( _xklDpy, _xklRootWindow, rulesAtom, XA_STRING, 8, - PropModeReplace, ( unsigned char * ) pval, len ); - XSync( _xklDpy, False ); + gint len, rv; + gchar *pval; + gchar *next; + gchar *all_layouts = xkl_config_rec_merge_layouts(data); + gchar *all_variants = xkl_config_rec_merge_variants(data); + gchar *all_options = xkl_config_rec_merge_options(data); + + len = (rules_file ? strlen(rules_file) : 0); + len += (data->model ? strlen(data->model) : 0); + len += (all_layouts ? strlen(all_layouts) : 0); + len += (all_variants ? strlen(all_variants) : 0); + len += (all_options ? strlen(all_options) : 0); + if (len < 1) + return TRUE; + + len += 5; /* trailing NULs */ + + pval = next = g_new(char, len + 1); + if (!pval) { + xkl_last_error_message = "Could not allocate buffer"; + if (all_layouts != NULL) + g_free(all_layouts); + if (all_variants != NULL) + g_free(all_variants); + if (all_options != NULL) + g_free(all_options); + return FALSE; + } + if (rules_file) { + strcpy(next, rules_file); + next += strlen(rules_file); + } + *next++ = '\0'; + if (data->model) { + strcpy(next, data->model); + next += strlen(data->model); + } + *next++ = '\0'; + if (data->layouts) { + strcpy(next, all_layouts); + next += strlen(all_layouts); + } + *next++ = '\0'; + if (data->variants) { + strcpy(next, all_variants); + next += strlen(all_variants); + } + *next++ = '\0'; + if (data->options) { + strcpy(next, all_options); + next += strlen(all_options); + } + *next++ = '\0'; + if ((next - pval) != len) { + xkl_debug(150, "Illegal final position: %d/%d\n", + (next - pval), len); + if (all_layouts != NULL) + g_free(all_layouts); + if (all_variants != NULL) + g_free(all_variants); + if (all_options != NULL) + g_free(all_options); + g_free(pval); + xkl_last_error_message = "Internal property parsing error"; + return FALSE; + } + + Display *display = xkl_engine_get_display(engine); + rv = XChangeProperty(display, xkl_engine_priv(engine, root_window), + rules_atom, XA_STRING, 8, PropModeReplace, + (unsigned char *) pval, len); + XSync(display, False); #if 0 - for( i = len - 1; --i >= 0; ) - if( pval[i] == '\0' ) - pval[i] = '?'; - XklDebug( 150, "Stored [%s] of length %d to [%s] of %X: %d\n", pval, len, - propName, _xklRootWindow, rv ); + for (i = len - 1; --i >= 0;) + if (pval[i] == '\0') + pval[i] = '?'; + XklDebug(150, "Stored [%s] of length %d to [%s] of %X: %d\n", pval, + len, propName, _xklRootWindow, rv); #endif - if ( allLayouts != NULL ) free( allLayouts ); - if ( allVariants != NULL ) free( allVariants ); - if ( allOptions != NULL ) free( allOptions ); - free( pval ); - return True; + if (all_layouts != NULL) + g_free(all_layouts); + if (all_variants != NULL) + g_free(all_variants); + if (all_options != NULL) + g_free(all_options); + g_free(pval); + return TRUE; } diff --git a/libxklavier/xklavier_toplevel.c b/libxklavier/xklavier_toplevel.c new file mode 100644 index 0000000..ab19bbb --- /dev/null +++ b/libxklavier/xklavier_toplevel.c @@ -0,0 +1,343 @@ +#include <time.h> + +#include <X11/Xmd.h> +#include <X11/Xatom.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +#include "xklavier_private.h" + +Window xkl_toplevel_window_prev; + +void +xkl_engine_set_toplevel_window_transparent(XklEngine * engine, + Window toplevel_win, + gboolean transparent) +{ + gboolean oldval; + + oldval = + xkl_engine_is_toplevel_window_transparent(engine, + toplevel_win); + xkl_debug(150, "toplevel_win " WINID_FORMAT " was %stransparent\n", + toplevel_win, oldval ? "" : "not "); + if (transparent && !oldval) { + CARD32 prop = 1; + XChangeProperty(xkl_engine_get_display(engine), + toplevel_win, + xkl_engine_priv(engine, atoms) + [XKLAVIER_TRANSPARENT], XA_INTEGER, 32, + PropModeReplace, + (const unsigned char *) &prop, 1); + } else if (!transparent && oldval) { + XDeleteProperty(xkl_engine_get_display(engine), + toplevel_win, + xkl_engine_priv(engine, atoms) + [XKLAVIER_TRANSPARENT]); + } +} + +/* + * "Adds" app window to the set of managed windows. + * Actually, no data structures involved. The only thing we do is save app state + * and register ourselves us listeners. + * Note: User's callback is called + */ +void +xkl_engine_add_toplevel_window(XklEngine * engine, Window toplevel_win, + Window parent, + gboolean ignore_existing_state, + XklState * init_state) +{ + XklState state = *init_state; + gint default_group_to_use = -1; + + if (toplevel_win == xkl_engine_priv(engine, root_window)) + xkl_debug(150, "??? root app win ???\n"); + + xkl_debug(150, + "Trying to add window " WINID_FORMAT + "/%s with group %d\n", toplevel_win, + xkl_get_debug_window_title(engine, toplevel_win), + init_state->group); + + if (!ignore_existing_state) { + gboolean have_state = + xkl_engine_get_toplevel_window_state(engine, + toplevel_win, + &state); + + if (have_state) { + xkl_debug(150, + "The window " WINID_FORMAT + " does not require to be added, it already has the xklavier state \n", + toplevel_win); + return; + } + } + + g_signal_emit_by_name(engine, "new-toplevel_window", toplevel_win, + parent, &default_group_to_use); + + if (default_group_to_use == -1) + default_group_to_use = + xkl_engine_priv(engine, default_group); + + if (default_group_to_use != -1) + state.group = default_group_to_use; + + xkl_engine_save_toplevel_window_state(engine, toplevel_win, + &state); + xkl_engine_select_input_merging(engine, toplevel_win, + FocusChangeMask | + PropertyChangeMask); + + if (default_group_to_use != -1) { + if (xkl_engine_priv(engine, curr_toplvl_win) == + toplevel_win) { + if ((xkl_engine_priv(engine, secondary_groups_mask) + & (1 << default_group_to_use)) != 0) + xkl_engine_allow_one_switch_to_secondary_group + (engine); + xkl_engine_lock_group(engine, + default_group_to_use); + } + } + + if (parent == (Window) NULL) + parent = + xkl_engine_get_registered_parent(engine, toplevel_win); + + xkl_debug(150, "done\n"); +} + +/* + * Checks the window and goes up + */ +gboolean +xkl_engine_find_toplevel_window_bottom_to_top(XklEngine * engine, + Window win, + Window * toplevel_win_out) +{ + Window parent = (Window) NULL, rwin = (Window) NULL, *children = + NULL; + guint num = 0; + + if (win == (Window) NULL + || win == xkl_engine_priv(engine, root_window)) { + *toplevel_win_out = win; + xkl_last_error_message = "The window is either 0 or root"; + return FALSE; + } + + if (xkl_engine_if_window_has_wm_state(engine, win)) { + *toplevel_win_out = win; + return TRUE; + } + + xkl_engine_priv(engine, last_error_code) = + xkl_engine_query_tree(engine, win, &rwin, &parent, &children, + &num); + + if (xkl_engine_priv(engine, last_error_code) != Success) { + *toplevel_win_out = (Window) NULL; + return FALSE; + } + + if (children != NULL) + XFree(children); + + return xkl_engine_find_toplevel_window_bottom_to_top(engine, + parent, + toplevel_win_out); +} + +/* + * Recursively finds "App window" (window with WM_STATE) for given window. + * First, checks the window itself + * Then, for first level of recursion, checks childen, + * Then, goes to parent. + * NOTE: root window cannot be "App window" under normal circumstances + */ +gboolean +xkl_engine_find_toplevel_window(XklEngine * engine, Window win, + Window * toplevel_win_out) +{ + Window parent = (Window) NULL, + rwin = (Window) NULL, *children = NULL, *child; + guint num = 0; + gboolean rv; + + if (win == (Window) NULL + || win == xkl_engine_priv(engine, root_window)) { + *toplevel_win_out = (Window) NULL; + xkl_last_error_message = "The window is either 0 or root"; + xkl_debug(150, + "Window " WINID_FORMAT + " is either 0 or root so could not get the app window for it\n", + win); + return FALSE; + } + + if (xkl_engine_if_window_has_wm_state(engine, win)) { + *toplevel_win_out = win; + return TRUE; + } + + xkl_engine_priv(engine, last_error_code) = + xkl_engine_query_tree(engine, win, &rwin, &parent, &children, + &num); + + if (xkl_engine_priv(engine, last_error_code) != Success) { + *toplevel_win_out = (Window) NULL; + xkl_debug(150, + "Could not get tree for window " WINID_FORMAT + " so could not get the app window for it\n", + win); + return FALSE; + } + + /* + * Here we first check the children (in case win is just above some "App Window") + * and then go upstairs + */ + child = children; + while (num) { + if (xkl_engine_if_window_has_wm_state(engine, *child)) { + *toplevel_win_out = *child; + if (children != NULL) + XFree(children); + return TRUE; + } + child++; + num--; + } + + if (children != NULL) + XFree(children); + + rv = xkl_engine_find_toplevel_window_bottom_to_top(engine, parent, + toplevel_win_out); + + if (!rv) + xkl_debug(200, + "Could not get the app window for " WINID_FORMAT + "/%s\n", win, xkl_get_debug_window_title(engine, + win)); + + return rv; +} + +/* + * Gets the state from the window property + */ +gboolean +xkl_engine_get_toplevel_window_state(XklEngine * engine, + Window toplevel_win, + XklState * state_out) +{ + Atom type_ret; + int format_ret; + unsigned long nitems, rest; + CARD32 *prop = NULL; + gboolean ret = FALSE; + + gint grp = -1; + guint inds = 0; + + if ((XGetWindowProperty + (xkl_engine_get_display(engine), toplevel_win, + xkl_engine_priv(engine, atoms)[XKLAVIER_STATE], 0L, + XKLAVIER_STATE_PROP_LENGTH, False, XA_INTEGER, &type_ret, + &format_ret, &nitems, &rest, + (unsigned char **) (void *) &prop) == Success) + && (type_ret == XA_INTEGER) && (format_ret == 32)) { + grp = prop[0]; + if (grp >= xkl_engine_get_num_groups(engine) || grp < 0) + grp = 0; + + inds = prop[1]; + + if (state_out != NULL) { + state_out->group = grp; + state_out->indicators = inds; + } + if (prop != NULL) + XFree(prop); + + ret = TRUE; + } + + if (ret) + xkl_debug(150, + "Appwin " WINID_FORMAT + ", '%s' has the group %d, indicators %X\n", + toplevel_win, + xkl_get_debug_window_title(engine, toplevel_win), + grp, inds); + else + xkl_debug(150, + "Appwin " WINID_FORMAT + ", '%s' does not have state\n", toplevel_win, + xkl_get_debug_window_title(engine, + toplevel_win)); + + return ret; +} + +/* + * Deletes the state from the window properties + */ +void +xkl_engine_remove_toplevel_window_state(XklEngine * engine, + Window toplevel_win) +{ + XDeleteProperty(xkl_engine_get_display(engine), toplevel_win, + xkl_engine_priv(engine, atoms)[XKLAVIER_STATE]); +} + +/* + * Saves the state into the window properties + */ +void +xkl_engine_save_toplevel_window_state(XklEngine * engine, + Window toplevel_win, + XklState * state) +{ + CARD32 prop[XKLAVIER_STATE_PROP_LENGTH]; + + prop[0] = state->group; + prop[1] = state->indicators; + + XChangeProperty(xkl_engine_get_display(engine), toplevel_win, + xkl_engine_priv(engine, atoms)[XKLAVIER_STATE], + XA_INTEGER, 32, PropModeReplace, + (const unsigned char *) prop, + XKLAVIER_STATE_PROP_LENGTH); + + xkl_debug(160, + "Saved the group %d, indicators %X for appwin " + WINID_FORMAT "\n", state->group, state->indicators, + toplevel_win); +} + +gboolean +xkl_engine_is_toplevel_window_transparent(XklEngine * engine, + Window toplevel_win) +{ + Atom type_ret; + int format_ret; + unsigned long nitems, rest; + CARD32 *prop = NULL; + if ((XGetWindowProperty + (xkl_engine_get_display(engine), toplevel_win, + xkl_engine_priv(engine, atoms)[XKLAVIER_TRANSPARENT], 0L, 1, + False, XA_INTEGER, &type_ret, &format_ret, &nitems, &rest, + (unsigned char **) (void *) &prop) == Success) + && (type_ret == XA_INTEGER) && (format_ret == 32)) { + if (prop != NULL) + XFree(prop); + return TRUE; + } + return FALSE; +} diff --git a/libxklavier/xklavier_util.c b/libxklavier/xklavier_util.c index d87247e..c0de9a5 100644 --- a/libxklavier/xklavier_util.c +++ b/libxklavier/xklavier_util.c @@ -1,271 +1,309 @@ #include <time.h> +#include <string.h> #include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#include <X11/Xlibint.h> #include "xklavier_private.h" -XklState *XklGetCurrentState( ) +XklState * +xkl_engine_get_current_state(XklEngine * engine) { - return &_xklCurState; + return &xkl_engine_priv(engine, curr_state); } -const char *XklGetLastError( ) +const gchar * +xkl_get_last_error() { - return _xklLastErrorMsg; + return xkl_last_error_message; } -unsigned char *XklGetWindowTitle( Window w ) +gchar * +xkl_engine_get_window_title(XklEngine * engine, Window w) { - Atom type_ret; - int format_ret; - unsigned long nitems, rest; - unsigned char *prop; - - if( Success == XGetWindowProperty( _xklDpy, w, _xklAtoms[WM_NAME], 0L, - -1L, False, XA_STRING, &type_ret, - &format_ret, &nitems, &rest, &prop ) ) - return prop; - else - return NULL; + Atom type_ret; + int format_ret; + unsigned long nitems, rest; + unsigned char *prop; + + if (Success == + XGetWindowProperty(xkl_engine_get_display(engine), w, + xkl_engine_priv(engine, atoms)[WM_NAME], 0L, + -1L, False, XA_STRING, &type_ret, + &format_ret, &nitems, &rest, &prop)) + return (gchar *) prop; + else + return NULL; } -Bool XklIsSameApp( Window win1, Window win2 ) +gboolean +xkl_engine_is_window_from_same_toplevel_window(XklEngine * engine, + Window win1, Window win2) { - Window app1, app2; - return _XklGetAppWindow( win1, &app1 ) && - _XklGetAppWindow( win2, &app2 ) && app1 == app2; + Window app1, app2; + return xkl_engine_find_toplevel_window(engine, win1, &app1) && + xkl_engine_find_toplevel_window(engine, win2, &app2) + && app1 == app2; } -Bool XklGetState( Window win, XklState * state_return ) +gboolean +xkl_engine_get_state(XklEngine * engine, Window win, XklState * state_out) { - Window appWin; + Window app_win; - if( !_XklGetAppWindow( win, &appWin ) ) - { - if( state_return != NULL ) - state_return->group = -1; - return False; - } + if (!xkl_engine_find_toplevel_window(engine, win, &app_win)) { + if (state_out != NULL) + state_out->group = -1; + return FALSE; + } - return _XklGetAppState( appWin, state_return ); + return xkl_engine_get_toplevel_window_state(engine, app_win, + state_out); } -void XklDelState( Window win ) +void +xkl_engine_delete_state(XklEngine * engine, Window win) { - Window appWin; + Window app_win; - if( _XklGetAppWindow( win, &appWin ) ) - _XklDelAppState( appWin ); + if (xkl_engine_find_toplevel_window(engine, win, &app_win)) + xkl_engine_remove_toplevel_window_state(engine, app_win); } -void XklSaveState( Window win, XklState * state ) +void +xkl_engine_save_state(XklEngine * engine, Window win, XklState * state) { - Window appWin; + Window app_win; - if( !( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) ) - return; + if (! + (xkl_engine_priv(engine, listener_type) & + XKLL_MANAGE_WINDOW_STATES)) + return; - if( _XklGetAppWindow( win, &appWin ) ) - _XklSaveAppState( appWin, state ); + if (xkl_engine_find_toplevel_window(engine, win, &app_win)) + xkl_engine_save_toplevel_window_state(engine, app_win, + state); } -/** +/* * Prepares the name of window suitable for debugging (32characters long). */ -char *_XklGetDebugWindowTitle( Window win ) +gchar * +xkl_get_debug_window_title(XklEngine * engine, Window win) { - static char sname[33]; - unsigned char *name; - strcpy( sname, "NULL" ); - if( win != ( Window ) NULL ) - { - name = XklGetWindowTitle( win ); - if( name != NULL ) - { - snprintf( sname, sizeof( sname ), "%.32s", name ); - free( name ); - } - } - return sname; + static gchar sname[33]; + gchar *name; + strcpy(sname, "NULL"); + if (win != (Window) NULL) { + name = xkl_engine_get_window_title(engine, win); + if (name != NULL) { + snprintf(sname, sizeof(sname), "%.32s", name); + g_free(name); + } + } + return sname; } -Window XklGetCurrentWindow( ) +Window +xkl_engine_get_current_window(XklEngine * engine) { - return _xklCurClient; + return xkl_engine_priv(engine, curr_toplvl_win); } -/** +/* * Loads subtree. * All the windows with WM_STATE are added. * All the windows within level 0 are listened for focus and property */ -Bool _XklLoadSubtree( Window window, int level, XklState * initState ) +gboolean +xkl_engine_load_subtree(XklEngine * engine, Window window, gint level, + XklState * init_state) { - Window rwin = ( Window ) NULL, - parent = ( Window ) NULL, *children = NULL, *child; - unsigned int num = 0; - Bool retval = True; - - _xklLastErrorCode = - _XklStatusQueryTree( _xklDpy, window, &rwin, &parent, &children, &num ); - - if( _xklLastErrorCode != Success ) - { - return False; - } - - child = children; - while( num ) - { - if( _XklHasWmState( *child ) ) - { - 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( 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( 200, "But we are at level 0 so we'll spy on it\n" ); - _XklSelectInputMerging( *child, - FocusChangeMask | PropertyChangeMask ); - } else - XklDebug( 200, "And we are at level %d so we'll not spy on it\n", - level ); - - retval = _XklLoadSubtree( *child, level + 1, initState ); - } - - child++; - num--; - } - - if( children != NULL ) - XFree( children ); - - return retval; + Window rwin = (Window) NULL, + parent = (Window) NULL, *children = NULL, *child; + guint num = 0; + gboolean retval = True; + + xkl_engine_priv(engine, last_error_code) = + xkl_engine_query_tree(engine, window, &rwin, &parent, + &children, &num); + + if (xkl_engine_priv(engine, last_error_code) != Success) { + return FALSE; + } + + child = children; + while (num) { + if (xkl_engine_if_window_has_wm_state(engine, *child)) { + xkl_debug(160, + "Window " WINID_FORMAT + " '%s' has WM_STATE so we'll add it\n", + *child, + xkl_get_debug_window_title(engine, + *child)); + xkl_engine_add_toplevel_window(engine, *child, + window, TRUE, + init_state); + } else { + xkl_debug(200, + "Window " WINID_FORMAT + " '%s' does not have have WM_STATE so we'll not add it\n", + *child, + xkl_get_debug_window_title(engine, + *child)); + + if (level == 0) { + xkl_debug(200, + "But we are at level 0 so we'll spy on it\n"); + xkl_engine_select_input_merging(engine, + *child, + FocusChangeMask + | + PropertyChangeMask); + } else + xkl_debug(200, + "And we are at level %d so we'll not spy on it\n", + level); + + retval = + xkl_engine_load_subtree(engine, *child, + level + 1, init_state); + } + + child++; + num--; + } + + if (children != NULL) + XFree(children); + + return retval; } -/** +/* * Checks whether given window has WM_STATE property (i.e. "App window"). */ -Bool _XklHasWmState( Window win ) -{ /* ICCCM 4.1.3.1 */ - Atom type = None; - int format; - unsigned long nitems; - unsigned long after; - unsigned char *data = NULL; /* Helps in the case of BadWindow error */ - - XGetWindowProperty( _xklDpy, win, _xklAtoms[WM_STATE], 0, 0, False, - _xklAtoms[WM_STATE], &type, &format, &nitems, &after, - &data ); - if( data != NULL ) - XFree( data ); /* To avoid an one-byte memory leak because after successfull return - * data array always contains at least one nul byte (NULL-equivalent) */ - return type != None; +gboolean +xkl_engine_if_window_has_wm_state(XklEngine * engine, Window win) +{ /* ICCCM 4.1.3.1 */ + Atom type = None; + int format; + unsigned long nitems; + unsigned long after; + unsigned char *data = NULL; /* Helps in the case of BadWindow error */ + + XGetWindowProperty(xkl_engine_get_display(engine), win, + xkl_engine_priv(engine, atoms)[WM_STATE], 0, 0, + False, xkl_engine_priv(engine, atoms)[WM_STATE], + &type, &format, &nitems, &after, &data); + if (data != NULL) + XFree(data); /* To avoid an one-byte memory leak because after successfull return + * data array always contains at least one nul byte (NULL-equivalent) */ + return type != None; } -/** +/* * Finds out the official parent window (accortind to XQueryTree) */ -Window _XklGetRegisteredParent( Window win ) +Window +xkl_engine_get_registered_parent(XklEngine * engine, Window win) { - Window parent = ( Window ) NULL, rw = ( Window ) NULL, *children = NULL; - unsigned int nchildren = 0; + Window parent = (Window) NULL, rw = (Window) NULL, *children = + NULL; + guint nchildren = 0; - _xklLastErrorCode = - _XklStatusQueryTree( _xklDpy, win, &rw, &parent, &children, &nchildren ); + xkl_engine_priv(engine, last_error_code) = + xkl_engine_query_tree(engine, win, &rw, &parent, &children, + &nchildren); - if( children != NULL ) - XFree( children ); + if (children != NULL) + XFree(children); - return _xklLastErrorCode == Success ? parent : ( Window ) NULL; + return xkl_engine_priv(engine, last_error_code) == + Success ? parent : (Window) NULL; } /** * Make sure about the result. Origial XQueryTree is pretty stupid beast:) */ -Status _XklStatusQueryTree( Display * display, - Window w, - Window * root_return, - Window * parent_return, - Window ** children_return, - unsigned int *nchildren_return ) +Status +xkl_engine_query_tree(XklEngine * engine, Window w, + Window * root_out, + Window * parent_out, + Window ** children_out, guint * nchildren_out) { - Bool result; - - result = ( Bool ) XQueryTree( display, - w, - root_return, - parent_return, - children_return, nchildren_return ); - if( !result ) - { - XklDebug( 160, - "Could not get tree info for window " WINID_FORMAT ": %d\n", w, - result ); - _xklLastErrorMsg = "Could not get the tree info"; - } - - return result ? Success : FirstExtensionError; + gboolean result; + unsigned int nc; + + result = (gboolean) XQueryTree(xkl_engine_get_display(engine), + w, + root_out, + parent_out, children_out, &nc); + *nchildren_out = nc; + + if (!result) { + xkl_debug(160, + "Could not get tree info for window " + WINID_FORMAT ": %d\n", w, result); + xkl_last_error_message = "Could not get the tree info"; + } + + return result ? Success : FirstExtensionError; } -const char *_XklGetEventName( int type ) +const gchar * +xkl_event_get_name(gint type) { - /* Not really good to use the fact of consecutivity - but X protocol is already standartized so... */ - static const char *evtNames[] = { - "KeyPress", - "KeyRelease", - "ButtonPress", - "ButtonRelease", - "MotionNotify", - "EnterNotify", - "LeaveNotify", - "FocusIn", - "FocusOut", - "KeymapNotify", - "Expose", - "GraphicsExpose", - "NoExpose", - "VisibilityNotify", - "CreateNotify", - "DestroyNotify", - "UnmapNotify", - "MapNotify", - "MapRequest", - "ReparentNotify", - "ConfigureNotify", - "ConfigureRequest", - "GravityNotify", - "ResizeRequest", - "CirculateNotify", - "CirculateRequest", - "PropertyNotify", - "SelectionClear", - "SelectionRequest", - "SelectionNotify", - "ColormapNotify", "ClientMessage", "MappingNotify", "LASTEvent" - }; - type -= KeyPress; - if( type < 0 || - type >= ( sizeof( evtNames ) / sizeof( evtNames[0] ) ) ) - return "UNKNOWN"; - return evtNames[type]; + /* Not really good to use the fact of consecutivity + but X protocol is already standartized so... */ + static const gchar *evt_names[] = { + "KeyPress", + "KeyRelease", + "ButtonPress", + "ButtonRelease", + "MotionNotify", + "EnterNotify", + "LeaveNotify", + "FocusIn", + "FocusOut", + "KeymapNotify", + "Expose", + "GraphicsExpose", + "NoExpose", + "VisibilityNotify", + "CreateNotify", + "DestroyNotify", + "UnmapNotify", + "MapNotify", + "MapRequest", + "ReparentNotify", + "ConfigureNotify", + "ConfigureRequest", + "GravityNotify", + "ResizeRequest", + "CirculateNotify", + "CirculateRequest", + "PropertyNotify", + "SelectionClear", + "SelectionRequest", + "SelectionNotify", + "ColormapNotify", "ClientMessage", "MappingNotify", + "LASTEvent" + }; + type -= KeyPress; + if (type < 0 || type >= (sizeof(evt_names) / sizeof(evt_names[0]))) + return "UNKNOWN"; + return evt_names[type]; } -void _XklUpdateCurState( int group, unsigned indicators, const char reason[] ) +void +xkl_engine_update_current_state(XklEngine * engine, int group, + unsigned indicators, const char reason[]) { - XklDebug( 150, - "Updating the current state with [g:%d/i:%u], reason: %s\n", - group, indicators, reason ); - _xklCurState.group = group; - _xklCurState.indicators = indicators; + xkl_debug(150, + "Updating the current state with [g:%d/i:%u], reason: %s\n", + group, indicators, reason); + xkl_engine_priv(engine, curr_state).group = group; + xkl_engine_priv(engine, curr_state).indicators = indicators; } diff --git a/libxklavier/xklavier_xkb.c b/libxklavier/xklavier_xkb.c index c2b3e60..ebb473a 100644 --- a/libxklavier/xklavier_xkb.c +++ b/libxklavier/xklavier_xkb.c @@ -4,31 +4,25 @@ #include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#include <X11/Xlibint.h> #include "xklavier_private.h" #include "xklavier_private_xkb.h" #ifdef XKB_HEADERS_PRESENT -XkbDescPtr _xklXkb; -static XkbDescPtr precachedXkb = NULL; - -char *_xklIndicatorNames[XkbNumIndicators]; - -int _xklXkbEventType, _xklXkbError; - -static char *groupNames[XkbNumKbdGroups]; - -const char **_XklXkbGetGroupNames( void ) +const gchar ** +xkl_xkb_get_groups_names(XklEngine * engine) { - return ( const char ** ) groupNames; + return (const gchar **) xkl_engine_backend(engine, XklXkb, + group_names); } -int _XklXkbPauseListen( void ) +gint +xkl_xkb_pause_listen(XklEngine * engine) { - XkbSelectEvents( _xklDpy, XkbUseCoreKbd, XkbAllEventsMask, 0 ); -/* XkbSelectEventDetails( _xklDpy, + XkbSelectEvents(xkl_engine_get_display(engine), XkbUseCoreKbd, + XkbAllEventsMask, 0); +/* XkbSelectEventDetails( xkl_display, XkbUseCoreKbd, XkbStateNotify, 0, @@ -36,12 +30,13 @@ int _XklXkbPauseListen( void ) !!_XklSelectInput( _xklRootWindow, 0 ); */ - return 0; + return 0; } -int _XklXkbResumeListen( void ) +gint +xkl_xkb_resume_listen(XklEngine * engine) { - /* What events we want */ + /* What events we want */ #define XKB_EVT_MASK \ (XkbStateNotifyMask| \ XkbNamesNotifyMask| \ @@ -50,35 +45,43 @@ int _XklXkbResumeListen( void ) XkbIndicatorMapNotifyMask| \ XkbNewKeyboardNotifyMask) - XkbSelectEvents( _xklDpy, XkbUseCoreKbd, XKB_EVT_MASK, XKB_EVT_MASK ); + Display *display = xkl_engine_get_display(engine); + XkbSelectEvents(display, XkbUseCoreKbd, XKB_EVT_MASK, + XKB_EVT_MASK); #define XKB_STATE_EVT_DTL_MASK \ (XkbGroupStateMask) - XkbSelectEventDetails( _xklDpy, - XkbUseCoreKbd, - XkbStateNotify, - XKB_STATE_EVT_DTL_MASK, XKB_STATE_EVT_DTL_MASK ); + XkbSelectEventDetails(display, + XkbUseCoreKbd, + XkbStateNotify, + XKB_STATE_EVT_DTL_MASK, + XKB_STATE_EVT_DTL_MASK); #define XKB_NAMES_EVT_DTL_MASK \ (XkbGroupNamesMask|XkbIndicatorNamesMask) - XkbSelectEventDetails( _xklDpy, - XkbUseCoreKbd, - XkbNamesNotify, - XKB_NAMES_EVT_DTL_MASK, XKB_NAMES_EVT_DTL_MASK ); - return 0; + XkbSelectEventDetails(display, + XkbUseCoreKbd, + XkbNamesNotify, + XKB_NAMES_EVT_DTL_MASK, + XKB_NAMES_EVT_DTL_MASK); + return 0; } -unsigned _XklXkbGetMaxNumGroups( void ) +guint +xkl_xkb_get_max_num_groups(XklEngine * engine) { - return xklVTable->features & XKLF_MULTIPLE_LAYOUTS_SUPPORTED ? - XkbNumKbdGroups : 1; + return xkl_engine_priv(engine, + features) & XKLF_MULTIPLE_LAYOUTS_SUPPORTED + ? XkbNumKbdGroups : 1; } -unsigned _XklXkbGetNumGroups( void ) +guint +xkl_xkb_get_num_groups(XklEngine * engine) { - return _xklXkb->ctrls->num_groups; + return xkl_engine_backend(engine, XklXkb, + cached_desc)->ctrls->num_groups; } #define KBD_MASK \ @@ -88,448 +91,511 @@ unsigned _XklXkbGetNumGroups( void ) #define NAMES_MASK \ ( XkbGroupNamesMask | XkbIndicatorNamesMask ) -void _XklXkbFreeAllInfo( void ) +void +xkl_xkb_free_all_info(XklEngine * engine) { - int i; - char **pi = _xklIndicatorNames; - for( i = 0; i < XkbNumIndicators; i++, pi++ ) - { - /* only free non-empty ones */ - if( *pi && **pi ) - XFree( *pi ); - } - if( _xklXkb != NULL ) - { - int i; - char **groupName = groupNames; - for( i = _xklXkb->ctrls->num_groups; --i >= 0; groupName++ ) - if( *groupName ) - { - XFree( *groupName ); - *groupName = NULL; - } - XkbFreeKeyboard( _xklXkb, XkbAllComponentsMask, True ); - _xklXkb = NULL; - } - - /* just in case - never actually happens...*/ - if( precachedXkb != NULL ) - { - XkbFreeKeyboard( precachedXkb, XkbAllComponentsMask, True ); - precachedXkb = NULL; - } + gint i; + gchar **pi = xkl_engine_backend(engine, XklXkb, indicator_names); + for (i = 0; i < XkbNumIndicators; i++, pi++) { + /* only free non-empty ones */ + if (*pi && **pi) + XFree(*pi); + } + XkbDescPtr desc = xkl_engine_backend(engine, XklXkb, cached_desc); + if (desc != NULL) { + int i; + char **group_name = + xkl_engine_backend(engine, XklXkb, group_names); + for (i = desc->ctrls->num_groups; --i >= 0; group_name++) + if (*group_name) { + XFree(*group_name); + *group_name = NULL; + } + XkbFreeKeyboard(desc, XkbAllComponentsMask, True); + xkl_engine_backend(engine, XklXkb, cached_desc) = NULL; + } + + /* just in case - never actually happens... */ + desc = xkl_engine_backend(engine, XklXkb, actual_desc); + if (desc != NULL) { + XkbFreeKeyboard(desc, XkbAllComponentsMask, True); + xkl_engine_backend(engine, XklXkb, actual_desc) = NULL; + } } -static Bool _XklXkbLoadPrecachedXkb( void ) +static gboolean +xkl_xkb_load_actual_desc(XklEngine * engine) { - Bool rv = False; - Status status; - - precachedXkb = XkbGetMap( _xklDpy, KBD_MASK, XkbUseCoreKbd ); - if( precachedXkb != NULL ) - { - rv = Success == ( status = XkbGetControls( _xklDpy, CTRLS_MASK, precachedXkb ) ) && - Success == ( status = XkbGetNames( _xklDpy, NAMES_MASK, precachedXkb ) ) && - Success == ( status = XkbGetIndicatorMap( _xklDpy, XkbAllIndicatorsMask, precachedXkb ) ); - if( !rv ) - { - _xklLastErrorMsg = "Could not load controls/names/indicators"; - XklDebug( 0, "%s: %d\n", _xklLastErrorMsg, status ); - XkbFreeKeyboard( precachedXkb, XkbAllComponentsMask, True ); - - } - } - return rv; + gboolean rv = FALSE; + Status status; + + Display *display = xkl_engine_get_display(engine); + XkbDescPtr desc = XkbGetMap(display, KBD_MASK, XkbUseCoreKbd); + xkl_engine_backend(engine, XklXkb, actual_desc) = desc; + if (desc != NULL) { + rv = Success == (status = XkbGetControls(display, + CTRLS_MASK, + desc)) && + Success == (status = XkbGetNames(display, + NAMES_MASK, + desc)) && + Success == (status = XkbGetIndicatorMap(display, + XkbAllIndicatorsMask, + desc)); + if (!rv) { + xkl_last_error_message = + "Could not load controls/names/indicators"; + xkl_debug(0, "%s: %d\n", + xkl_last_error_message, status); + XkbFreeKeyboard(desc, XkbAllComponentsMask, True); + xkl_engine_backend(engine, XklXkb, actual_desc) = + NULL; + } + } + return rv; } -Bool _XklXkbIfCachedInfoEqualsActual( void ) +gboolean +xkl_xkb_if_cached_info_equals_actual(XklEngine * engine) { - int i; - Atom *pa1, *pa2; - Bool rv = False; - - if( _XklXkbLoadPrecachedXkb() ) - { - /* First, compare the number of groups */ - if( _xklXkb->ctrls->num_groups == precachedXkb->ctrls->num_groups ) - { - /* Then, compare group names, just atoms */ - pa1 = _xklXkb->names->groups; - pa2 = precachedXkb->names->groups; - for( i = _xklXkb->ctrls->num_groups; --i >= 0; pa1++, pa2++ ) - if( *pa1 != *pa2 ) - break; - - /* Then, compare indicator names, just atoms */ - if( i < 0 ) - { - pa1 = _xklXkb->names->indicators; - pa2 = precachedXkb->names->indicators; - for( i = XkbNumIndicators; --i >= 0; pa1++, pa2++ ) - if( *pa1 != *pa2 ) - break; - rv = i < 0; - } - } - /** + gint i; + Atom *pa1, *pa2; + gboolean rv = FALSE; + + if (xkl_xkb_load_actual_desc(engine)) { + /* First, compare the number of groups */ + XkbDescPtr cached = + xkl_engine_backend(engine, XklXkb, cached_desc); + XkbDescPtr actual = + xkl_engine_backend(engine, XklXkb, actual_desc); + + if (cached->ctrls->num_groups == actual->ctrls->num_groups) { + /* Then, compare group names, just atoms */ + pa1 = cached->names->groups; + pa2 = actual->names->groups; + for (i = cached->ctrls->num_groups; --i >= 0; + pa1++, pa2++) + if (*pa1 != *pa2) + break; + + /* Then, compare indicator names, just atoms */ + if (i < 0) { + pa1 = cached->names->indicators; + pa2 = actual->names->indicators; + for (i = XkbNumIndicators; --i >= 0; + pa1++, pa2++) + if (*pa1 != *pa2) + break; + rv = i < 0; + } + } + /* * in case of failure, reuse in _XklXkbLoadAllInfo * in case of success - free it */ - if( rv ) - { - XkbFreeKeyboard( precachedXkb, XkbAllComponentsMask, True ); - precachedXkb = NULL; - } - } else - { - XklDebug( 0, "Could not load the XkbDescPtr for comparison\n" ); - } - return rv; + if (rv) { + XkbFreeKeyboard(actual, + XkbAllComponentsMask, True); + xkl_engine_backend(engine, XklXkb, actual_desc) = + NULL; + } + } else { + xkl_debug(0, + "Could not load the XkbDescPtr for comparison\n"); + } + return rv; } -/** +/* * Load some XKB parameters */ -Bool _XklXkbLoadAllInfo( void ) +gboolean +xkl_xkb_load_all_info(XklEngine * engine) { - int i; - Atom *pa; - char **groupName; - char **pi = _xklIndicatorNames; - - if ( precachedXkb == NULL ) - if ( !_XklXkbLoadPrecachedXkb() ) - { - _xklLastErrorMsg = "Could not load keyboard"; - return False; - } - - /* take it from the cache (in most cases LoadAll is called from ResetAll which in turn ...)*/ - _xklXkb = precachedXkb; - precachedXkb = NULL; - - /* First, output the number of the groups */ - XklDebug( 200, "found %d groups\n", _xklXkb->ctrls->num_groups ); - - /* Then, cache (and output) the names of the groups */ - pa = _xklXkb->names->groups; - groupName = groupNames; - for( i = _xklXkb->ctrls->num_groups; --i >= 0; pa++, groupName++ ) - { - *groupName = XGetAtomName( _xklDpy, - *pa == None ? - XInternAtom( _xklDpy, "-", False ) : *pa ); - XklDebug( 200, "group %d has name [%s]\n", i, *groupName ); - } - - _xklLastErrorCode = - XkbGetIndicatorMap( _xklDpy, XkbAllIndicatorsMask, _xklXkb ); - - if( _xklLastErrorCode != Success ) - { - _xklLastErrorMsg = "Could not load indicator map"; - return False; - } - - /* Then, cache (and output) the names of the indicators */ - pa = _xklXkb->names->indicators; - for( i = XkbNumIndicators; --i >= 0; pi++, pa++ ) - { - Atom a = *pa; - if( a != None ) - *pi = XGetAtomName( _xklDpy, a ); - else - *pi = ""; - - XklDebug( 200, "Indicator[%d] is %s\n", i, *pi ); - } - - XklDebug( 200, "Real indicators are %X\n", - _xklXkb->indicators->phys_indicators ); - - if( _xklConfigCallback != NULL ) - ( *_xklConfigCallback ) ( _xklConfigCallbackData ); - return True; + gint i; + Atom *pa; + gchar **group_name; + gchar **pi = xkl_engine_backend(engine, XklXkb, indicator_names); + Display *display = xkl_engine_get_display(engine); + XkbDescPtr actual = + xkl_engine_backend(engine, XklXkb, actual_desc); + + if (actual == NULL) + if (!xkl_xkb_load_actual_desc(engine)) { + xkl_last_error_message = "Could not load keyboard"; + return FALSE; + } + + /* take it from the cache (in most cases LoadAll is called from ResetAll which in turn ...) */ + XkbDescPtr cached = actual = + xkl_engine_backend(engine, XklXkb, actual_desc); + xkl_engine_backend(engine, XklXkb, cached_desc) = + xkl_engine_backend(engine, XklXkb, actual_desc); + xkl_engine_backend(engine, XklXkb, actual_desc) = NULL; + + /* First, output the number of the groups */ + xkl_debug(200, "found %d groups\n", cached->ctrls->num_groups); + + /* Then, cache (and output) the names of the groups */ + pa = cached->names->groups; + group_name = xkl_engine_backend(engine, XklXkb, group_names); + for (i = cached->ctrls->num_groups; --i >= 0; pa++, group_name++) { + *group_name = + XGetAtomName(display, + *pa == None ? XInternAtom(display, + "-", + False) : *pa); + xkl_debug(200, "Group %d has name [%s]\n", i, *group_name); + } + + xkl_engine_priv(engine, last_error_code) = + XkbGetIndicatorMap(display, XkbAllIndicatorsMask, cached); + + if (xkl_engine_priv(engine, last_error_code) != Success) { + xkl_last_error_message = "Could not load indicator map"; + return FALSE; + } + + /* Then, cache (and output) the names of the indicators */ + pa = cached->names->indicators; + for (i = XkbNumIndicators; --i >= 0; pi++, pa++) { + Atom a = *pa; + if (a != None) + *pi = XGetAtomName(display, a); + else + *pi = ""; + + xkl_debug(200, "Indicator[%d] is %s\n", i, *pi); + } + + xkl_debug(200, "Real indicators are %X\n", + cached->indicators->phys_indicators); + + g_signal_emit_by_name(engine, "X-config-changed"); + + return TRUE; } -void _XklXkbLockGroup( int group ) +void +xkl_xkb_lock_group(XklEngine * engine, gint group) { - XklDebug( 100, "Posted request for change the group to %d ##\n", group ); - XkbLockGroup( _xklDpy, XkbUseCoreKbd, group ); - XSync( _xklDpy, False ); + Display *display = xkl_engine_get_display(engine); + xkl_debug(100, "Posted request for change the group to %d ##\n", + group); + XkbLockGroup(display, XkbUseCoreKbd, group); + XSync(display, False); } -/** +/* * Updates current internal state from X state */ -void _XklXkbGetRealState( XklState * curState_return ) +void +xkl_xkb_get_server_state(XklEngine * engine, XklState * current_state_out) { - XkbStateRec state; - - curState_return->group = 0; - if( Success == XkbGetState( _xklDpy, XkbUseCoreKbd, &state ) ) - curState_return->group = state.locked_group; - - if( Success == - XkbGetIndicatorState( _xklDpy, XkbUseCoreKbd, - &curState_return->indicators ) ) - curState_return->indicators &= _xklXkb->indicators->phys_indicators; - else - curState_return->indicators = 0; + XkbStateRec state; + Display *display = xkl_engine_get_display(engine); + + current_state_out->group = 0; + if (Success == XkbGetState(display, XkbUseCoreKbd, &state)) + current_state_out->group = state.locked_group; + + if (Success == + XkbGetIndicatorState(display, XkbUseCoreKbd, + ¤t_state_out->indicators)) + current_state_out->indicators &= + xkl_engine_backend(engine, XklXkb, + cached_desc)->indicators-> + phys_indicators; + else + current_state_out->indicators = 0; } /* * Actually taken from mxkbledpanel, valueChangedProc */ -Bool _XklSetIndicator( int indicatorNum, Bool set ) +gboolean +xkl_xkb_set_indicator(XklEngine * engine, gint indicator_num, gboolean set) { - XkbIndicatorMapPtr map; - - map = _xklXkb->indicators->maps + indicatorNum; - - /* The 'flags' field tells whether this indicator is automatic - * (XkbIM_NoExplicit - 0x80), explicit (XkbIM_NoAutomatic - 0x40), - * or neither (both - 0xC0). - * - * If NoAutomatic is set, the server ignores the rest of the - * fields in the indicator map (i.e. it disables automatic control - * of the LED). If NoExplicit is set, the server prevents clients - * from explicitly changing the value of the LED (using the core - * protocol *or* XKB). If NoAutomatic *and* NoExplicit are set, - * the LED cannot be changed (unless you change the map first). - * If neither NoAutomatic nor NoExplicit are set, the server will - * change the LED according to the indicator map, but clients can - * override that (until the next automatic change) using the core - * protocol or XKB. - */ - switch ( map->flags & ( XkbIM_NoExplicit | XkbIM_NoAutomatic ) ) - { - case XkbIM_NoExplicit | XkbIM_NoAutomatic: - { - /* Can do nothing. Just ignore the indicator */ - return True; - } - - case XkbIM_NoAutomatic: - { - if( _xklXkb->names->indicators[indicatorNum] != None ) - XkbSetNamedIndicator( _xklDpy, XkbUseCoreKbd, - _xklXkb->names->indicators[indicatorNum], set, - False, NULL ); - else - { - XKeyboardControl xkc; - xkc.led = indicatorNum; - xkc.led_mode = set ? LedModeOn : LedModeOff; - XChangeKeyboardControl( _xklDpy, KBLed | KBLedMode, &xkc ); - XSync( _xklDpy, 0 ); - } - - return True; - } - - case XkbIM_NoExplicit: - break; - } - - /* The 'ctrls' field tells what controls tell this indicator to - * to turn on: RepeatKeys (0x1), SlowKeys (0x2), BounceKeys (0x4), - * StickyKeys (0x8), MouseKeys (0x10), AccessXKeys (0x20), - * TimeOut (0x40), Feedback (0x80), ToggleKeys (0x100), - * Overlay1 (0x200), Overlay2 (0x400), GroupsWrap (0x800), - * InternalMods (0x1000), IgnoreLockMods (0x2000), - * PerKeyRepeat (0x3000), or ControlsEnabled (0x4000) - */ - if( map->ctrls ) - { - unsigned long which = map->ctrls; - - XkbGetControls( _xklDpy, XkbAllControlsMask, _xklXkb ); - if( set ) - _xklXkb->ctrls->enabled_ctrls |= which; - else - _xklXkb->ctrls->enabled_ctrls &= ~which; - XkbSetControls( _xklDpy, which | XkbControlsEnabledMask, _xklXkb ); - } - - /* The 'which_groups' field tells when this indicator turns on - * for the 'groups' field: base (0x1), latched (0x2), locked (0x4), - * or effective (0x8). - */ - if( map->groups ) - { - int i; - unsigned int group = 1; - - /* Turning on a group indicator is kind of tricky. For - * now, we will just Latch or Lock the first group we find - * if that is what this indicator does. Otherwise, we're - * just going to punt and get out of here. - */ - if( set ) - { - for( i = XkbNumKbdGroups; --i >= 0; ) - if( ( 1 << i ) & map->groups ) - { - group = i; - break; - } - if( map->which_groups & ( XkbIM_UseLocked | XkbIM_UseEffective ) ) - { - /* 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 */ - return True; - } - } else - /* Turning off a group indicator will mean that we just - * Lock the first group that this indicator doesn't watch. - */ - { - for( i = XkbNumKbdGroups; --i >= 0; ) - if( !( ( 1 << i ) & map->groups ) ) - { - group = i; - break; - } - XklLockGroup( group ); - } - } - - /* The 'which_mods' field tells when this indicator turns on - * for the modifiers: base (0x1), latched (0x2), locked (0x4), - * or effective (0x8). - * - * The 'real_mods' field tells whether this turns on when one of - * the real X modifiers is set: Shift (0x1), Lock (0x2), Control (0x4), - * Mod1 (0x8), Mod2 (0x10), Mod3 (0x20), Mod4 (0x40), or Mod5 (0x80). - * - * The 'virtual_mods' field tells whether this turns on when one of - * the virtual modifiers is set. - * - * The 'mask' field tells what real X modifiers the virtual_modifiers - * map to? - */ - if( map->mods.real_mods || map->mods.mask ) - { - unsigned int affect, mods; - - affect = ( map->mods.real_mods | map->mods.mask ); - - mods = set ? affect : 0; - - if( map->which_mods & ( XkbIM_UseLocked | XkbIM_UseEffective ) ) - XkbLockModifiers( _xklDpy, XkbUseCoreKbd, affect, mods ); - else if( map->which_mods & XkbIM_UseLatched ) - XkbLatchModifiers( _xklDpy, XkbUseCoreKbd, affect, mods ); - else - { - return True; - } - } - return True; + XkbIndicatorMapPtr map; + Display *display = xkl_engine_get_display(engine); + XkbDescPtr cached = + xkl_engine_backend(engine, XklXkb, cached_desc); + + map = cached->indicators->maps + indicator_num; + + /* The 'flags' field tells whether this indicator is automatic + * (XkbIM_NoExplicit - 0x80), explicit (XkbIM_NoAutomatic - 0x40), + * or neither (both - 0xC0). + * + * If NoAutomatic is set, the server ignores the rest of the + * fields in the indicator map (i.e. it disables automatic control + * of the LED). If NoExplicit is set, the server prevents clients + * from explicitly changing the value of the LED (using the core + * protocol *or* XKB). If NoAutomatic *and* NoExplicit are set, + * the LED cannot be changed (unless you change the map first). + * If neither NoAutomatic nor NoExplicit are set, the server will + * change the LED according to the indicator map, but clients can + * override that (until the next automatic change) using the core + * protocol or XKB. + */ + switch (map->flags & (XkbIM_NoExplicit | XkbIM_NoAutomatic)) { + case XkbIM_NoExplicit | XkbIM_NoAutomatic: + { + /* Can do nothing. Just ignore the indicator */ + return TRUE; + } + + case XkbIM_NoAutomatic: + { + if (cached->names-> + indicators[indicator_num] != None) + XkbSetNamedIndicator(display, + XkbUseCoreKbd, + cached->names-> + indicators + [indicator_num], set, + False, NULL); + else { + XKeyboardControl xkc; + xkc.led = indicator_num; + xkc.led_mode = + set ? LedModeOn : LedModeOff; + XChangeKeyboardControl(display, + KBLed | KBLedMode, + &xkc); + XSync(display, False); + } + + return TRUE; + } + + case XkbIM_NoExplicit: + break; + } + + /* The 'ctrls' field tells what controls tell this indicator to + * to turn on: RepeatKeys (0x1), SlowKeys (0x2), BounceKeys (0x4), + * StickyKeys (0x8), MouseKeys (0x10), AccessXKeys (0x20), + * TimeOut (0x40), Feedback (0x80), ToggleKeys (0x100), + * Overlay1 (0x200), Overlay2 (0x400), GroupsWrap (0x800), + * InternalMods (0x1000), IgnoreLockMods (0x2000), + * PerKeyRepeat (0x3000), or ControlsEnabled (0x4000) + */ + if (map->ctrls) { + gulong which = map->ctrls; + + XkbGetControls(display, XkbAllControlsMask, cached); + if (set) + cached->ctrls->enabled_ctrls |= which; + else + cached->ctrls->enabled_ctrls &= ~which; + XkbSetControls(display, which | XkbControlsEnabledMask, + cached); + } + + /* The 'which_groups' field tells when this indicator turns on + * for the 'groups' field: base (0x1), latched (0x2), locked (0x4), + * or effective (0x8). + */ + if (map->groups) { + gint i; + guint group = 1; + + /* Turning on a group indicator is kind of tricky. For + * now, we will just Latch or Lock the first group we find + * if that is what this indicator does. Otherwise, we're + * just going to punt and get out of here. + */ + if (set) { + for (i = XkbNumKbdGroups; --i >= 0;) + if ((1 << i) & map->groups) { + group = i; + break; + } + if (map-> + which_groups & (XkbIM_UseLocked | + XkbIM_UseEffective)) { + /* Important: Groups should be ignored here - because they are handled separately! */ + /* XklLockGroup( group ); */ + } else if (map->which_groups & XkbIM_UseLatched) + XkbLatchGroup(display, XkbUseCoreKbd, + group); + else { + /* Can do nothing. Just ignore the indicator */ + return TRUE; + } + } else + /* Turning off a group indicator will mean that we just + * Lock the first group that this indicator doesn't watch. + */ + { + for (i = XkbNumKbdGroups; --i >= 0;) + if (!((1 << i) & map->groups)) { + group = i; + break; + } + xkl_xkb_lock_group(engine, group); + } + } + + /* The 'which_mods' field tells when this indicator turns on + * for the modifiers: base (0x1), latched (0x2), locked (0x4), + * or effective (0x8). + * + * The 'real_mods' field tells whether this turns on when one of + * the real X modifiers is set: Shift (0x1), Lock (0x2), Control (0x4), + * Mod1 (0x8), Mod2 (0x10), Mod3 (0x20), Mod4 (0x40), or Mod5 (0x80). + * + * The 'virtual_mods' field tells whether this turns on when one of + * the virtual modifiers is set. + * + * The 'mask' field tells what real X modifiers the virtual_modifiers + * map to? + */ + if (map->mods.real_mods || map->mods.mask) { + guint affect, mods; + + affect = (map->mods.real_mods | map->mods.mask); + + mods = set ? affect : 0; + + if (map-> + which_mods & (XkbIM_UseLocked | XkbIM_UseEffective)) + XkbLockModifiers(display, XkbUseCoreKbd, + affect, mods); + else if (map->which_mods & XkbIM_UseLatched) + XkbLatchModifiers(display, XkbUseCoreKbd, + affect, mods); + else { + return TRUE; + } + } + return TRUE; } #endif -int _XklXkbInit( void ) +gint +xkl_xkb_init(XklEngine * engine) { + Display *display = xkl_engine_get_display(engine); + #ifdef XKB_HEADERS_PRESENT - int opcode; - Bool _xklXkbExtPresent; - static XklVTable xklXkbVTable = -{ - "XKB", - XKLF_CAN_TOGGLE_INDICATORS | - XKLF_CAN_OUTPUT_CONFIG_AS_ASCII | - XKLF_CAN_OUTPUT_CONFIG_AS_BINARY, - _XklXkbConfigActivate, - _XklXkbConfigInit, - _XklXkbConfigLoadRegistry, - _XklXkbConfigWriteFile, - _XklXkbEventHandler, - _XklXkbFreeAllInfo, - _XklXkbGetGroupNames, - _XklXkbGetMaxNumGroups, - _XklXkbGetNumGroups, - _XklXkbGetRealState, - _XklXkbIfCachedInfoEqualsActual, - _XklXkbLoadAllInfo, - _XklXkbLockGroup, - _XklXkbPauseListen, - _XklXkbResumeListen, - _XklXkbSetIndicators, - }; - - if( getenv( "XKL_XKB_DISABLE" ) != NULL ) - return -1; - - _xklXkbExtPresent = XkbQueryExtension( _xklDpy, - &opcode, &_xklXkbEventType, - &_xklXkbError, NULL, NULL ); - if( !_xklXkbExtPresent ) - { - XSetErrorHandler( ( XErrorHandler ) _xklDefaultErrHandler ); - return -1; - } - - XklDebug( 160, - "xkbEvenType: %X, xkbError: %X, display: %p, root: " WINID_FORMAT - "\n", _xklXkbEventType, _xklXkbError, _xklDpy, _xklRootWindow ); - - xklXkbVTable.baseConfigAtom = - XInternAtom( _xklDpy, _XKB_RF_NAMES_PROP_ATOM, False ); - 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 0; + gint opcode; + gboolean xkl_xkb_ext_present; + + xkl_engine_priv(engine, backend_id) = "XKB"; + xkl_engine_priv(engine, features) = XKLF_CAN_TOGGLE_INDICATORS | + XKLF_CAN_OUTPUT_CONFIG_AS_ASCII | + XKLF_CAN_OUTPUT_CONFIG_AS_BINARY; + xkl_engine_priv(engine, activate_config_rec) = + xkl_xkb_activate_config_rec; + xkl_engine_priv(engine, init_config_registry) = + xkl_xkb_init_config_registry; + xkl_engine_priv(engine, load_config_registry) = + xkl_xkb_load_config_registry; + xkl_engine_priv(engine, write_config_rec_to_file) = + xkl_xkb_write_config_rec_to_file; + xkl_engine_priv(engine, get_groups_names) = + xkl_xkb_get_groups_names; + xkl_engine_priv(engine, get_max_num_groups) = + xkl_xkb_get_max_num_groups; + xkl_engine_priv(engine, get_num_groups) = xkl_xkb_get_num_groups; + xkl_engine_priv(engine, lock_group) = xkl_xkb_lock_group; + xkl_engine_priv(engine, process_x_event) = xkl_xkb_process_x_event; + xkl_engine_priv(engine, free_all_info) = xkl_xkb_free_all_info; + xkl_engine_priv(engine, if_cached_info_equals_actual) = + xkl_xkb_if_cached_info_equals_actual; + xkl_engine_priv(engine, load_all_info) = xkl_xkb_load_all_info; + xkl_engine_priv(engine, get_server_state) = + xkl_xkb_get_server_state; + xkl_engine_priv(engine, pause_listen) = xkl_xkb_pause_listen; + xkl_engine_priv(engine, resume_listen) = xkl_xkb_resume_listen; + xkl_engine_priv(engine, set_indicators) = xkl_xkb_set_indicators; + xkl_engine_priv(engine, finalize) = xkl_xkb_term; + + if (getenv("XKL_XKB_DISABLE") != NULL) + return -1; + + xkl_engine_priv(engine, backend) = g_new0(XklXkb, 1); + + xkl_xkb_ext_present = XkbQueryExtension(display, + &opcode, + &xkl_engine_backend(engine, + XklXkb, + event_type), + &xkl_engine_backend(engine, + XklXkb, + error_code), + NULL, NULL); + if (!xkl_xkb_ext_present) { + XSetErrorHandler((XErrorHandler) + xkl_engine_priv(engine, + default_error_handler)); + return -1; + } + + xkl_debug(160, + "xkbEvenType: %X, xkbError: %X, display: %p, root: " + WINID_FORMAT "\n", xkl_engine_backend(engine, XklXkb, + event_type), + xkl_engine_backend(engine, XklXkb, error_code), display, + xkl_engine_priv(engine, root_window)); + + xkl_engine_priv(engine, base_config_atom) = + XInternAtom(display, _XKB_RF_NAMES_PROP_ATOM, False); + xkl_engine_priv(engine, backup_config_atom) = + XInternAtom(display, "_XKB_RULES_NAMES_BACKUP", False); + + xkl_engine_priv(engine, default_model) = "pc101"; + xkl_engine_priv(engine, default_layout) = "us"; + + /* First, we have to assign xkl_vtable - + because this function uses it */ + + if (xkl_xkb_multiple_layouts_supported(engine)) + xkl_engine_priv(engine, features) |= + XKLF_MULTIPLE_LAYOUTS_SUPPORTED; + + return 0; #else - XklDebug( 160, - "NO XKB LIBS, display: %p, root: " WINID_FORMAT - "\n", _xklDpy, _xklRootWindow ); - return -1; + xkl_debug(160, + "NO XKB LIBS, display: %p, root: " WINID_FORMAT + "\n", display, xkl_engine_priv(engine, root_window)); + return -1; #endif } +void +xkl_xkb_term(XklEngine * engine) +{ +} + #ifdef XKB_HEADERS_PRESENT -const char *_XklXkbGetXkbEventName( int xkb_type ) +const gchar * +xkl_xkb_event_get_name(gint xkb_type) { - /* Not really good to use the fact of consecutivity - but XKB protocol extension is already standartized so... */ - static const char *evtNames[] = { - "XkbNewKeyboardNotify", - "XkbMapNotify", - "XkbStateNotify", - "XkbControlsNotify", - "XkbIndicatorStateNotify", - "XkbIndicatorMapNotify", - "XkbNamesNotify", - "XkbCompatMapNotify", - "XkbBellNotify", - "XkbActionMessage", - "XkbAccessXNotify", - "XkbExtensionDeviceNotify", - "LASTEvent" - }; - xkb_type -= XkbNewKeyboardNotify; - if( xkb_type < 0 || - xkb_type >= ( sizeof( evtNames ) / sizeof( evtNames[0] ) ) ) - return "UNKNOWN"; - return evtNames[xkb_type]; + /* Not really good to use the fact of consecutivity + but XKB protocol extension is already standartized so... */ + static const gchar *evt_names[] = { + "XkbNewKeyboardNotify", + "XkbMapNotify", + "XkbStateNotify", + "XkbControlsNotify", + "XkbIndicatorStateNotify", + "XkbIndicatorMapNotify", + "XkbNamesNotify", + "XkbCompatMapNotify", + "XkbBellNotify", + "XkbActionMessage", + "XkbAccessXNotify", + "XkbExtensionDeviceNotify", + "LASTEvent" + }; + xkb_type -= XkbNewKeyboardNotify; + if (xkb_type < 0 || + xkb_type >= (sizeof(evt_names) / sizeof(evt_names[0]))) + return "UNKNOWN/OOR"; + return evt_names[xkb_type]; } #endif diff --git a/libxklavier/xklavier_xmm.c b/libxklavier/xklavier_xmm.c index 83818a1..e37b3d8 100755 --- a/libxklavier/xklavier_xmm.c +++ b/libxklavier/xklavier_xmm.c @@ -2,10 +2,10 @@ #include <stdlib.h> #include <string.h> +#include <X11/Xmd.h> #include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#include <X11/Xlibint.h> #include <X11/keysym.h> #include "config.h" @@ -15,264 +15,325 @@ #define SHORTCUT_OPTION_PREFIX "grp:" -char* currentXmmRules = NULL; +const gchar ** +xkl_xmm_get_groups_names(XklEngine * engine) +{ + return (const gchar **) xkl_engine_backend(engine, XklXmm, + current_config).layouts; +} + +void +xkl_xmm_shortcuts_grab(XklEngine * engine) +{ + const XmmShortcut *shortcut; + const XmmSwitchOption *option = + xkl_xmm_shortcut_get_current(engine); -XklConfigRec currentXmmConfig; + xkl_debug(150, "Found shortcut option: %p\n", option); + if (option == NULL) + return; -Atom xmmStateAtom; + shortcut = option->shortcuts; + while (shortcut->keysym != XK_VoidSymbol) { + int keycode = + XKeysymToKeycode(xkl_engine_get_display(engine), + shortcut->keysym); + xkl_xmm_grab_ignoring_indicators(engine, keycode, + shortcut->modifiers); + shortcut++; + } +} -const char **_XklXmmGetGroupNames( void ) +void +xkl_xmm_shortcuts_ungrab(XklEngine * engine) { - return (const char **)currentXmmConfig.layouts; + const XmmShortcut *shortcut; + const XmmSwitchOption *option = + xkl_xmm_shortcut_get_current(engine); + + if (option == NULL) + return; + + shortcut = option->shortcuts; + while (shortcut->keysym != XK_VoidSymbol) { + int keycode = + XKeysymToKeycode(xkl_engine_get_display(engine), + shortcut->keysym); + xkl_xmm_ungrab_ignoring_indicators(engine, keycode, + shortcut->modifiers); + shortcut++; + } } -void _XklXmmGrabShortcuts( void ) +XmmSwitchOption * +xkl_xmm_shortcut_get_current(XklEngine * engine) { - 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 ); - } + const gchar *option_name = + xkl_xmm_shortcut_get_current_option_name(engine); + + xkl_debug(150, "Configured switch option: [%s]\n", option_name); + + if (option_name == NULL) + return NULL; + + return (XmmSwitchOption *) + g_hash_table_lookup(xkl_engine_backend + (engine, XklXmm, switch_options), + (gconstpointer) option_name); } -void _XklXmmUngrabShortcuts( void ) +const gchar * +xkl_xmm_shortcut_get_current_option_name(XklEngine * engine) { - 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 ); - } + gchar **option = + xkl_engine_backend(engine, XklXmm, current_config).options; + if (option == NULL) + return NULL; + + while (*option != NULL) { + /* starts with "grp:" */ + if (strstr(*option, SHORTCUT_OPTION_PREFIX) != NULL) { + return *option + sizeof SHORTCUT_OPTION_PREFIX - 1; + } + option++; + } + return NULL; } -XmmSwitchOptionPtr _XklXmmGetCurrentShortcut( void ) +const XmmSwitchOption * +xkl_xmm_find_switch_option(XklEngine * engine, gint keycode, + guint state, gint * current_shortcut_rv) { - const char* optionName = _XklXmmGetCurrentShortcutOptionName(); - XmmSwitchOptionPtr switchOption = allSwitchOptions; - XklDebug( 150, "Configured switch option: [%s]\n", optionName ); - if( optionName == NULL ) - return NULL; - while( switchOption->optionName != NULL ) - { - if( !strcmp( switchOption->optionName, optionName ) ) - return switchOption; - switchOption++; - } - return NULL; + const XmmSwitchOption *rv = xkl_xmm_shortcut_get_current(engine); + + if (rv != NULL) { + XmmShortcut *sc = rv->shortcuts; + while (sc->keysym != XK_VoidSymbol) { + if ((XKeysymToKeycode + (xkl_engine_get_display(engine), + sc->keysym) == keycode) + && ((state & sc->modifiers) == sc->modifiers)) { + return rv; + } + sc++; + } + } + return NULL; } -const char* _XklXmmGetCurrentShortcutOptionName( void ) +gint +xkl_xmm_resume_listen(XklEngine * engine) { - 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; + if (xkl_engine_priv(engine, listener_type) & XKLL_MANAGE_LAYOUTS) + xkl_xmm_shortcuts_grab(engine); + return 0; } -XmmSwitchOptionPtr _XklXmmFindSwitchOption( unsigned keycode, - unsigned state, - int* currentShortcut_rv ) +gint +xkl_xmm_pause_listen(XklEngine * engine) { - 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; + if (xkl_engine_priv(engine, listener_type) & XKLL_MANAGE_LAYOUTS) + xkl_xmm_shortcuts_ungrab(engine); + return 0; } -int _XklXmmResumeListen( void ) +guint +xkl_xmm_get_max_num_groups(XklEngine * engine) { - if( _xklListenerType & XKLL_MANAGE_LAYOUTS ) - _XklXmmGrabShortcuts(); - return 0; + return 0; } -int _XklXmmPauseListen( void ) +guint +xkl_xmm_get_num_groups(XklEngine * engine) { - if( _xklListenerType & XKLL_MANAGE_LAYOUTS ) - _XklXmmUngrabShortcuts(); - return 0; + gint rv = 0; + gchar **p = + xkl_engine_backend(engine, XklXmm, current_config).layouts; + if (p != NULL) + while (*p++ != NULL) + rv++; + return rv; } -unsigned _XklXmmGetMaxNumGroups( void ) +void +xkl_xmm_free_all_info(XklEngine * engine) { - return 0; + gchar *current_rules = + xkl_engine_backend(engine, XklXmm, current_rules); + if (current_rules != NULL) { + g_free(current_rules); + current_rules = NULL; + xkl_engine_backend(engine, XklXmm, current_rules) = NULL; + } + xkl_config_rec_reset(&xkl_engine_backend + (engine, XklXmm, current_config)); } -unsigned _XklXmmGetNumGroups( void ) +gboolean +xkl_xmm_if_cached_info_equals_actual(XklEngine * engine) { - return currentXmmConfig.numLayouts; + return FALSE; } - -void _XklXmmFreeAllInfo( void ) + +gboolean +xkl_xmm_load_all_info(XklEngine * engine) { - if( currentXmmRules != NULL ) - { - free( currentXmmRules ); - currentXmmRules = NULL; - } - XklConfigRecReset( ¤tXmmConfig ); + return + xkl_config_rec_get_full_from_server(&xkl_engine_backend + (engine, XklXmm, + current_rules), + &xkl_engine_backend(engine, + XklXmm, + current_config), + engine); } -Bool _XklXmmIfCachedInfoEqualsActual( void ) +void +xkl_xmm_get_server_state(XklEngine * engine, XklState * state) { - return False; + unsigned char *propval = NULL; + Atom actual_type; + int actual_format; + unsigned long bytes_remaining; + unsigned long actual_items; + int result; + + memset(state, 0, sizeof(*state)); + + result = + XGetWindowProperty(xkl_engine_get_display(engine), + xkl_engine_priv(engine, root_window), + xkl_engine_backend(engine, XklXmm, + state_atom), 0L, 1L, + False, XA_INTEGER, &actual_type, + &actual_format, &actual_items, + &bytes_remaining, &propval); + + if (Success == result) { + if (actual_format == 32 || actual_items == 1) { + state->group = *(CARD32 *) propval; + } else { + xkl_debug(160, + "Could not get the xmodmap current group\n"); + } + XFree(propval); + } else { + xkl_debug(160, + "Could not get the xmodmap current group: %d\n", + result); + } } -Bool _XklXmmLoadAllInfo( ) +void +xkl_xmm_actualize_group(XklEngine * engine, gint group) { - return _XklConfigGetFullFromServer( ¤tXmmRules, ¤tXmmConfig ); + char cmd[1024]; + int res; + const gchar *layout_name = NULL; + + if (xkl_xmm_get_num_groups(engine) < group) + return; + + layout_name = + xkl_engine_backend(engine, XklXmm, + current_config).layouts[group]; + + snprintf(cmd, sizeof cmd, + "xmodmap %s/xmodmap.%s", XMODMAP_BASE, layout_name); + + res = system(cmd); + if (res > 0) { + xkl_debug(0, "xmodmap error %d\n", res); + } else if (res < 0) { + xkl_debug(0, "Could not execute xmodmap: %d\n", res); + } + XSync(xkl_engine_get_display(engine), False); } -void _XklXmmGetRealState( XklState * state ) +void +xkl_xmm_lock_group(XklEngine * engine, gint group) { - 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 ) - { - if( actualFormat == 32 || actualItems == 1 ) - { - state->group = *(CARD32*)propval; - } else - { - XklDebug( 160, "Could not get the xmodmap current group\n" ); - } - XFree( propval ); - } else - { - XklDebug( 160, "Could not get the xmodmap current group: %d\n", result ); - } + CARD32 propval; + + if (xkl_xmm_get_num_groups(engine) < group) + return; + + /* updating the status property */ + propval = group; + Display *display = xkl_engine_get_display(engine); + XChangeProperty(display, xkl_engine_priv(engine, root_window), + xkl_engine_backend(engine, XklXmm, state_atom), + XA_INTEGER, 32, PropModeReplace, + (unsigned char *) &propval, 1); + XSync(display, False); } -void _XklXmmActualizeGroup( int group ) +void +xkl_xmm_set_indicators(XklEngine * engine, const XklState * window_state) { - 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 ) + +gint +xkl_xmm_init(XklEngine * engine) { - 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 ); + xkl_engine_priv(engine, backend_id) = "xmodmap"; + xkl_engine_priv(engine, features) = + XKLF_MULTIPLE_LAYOUTS_SUPPORTED | + XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT; + xkl_engine_priv(engine, activate_config_rec) = + xkl_xmm_activate_config_rec; + xkl_engine_priv(engine, init_config_registry) = + xkl_xmm_init_config_registry; + xkl_engine_priv(engine, load_config_registry) = + xkl_xmm_load_config_registry; + xkl_engine_priv(engine, write_config_rec_to_file) = NULL; + + xkl_engine_priv(engine, get_groups_names) = + xkl_xmm_get_groups_names; + xkl_engine_priv(engine, get_max_num_groups) = + xkl_xmm_get_max_num_groups; + xkl_engine_priv(engine, get_num_groups) = xkl_xmm_get_num_groups; + xkl_engine_priv(engine, lock_group) = xkl_xmm_lock_group; + + xkl_engine_priv(engine, process_x_event) = xkl_xmm_process_x_event; + xkl_engine_priv(engine, free_all_info) = xkl_xmm_free_all_info; + xkl_engine_priv(engine, if_cached_info_equals_actual) = + xkl_xmm_if_cached_info_equals_actual; + xkl_engine_priv(engine, load_all_info) = xkl_xmm_load_all_info; + xkl_engine_priv(engine, get_server_state) = + xkl_xmm_get_server_state; + xkl_engine_priv(engine, pause_listen) = xkl_xmm_pause_listen; + xkl_engine_priv(engine, resume_listen) = xkl_xmm_resume_listen; + xkl_engine_priv(engine, set_indicators) = xkl_xmm_set_indicators; + xkl_engine_priv(engine, finalize) = xkl_xmm_term; + + if (getenv("XKL_XMODMAP_DISABLE") != NULL) + return -1; + + Display *display = xkl_engine_get_display(engine); + xkl_engine_priv(engine, base_config_atom) = + XInternAtom(display, "_XMM_NAMES", False); + xkl_engine_priv(engine, backup_config_atom) = + XInternAtom(display, "_XMM_NAMES_BACKUP", False); + + xkl_engine_priv(engine, backend) = g_new0(XklXmm, 1); + + xkl_engine_backend(engine, XklXmm, state_atom) = + XInternAtom(display, "_XMM_STATE", False); + + xkl_engine_priv(engine, default_model) = "generic"; + xkl_engine_priv(engine, default_layout) = "us"; + + xkl_xmm_init_switch_options((XklXmm *) + xkl_engine_priv(engine, backend)); + + return 0; } -int _XklXmmInit( void ) +void +xkl_xmm_term(XklEngine * engine) { - static XklVTable xklXmmVTable = - { - "xmodmap", - XKLF_MULTIPLE_LAYOUTS_SUPPORTED | - XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT, - _XklXmmConfigActivate, - _XklXmmConfigInit, - _XklXmmConfigLoadRegistry, - NULL, - _XklXmmEventHandler, - _XklXmmFreeAllInfo, - _XklXmmGetGroupNames, - _XklXmmGetMaxNumGroups, - _XklXmmGetNumGroups, - _XklXmmGetRealState, - _XklXmmIfCachedInfoEqualsActual, - _XklXmmLoadAllInfo, - _XklXmmLockGroup, - _XklXmmPauseListen, - _XklXmmResumeListen, - NULL, - }; - - if( getenv( "XKL_XMODMAP_DISABLE" ) != NULL ) - return -1; - - 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; - - return 0; + xkl_xmm_term_switch_options((XklXmm *) + xkl_engine_priv(engine, backend)); } diff --git a/libxklavier/xklavier_xmm_opts.c b/libxklavier/xklavier_xmm_opts.c index d082482..8a02edc 100644 --- a/libxklavier/xklavier_xmm_opts.c +++ b/libxklavier/xklavier_xmm_opts.c @@ -5,7 +5,6 @@ #include <X11/Xatom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#include <X11/Xlibint.h> #include <X11/keysym.h> #include "config.h" @@ -15,90 +14,139 @@ #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 } - } +static XmmSwitchOption options[] = { + {{{XK_Alt_R, 0} + , {XK_VoidSymbol} + } + , {1}}, + {{{XK_Alt_L, 0} + , {XK_VoidSymbol} + } + , {1}}, + {{{XK_Caps_Lock, 0} + , {XK_VoidSymbol} + } + , {1}}, + {{{XK_Caps_Lock, ShiftMask} + , {XK_VoidSymbol} + } + , {1}}, + {{{XK_Shift_R, ShiftMask} + , + {XK_Shift_L, ShiftMask} + , {XK_VoidSymbol} + } + , {1, -1}}, + {{{XK_Alt_R, Mod1Mask} + , + {XK_Alt_L, Mod1Mask} + , {XK_VoidSymbol} + } + , {1, -1}}, + {{{XK_Control_R, ControlMask} + , + {XK_Control_L, ControlMask} + , {XK_VoidSymbol} + } + , {1, -1}}, + {{{XK_Control_R, ShiftMask} + , + {XK_Control_L, ShiftMask} + , + {XK_Shift_R, ControlMask} + , + {XK_Shift_L, ControlMask} + , {XK_VoidSymbol} + } + , {1, -1, 1, -1}}, + {{{XK_Control_R, Mod1Mask} + , + {XK_Control_L, Mod1Mask} + , + {XK_Alt_R, ControlMask} + , + {XK_Alt_L, ControlMask} + , {XK_VoidSymbol} + } + , {1, -1, 1, -1}}, + {{{XK_Shift_R, Mod1Mask} + , + {XK_Shift_L, Mod1Mask} + , + {XK_Alt_R, ShiftMask} + , + {XK_Alt_L, ShiftMask} + , {XK_VoidSymbol} + } + , {1, -1, 1, -1}}, + {{{XK_Menu, 0} + , {XK_VoidSymbol} + } + , {1}}, + {{{XK_Super_L, 0} + , {XK_VoidSymbol} + } + , {1}}, + {{{XK_Super_R, 0} + , {XK_VoidSymbol} + } + , {1}}, + {{{XK_Shift_L, 0} + , {XK_VoidSymbol} + } + , {1}}, + {{{XK_Shift_R, 0} + , {XK_VoidSymbol} + } + , {1}}, + {{{XK_Control_L, 0} + , {XK_VoidSymbol} + } + , {1}}, + {{{XK_Control_R, 0} + , {XK_VoidSymbol} + } + , {1}} +}; + +static const gchar *option_names[] = { + "ralt_toggle", + "lalt_toggle", + "caps_toggle", + "shift_caps_toggle", + "shifts_toggle", + "alts_toggle", + "ctrls_toggle", + "ctrl_shift_toggle", + "ctrl_alt_toggle", + "alt_shift_toggle", + "menu_toggle", + "lwin_toggle", + "rwin_toggle", + "lshift_toggle", + "rshift_toggle", + "lctrl_toggle", + "rctrl_toggle" }; + +void +xkl_xmm_init_switch_options(XklXmm * xmm) +{ + int i; + const gchar **pname = option_names; + const XmmSwitchOption *poption = options; + + xmm->switch_options = g_hash_table_new(g_str_hash, g_str_equal); + + for (i = sizeof(option_names) / sizeof(option_names[0]); --i >= 0;) + g_hash_table_insert(xmm->switch_options, + (gpointer) (*pname++), + (gpointer) (poption++)); +} + +void +xkl_xmm_term_switch_options(XklXmm * xmm) +{ + g_hash_table_destroy(xmm->switch_options); + xmm->switch_options = NULL; +} diff --git a/tests/.indent.pro b/tests/.indent.pro new file mode 100644 index 0000000..dbec33f --- /dev/null +++ b/tests/.indent.pro @@ -0,0 +1,3 @@ +-kr +-i8 +-psl diff --git a/tests/Makefile.am b/tests/Makefile.am index 9d844da..3690756 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,7 +4,7 @@ test_config_SOURCES=test_config.c test_monitor_SOURCES=test_monitor.c -AM_CFLAGS=-Wall -Werror -I$(includedir) -I$(x_includes) -I$(top_srcdir) +AM_CFLAGS=-Wall -Werror -I$(includedir) -I$(x_includes) -I$(top_srcdir) $(GLIB_CFLAGS) -AM_LDFLAGS=$(top_builddir)/libxklavier/libxklavier.la -L$(x_libraries) -lX11 +AM_LDFLAGS=$(top_builddir)/libxklavier/libxklavier.la -L$(x_libraries) -lX11 $(GLIB_LIBS) diff --git a/tests/test_config.c b/tests/test_config.c index 9cc17be..ea35aa2 100644 --- a/tests/test_config.c +++ b/tests/test_config.c @@ -6,217 +6,223 @@ #include <string.h> #include <X11/Xlib.h> #include <libxklavier/xklavier.h> -#include <libxklavier/xklavier_config.h> #ifdef HAVE_SETLOCALE # include <locale.h> #endif -#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 ); +extern void xkl_config_rec_dump(FILE * file, XklConfigRec * data); enum { ACTION_NONE, ACTION_GET, ACTION_SET, ACTION_WRITE }; -static void printUsage(void) +static void +print_usage(void) { - printf( "Usage: test_config (-g)|(-s -m <model> -l <layouts> -o <options>)|(-h)|(-ws)|(-wb)(-d <debugLevel>)\n" ); - printf( "Options:\n" ); - printf( " -g - Dump the current config, load original system settings and revert back\n" ); - printf( " -s - Set the configuration given my -m -l -o options. Similar to setxkbmap\n" ); - printf( " -ws - Write the binary XKB config file (" PACKAGE ".xkm)\n" ); - printf( " -wb - Write the source XKB config file (" PACKAGE ".xkb)\n" ); - printf( " -d - Set the debug level (by default, 0)\n" ); - printf( " -h - Show this help\n" ); + printf + ("Usage: test_config (-g)|(-s -m <model> -l <layouts> -o <options>)|(-h)|(-ws)|(-wb)(-d <debugLevel>)\n"); + printf("Options:\n"); + printf + (" -g - Dump the current config, load original system settings and revert back\n"); + printf + (" -s - Set the configuration given my -m -l -o options. Similar to setxkbmap\n"); + printf(" -ws - Write the binary XKB config file (" PACKAGE + ".xkm)\n"); + printf(" -wb - Write the source XKB config file (" PACKAGE + ".xkb)\n"); + printf(" -d - Set the debug level (by default, 0)\n"); + printf(" -h - Show this help\n"); } -int main( int argc, char * const argv[] ) +int +main(int argc, char *const argv[]) { - int c, i; - int action = ACTION_NONE; - const char* model = NULL; - const char* layouts = NULL; - const char* options = NULL; - int debugLevel = -1; - int binary = 0; - Display *dpy; - - while (1) - { - c = getopt( argc, argv, "hsgm:l:o:d:w:" ); - if ( c == -1 ) - break; - switch (c) - { - case 's': - printf( "Set the config\n" ); - action = ACTION_SET; - break; - case 'g': - printf( "Get the config\n" ); - action = ACTION_GET; - break; - case 'm': - printf( "Model: [%s]\n", model = optarg ); - break; - case 'l': - printf( "Layouts: [%s]\n", layouts = optarg ); - break; - case 'o': - printf( "Options: [%s]\n", options = optarg ); - break; - case 'h': - printUsage(); - exit(0); - case 'd': - debugLevel = atoi( optarg ); - break; - case 'w': - action = ACTION_WRITE; - binary = ( 'b' == optarg[0] ); - default: - fprintf( stderr, "?? getopt returned character code 0%o ??\n", c ); - printUsage(); - } - } - - if ( action == ACTION_NONE ) - { - printUsage(); - exit( 0 ); - } + int c; + int action = ACTION_NONE; + const char *model = NULL; + const char *layouts = NULL; + const char *options = NULL; + int debug_level = -1; + int binary = 0; + Display *dpy; + + g_type_init_with_debug_flags(G_TYPE_DEBUG_OBJECTS | + G_TYPE_DEBUG_SIGNALS); + + while (1) { + c = getopt(argc, argv, "hsgm:l:o:d:w:"); + if (c == -1) + break; + switch (c) { + case 's': + printf("Set the config\n"); + action = ACTION_SET; + break; + case 'g': + printf("Get the config\n"); + action = ACTION_GET; + break; + case 'm': + printf("Model: [%s]\n", model = optarg); + break; + case 'l': + printf("Layouts: [%s]\n", layouts = optarg); + break; + case 'o': + printf("Options: [%s]\n", options = optarg); + break; + case 'h': + print_usage(); + exit(0); + case 'd': + debug_level = atoi(optarg); + break; + case 'w': + action = ACTION_WRITE; + binary = ('b' == optarg[0]); + default: + fprintf(stderr, + "?? getopt returned character code 0%o ??\n", + c); + print_usage(); + } + } + + if (action == ACTION_NONE) { + print_usage(); + exit(0); + } #ifdef HAVE_SETLOCALE - setlocale( LC_ALL, "" ); + setlocale( LC_ALL, "" ); #endif - dpy = XOpenDisplay( NULL ); - if ( dpy == NULL ) - { - fprintf( stderr, "Could not open display\n" ); - exit(1); - } - printf( "opened display: %p\n", dpy ); - if ( !XklInit( dpy ) ) - { - XklConfigRec currentConfig, r2; - if( debugLevel != -1 ) - XklSetDebugLevel( debugLevel ); - XklDebug( 0, "Xklavier initialized\n" ); - XklConfigInit(); - XklConfigLoadRegistry(); - XklDebug( 0, "Xklavier registry loaded\n" ); - XklDebug( 0, "Backend: [%s]\n", XklGetBackendName() ); - XklDebug( 0, "Supported features: 0x0%X\n", XklGetBackendFeatures() ); - XklDebug( 0, "Max number of groups: %d\n", XklGetMaxNumGroups() ); - - XklConfigRecInit( ¤tConfig ); - XklConfigGetFromServer( ¤tConfig ); - - switch ( action ) - { - case ACTION_GET: - XklDebug( 0, "Got config from the server\n" ); - XklConfigDump( stdout, ¤tConfig ); - - XklConfigRecInit( &r2 ); - - if ( XklConfigGetFromBackup( &r2 ) ) - { - XklDebug( 0, "Got config from the backup\n" ); - XklConfigDump( stdout, &r2 ); - } - - if ( XklConfigActivate( &r2 ) ) - { - XklDebug( 0, "The backup configuration restored\n" ); - if ( XklConfigActivate( ¤tConfig ) ) - { - XklDebug( 0, "Reverting the configuration change\n" ); - } else - { - XklDebug( 0, "The configuration could not be reverted: %s\n", XklGetLastError() ); - } - } else - { - XklDebug( 0, "The backup configuration could not be restored: %s\n", XklGetLastError() ); - } - - XklConfigRecDestroy( &r2 ); - break; - case ACTION_SET: - if ( model != NULL ) - { - if ( currentConfig.model != NULL ) free ( currentConfig.model ); - currentConfig.model = strdup( model ); - } - - if ( layouts != NULL ) - { - if ( currentConfig.layouts != NULL ) - { - for ( i = currentConfig.numLayouts; --i >=0; ) - free ( currentConfig.layouts[i] ); - free ( currentConfig.layouts ); - for ( i = currentConfig.numVariants; --i >=0; ) - free ( currentConfig.variants[i] ); - free ( currentConfig.variants ); - } - currentConfig.numLayouts = - currentConfig.numVariants = 1; - currentConfig.layouts = malloc( sizeof ( char* ) ); - currentConfig.layouts[0] = strdup( layouts ); - currentConfig.variants = malloc( sizeof ( char* ) ); - currentConfig.variants[0] = strdup( "" ); - } - - if ( options != NULL ) - { - if ( currentConfig.options != NULL ) - { - for ( i = currentConfig.numOptions; --i >=0; ) - free ( currentConfig.options[i] ); - free ( currentConfig.options ); - } - currentConfig.numOptions = 1; - currentConfig.options = malloc( sizeof ( char* ) ); - currentConfig.options[0] = strdup( options ); - } - - XklDebug( 0, "New config:\n" ); - XklConfigDump( stdout, ¤tConfig ); - if ( XklConfigActivate( ¤tConfig ) ) - XklDebug( 0, "Set the config\n" ); - else - XklDebug( 0, "Could not set the config: %s\n", XklGetLastError() ); - break; - case ACTION_WRITE: - XklConfigWriteFile( binary ? ( PACKAGE ".xkm" ) : ( PACKAGE ".xkb" ), - ¤tConfig, - binary ); - XklDebug( 0, "The file " PACKAGE "%s is written\n", - binary ? ".xkm" : ".xkb" ); - break; - } - - XklConfigRecDestroy( ¤tConfig ); - - XklConfigFreeRegistry(); - XklConfigTerm(); - XklDebug( 0, "Xklavier registry freed\n" ); - XklDebug( 0, "Xklavier terminating\n" ); - XklTerm(); - } else - { - fprintf( stderr, "Could not init Xklavier: %s\n", XklGetLastError() ); - exit(2); - } - printf( "closing display: %p\n", dpy ); - XCloseDisplay(dpy); - return 0; + dpy = XOpenDisplay(NULL); + if (dpy == NULL) { + fprintf(stderr, "Could not open display\n"); + exit(1); + } + if (debug_level != -1) + xkl_set_debug_level(debug_level); + XklEngine *engine = xkl_engine_get_instance(dpy); + if (engine != NULL) { + XklConfigRec *current_config, *r2; + xkl_debug(0, "Xklavier initialized\n"); + XklConfigRegistry *config = + xkl_config_registry_get_instance(engine); + xkl_config_registry_load(config); + xkl_debug(0, "Xklavier registry loaded\n"); + xkl_debug(0, "Backend: [%s]\n", + xkl_engine_get_backend_name(engine)); + xkl_debug(0, "Supported features: 0x0%X\n", + xkl_engine_get_features(engine)); + xkl_debug(0, "Max number of groups: %d\n", + xkl_engine_get_max_num_groups(engine)); + + current_config = xkl_config_rec_new(); + xkl_config_rec_get_from_server(current_config, engine); + + switch (action) { + case ACTION_GET: + xkl_debug(0, "Got config from the server\n"); + xkl_config_rec_dump(stdout, current_config); + + r2 = xkl_config_rec_new(); + + if (xkl_config_rec_get_from_backup(r2, engine)) { + xkl_debug(0, + "Got config from the backup\n"); + xkl_config_rec_dump(stdout, r2); + } + + if (xkl_config_rec_activate(r2, engine)) { + xkl_debug(0, + "The backup configuration restored\n"); + if (xkl_config_rec_activate + (current_config, engine)) { + xkl_debug(0, + "Reverting the configuration change\n"); + } else { + xkl_debug(0, + "The configuration could not be reverted: %s\n", + xkl_get_last_error()); + } + } else { + xkl_debug(0, + "The backup configuration could not be restored: %s\n", + xkl_get_last_error()); + } + + g_object_unref(G_OBJECT(r2)); + break; + case ACTION_SET: + if (model != NULL) { + if (current_config->model != NULL) + g_free(current_config->model); + current_config->model = g_strdup(model); + } + + if (layouts != NULL) { + if (current_config->layouts != NULL) + g_strfreev(current_config-> + layouts); + if (current_config->variants != NULL) + g_strfreev(current_config-> + variants); + + current_config->layouts = + g_new0(char *, 2); + current_config->layouts[0] = + g_strdup(layouts); + current_config->variants = + g_new0(char *, 2); + current_config->variants[0] = g_strdup(""); + } + + if (options != NULL) { + if (current_config->options != NULL) + g_strfreev(current_config-> + options); + + current_config->options = + g_new0(char *, 2); + current_config->options[0] = + g_strdup(options); + } + + xkl_debug(0, "New config:\n"); + xkl_config_rec_dump(stdout, current_config); + if (xkl_config_rec_activate + (current_config, engine)) + xkl_debug(0, "Set the config\n"); + else + xkl_debug(0, + "Could not set the config: %s\n", + xkl_get_last_error()); + break; + case ACTION_WRITE: + xkl_config_rec_write_to_file(engine, + binary ? (PACKAGE + ".xkm") + : (PACKAGE ".xkb"), + current_config, + binary); + xkl_debug(0, "The file " PACKAGE "%s is written\n", + binary ? ".xkm" : ".xkb"); + break; + } + + g_object_unref(G_OBJECT(current_config)); + + xkl_config_registry_free(config); + g_object_unref(G_OBJECT(config)); + xkl_debug(0, "Xklavier registry freed\n"); + xkl_debug(0, "Xklavier terminating\n"); + g_object_unref(G_OBJECT(engine)); + } else { + fprintf(stderr, "Could not init _xklavier\n"); + exit(2); + } + printf("closing display: %p\n", dpy); + XCloseDisplay(dpy); + return 0; } diff --git a/tests/test_monitor.c b/tests/test_monitor.c index 515c328..6928222 100644 --- a/tests/test_monitor.c +++ b/tests/test_monitor.c @@ -6,103 +6,120 @@ #include <X11/Xutil.h> #include <X11/XKBlib.h> #include <libxklavier/xklavier.h> -#include <libxklavier/xklavier_config.h> -extern void XklConfigDump( FILE* file, - XklConfigRecPtr data ); +extern void xkl_config_dump(FILE * file, XklConfigRec * data); -static void printUsage() +static void +print_usage() { - printf( "Usage: test_monitor (-l1)(-l2)(-l3)(-h)(-d <debugLevel>)\n" ); - printf( "Options:\n" ); - printf( " -d - Set the debug level (by default, 0)\n" ); - printf( " -h - Show this help\n" ); - printf( " -l1 - listen to manage layouts\n" ); - printf( " -l2 - listen to manage window states\n" ); - printf( " -l3 - listen to track the keyboard state\n" ); + printf + ("Usage: test_monitor (-l1)(-l2)(-l3)(-h)(-d <debugLevel>)\n"); + printf("Options:\n"); + printf(" -d - Set the debug level (by default, 0)\n"); + printf(" -h - Show this help\n"); + 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[] ) +void +state_changed(XklEngine * engine, XklEngineStateChange type, gint new_group, + gboolean restore) { - int c; - int debugLevel = -1; - XkbEvent ev; - Display* dpy; - int listenerType = 0, lt; - int listenerTypes[] = { XKLL_MANAGE_LAYOUTS, - XKLL_MANAGE_WINDOW_STATES, - XKLL_TRACK_KEYBOARD_STATE }; + xkl_debug(0, "State changed: %d,%d,%d\n", type, new_group, + restore); +} + +int +main(int argc, char *argv[]) +{ + int c; + int debug_level = -1; + XkbEvent ev; + Display *dpy; + int listener_type = 0, lt; + int listener_types[] = { XKLL_MANAGE_LAYOUTS, + XKLL_MANAGE_WINDOW_STATES, + XKLL_TRACK_KEYBOARD_STATE + }; + + g_type_init_with_debug_flags(G_TYPE_DEBUG_OBJECTS | + G_TYPE_DEBUG_SIGNALS); + + while (1) { + c = getopt(argc, argv, "hd:l:"); + if (c == -1) + break; + switch (c) { + case 'h': + print_usage(); + exit(0); + case 'd': + debug_level = atoi(optarg); + break; + case 'l': + lt = optarg[0] - '1'; + if (lt >= 0 + && lt < + sizeof(listener_types) / + sizeof(listener_types[0])) + listener_type |= listener_types[lt]; + break; + default: + fprintf(stderr, + "?? getopt returned character code 0%o ??\n", + c); + print_usage(); + exit(0); + } + } - while (1) - { - c = getopt( argc, argv, "hd:l:" ); - if ( c == -1 ) - break; - switch (c) - { - case 'h': - printUsage(); - exit(0); - 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(); - exit(0); - } - } + dpy = XOpenDisplay(NULL); + if (dpy == NULL) { + fprintf(stderr, "Could not open display\n"); + exit(1); + } + if (debug_level != -1) + xkl_set_debug_level(debug_level); + XklEngine *engine = xkl_engine_get_instance(dpy); + if (engine != NULL) { + XklConfigRec *current_config; + xkl_debug(0, "Xklavier initialized\n"); + XklConfigRegistry *config = + xkl_config_registry_get_instance(engine); + xkl_config_registry_load(config); + xkl_debug(0, "Xklavier registry loaded\n"); - dpy = XOpenDisplay( NULL ); - if ( dpy == NULL ) - { - fprintf( stderr, "Could not open display\n" ); - exit(1); - } - printf( "opened display: %p\n", dpy ); - if( !XklInit( dpy ) ) - { - XklConfigRec currentConfig; - if( debugLevel != -1 ) - XklSetDebugLevel( debugLevel ); - XklDebug( 0, "Xklavier initialized\n" ); - XklConfigInit(); - XklConfigLoadRegistry(); - XklDebug( 0, "Xklavier registry loaded\n" ); + current_config = xkl_config_rec_new(); + xkl_config_rec_get_from_server(current_config, engine); - XklConfigRecInit( ¤tConfig ); - XklConfigGetFromServer( ¤tConfig ); + g_signal_connect(engine, "X-state-changed", + G_CALLBACK(state_changed), NULL); - XklDebug( 0, "Now, listening...\n" ); - XklStartListen( listenerType ); + xkl_debug(0, "Now, listening: %X...\n", listener_type); + xkl_engine_start_listen(engine, listener_type); - while (1) - { - XNextEvent( dpy, &ev.core ); - if ( XklFilterEvents( &ev.core ) ) - XklDebug( 200, "Unknown event %d\n", ev.type ); - } + while (1) { + XNextEvent(dpy, &ev.core); + if (xkl_engine_filter_events(engine, &ev.core)) + xkl_debug(200, "Unknown event %d\n", + ev.type); + } - XklStopListen(); + xkl_engine_stop_listen(engine); - XklConfigRecDestroy( ¤tConfig ); + g_object_unref(G_OBJECT(current_config)); - XklConfigFreeRegistry(); - XklConfigTerm(); - XklDebug( 0, "Xklavier registry freed\n" ); - XklDebug( 0, "Xklavier terminating\n" ); - XklTerm(); - } else - { - fprintf( stderr, "Could not init Xklavier: %s\n", XklGetLastError() ); - exit(2); - } - printf( "closing display: %p\n", dpy ); - XCloseDisplay(dpy); - return 0; + xkl_config_registry_free(config); + g_object_unref(G_OBJECT(config)); + xkl_debug(0, "Xklavier registry freed\n"); + xkl_debug(0, "Xklavier terminating\n"); + g_object_unref(G_OBJECT(engine)); + } else { + fprintf(stderr, "Could not init Xklavier\n"); + exit(2); + } + printf("closing display: %p\n", dpy); + XCloseDisplay(dpy); + return 0; } |