pax_global_header 0000666 0000000 0000000 00000000064 12210555441 0014511 g ustar 00root root 0000000 0000000 52 comment=83a0bd56de9cfce918a47bdf601a9ecdb5cd56de
superkb-0.23/ 0000775 0000000 0000000 00000000000 12210555441 0013110 5 ustar 00root root 0000000 0000000 superkb-0.23/INSTALL 0000664 0000000 0000000 00000000464 12210555441 0014145 0 ustar 00root root 0000000 0000000 To install, you should only need to:
1. "make".
2. As root, "make install".
It should detect everything automagically.
It it doesn't compile, try different values for the entries in the
"configuration" file. Values for "PUTICON_*" can be either "y", "n" or "m", for
"yes", "no", and "module", a la kernel.
superkb-0.23/LICENSE 0000664 0000000 0000000 00000035422 12210555441 0014123 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
superkb-0.23/Makefile 0000775 0000000 0000000 00000014422 12210555441 0014556 0 ustar 00root root 0000000 0000000
#Build configuration file.
CONFIGURATION=configuration
-include $(CONFIGURATION)
#Module information:
#puticon/puticon-gdkpixbuf
obj-$(PUTICON_GDKPIXBUF) += puticon/puticon-gdkpixbuf.o
syms-$(PUTICON_GDKPIXBUF) += -DWITH_GDKPIXBUF
ldlibs-$(PUTICON_GDKPIXBUF) += $(shell pkg-config gdk-pixbuf-xlib-2.0 --libs)
cflags-$(PUTICON_GDKPIXBUF) += $(shell pkg-config gdk-pixbuf-xlib-2.0 --cflags)
#puticon/puticon-imlib2 (which I prefer)
obj-$(PUTICON_IMLIB2) += puticon/puticon-imlib2.o
syms-$(PUTICON_IMLIB2) += -DWITH_IMLIB2
ldlibs-$(PUTICON_IMLIB2) += $(shell pkg-config imlib2 --libs)
cflags-$(PUTICON_IMLIB2) += $(shell pkg-config imlib2 --cflags)
#drawkblibs/drawkblibs-xlib
obj-$(DRAWKBLIBS_XLIB) += drawkblibs/drawkblibs-xlib.o
syms-$(DRAWKBLIBS_XLIB) += -DWITH_DRAWKBLIBS_XLIB
ldlibs-$(DRAWKBLIBS_XLIB) += $(shell pkg-config x11 --libs)
cflags-$(DRAWKBLIBS_XLIB) += $(shell pkg-config x11 --cflags)
#drawkblibs/drawkblibs-cairo
obj-$(DRAWKBLIBS_CAIRO) += drawkblibs/drawkblibs-cairo.o
syms-$(DRAWKBLIBS_CAIRO) += -DWITH_DRAWKBLIBS_CAIRO
ldlibs-$(DRAWKBLIBS_CAIRO) += $(shell pkg-config x11 renderproto xrender cairo cairo-xlib pangocairo --libs)
cflags-$(DRAWKBLIBS_CAIRO) += $(shell pkg-config x11 renderproto xrender cairo cairo-xlib pangocairo --cflags) -DPANGO_ENABLE_BACKEND
cflags-y += $(shell pkg-config xft --cflags)
ldlibs-y += $(shell pkg-config xft --libs)
#Choose whether Xinerama will be emulated or real.
ifeq ($(XINERAMA_SUPPORT),n)
obj-y += screeninfo-xlib.o
else
obj-y += screeninfo-xinerama.o
ldlibs-y += $(shell pkg-config xinerama --libs)
cflags-y += $(shell pkg-config xinerama --cflags)
endif
version_extrainfo = $(shell ./extendedversioninfo.bash)
#Conditional -pedantic-errors because of pango 1.32.3, 1.32.4 and 1.32.5.
PEDANTIC_ERRORS := -pedantic-errors
ifeq ($(shell pkg-config --modversion pango),1.32.3)
PEDANTIC_ERRORS :=
endif
ifeq ($(shell pkg-config --modversion pango),1.32.4)
PEDANTIC_ERRORS :=
endif
ifeq ($(shell pkg-config --modversion pango),1.32.5)
PEDANTIC_ERRORS :=
endif
#Directory variables
ifndef PREFIX
PREFIX=usr/local/
endif
ifndef LIBDIRNAME
LIBDIRNAME=lib/
endif
MACROS=-DPREFIX=$(PREFIX) -DLIBDIRNAME=$(LIBDIRNAME)
#Special variables
SHELL=/bin/sh
CC=gcc
CFLAGS+=-Wall -std=c99 $(PEDANTIC_ERRORS) $(WEXTRA) $(syms-y) $(cflags-y) $(cflags-m) -ggdb -fPIC -DVEXTRA=\""$(version_extrainfo)"\" $(MACROS)
OBJS=superkb.o main.o superkbrc.o imagelib.o drawkblib.o debug.o timeval.o $(obj-y)
LDPARAMS=-lX11 -lm -ldl -L/usr/X11R6/lib -L/usr/X11/lib $(ldlibs-y)
#Convenience variables
HELP2MAN=help2man
#My variables
APP=superkb
SHARED=$(obj-m:.o=.so)
MODTYPE ?= m
.PHONY : all
all:
$(MAKE) configuration
$(MAKE) checkdep
$(MAKE) $(SHARED) $(APP)
$(MAKE) $(APP).1
$(APP).1: $(APP) superkb.1.inc
$(HELP2MAN) -n 'Graphical keyboard launcher with on-screen hints' --help-option=-h --version-option=-v -N -i superkb.1.inc ./$(APP) > $(APP).1
$(APP): $(OBJS)
$(CC) -o $(APP) $(OBJS) $(LDFLAGS) $(LDPARAMS)
@[ -f superkb ] && { \
echo ; \
echo "Superkb has been successfully compiled!"; \
echo ; \
echo "Please proceed to installation by issuing 'make install' as"; \
echo "root."; \
echo ; \
echo "(If you wish to use the program without installing, edit the"; \
echo "'configuration' file and replace '=m' values with '=y' and"; \
echo "recompile.)"; \
echo ; \
}
configuration:
-pkg-config xinerama --exists > /dev/null \
&& (echo "XINERAMA_SUPPORT=y" >> configuration) \
|| (echo "XINERAMA_SUPPORT=n" >> configuration)
-pkg-config gdk-pixbuf-xlib-2.0 --exists > /dev/null \
&& (echo "PUTICON_GDKPIXBUF=$(MODTYPE)" >> configuration) \
|| (echo "PUTICON_GDKPIXBUF=n" >> configuration)
-pkg-config imlib2 --exists > /dev/null \
&& (echo "PUTICON_IMLIB2=$(MODTYPE)" >> configuration) \
|| (echo "PUTICON_IMLIB2=n" >> configuration)
-echo "DRAWKBLIBS_XLIB=$(MODTYPE)" >> configuration
-pkg-config x11 renderproto xrender cairo cairo-xlib pangocairo --exists > /dev/null \
&& (echo "DRAWKBLIBS_CAIRO=$(MODTYPE)" >> configuration) \
|| (echo "DRAWKBLIBS_CAIRO=n" >> configuration)
checkdep:
@./approve-config
superkb.o: superkb.h
superkbrc.o: superkbrc.h globals.h
imagelib.o: imagelib.h configuration puticon/puticon.h $(obj-y)
drawkblib.o: drawkblib.h configuration drawkblibs/drawkblibs.h $(obj-y)
main.o: superkb.h imagelib.h drawkblib.h superkbrc.h screeninfo.h
drawkblibs/drawkblibs-xlib.o: drawkblibs/drawkblibs-xlib.h configuration
drawkblibs/drawkblibs-cairo.o: drawkblibs/drawkblibs-cairo.h configuration
puticon/puticon-imlib2.o: puticon/puticon-imlib2.h configuration
puticon/puticon-gdkpixbuf.o: puticon/puticon-gdkpixbuf.h configuration
$(SHARED): %.so: %.o
gcc $(ldlibs-m) $(LDFLAGS) -shared -o $@ $<
.PHONY : relink
relink:
-/bin/rm -f $(APP)
$(MAKE)
.PHONY : force
force:
$(MAKE) clean
$(MAKE)
.PHONY : install
install:
$(MAKE) install-shared
$(MAKE) install-man
$(MAKE) install-app
.PHONY : install-app
install-app:
mkdir -p $(DESTDIR)/$(PREFIX)/bin
cp $(APP) $(DESTDIR)/$(PREFIX)/bin
@[ -f ${DESTDIR}/$(PREFIX)/bin/superkb ] && { \
echo ; \
echo "Superkb has been successfully installed!"; \
echo ; \
echo "You will now need a .superkbrc configuration file in your home"; \
echo "directory. (Not root's home directory, but yours.)"; \
echo ; \
echo "There are sample files under the sample-config directory."; \
echo ; \
echo "Once you have done that, issue the 'superkb' command."; \
echo ; \
}
.PHONY : install-man
install-man:
mkdir -p $(DESTDIR)/$(PREFIX)/share/man/man1
install $(APP).1 $(DESTDIR)/$(PREFIX)/share/man/man1/
.PHONY : install-shared
install-shared:
mkdir -p $(DESTDIR)/$(PREFIX)/$(LIBDIRNAME)/superkb
[ -n "$(SHARED)" ] && cp $(SHARED) $(DESTDIR)/$(PREFIX)/$(LIBDIRNAME)/superkb/ || true
.PHONY : uninstall
uninstall:
$(MAKE) uninstall-app
$(MAKE) uninstall-man
$(MAKE) uninstall-shared
.PHONY : uninstall-shared
uninstall-shared:
[ -d /$(PREFIX)/$(LIBDIRNAME)/superkb ] && rm -fr $(DESTDIR)/$(PREFIX)/$(LIBDIRNAME)/superkb
.PHONY : uninstall-man
uninstall-man:
rm -fr $(DESTDIR)/$(PREFIX)/share/man/man1/$(APP).1
.PHONY : uninstall-app
uninstall-app:
rm -fr $(DESTDIR)/$(PREFIX)/bin/superkb
.PHONY : clean
clean:
-/bin/rm -f $(OBJS) $(APP) */*.o */*.so configuration
-/bin/rm -f `find -name "*~"`
-/bin/rm -f `find -name core`
-/bin/rm -f `find -name "core.*"`
-/bin/rm -fr $(APP).1
superkb-0.23/README.md 0000664 0000000 0000000 00000002542 12210555441 0014372 0 ustar 00root root 0000000 0000000 Superkb
=======
Keyboard-based task launcher with on-screen hints.
How it works
============
It works by activating by holding down a magic key, usually the Super_L/R keys, and displaying on-screen hints if held down for long enough.
Features
========
* Designed not to get in your way, but still be helpful.
* Unobtrusive on-screen hints.
* Replayable magic key.
* Mod-order independent: L+Super works the same as Super+L.
* Configuration in plain text.
* Toolkit independent.
* Supports X11 keyboard geometries.
* 3 different algorithms to render your keyboard.
* Small memory footprint: 20 MB RES, 150 MB VIRT
* Small disk footprint: 250 KB dynamic binary, 2.5 M static binary.
Installation
============
Fedora (included in distro)
---------------------------
* Fedora users since F17 can install it directly using yum install superkb
.
Ubuntu (manual compilation)
---------------------------
* Ubuntu users must manually compile it from source code. Some instructions for Debian and Ubuntu are available at http://superkb.org/wiki/index.php?title=Compilation_instructions_for_Superkb_0.21
Debian (manual compilation)
---------------------------
* Debian users must manually compile it from source code. Some instructions for Debian and Ubuntu are available at http://superkb.org/wiki/index.php?title=Compilation_instructions_for_Superkb_0.21
superkb-0.23/approve-config 0000775 0000000 0000000 00000012224 12210555441 0015756 0 ustar 00root root 0000000 0000000 #!/bin/bash
# Poor man's distro detection.
DISTRO=unknown
grep -q 'Debian' /etc/issue && DISTRO=debian
grep -q 'Ubuntu' /etc/issue && DISTRO=ubuntu
grep -q 'Fedora' /etc/issue && DISTRO=fedora
# Default everything to n, so variable is defined here if not in the file.
XINERAMA_SUPPORT=n
PUTICON_GDKPIXBUF=n
PUTICON_IMLIB2=n
DRAWKBLIBS_XLIB=n
DRAWKBLIBS_CAIRO=n
# Read configuration file.
. ./configuration
NEED_SOMETHING=n
SUGGEST_SOMETHING=n
if echo "$DRAWKBLIBS_XLIB $PUTICON_IMLIB2 $PUTICON_GDKPIXBUF" |
grep -q "^[my] n n$"; then
NEED_SOMETHING=y
need_index=$((${#NEED_COMPONENTS[@]}+1))
NEED_COMPONENTS[$need_index]='* Imlib2 library and development headers'
NEED_UBUNTU_SUGG[$need_index]='libimlib2-dev'
NEED_DEBIAN_SUGG[$need_index]='libimlib2-dev'
NEED_FEDORA_SUGG[$need_index]='imlib2-devel'
fi
if [ "$DRAWKBLIBS_XLIB" = "y" -o "$DRAWKBLIBS_XLIB" = "m" ]; then
if pkg-config xft renderproto xrender --exists > /dev/null; then
true
else
NEED_SOMETHING=y
need_index=$((${#NEED_COMPONENTS[@]}+1))
NEED_COMPONENTS[$need_index]='* Xft library and development headers'
NEED_UBUNTU_SUGG[$need_index]='libxft-dev'
NEED_DEBIAN_SUGG[$need_index]='libxft-dev'
NEED_FEDORA_SUGG[$need_index]='libXft-devel'
need_index=$((${#NEED_COMPONENTS[@]}+1))
NEED_COMPONENTS[$need_index]='* Xrender library and development headers'
NEED_UBUNTU_SUGG[$need_index]='libxrender-dev x11proto-render-dev'
NEED_DEBIAN_SUGG[$need_index]='libxrender-dev x11proto-render-dev'
NEED_FEDORA_SUGG[$need_index]='xorg-x11-proto-devel'
fi
fi
# Suggest Cairo if not detected.
if [ "$DRAWKBLIBS_CAIRO" = "n" ]; then
suggest_index=$((${#SUGGEST_COMPONENTS[@]}+1))
SUGGEST_SOMETHING=y
SUGGEST_COMPONENTS[$suggest_index]='* Cairo and Pango library and development headers'
SUGGEST_UBUNTU_SUGG[$suggest_index]='libcairo2-dev libpango1.0-dev'
SUGGEST_DEBIAN_SUGG[$suggest_index]='libcairo2-dev libpango1.0-dev'
SUGGEST_FEDORA_SUGG[$suggest_index]='cairo-devel pango-devel'
fi
# Suggest Xinerama if not detected.
if [ "$XINERAMA_SUPPORT" = "n" ]; then
suggest_index=$((${#SUGGEST_COMPONENTS[@]}+1))
SUGGEST_SOMETHING=y
SUGGEST_COMPONENTS[$suggest_index]='* Xinerama library and development headers'
SUGGEST_UBUNTU_SUGG[$suggest_index]='libxinerama-dev'
SUGGEST_DEBIAN_SUGG[$suggest_index]='libxinerama-dev'
SUGGEST_FEDORA_SUGG[$suggest_index]='libXinerama-devel'
fi
if [ "$NEED_SOMETHING" = "y" ]; then
echo
echo "-------------------------------------------------------------------"
echo
echo "ERROR: Superkb requires some components not found in your"
echo "system. Compilation can not continue without these components."
echo "Please install them accordingly. The required components are:";
echo
for I in `seq 1 $((${#NEED_COMPONENTS[@]}))`; do
echo "${NEED_COMPONENTS[$I]}"
done
echo
if [ "$DISTRO" = "fedora" ]; then
echo "Under Fedora, we suggest the following command:"
echo
echo -n '===> su -c '"'"'yum install '
for I in `seq 1 $((${#NEED_COMPONENTS[@]}))`; do
echo -n "${NEED_FEDORA_SUGG[$I]} "
done
echo "'"
echo
fi
if [ "$DISTRO" = "debian" ]; then
echo "Under Debian, we suggest the following command:"
echo
echo -n '===> su -c '"'"'apt-get install '
for I in `seq 1 $((${#NEED_COMPONENTS[@]}))`; do
echo -n "${NEED_DEBIAN_SUGG[$I]} "
done
echo "'"
echo
fi
if [ "$DISTRO" = "ubuntu" ]; then
echo "Under ubuntu, we suggest the following command:"
echo
echo -n '===> sudo apt-get install '
for I in `seq 1 $((${#NEED_COMPONENTS[@]}))`; do
echo -n "${NEED_UBUNTU_SUGG[$I]} "
done
echo
echo
fi
fi
if [ "$SUGGEST_SOMETHING" = "y" -a "$NEED_SOMETHING" = "n" ]; then
echo
echo "-------------------------------------------------------------------"
echo
echo "WARNING: In order to better enjoy Superkb, some components are"
echo "highly suggested. Compilation will continue. The suggested"
echo "components are:";
fi
if [ "$SUGGEST_SOMETHING" = "y" -a "$NEED_SOMETHING" = "y" ]; then
echo
echo
echo "In addition, the following components are highly suggested to"
echo "better experience Superkb:"
fi
if [ "$SUGGEST_SOMETHING" = "y" ]; then
echo
for I in `seq 1 $((${#SUGGEST_COMPONENTS[@]}))`; do
echo "${SUGGEST_COMPONENTS[$I]}"
done
echo
if [ "$DISTRO" = "fedora" ]; then
echo "Under Fedora, we suggest the following command:"
echo
echo -n '===> su -c '"'"'yum install '
for I in `seq 1 $((${#SUGGEST_COMPONENTS[@]}))`; do
echo -n "${SUGGEST_FEDORA_SUGG[$I]} "
done
echo "'"
echo
fi
if [ "$DISTRO" = "debian" ]; then
echo "Under Debian, we suggest the following command:"
echo
echo -n '===> su -c '"'"'apt-get install '
for I in `seq 1 $((${#SUGGEST_COMPONENTS[@]}))`; do
echo -n "${SUGGEST_DEBIAN_SUGG[$I]} "
done
echo "'"
echo
fi
if [ "$DISTRO" = "ubuntu" ]; then
echo "Under ubuntu, we suggest the following command:"
echo
echo -n '===> sudo apt-get install '
for I in `seq 1 $((${#SUGGEST_COMPONENTS[@]}))`; do
echo -n "${SUGGEST_UBUNTU_SUGG[$I]} "
done
echo
echo
fi
fi
if [ "$NEED_SOMETHING" = "y" ]; then
echo 'Your "configuration" file will be renamed as configuration-bad.'
mv configuration configuration-bad
exit 1;
fi
if [ "$SUGGEST_SOMETHING" = "y" ]; then
exit 0;
fi
superkb-0.23/debug.c 0000664 0000000 0000000 00000001073 12210555441 0014343 0 ustar 00root root 0000000 0000000 /*
* debug.c
*
* Copyright (C) 2008, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
#include
#include
#include "debug.h"
int running_debug_level = 0;
/* When you call "debug", you set the level to show the message at.
* level=1, means an important debug message.
* level=MAX_INT, means a very deep and obscure message.
*/
void debug(const int level, const char *fmt, ...)
{
if (level > running_debug_level)
return;
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
int debug_level;
superkb-0.23/debug.h 0000664 0000000 0000000 00000001077 12210555441 0014354 0 ustar 00root root 0000000 0000000 /*
* debug.h
*
* Copyright (C) 2008, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* Provides a unified way to print debug messages along the whole code.
*
* It does so by providing debug(). It should be used instead of *printf().
*
*/
#ifndef __DEBUG_H
#define __DEBUG_H
typedef void (debug_t)(const int level, const char *fmt, ...);
void debug(const int level, const char *fmt, ...);
typedef enum {
KEYBOARD_ACTIONS = 1,
VARIABLE_CHANGE_VALUES,
FUNCTION_CALLS,
VARIABLE_PRINT
} debug_levels_t;
extern int running_debug_level;
#endif
superkb-0.23/doc/ 0000775 0000000 0000000 00000000000 12210555441 0013655 5 ustar 00root root 0000000 0000000 superkb-0.23/doc/imlib2-howto-install.txt 0000664 0000000 0000000 00000000272 12210555441 0020377 0 ustar 00root root 0000000 0000000 wget http://easynews.dl.sourceforge.net/sourceforge/enlightenment/imlib2-1.2.2.tar.gz
tar xvzf imlib2-1.2.2.tar.gz
cd imlib2-1.2.2
./configure --prefix=/usr && make && sudo make install
superkb-0.23/drawkblib.c 0000664 0000000 0000000 00000006112 12210555441 0015215 0 ustar 00root root 0000000 0000000 /*
* drawkblib.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "drawkblib.h"
#include "drawkblibs/drawkblibs.h"
#include "drawkblibs/drawkblibs-xlib.h"
#include "drawkblibs/drawkblibs-cairo.h"
#define STR(str) #str
#define ESTR(str) STR(str)
#ifndef PREFIX
#define PREFIX "/usr/local/"
#endif
#define LIB_PREFIX "/" ESTR(PREFIX) "/" ESTR(LIBDIRNAME) "/"
#ifndef WITH_DRAWKBLIBS_XLIB
#define drawkblibs_xlib_init NULL
#endif
#ifndef WITH_DRAWKBLIBS_CAIRO
#define drawkblibs_cairo_init NULL
#endif
struct {
drawkb_create_t create;
drawkb_draw_t draw;
} drawkblib;
drawkblib_compiled_in_t drawkblib_compiled_in[] = {
{ "xlib", drawkblibs_xlib_init },
{ "cairo", drawkblibs_cairo_init },
{ NULL, NULL }
};
void drawkblib_GetValues(char *buf, unsigned long buf_n)
{
drawkblib_compiled_in_t *p;
if (buf == NULL) return;
strcpy(buf, "");
for (p = &drawkblib_compiled_in[0]; p->code != NULL; p++)
{
if (p->initlib) {
strncat(buf, p->code, buf_n);
strncat(buf, " ", buf_n);
}
}
DIR *dir;
struct dirent *entry;
dir = opendir(LIB_PREFIX "superkb");
if (dir == NULL)
return;
while ((entry = readdir(dir))) {
if (strncmp(entry->d_name, "drawkblibs-", 11) == 0
&& strncmp(&entry->d_name[strlen(entry->d_name)-3], ".so", 3) == 0) {
strncat(buf, entry->d_name+11, strlen(entry->d_name)-14 > buf_n ? buf_n : strlen(entry->d_name)-14);
strncat(buf, " ", buf_n);
}
}
}
int Init_drawkblib(const char *userlib)
{
/* First, find an appropriate drawkblib interface. */
/* ++ Try 1: Try loading user-specified lib (first compiled in, then
* with dlopen()). */
drawkblib_compiled_in_t *p;
for (p = &drawkblib_compiled_in[0]; p->code != NULL; p++)
{
if (strcmp(p->code, userlib) == 0 && p->initlib != NULL) {
p->initlib(&drawkblib.create, &drawkblib.draw);
return EXIT_SUCCESS;
}
}
char *fn = malloc(strlen(LIB_PREFIX) + strlen("superkb/drawkblibs-") + strlen(userlib)
+ strlen(".so") + 1);
strcpy(fn, LIB_PREFIX);
strcat(fn, "superkb/drawkblibs-");
strcat(fn, userlib);
strcat(fn, ".so");
void *drawkbdlib = dlopen(fn, RTLD_LAZY);
if (drawkbdlib) {
drawkblib_init_t initlib = (drawkblib_init_t)(intptr_t)dlsym(drawkbdlib, "Init");
if ((initlib)(&drawkblib.create, &drawkblib.draw) == EXIT_SUCCESS) {
return EXIT_SUCCESS;
}
} else {
fprintf(stderr, "Error loading drawkblib %s: %s\n", userlib, dlerror());
}
free(fn);
return EXIT_FAILURE;
}
drawkb_p drawkb_create(Display *dpy, const char *font, IQF_t IQF, painting_mode_t painting_mode, float scale, debug_t *debug, XkbDescPtr kbdesc, int use_gradients) {
return drawkblib.create(dpy, font, IQF, painting_mode, scale, debug, kbdesc, use_gradients);
}
void drawkb_draw(drawkb_p this, Drawable d, GC gc, unsigned int width, unsigned int height, XkbDescPtr kbdesc, puticon_t puticon) {
drawkblib.draw(this, d, gc, width, height, kbdesc, puticon);
}
superkb-0.23/drawkblib.h 0000664 0000000 0000000 00000001713 12210555441 0015224 0 ustar 00root root 0000000 0000000 /*
* drawkblib.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* This code provides Superkb with the actual functions to render the
* keyboard onto an X11 drawable.
*
* Multiple different codes may provide the functionality, and are located
* under drawkblibs/ as are drawkblib-xlib and drawkblib-cairo.
*
*/
#ifndef __drawkblib_H
#define __drawkblib_H
#include "drawkblibs/drawkblibs.h"
drawkb_p drawkb_create(Display *dpy, const char *font, IQF_t IQF, painting_mode_t painting_mode, float scale, debug_t *debug, XkbDescPtr kbdesc, int use_gradients);
typedef struct {
const char *code;
drawkblib_init_t initlib;
} drawkblib_compiled_in_t, *drawkblib_compiled_in_p;
void drawkb_draw(drawkb_p this, Drawable d, GC gc, unsigned int width, unsigned int height, XkbDescPtr kbdesc, puticon_t puticon);
int Init_drawkblib(const char *userlib);
void drawkblib_GetValues(char *buf, unsigned long buf_n);
#endif
superkb-0.23/drawkblibs/ 0000775 0000000 0000000 00000000000 12210555441 0015234 5 ustar 00root root 0000000 0000000 superkb-0.23/drawkblibs/drawkblibs-cairo.c 0000664 0000000 0000000 00000116374 12210555441 0020633 0 ustar 00root root 0000000 0000000 /*
* drawkblibs-cairo.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
#define _GNU_SOURCE
#include
#include "drawkblibs.h"
// #include "drawkblibs-cairo.h"
#ifndef WITH_DRAWKBLIBS_CAIRO
#define drawkblibs_cairo_init Init
#endif
/*
* drawkb.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
/*
* Bibliography: XKBlib.pdf.
*/
/* This module does all the keyboard drawing magic. */
/* If ever needed to call XkbComputeShapeBounds() you must immediately
* call drawkb_cairo_WorkaroundBoundsBug() afterwards. This works around a bug present
* in Xorg < 7.1.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "../drawkblib.h"
#include "../imagelib.h"
#include "../globals.h"
#define LINE_WIDTH 2
#define DEFAULT_SCREEN(dpy) (DefaultScreen(dpy))
#define DEFAULT_VISUAL(dpy) (DefaultVisual(dpy, DEFAULT_SCREEN(dpy)))
#define DEFAULT_COLORMAP(dpy) (DefaultColormap(dpy, DEFAULT_SCREEN(dpy)))
cairo_surface_t *surface;
double __scale;
IQF_t IQF;
int g_size;
double g_baseline;
XColor lightcolor;
XColor darkcolor;
XColor foreground;
XColor background;
typedef struct {
char *keystring;
char *keylabel;
} drawkb_cairo_keystrings_t;
drawkb_cairo_keystrings_t drawkb_cairo_keystrings[] = {
{ "dead_grave", "`" },
{ "dead_acute", "'" },
{ "grave", "`" },
{ "apostrophe", "'" },
{ "space", "" },
{ "Escape", "Esc" },
{ "comma", "," },
{ "period", "." },
{ "slash", "/" },
{ "minus", "-" },
{ "equal", "=" },
{ "Caps_Lock", "⇪" },
{ "Shift_L", "⇧" },
{ "Shift_R", "⇧" },
{ "semicolon", ";" },
{ "BackSpace", "⇦" },
{ "Return", "↵" },
{ "Control_L", "Ctrl" },
{ "Control_R", "Ctrl" },
{ "Alt_L", "Alt" },
{ "Up", "↑" },
{ "Down", "↓" },
{ "Left", "←" },
{ "Right", "→" },
{ "KP_Enter", "↵" },
{ "KP_Add", "+" },
{ "KP_Subtract", "-" },
{ "KP_Multiply", "*" },
{ "KP_Divide", "/" },
{ "Num_Lock", "⇭" },
{ "KP_Home", "Home" },
{ "KP_End", "End" },
{ "KP_Prior", "PgUp" },
{ "KP_Up", "↑" },
{ "KP_Down", "↓" },
{ "KP_Left", "←" },
{ "KP_Right", "→" },
{ "KP_Next", "PgDn" },
{ "KP_Begin", "Begin" },
{ "KP_Insert", "Ins" },
{ "KP_Delete", "Del" },
{ "Scroll_Lock", "ScrLk" },
{ "bracketleft", "[" },
{ "bracketright", "]" },
{ "braceleft", "{" },
{ "braceright", "}" },
{ "backslash", "\\" },
{ "ntilde", "ñ" },
{ "plus", "+" },
{ "ISO_Level3_Shift", "AltGr" },
{ "Insert", "Ins" },
{ "Delete", "Del" },
{ "Prior", "PgUp" },
{ "Next", "PgDn" },
{ "questiondown", "¿" },
{ "Print", "PrScr" },
{ "less", "<" },
{ "Tab", "⇥" },
{ "", "" }
};
typedef struct {
unsigned int index;
XkbBoundsRec labelbox;
XkbBoundsRec fullbox;
const char *glyph;
} key_data_t;
char *drawkb_cairo_LookupKeylabelFromKeystring(char *kss) {
int i = 0;
while (strcmp((drawkb_cairo_keystrings[i]).keystring, "") != 0) {
if (!strcmp(kss, (drawkb_cairo_keystrings[i]).keystring))
return (drawkb_cairo_keystrings[i]).keylabel;
i++;
}
return kss;
}
size_t mbstrlen(const char *s) {
int c = 0;
int r;
r = mblen(s, MB_CUR_MAX);
while (r > 0) {
++c;
s = s + r;
r = mblen(s, MB_CUR_MAX);
}
if (r == -1)
return -1;
return c;
}
void drawkb_cairo_WorkaroundBoundsBug(Display * dpy, XkbDescPtr _kb)
{
int i, j;
/* To workaround an X11R7.0 and previous bug */
if (VendorRelease(dpy) < 70100000 &&
VendorRelease(dpy) > 50000000 &&
!strcmp(ServerVendor(dpy), "The X.Org Foundation"))
{
for (i = 0; i < _kb->geom->num_shapes; i++)
{
XkbShapePtr s; /* shapes[i] */
s = &_kb->geom->shapes[i];
for (j = 0; j < s->num_outlines; j++)
{
if (s->outlines[j].num_points == 1)
{
s->bounds.x1 = s->bounds.y1 = 0;
}
}
}
}
}
void
drawkb_cairo_KbDrawBounds(cairo_t *cr,
unsigned int left, unsigned int top,
XkbBoundsPtr bounds, float line_width)
{
cairo_set_line_width (cr, line_width);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_rectangle (cr, (left + bounds->x1), (top + bounds->y1), (bounds->x2 - bounds->x1), (bounds->y2 - bounds->y1));
cairo_stroke (cr);
}
void drawkb_cairo_DrawHollowPolygon(Display * dpy, cairo_t *cr,
unsigned int t,
unsigned int l,
unsigned int b,
unsigned int r,
unsigned int corner_radius,
float line_width) {
double local_corner_radius = corner_radius;
cairo_set_line_width (cr, line_width);
cairo_move_to (cr, l + local_corner_radius, t);
cairo_line_to (cr, r - local_corner_radius, t);
cairo_arc (cr, r - local_corner_radius, t + local_corner_radius, local_corner_radius, -M_PI/2.0, 0);
cairo_line_to (cr, r, b - local_corner_radius);
cairo_arc (cr, r - local_corner_radius, b - local_corner_radius, local_corner_radius, 0, M_PI/2.0);
cairo_line_to (cr, l + local_corner_radius, b);
cairo_arc (cr, l + local_corner_radius, b - local_corner_radius, local_corner_radius, M_PI/2.0, M_PI);
cairo_line_to (cr, l, t + local_corner_radius);
cairo_arc (cr, l + local_corner_radius, t + local_corner_radius, local_corner_radius, M_PI, 3/2.0 * M_PI);
cairo_stroke (cr);
XFlush(dpy);
}
void drawkb_cairo_DrawFilledPolygon(Display * dpy, cairo_t *cr,
unsigned int t,
unsigned int l,
unsigned int b,
unsigned int r,
unsigned int corner_radius,
float line_width) {
double local_corner_radius = corner_radius;
cairo_set_line_width (cr, line_width);
cairo_move_to (cr, l + local_corner_radius, t);
cairo_line_to (cr, r - local_corner_radius, t);
cairo_arc (cr, r - local_corner_radius, t + local_corner_radius, local_corner_radius, -M_PI/2.0, 0);
cairo_line_to (cr, r, b - local_corner_radius);
cairo_arc (cr, r - local_corner_radius, b - local_corner_radius, local_corner_radius, 0, M_PI/2.0);
cairo_line_to (cr, l + local_corner_radius, b);
cairo_arc (cr, l + local_corner_radius, b - local_corner_radius, local_corner_radius, M_PI/2.0, M_PI);
cairo_line_to (cr, l, t + local_corner_radius);
cairo_arc (cr, l + local_corner_radius, t + local_corner_radius, local_corner_radius, M_PI, 3/2.0 * M_PI);
cairo_fill (cr);
XFlush(dpy);
}
/* Graphic context should have already been set. */
void
drawkb_cairo_KbDrawShape(drawkb_p this, cairo_t *cr, signed int angle,
unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbShapePtr shape, XkbColorPtr color,
Bool is_key, float line_width)
{
cairo_pattern_t * pat = NULL;
this->debug (15, "[dk] + This shape is: left=%d, top=%d, angle=%d\n", left, top, angle);
cairo_save(cr);
cairo_translate(cr, left, top);
cairo_rotate(cr, angle*M_PI/1800.0);
// drawkb_cairo_KbDrawBounds(this->dpy, cr, angle, left, top, _kb, &shape->bounds, line_width);
XkbOutlinePtr source;
int i;
int t = 0, l = 0, b = 0, r = 0;
//int j;
int shapes_to_paint = 1;
if (this->painting_mode == FULL_SHAPE) shapes_to_paint = shape->num_outlines;
for (i = 0; i < (is_key ? shapes_to_paint : shape->num_outlines); i++) {
source = &shape->outlines[i];
double corner_radius = source->corner_radius;
switch (source->num_points) {
case 1:
t = l = 0;
b = source->points[0].y;
r = source->points[0].x;
break;
case 2:
t = source->points[0].y;
l = source->points[0].x;
b = source->points[1].y;
r = source->points[1].x;
break;
default:
;
}
if (source->num_points <= 2) {
if (this->painting_mode == FULL_SHAPE || this->painting_mode == FLAT_KEY) {
if ( i % 2 == 0 ) {
if ( this->use_gradients) {
pat = cairo_pattern_create_linear(l, t, l, b);
cairo_pattern_add_color_stop_rgba(pat, 0, darkcolor.red/65535.0, darkcolor.green/65535.0, darkcolor.blue/65535.0, 0.33);
cairo_pattern_add_color_stop_rgba(pat, 0.66, darkcolor.red/65535.0, darkcolor.green/65535.0, darkcolor.blue/65535.0, 0.75);
cairo_pattern_add_color_stop_rgba(pat, 1, darkcolor.red/65535.0, darkcolor.green/65535.0, darkcolor.blue/65535.0, 1);
cairo_set_source(cr, pat);
} else {
cairo_set_source_rgb(cr, darkcolor.red/65535.0, darkcolor.green/65535.0, darkcolor.blue/65535.0);
}
} else {
if ( this->use_gradients) {
pat = cairo_pattern_create_linear(l, t, l, b);
cairo_pattern_add_color_stop_rgba(pat, 0, background.red/65535.0, background.green/65535.0, background.blue/65535.0, 0.33);
cairo_pattern_add_color_stop_rgba(pat, 0.33, background.red/65535.0, background.green/65535.0, background.blue/65535.0, 0.75);
cairo_pattern_add_color_stop_rgba(pat, 1, background.red/65535.0, background.green/65535.0, background.blue/65535.0, 1);
cairo_set_source(cr, pat);
} else {
cairo_set_source_rgb(cr, background.red/65535.0, background.green/65535.0, background.blue/65535.0);
}
}
drawkb_cairo_DrawFilledPolygon(this->dpy, cr, t, l, b, r, corner_radius, line_width);
if ( this->use_gradients) {
cairo_pattern_destroy(pat);
}
} else {
cairo_set_source_rgb(cr, darkcolor.red/65535.0, darkcolor.green/65535.0, darkcolor.blue/65535.0);
drawkb_cairo_DrawHollowPolygon(this->dpy, cr, t, l, b, r, corner_radius, line_width);
}
}
}
cairo_restore(cr);
XFlush(this->dpy);
}
void
drawkb_cairo_KbDrawDoodad(drawkb_p this, cairo_t *cr, /*XftFont *f, */signed int angle,
unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbDoodadPtr doodad, float line_width)
{
switch (doodad->any.type) {
case XkbOutlineDoodad:
drawkb_cairo_KbDrawShape(this, cr, angle + doodad->shape.angle,
left + doodad->shape.left,
top + doodad->shape.top, _kb,
&_kb->geom->shapes[doodad->shape.shape_ndx],
&_kb->geom->colors[doodad->shape.color_ndx], False, line_width);
break;
case XkbSolidDoodad:
drawkb_cairo_KbDrawShape(this, cr, angle + doodad->shape.angle,
left + doodad->shape.left,
top + doodad->shape.top, _kb,
&_kb->geom->shapes[doodad->shape.shape_ndx],
&_kb->geom->colors[doodad->shape.color_ndx], False, line_width);
break;
case XkbTextDoodad:
/* XftDrawString8(dw, current, NULL, scale * (left + doodad->text.left), scale * (top + doodad->text.top) + 6, (unsigned char *)doodad->text.text, strlen(doodad->text.text));*/
break;
case XkbIndicatorDoodad:
drawkb_cairo_KbDrawShape(this, cr, angle + doodad->indicator.angle,
left + doodad->indicator.left,
top + doodad->indicator.top, _kb,
&_kb->geom->shapes[doodad->indicator.shape_ndx],
&_kb->geom->colors[doodad->indicator.on_color_ndx],
False, line_width);
break;
case XkbLogoDoodad:
drawkb_cairo_KbDrawShape(this, cr, angle + doodad->logo.angle,
left + doodad->logo.left,
top + doodad->logo.top, _kb,
&_kb->geom->shapes[doodad->logo.shape_ndx],
&_kb->geom->colors[doodad->logo.color_ndx], False,
line_width);
break;
}
}
typedef enum {
JUST_LEFT,
JUST_CENTER,
JUST_RIGHT
} justify_t;
void drawkb_cairo_pango_echo(cairo_t *cr, PangoFontDescription *fontdesc, const char *s, justify_t justify)
{
PangoLayout *layout;
cairo_save(cr);
/* Create a PangoLayout, set the font and text */
layout = pango_cairo_create_layout (cr);
pango_layout_set_text (layout, s, -1);
pango_layout_set_font_description (layout, fontdesc);
PangoRectangle logical_rect;
pango_layout_get_extents(layout, NULL, &logical_rect);
if (justify == JUST_CENTER) {
cairo_translate(cr, (logical_rect.x - logical_rect.width / 2) / PANGO_SCALE, 0 / PANGO_SCALE);
} else if (justify == JUST_LEFT) {
cairo_translate(cr, logical_rect.x / PANGO_SCALE, 0 / PANGO_SCALE);
} else {
cairo_translate(cr, (logical_rect.x - logical_rect.width) / PANGO_SCALE, 0 / PANGO_SCALE);
}
// Inform Pango to re-layout the text with the new transformation
pango_cairo_update_layout (cr, layout);
pango_cairo_show_layout (cr, layout);
/* free the layout object */
g_object_unref (layout);
cairo_restore(cr);
}
void drawkb_cairo_load_and_draw_icon(drawkb_p this, cairo_t *cr, const int x, const int y, const float screen_width, const float screen_height, const char * icon) {
this->debug(4, "--> drawkb_cairo_load_and_draw_icon(%p, %d, %d, %f, %f, %s);\n", cr, x, y, screen_width, screen_height, icon);
if (screen_width <= 0) {
this->debug(4, "-----> BAD CALL: width is <= 0\n");
return;
}
if (screen_height <= 0) {
this->debug(4, "-----> BAD CALL: height is <= 0\n");
return;
}
cairo_save(cr);
cairo_surface_t *iqf = cairo_image_surface_create_from_png(icon);
// If surface is not a "nil" surface...
if (cairo_surface_get_reference_count (iqf) > 0) {
unsigned int file_width = cairo_image_surface_get_width(iqf);
unsigned int file_height = cairo_image_surface_get_height(iqf);
if (file_width > 0 && file_height > 0) {
cairo_translate(cr, x, y);
this->debug (15, "[dk] + screen_width, screen_height, file_width, file_height: %f, %f, %d, %d\n", screen_width, screen_height, file_width, file_height);
cairo_scale (cr, (screen_width/file_width), (screen_height/file_height));
cairo_set_source_surface(cr, iqf, 0, 0);
cairo_paint (cr);
}
}
cairo_surface_destroy (iqf);
cairo_restore(cr);
this->debug(4, "<-- drawkb_cairo_load_and_draw_icon();\n");
}
void
drawkb_cairo_KbDrawKey(drawkb_p this, cairo_t *cr, signed int angle,
unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbKeyPtr key, key_data_t key_data, puticon_t PutIcon,
PangoFontDescription *font_unbound_char, PangoFontDescription *font_unbound_string, PangoFontDescription *font_bound, float line_width)
{
this->debug (15, "[dk] + This key is: left=%d, top=%d, angle=%d\n", left, top, angle);
cairo_save(cr);
cairo_translate(cr, left, top);
cairo_rotate(cr, angle*M_PI/1800.0);
unsigned int fixed_num_keys;
unsigned long i;
char buf[1024]="";
int buf_n = 1023;
drawkb_cairo_KbDrawShape(this, cr, angle,
0, 0, _kb,
&_kb->geom->shapes[key->shape_ndx],
&_kb->geom->colors[key->color_ndx], True, line_width);
/* // THIS IS DEBUGGING CODE TO DRAW LIMITS OF LABELBOX AND FULLBOX.
// UNCOMMENT IF NEEDED.
cairo_save(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
drawkb_cairo_DrawHollowPolygon(this->dpy, cr, key_data.fullbox.y1, key_data.fullbox.x1, key_data.fullbox.y2, key_data.fullbox.x2, 0, line_width);
cairo_set_source_rgb(cr, 1, 1, 1);
drawkb_cairo_DrawHollowPolygon(this->dpy, cr, key_data.labelbox.y1, key_data.labelbox.x1, key_data.labelbox.y2, key_data.labelbox.x2, 0, line_width);
cairo_restore(cr);
*/
/* This is to work around an XKB apparent bug. */
fixed_num_keys = _kb->names->num_keys;
if (!fixed_num_keys)
fixed_num_keys = 256;
char name[5];
char glyph[256];
char keystring[256];
char *kss;
for (i = 0; i < fixed_num_keys; i++) {
name[0] = '\0';
glyph[0] = '\0';
keystring[0] = '\0';
if (!strncmp(key->name.name, _kb->names->keys[i].name, 4)) {
strncpy(name, _kb->names->keys[i].name, 4);
KeySym ks;
ks = XkbKeycodeToKeysym(this->dpy, i, 0, 0);
kss = XKeysymToString(ks);
if (kss) {
strncpy(keystring, kss, 255);
this->debug (15, "[dk] + Key name: %s\n", kss);
kss = drawkb_cairo_LookupKeylabelFromKeystring(kss);
if (!kss) continue;
strncpy(glyph, kss, 255);
if (this->IQF(XStringToKeysym(keystring), 0, buf, buf_n) == EXIT_SUCCESS) {
cairo_save(cr);
cairo_translate(cr, key_data.labelbox.x1, key_data.labelbox.y1);
cairo_set_source_rgb(cr, foreground.red/65535.0, foreground.green/65535.0, foreground.blue/65535.0);
this->debug(8, "[pe] a1: %s\n", cairo_status_to_string(cairo_status(cr)));
drawkb_cairo_pango_echo(cr, font_bound, glyph, JUST_LEFT);
this->debug(8, "[pe] a2: %s\n", cairo_status_to_string(cairo_status(cr)));
cairo_restore(cr);
if (strcmp(buf, "") != 0) {
int size = key_data.labelbox.x2 - key_data.labelbox.x1 + 1;
if (key_data.fullbox.y2 - key_data.labelbox.y2 + 1 < size)
size = key_data.fullbox.y2 - key_data.labelbox.y2 + 1;
cairo_save(cr);
drawkb_cairo_load_and_draw_icon(this, cr, key_data.fullbox.x2 - size + 1, key_data.fullbox.y2 - size + 1, size, size, buf);
cairo_restore(cr);
}
} else {
if (this->painting_mode == FLAT_KEY) {
cairo_set_source_rgb(cr, background.red/65535.0, background.green/65535.0, background.blue/65535.0);
} else {
cairo_set_source_rgb(cr, lightcolor.red/65535.0, lightcolor.green/65535.0, lightcolor.blue/65535.0);
}
if (mbstrlen(kss) == 1) {
cairo_save(cr);
this->debug (15, "[dk] labelbox: %d, %d\n", key_data.labelbox.x1, key_data.labelbox.y1);
cairo_translate(cr, (key_data.labelbox.x2 + key_data.labelbox.x1) / 2, key_data.labelbox.y1);
this->debug(8, "[pe] b1: %s\n", cairo_status_to_string(cairo_status(cr)));
drawkb_cairo_pango_echo(cr, font_unbound_char, glyph, JUST_CENTER);
this->debug(8, "[pe] b2: %s\n", cairo_status_to_string(cairo_status(cr)));
cairo_restore(cr);
} else {
this->debug (12, "[ft] baseline: %f\n", g_baseline);
cairo_save(cr);
cairo_translate(cr, key_data.labelbox.x1, key_data.labelbox.y1);
this->debug(8, "[pe] c1: %s\n", cairo_status_to_string(cairo_status(cr)));
drawkb_cairo_pango_echo(cr, font_unbound_string, kss, JUST_LEFT);
this->debug(8, "[pe] c2: %s\n", cairo_status_to_string(cairo_status(cr)));
cairo_restore(cr);
}
}
}
break;
}
}
cairo_restore(cr);
}
PangoRectangle * drawkb_cairo_get_rendered_extents_alloc(drawkb_p this, cairo_t *cr, PangoFontDescription **fontdesc, const char *s) {
cairo_save(cr);
PangoLayout *layout;
PangoRectangle *ink_rect;
PangoRectangle *logical_rect;
ink_rect = malloc(sizeof(PangoRectangle));
logical_rect = malloc(sizeof(PangoRectangle));
layout = pango_cairo_create_layout(cr);
pango_layout_set_font_description (layout, *fontdesc);
pango_layout_set_text (layout, s, -1);
pango_cairo_update_layout (cr, layout);
pango_layout_get_extents(layout, ink_rect, logical_rect);
g_object_unref (layout);
free(ink_rect);
cairo_restore(cr);
return logical_rect;
}
void my_pango_font_description_set_size (PangoFontDescription *desc, gint size)
{
if (size <= 0) return;
pango_font_description_set_size(desc, size);
}
int drawkb_cairo_increase_to_best_size_by_height(drawkb_p this, cairo_t *cr, XkbBoundsRec labelbox, PangoFontDescription **fontdesc, const char *s, unsigned int *size)
{
PangoRectangle *extents;
this->debug (10, " --> %s (labelbox(x1=%d, y1=%d, x2=%d, y2=%d), s=%s, size=%d\n", __func__, labelbox.x1, labelbox.y1, labelbox.x2, labelbox.y2, s, *size);
int labelbox_height = labelbox.y2 - labelbox.y1;
float size_now = 100000.0;
float size_last = 0;
float saved_size_now = 0;
size_now = *size;
size_last = *size / 2;
if (*size == 0) {
size_now = 100000.0;
size_last = 0;
}
my_pango_font_description_set_size(*fontdesc, size_now);
extents = drawkb_cairo_get_rendered_extents_alloc(this, cr, fontdesc, s);
this->debug(11, " == size_now, size_last: %f, %f\n", size_now, size_last);
this->debug(11, " == extents_h vs labelbox_h: %d, %d\n", extents->height / PANGO_SCALE, labelbox_height);
#define W_PRECISION 20
#define H_PRECISION 20
while ( fabs(size_now - size_last) > PANGO_SCALE )
{
this->debug(13, " ===== Not within height precision yet: %f %f\n", size_now, size_last );
saved_size_now = size_now;
if ((extents->height / PANGO_SCALE) < labelbox_height) {
this->debug(13, " ===== (extents->height / PANGO_SCALE) < labelbox_height\n");
if (size_now > size_last) size_now = size_now * 2;
if (size_now < size_last) size_now = (size_now + size_last ) / 2;
} else if ((extents->height / PANGO_SCALE) > labelbox_height) {
this->debug(13, " ===== (extents->height / PANGO_SCALE) > labelbox_height\n");
if (size_now < size_last) size_now = size_now / 2;
if (size_now > size_last) size_now = (size_now + size_last ) / 2;
}
size_last = saved_size_now;
free(extents);
my_pango_font_description_set_size(*fontdesc, size_now);
extents = drawkb_cairo_get_rendered_extents_alloc(this, cr, fontdesc, s);
this->debug(11, " == size_now, size_last: %f, %f\n", size_now, size_last);
this->debug(11, " == extents_h vs labelbox_h: %d, %d\n", extents->height / PANGO_SCALE, labelbox_height);
}
this->debug(13, " ===== Enough precision: %f %f\n", size_now, size_last );
this->debug(10, " <-- %s final size value: %f\n", __func__, size_now);
*size = size_now;
return size_now;
}
int drawkb_cairo_reduce_to_best_size_by_width(drawkb_p this, cairo_t *cr, XkbBoundsRec labelbox, PangoFontDescription **fontdesc, const char *s, unsigned int *size)
{
PangoRectangle *extents;
this->debug (10, " --> %s (labelbox(x1=%d, y1=%d, x2=%d, y2=%d), s=%s, size=%d\n", __func__, labelbox.x1, labelbox.y1, labelbox.x2, labelbox.y2, s, *size);
int labelbox_width = labelbox.x2 - labelbox.x1;
float size_now = 100000.0;
float size_last = 0;
float saved_size_now = 0;
size_now = *size;
size_last = *size / 2;
if (*size == 0) {
size_now = 100000.0;
size_last = 0;
}
my_pango_font_description_set_size(*fontdesc, size_now);
extents = drawkb_cairo_get_rendered_extents_alloc(this, cr, fontdesc, s);
this->debug(11, " == size_now, size_last: %f, %f\n", size_now, size_last);
this->debug(11, " == extents_w vs labelbox_w: %d, %d\n", extents->width / PANGO_SCALE, labelbox_width);
#define W_PRECISION 20
#define H_PRECISION 20
if (extents->width / PANGO_SCALE <= labelbox_width)
return size_now;
/* Find best for width */
while ( abs(size_now - size_last) > PANGO_SCALE )
{
this->debug(13, " ===== Not within height precision yet: %f %f\n", size_now, size_last );
saved_size_now = size_now;
if ((extents->width / PANGO_SCALE) < labelbox_width) {
this->debug(13, " ===== (extents->width / PANGO_SCALE) < labelbox_width\n");
if (size_now > size_last) size_now = size_now * 2;
if (size_now < size_last) size_now = (size_now + size_last ) / 2;
} else if ((extents->width / PANGO_SCALE) > labelbox_width) {
this->debug(13, " ===== (extents->width / PANGO_SCALE) > labelbox_width\n");
if (size_now < size_last) size_now = size_now / 2;
if (size_now > size_last) size_now = (size_now + size_last ) / 2;
}
size_last = saved_size_now;
free(extents);
my_pango_font_description_set_size(*fontdesc, size_now);
extents = drawkb_cairo_get_rendered_extents_alloc(this, cr, fontdesc, s);
this->debug(11, " == size_now, size_last: %f, %f\n", size_now, size_last);
this->debug(11, " == extents_w vs labelbox_w: %d, %d\n", extents->width / PANGO_SCALE, labelbox_width);
}
this->debug(13, " ===== Enough precision: %f %f\n", size_now, size_last );
this->debug(10, " <-- %s final size value: %f\n", __func__, size_now);
*size = size_now;
return size_now;
}
void
drawkb_cairo_KbDrawRow(drawkb_p this, cairo_t *cr, signed int angle,
unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbRowPtr row, puticon_t PutIcon, float line_width)
{
PangoFontDescription *font_unbound_char;
PangoFontDescription *font_unbound_string;
PangoFontDescription *font_bound;
font_unbound_string = pango_font_description_from_string(this->font);
font_unbound_char = pango_font_description_from_string(this->font);
font_bound = pango_font_description_from_string(this->font);
this->debug (15, "[dk] + This row is: left=%d, top=%d, angle=%d\n", left, top, angle);
cairo_save(cr);
cairo_translate(cr, left, top);
cairo_rotate(cr, angle*M_PI/1800.0);
unsigned int i;
unsigned int next_piece = 0;
XkbBoundsRec labelbox;
XkbBoundsRec fullbox;
// drawkb_cairo_KbDrawBounds(this->dpy, w, cr, angle, scale, row->left, row->top, _kb, &row->bounds);
unsigned int size_bound = 0;
unsigned int size_unbound_char = 0;
unsigned int size_unbound_string = 0;
/* This is to work around an XKB apparent bug. */
unsigned int fixed_num_keys = _kb->names->num_keys;
if (!fixed_num_keys)
fixed_num_keys = 256;
unsigned int j;
key_data_t *key_data = NULL;
unsigned int key_data_n = 0;
int already_increased_size_bound = 0;
int already_increased_size_unbound_char = 0;
int already_increased_size_unbound_string = 0;
for (j = 0; j < row->num_keys; j++) {
XkbKeyPtr key = &row->keys[j];
this->debug (4, "drawkb_cairo_KbDrawRow: processing key j=%d\n ", j);
list_add_element (key_data, key_data_n, key_data_t);
memset(&(key_data[key_data_n-1]), 0, sizeof(key_data_t));
key_data[key_data_n-1].index = j;
char name[5];
char glyph[256];
char keystring[256];
char *kss;
for (i = 0; i < fixed_num_keys; i++) {
name[0] = '\0';
glyph[0] = '\0';
keystring[0] = '\0';
if (strncmp(key->name.name, _kb->names->keys[i].name, 4) != 0)
continue;
strncpy(name, _kb->names->keys[i].name, 4);
KeySym ks;
ks = XkbKeycodeToKeysym(this->dpy, i, 0, 0);
kss = XKeysymToString(ks);
if (!kss)
continue;
strncpy(keystring, kss, 255);
this->debug (15, "[dk] + Calculating best font size for \"%s\"\n", kss);
kss = drawkb_cairo_LookupKeylabelFromKeystring(kss);
if (!kss)
continue;
strncpy(glyph, kss, 255);
/* Calculate label + icon box bounds */
int fullbox_border = line_width;
int fullbox_margin = this->painting_mode == FULL_SHAPE ? 0 : line_width;
XkbBoundsRec kr, *k = &kr;
if (this->painting_mode == FULL_SHAPE) {
XkbComputeShapeTop(&_kb->geom->shapes[key->shape_ndx], k);
} else if (this->painting_mode == BASE_OUTLINE_ONLY) {
k = &_kb->geom->shapes[key->shape_ndx].bounds;
fullbox_border = line_width;
} else if (this->painting_mode == FLAT_KEY) {
k = &_kb->geom->shapes[key->shape_ndx].bounds;
} else {
assert (0);
}
fullbox.x1 = k->x1 + fullbox_margin + fullbox_border;
fullbox.x2 = k->x2 - fullbox_margin - fullbox_border + 1;
fullbox.y1 = k->y1 + fullbox_margin + fullbox_border;
fullbox.y2 = k->y2 - fullbox_margin - fullbox_border + 1;
/* End calculate label + icon box bounds */
/* Default labelbox. Overriden according to key binding status. */
labelbox.x1 = fullbox.x1;
labelbox.x2 = fullbox.x2;
labelbox.y1 = fullbox.y1;
labelbox.y2 = fullbox.y2;
if (strcmp(glyph, "") != 0) {
if (this->IQF(XStringToKeysym(keystring), 0, NULL, 0) == EXIT_SUCCESS) {
/* If this key is a bound key... */
labelbox.y2 = labelbox.y1 + (labelbox.y2 - labelbox.y1) * 0.33;
if (!already_increased_size_bound) {
drawkb_cairo_increase_to_best_size_by_height(this, cr, labelbox, &font_bound, glyph, &size_bound);
already_increased_size_bound = 1;
}
drawkb_cairo_reduce_to_best_size_by_width(this, cr, labelbox, &font_bound, glyph, &size_bound);
this->debug (15, "[dk] + Computed size %d as a bound key.\n", size_bound);
} else if (mbstrlen(glyph) == 1) {
/* If this key is a single char unbound key... */
if (!already_increased_size_unbound_char) {
drawkb_cairo_increase_to_best_size_by_height(this, cr, labelbox, &font_bound, glyph, &size_unbound_char);
already_increased_size_unbound_char = 1;
}
drawkb_cairo_reduce_to_best_size_by_width(this, cr, labelbox, &font_unbound_char, glyph, &size_unbound_char);
this->debug (15, "[dk] + Computed size %d as a single-char unbound key.\n", size_unbound_char);
} else {
/* This is a multiple char unbound key. */
labelbox.x1 += 20;
labelbox.x2 -= 20;
labelbox.y1 = fullbox.y1 + (fullbox.y2 - fullbox.y1) * 0.5;
labelbox.y2 = fullbox.y1 + (fullbox.y2 - fullbox.y1) * 0.75;
if (!already_increased_size_unbound_string) {
drawkb_cairo_increase_to_best_size_by_height(this, cr, labelbox, &font_bound, glyph, &size_unbound_string);
already_increased_size_unbound_string = 1;
}
drawkb_cairo_reduce_to_best_size_by_width(this, cr, labelbox, &font_unbound_string, glyph, &size_unbound_string);
this->debug (15, "[dk] + Computed size %d as a multichar unbound key.\n", size_unbound_string);
}
this->debug (15, "[dk] + Its labelbox is (x1, x2, y1, y2): %d, %d, %d, %d\n", labelbox.x1, labelbox.x2, labelbox.y1, labelbox.y2);
this->debug (15, "[dk] + Its fullbox is (x1, x2, y1, y2): %d, %d, %d, %d\n", fullbox.x1, fullbox.x2, fullbox.y1, fullbox.y2);
}
memcpy(&(key_data[key_data_n-1].labelbox), &labelbox, sizeof(XkbBoundsRec));
memcpy(&(key_data[key_data_n-1].fullbox), &fullbox, sizeof(XkbBoundsRec));
key_data[key_data_n-1].glyph = glyph;
break;
}
}
this->debug (15, "[dk] -- Best font sizes calculated: %d, %d, %d\n", size_unbound_string, size_unbound_char, size_bound);
my_pango_font_description_set_size(font_unbound_string, size_unbound_string);
my_pango_font_description_set_size(font_unbound_char, size_unbound_char);
my_pango_font_description_set_size(font_bound, size_bound);
for (i = 0; i < row->num_keys; i++) {
for (j = 0; j < key_data_n && key_data[j].index != i; j++);
assert(j < key_data_n);
if (!row->vertical) {
drawkb_cairo_KbDrawKey(this, cr, 0,
row->left + next_piece + row->keys[i].gap,
row->top,
_kb, &row->keys[i], key_data[i], PutIcon, font_unbound_char, font_unbound_string, font_bound, line_width);
next_piece +=
_kb->geom->shapes[row->keys[i].shape_ndx].bounds.x2 + row->keys[i].gap;
cairo_save(cr);
// drawkb_cairo_DrawHollowPolygon(this->dpy, cr, row->left + next_piece + row->keys[i].gap+labelbox.x1, row->top+labelbox.y1, row->top+labelbox.y2, row->left + next_piece + row->keys[i].gap+labelbox.x2, 0, line_width);
cairo_restore(cr);
} else {
drawkb_cairo_KbDrawKey(this, cr, 0,
row->left, row->top + next_piece + row->keys[i].gap,
_kb, &row->keys[i], key_data[i], PutIcon, font_unbound_char, font_unbound_string, font_bound, line_width);
next_piece +=
_kb->geom->shapes[row->keys[i].shape_ndx].bounds.y2 + row->keys[i].gap;
cairo_save(cr);
// drawkb_cairo_DrawHollowPolygon(this->dpy, cr, row->left + next_piece + row->keys[i].gap, row->top+labelbox.y1, row->top+labelbox.y2, row->left + next_piece + row->keys[i].gap+labelbox.x2, 0, line_width);
cairo_restore(cr);
}
}
free(key_data);
cairo_restore(cr);
}
void
drawkb_cairo_KbDrawSection(drawkb_p this, cairo_t *cr, signed int angle,
unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbSectionPtr section, puticon_t PutIcon, float line_width)
{
int i, p;
// drawkb_cairo_KbDrawBounds(this->dpy, w, gc, angle, left + section->left, top + section->top, _kb, §ion->bounds, line_width);
if (section->name)
this->debug(7, "[dr] Drawing section: %s\n", XGetAtomName(this->dpy, section->name));
if (section->name)
this->debug (15, "[dk] + This section is: mame=%s, left=%d, top=%d, angle=%d\n", XGetAtomName(this->dpy, section->name), left, top, angle);
else
this->debug (15, "[dk] + This section is: mame=%s, left=%d, top=%d, angle=%d\n", "(Unnamed)", left, top, angle);
cairo_save(cr);
cairo_translate(cr, left, top);
cairo_rotate(cr, angle*M_PI/1800.0);
for (i = 0; i < section->num_rows; i++) {
XkbComputeRowBounds(_kb->geom, section, §ion->rows[i]);
drawkb_cairo_KbDrawRow(this, cr, angle + section->angle,
section->left, top + section->top, _kb,
§ion->rows[i], PutIcon, line_width);
}
for (p = 0; p <= 255; p++) {
for (i = 0; i < section->num_doodads; i++) {
if (section->doodads[i].any.priority == p) {
drawkb_cairo_KbDrawDoodad(this, cr, angle + section->angle,
section->left, top + section->top, _kb,
§ion->doodads[i], line_width);
}
}
}
cairo_restore(cr);
}
void
drawkb_cairo_drawkb_cairo_KbDrawComponents(drawkb_p this, cairo_t *cr, signed int angle,
unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbSectionPtr sections,
int sections_n, XkbDoodadPtr doodads, int doodads_n, puticon_t PutIcon, float line_width)
{
int i, p;
/* FIXME: This algorithm REALLY NEEDS AND CRYING BEGS for optimization.
* Indexing sections and doodads into a binary or balanced tree would be
* the best.
*/
this->debug (15, "[dk] This component is: left=%d, top=%d, angle=%d\n", left, top, angle);
cairo_save(cr);
cairo_translate(cr, left, top);
cairo_rotate(cr, angle*M_PI/1800.0);
for (p = 0; p <= 255; p++) {
for (i = 0; i < sections_n; i++) {
if (sections[i].priority == p) {
drawkb_cairo_KbDrawSection(this, cr, 0, left,
top, _kb, §ions[i], PutIcon, line_width);
}
}
for (i = 0; i < doodads_n; i++) {
if (doodads[i].any.priority == p) {
drawkb_cairo_KbDrawDoodad(this, cr, 0, left,
0, _kb, &doodads[i], line_width);
// top, _kb, &doodads[i]);
}
}
}
cairo_restore(cr);
}
/* Shamelessley taken from the code on Pango Cairo, just to avoid dependance
* Pango 1.22. */
PangoContext *
local_pango_font_map_create_context (PangoFontMap *fontmap)
{
PangoContext *context;
g_return_val_if_fail (fontmap != NULL, NULL);
context = pango_context_new ();
pango_context_set_font_map (context, fontmap);
return context;
}
PangoContext *
local_pango_cairo_create_context (cairo_t *cr)
{
PangoFontMap *fontmap;
PangoContext *context;
g_return_val_if_fail (cr != NULL, NULL);
fontmap = pango_cairo_font_map_get_default ();
context = local_pango_font_map_create_context (fontmap);
pango_cairo_update_context (cr, context);
return context;
}
void drawkb_cairo_fill_gradient(drawkb_p this, cairo_t *cr, int width_mm, int height_mm) {
cairo_pattern_t * pat;
pat = cairo_pattern_create_linear(0, 0, 0, height_mm);
cairo_pattern_add_color_stop_rgba(pat, 0, lightcolor.red/65535.0, lightcolor.green/65535.0, lightcolor.blue/65535.0, 0.5);
cairo_pattern_add_color_stop_rgba(pat, 1, darkcolor.red/65535.0, darkcolor.green/65535.0, darkcolor.blue/65535.0, 0.5);
cairo_set_source(cr, pat);
cairo_move_to(cr, 0, 0);
cairo_line_to(cr, width_mm, 0);
cairo_line_to(cr, width_mm, height_mm);
cairo_line_to(cr, 0, height_mm);
cairo_line_to(cr, 0, 0);
cairo_fill(cr);
cairo_pattern_destroy(pat);
}
void drawkb_cairo_draw(drawkb_p this, Drawable d, GC gc, unsigned int width, unsigned int height, XkbDescPtr kbdesc, puticon_t PutIcon)
{
cairo_t *cr;
float scale;
Display *dpy = this->dpy;
XGCValues xgcv;
XGetGCValues(dpy, gc, GCForeground | GCBackground, &xgcv);
background.pixel = xgcv.background;
foreground.pixel = xgcv.foreground;
XQueryColor(dpy, DEFAULT_COLORMAP(dpy), &background);
XQueryColor(dpy, DEFAULT_COLORMAP(dpy), &foreground);
lightcolor.red = ((background.red - foreground.red) * 0.8) + foreground.red;
lightcolor.green = ((background.green - foreground.green) * 0.8) + foreground.green;
lightcolor.blue = ((background.blue - foreground.blue) * 0.8) + foreground.blue;
XAllocColor(dpy, DEFAULT_COLORMAP(dpy), &lightcolor);
darkcolor.red = ((background.red - 0) * 0.7);
darkcolor.green = ((background.green - 0) * 0.7);
darkcolor.blue = ((background.blue - 0) * 0.7);
XAllocColor(dpy, DEFAULT_COLORMAP(dpy), &darkcolor);
this->debug(10, "rgb: %d, %d, %d\n", background.red, background.green, background.blue);
this->debug(10, "rgb: %d, %d, %d\n", foreground.red, foreground.green, foreground.blue);
this->debug(10, "rgb: %d, %d, %d\n", lightcolor.red, lightcolor.green, lightcolor.blue);
this->debug(10, "rgb: %d, %d, %d\n", darkcolor.red, darkcolor.green, darkcolor.blue);
XkbGeometryPtr kbgeom = kbdesc->geom;
/* Get what scale should drawkb work with, according to drawable's
* width and height. */
double scalew = (float) width / kbgeom->width_mm;
double scaleh = (float) height / kbgeom->height_mm;
/* Work with the smallest scale. */
if (scalew < scaleh) {
scale = scalew;
} else { /* scalew >= scaleh */
scale = scaleh;
}
/* Override scale for debugging purposes */
/* scale = 0.1; */
int left = 0;
int top = 0;
int angle = 0;
/* Draw top-level rectangle */
// XDrawRectangle(this->dpy, d, cr, left, top, scale * kbdesc->geom->width_mm,
// scale * kbdesc->geom->height_mm);
surface = cairo_xlib_surface_create (dpy, d, DEFAULT_VISUAL(dpy), kbgeom->width_mm, kbgeom->height_mm);
cr = cairo_create (surface);
cairo_scale(cr, scale, scale);
PangoContext *pc = local_pango_cairo_create_context(cr);
PangoFontDescription *fontdesc;
PangoFontMetrics *pm;
fontdesc = pango_font_description_from_string(this->font);
pm = pango_font_get_metrics(pango_context_load_font(pc, fontdesc), NULL);
int asc = pango_font_metrics_get_ascent(pm);
int des = pango_font_metrics_get_descent(pm);
this->debug (11, "[fm] asc, desc = %d, %d\n", asc, des);
g_baseline =
(float) asc / (asc + des);
g_object_unref(pc);
float line_width = 2 / scale;
if (this->use_gradients) {
drawkb_cairo_fill_gradient(this, cr, kbgeom->width_mm, kbgeom->height_mm);
}
/* Draw each component (section or doodad) of the top-level kbdesc->geometry, in
* priority order. Note that priority handling is left to the function. */
drawkb_cairo_drawkb_cairo_KbDrawComponents(this, cr, angle, left, top, kbdesc,
kbdesc->geom->sections, kbdesc->geom->num_sections,
kbdesc->geom->doodads, kbdesc->geom->num_doodads, PutIcon, line_width);
XFlush(this->dpy);
}
/* Checks for font existance and tries to fallback if not. */
int drawkb_cairo_Init_Font(drawkb_p this, const char *font)
{
if (!font) {
fprintf(stderr, "User didn't specify font.\n");
}
strncpy(this->font, font, 499);
/* Try 1: User drawkb_configured. */
if (this->font) {
/* Dummy */
return EXIT_SUCCESS;
fprintf(stderr, "Failed to initialize user configured font.\n");
}
/* FILLTHEGAP */
/* Try 2: Ask NETWM (like in a skin). */
/* Try 3: Fallback to XKB's. */
if (this->kbdesc->geom->label_font) {
/* Dummy */
return EXIT_SUCCESS;
}
/* FILLTHEGAP */
/* Try 4: Ask for whatever ("*-iso8859-1" && !"*-symbol") font. */
return EXIT_FAILURE;
}
drawkb_p drawkb_cairo_create(Display *dpy, const char *font,
IQF_t IQF, painting_mode_t painting_mode, float scale, debug_t *debug,
XkbDescPtr kbdesc, int use_gradients)
{
drawkb_p this = (drawkb_p) malloc(sizeof(drawkb_t));
this->IQF = IQF;
this->painting_mode = painting_mode;
this->dpy = dpy;
this->debug = debug;
this->kbdesc = kbdesc;
this->use_gradients = use_gradients;
/* drawkb_cairo_Init_Font needs drawkb_cairo_Init_Geometry to succeed, because one of
* the fallback fonts is the XKB's specified font label, and
* therefore, geometry must be loaded. */
if (drawkb_cairo_Init_Font(this, font) == EXIT_FAILURE)
{
fprintf(stderr, "Failed to initialize font: %s.\n"
"Possible causes are:\n"
" + You did not quote the name and the name contains spaces.\n"
" + The font doesn't exist.\n", font);
return NULL;
}
drawkb_cairo_WorkaroundBoundsBug(dpy, kbdesc);
return this;
}
int drawkblibs_cairo_init(
drawkb_create_t *ret_create,
drawkb_draw_t *ret_draw)
{
*ret_create = drawkb_cairo_create;
*ret_draw = drawkb_cairo_draw;
return EXIT_SUCCESS;
}
superkb-0.23/drawkblibs/drawkblibs-cairo.h 0000664 0000000 0000000 00000001545 12210555441 0020631 0 ustar 00root root 0000000 0000000 /*
* drawkblibs-cairo.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* This is the actual implementation of drawkb by using cairo to render the
* keyboard onto an X11 drawable .
*
* This code is not used by Superkb directly, but by drawkblib.c This allows
* drawkblib.c to provide multiple options to keyboard rendering.
*
* See drawkblib.h for details.
*
*/
#ifndef __DRAWKBLIBS_CAIRO_H
#define __DRAWKBLIBS_CAIRO_H
#include "drawkblibs.h"
int drawkb_cairo_create(Display *dpy, const char *imagelib, const char *font, IQF_t IQF, painting_mode_t painting_mode, float scale);
void drawkb_cairo_draw(drawkb_p this, Drawable d, GC gc, unsigned int width, unsigned int height, XkbDescPtr kbdesc, puticon_t puticon);
int drawkblibs_cairo_init (
drawkb_create_t *ret_create,
drawkb_draw_t *ret_draw
);
#endif
superkb-0.23/drawkblibs/drawkblibs-xlib.c 0000664 0000000 0000000 00000110645 12210555441 0020467 0 ustar 00root root 0000000 0000000 /*
* drawkblibs-xlib.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
#include
#include "drawkblibs.h"
// #include "drawkblibs-xlib.h"
#ifndef WITH_DRAWKBLIBS_XLIB
#define drawkblibs_xlib_init Init
#endif
/*
* drawkb.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
/*
* Bibliography: XKBlib.pdf.
*/
/* This module does all the keyboard drawing magic. */
/* If ever needed to call XkbComputeShapeBounds() you must immediately
* call WorkaroundBoundsBug() afterwards. This works around a bug present
* in Xorg < 7.1.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "../drawkblib.h"
#include "../imagelib.h"
#include "../globals.h"
#define LINE_WIDTH 2
#define pxl (1 / scale)
#define DEFAULT_SCREEN(dpy) (DefaultScreen(dpy))
#define DEFAULT_VISUAL(dpy) (DefaultVisual(dpy, DEFAULT_SCREEN(dpy)))
#define DEFAULT_COLORMAP(dpy) (DefaultColormap(dpy, DEFAULT_SCREEN(dpy)))
double __scale;
XkbDescPtr kbdesc;
XkbGeometryPtr kb_geom;
IQF_t IQF;
int g_size;
double g_baseline;
XColor lightcolor;
XColor darkcolor;
XColor foreground;
XColor background;
XftColor xftlightcolor;
XftColor xftdarkcolor;
XftColor xftbackground;
XftColor xftforeground;
XftColor *current;
XftDraw *dw = NULL;
typedef struct {
char *keystring;
char *keylabel;
} keystrings_t;
keystrings_t keystrings[] = {
{ "dead_grave", "`" },
{ "dead_acute", "'" },
{ "grave", "`" },
{ "apostrophe", "'" },
{ "space", "" },
{ "Escape", "Esc" },
{ "comma", "," },
{ "period", "." },
{ "slash", "/" },
{ "minus", "-" },
{ "equal", "=" },
{ "Caps_Lock", "Caps Lock" },
{ "Shift_L", "Shift" },
{ "Shift_R", "Shift" },
{ "semicolon", ";" },
{ "BackSpace", "Backspace" },
{ "Return", "Enter" },
{ "Control_L", "Ctrl" },
{ "Control_R", "Ctrl" },
{ "Alt_L", "Alt" },
{ "KP_Enter", "Enter" },
{ "KP_Add", "+" },
{ "KP_Subtract", "-" },
{ "KP_Multiply", "*" },
{ "KP_Divide", "/" },
{ "Num_Lock", "NumLk" },
{ "KP_Home", "Home" },
{ "KP_End", "End" },
{ "KP_Prior", "PgUp" },
{ "KP_Up", "Up" },
{ "KP_Down", "Down" },
{ "KP_Left", "Left" },
{ "KP_Right", "Right" },
{ "KP_Next", "Next" },
{ "KP_Begin", "Begin" },
{ "KP_Insert", "Ins" },
{ "KP_Delete", "Del" },
{ "Scroll_Lock", "ScrLk" },
{ "bracketleft", "[" },
{ "bracketright", "]" },
{ "braceleft", "{" },
{ "braceright", "}" },
{ "backslash", "\\" },
{ "ntilde", "ñ" },
{ "plus", "+" },
{ "ISO_Level3_Shift", "AltGr" },
{ "Insert", "Ins" },
{ "Delete", "Del" },
{ "Prior", "PgUp" },
{ "Next", "PgDn" },
{ "questiondown", "¿" },
{ "Print", "PrScr" },
{ "", "" }
};
typedef struct {
unsigned int index;
XkbBoundsRec labelbox;
unsigned int size;
const char *glyph;
} key_data_t;
char *LookupKeylabelFromKeystring(char *kss) {
int i = 0;
while (strcmp((keystrings[i]).keystring, "") != 0) {
if (!strcmp(kss, (keystrings[i]).keystring))
return (keystrings[i]).keylabel;
i++;
}
return kss;
}
int MyXftTextWidth(Display *dpy, XftFont *fs, const char *s, int len) {
XGlyphInfo xgi;
XftTextExtents8(dpy, fs, (unsigned char *) s, len, &xgi);
return xgi.xOff;
}
/* FIXME: Same problem as XLoadQueryScalableFont(). It doesn't check
* for i < 500*sizeof(char).
*/
int XSetFontNameToScalable(const char *name, char *newname, int newname_n)
{
int i, j, field;
/* catch obvious errors */
if ((name == NULL) || (name[0] != '-'))
return 0;
/* copy the font name, changing the scalable fields as we do so */
/* FIXME: "&& i < buf_n - 1": better safe than sorry (i < buf_n?) */
for (i = j = field = 0;
name[i] != '\0' && field <= 14 && i < newname_n - 1; i++) {
newname[j++] = name[i];
if (name[i] == '-') {
field++;
switch (field) {
case 7: /* pixel size */
case 12: /* average width */
/* change from "-whatever-" to "-0-" */
newname[j] = '0';
j++;
while (name[i + 1] != '\0' && name[i + 1] != '-')
i++;
break;
case 8: /* point size */
/* change from "-whatever-" to "-0-" */
newname[j] = '0';
j++;
while (name[i + 1] != '\0' && name[i + 1] != '-')
i++;
break;
case 9: /* x-resolution */
case 10: /* y-resolution */
/* change from "-whatever-" to "-*-" */
newname[j] = '*';
j++;
while (name[i + 1] != '\0' && name[i + 1] != '-')
i++;
break;
}
}
}
newname[j] = '\0';
/* if there aren't 14 hyphens, it isn't a well formed name */
return field;
}
/* TAKEN FROM O'REILLY XLIB PROGRAMMING MANUAL.
*
* This routine is passed a scalable font name and a point size. It returns
* an XftFont * for the given font scaled to the specified size and the
* exact resolution of the screen. The font name is assumed to be a
* well-formed XLFD name, and to have pixel size, point size, and average
* width fields of "0" and arbitrary x-resolution and y-resolution fields.
* Size is specified in tenths of points. Returns NULL if the name is
* malformed or no such font exists.
*
* FIXME: It doesn't check for i < 500*sizeof(char).
*/
XftFont *XLoadQueryScalableFont(Display * dpy, int screen, char *name,
int size)
{
XftFont *fs;
int i, j, field;
char newname[500]; /* big enough for a long font name */
int res_x, res_y; /* resolution values for this screen */
/* catch obvious errors */
if ((name == NULL) || (name[0] != '-'))
return NULL;
/* calculate our screen resolution in dots per inch. 25.4mm = 1 inch */
res_x =
DisplayWidth(dpy, screen) / (DisplayWidthMM(dpy, screen) / 25.4);
res_y =
DisplayHeight(dpy, screen) / (DisplayHeightMM(dpy, screen) / 25.4);
/* copy the font name, changing the scalable fields as we do so */
for (i = j = field = 0; name[i] != '\0' && field <= 14; i++) {
newname[j++] = name[i];
if (name[i] == '-') {
field++;
switch (field) {
case 8: /* pixel size */
case 12: /* average width */
/* change from "-0-" to "-*-" */
newname[j] = '*';
j++;
if (name[i + 1] != '\0')
i++;
break;
case 7: /* point size */
/* change from "-0-" to "--" */
sprintf(&newname[j], "%d", size);
while (newname[j] != '\0')
j++;
if (name[i + 1] != '\0')
i++;
break;
case 9: /* x-resolution */
case 10: /* y-resolution */
/* change from an unspecified resolution to res_x or res_y */
sprintf(&newname[j], "%d", (field == 9) ? res_x : res_y);
while (newname[j] != '\0')
j++;
while ((name[i + 1] != '-') && (name[i + 1] != '\0'))
i++;
break;
}
}
}
newname[j] = '\0';
/* if there aren't 14 hyphens, it isn't a well formed name */
if (field != 14)
return NULL;
fs = XftFontOpenXlfd(dpy, 0, newname);
return fs;
}
/*
int drawkb_set_font(drawkb_p this)
{
// FIXME: Validate font name.
// FILLTHEGAP: Support font-family-only values.
XSetFontNameToScalable(font, this->font, 500);
char * ptr;
ptr = realloc(this->font, strlen(font));
if (!ptr)
return EXIT_FAILURE;
strcpy(this->font, font);
return EXIT_SUCCESS;
XftFont *fs;
fs = XLoadQueryScalableFont(this->dpy, 0, this->font, 1000);
if (fs) {
return EXIT_SUCCESS;
}
XftFontClose(dpy, fs);
}
void drawkb_set_dpy(drawkb_p this, Display *dpy)
{
this->dpy = dpy;
}
*/
void WorkaroundBoundsBug(Display * dpy, XkbDescPtr _kb)
{
int i, j;
/* To workaround an X11R7.0 and previous bug */
if (VendorRelease(dpy) < 70100000 &&
VendorRelease(dpy) > 50000000 &&
!strcmp(ServerVendor(dpy), "The X.Org Foundation"))
{
for (i = 0; i < _kb->geom->num_shapes; i++)
{
XkbShapePtr s; /* shapes[i] */
s = &_kb->geom->shapes[i];
for (j = 0; j < s->num_outlines; j++)
{
if (s->outlines[j].num_points == 1)
{
s->bounds.x1 = s->bounds.y1 = 0;
}
}
}
}
}
void
RotatePoint(double left, double top, double angle, double rot_left,
double rot_top, double *new_left, double *new_top)
{
if (angle == 0) {
*new_left = left;
*new_top = top;
return;
}
double r;
double a;
const double PI = 3.14159265358979323846;
double l = left - rot_left;
double t = top - rot_top;
r = sqrt(l * l + t * t);
if (l == 0) {
if (t > 0) {
a = PI * 1 / 2;
} else if (t == 0) {
a = 0;
} else {
a = PI * 3 / 2;
}
} else {
a = atan((double) t / l);
}
if (new_left != NULL)
*new_left =
(double) rot_left + (double) r * cos((double) a + (double) angle / 1800 * PI);
if (new_top != NULL)
*new_top =
(double) rot_top + (double) r * sin((double) a + (double) angle / 1800 * PI);
}
void
RotateArc(double left, double top, double width, double height,
double start, double end, double angle, double rot_left,
double rot_top, double *new_x, double *new_y,
double *new_width, double *new_height,
double *new_start, double *new_end)
{
double center_x, center_y;
center_x = left + width / 2 - rot_left;
center_y = top + height / 2 - rot_top;
RotatePoint(center_x, center_y, angle, 0, 0, ¢er_x, ¢er_y);
if (new_x)
*new_x = rot_left + center_x - width / 2;
if (new_y)
*new_y = rot_top + center_y - height / 2;
if (new_start)
*new_start = start - 6.4 * angle / 10;
if (new_end)
*new_end = end - 6.4 * angle / 10;
/* FIXME: Since these are always the same as the input values, function
* can be significantly reduced. */
if (new_width)
*new_width = width;
if (new_height)
*new_height = height;
}
void
KbDrawBounds(Display * dpy, Drawable w, GC gc, unsigned int angle,
double scale, unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbBoundsPtr bounds)
{
GC gc_backup;
/* FIXME: I know, there must be faster ways, but this was faster to code. */
memcpy(&gc_backup, &gc, sizeof(GC));
XSetLineAttributes(dpy, gc, LINE_WIDTH, LineOnOffDash, CapButt, JoinMiter);
XDrawRectangle(dpy, w, gc, scale * (left + bounds->x1),
scale * (top + bounds->y1),
scale * (bounds->x2 - bounds->x1),
scale * (bounds->y2 - bounds->y1));
memcpy(&gc, &gc_backup, sizeof(GC));
}
void DrawFilledPolygon(Display * dpy, Drawable w, GC gc, double scale,
unsigned int left,
unsigned int top,
unsigned int angle,
unsigned int rot_left,
unsigned int rot_top,
unsigned int t,
unsigned int l,
unsigned int b,
unsigned int r,
unsigned int corner_radius) {
XPoint point[8];
int npoints;
int shape;
int mode;
double px, py;
npoints = 8;
shape = Convex;
mode = CoordModeOrigin;
double local_corner_radius = corner_radius + 0 * pxl;
RotatePoint(left + l + local_corner_radius, top + t, angle,
rot_left, rot_top, &px, &py);
point[0].x = scale * px;
point[0].y = scale * py;
RotatePoint(left + r - local_corner_radius, top + t, angle,
rot_left, rot_top, &px, &py);
point[1].x = scale * px;
point[1].y = scale * py;
RotatePoint(left + r, top + t + local_corner_radius, angle,
rot_left, rot_top, &px, &py);
point[2].x = scale * px;
point[2].y = scale * py;
RotatePoint(left + r, top + b - local_corner_radius, angle,
rot_left, rot_top, &px, &py);
point[3].x = scale * px;
point[3].y = scale * py;
RotatePoint(left + r - local_corner_radius, top + b, angle,
rot_left, rot_top, &px, &py);
point[4].x = scale * px;
point[4].y = scale * py;
RotatePoint(left + l + local_corner_radius, top + b, angle,
rot_left, rot_top, &px, &py);
point[5].x = scale * px;
point[5].y = scale * py;
RotatePoint(left + l, top + b - local_corner_radius, angle,
rot_left, rot_top, &px, &py);
point[6].x = scale * px;
point[6].y = scale * py;
RotatePoint(left + l, top + t + local_corner_radius, angle,
rot_left, rot_top, &px, &py);
point[7].x = scale * px;
point[7].y = scale * py;
XFillPolygon(dpy, w, gc, point, npoints, shape, mode);
}
/* Graphic context should have already been set. */
void
KbDrawShape(drawkb_p this, Drawable w, GC gc, unsigned int angle,
unsigned int rot_left, unsigned int rot_top, double scale,
unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbShapePtr shape, XkbColorPtr color,
Bool is_key)
{
/* KbDrawBounds(this->dpy, w, gc, angle, scale, left, top, _kb, &shape->bounds); */
XkbOutlinePtr source;
int i;
int t = 0, l = 0, b = 0, r = 0;
int j;
int shapes_to_paint = 1;
if (this->painting_mode == FULL_SHAPE) shapes_to_paint = shape->num_outlines;
for (i = 0; i < (is_key ? shapes_to_paint : shape->num_outlines); i++) {
source = &shape->outlines[i];
double corner_radius = source->corner_radius + 1 * pxl;
XSetLineAttributes(this->dpy, gc, LINE_WIDTH, LineSolid, CapButt, JoinMiter);
switch (source->num_points) {
case 1:
t = l = 0;
b = source->points[0].y;
r = source->points[0].x;
break;
case 2:
t = source->points[0].y;
l = source->points[0].x;
b = source->points[1].y;
r = source->points[1].x;
break;
default:
/* FIXME: Should also take care of angle and corner radius */
for (j = 0; j < source->num_points - 1; j++) {
XDrawLine(this->dpy, w, gc, scale * (left + source->points[j].x),
scale * (top + source->points[j].y),
scale * (left + source->points[j + 1].x),
scale * (top + source->points[j + 1].y));
}
XDrawLine(this->dpy, w, gc, scale * (left + source->points[j].x),
scale * (top + source->points[j].y),
scale * (left + source->points[0].x),
scale * (top + source->points[0].y));
break;
}
if (source->num_points <= 2) {
double ax, ay, bx, by;
double arch, arcw, arcs, arce;
unsigned long color;
if (this->painting_mode == FULL_SHAPE || this->painting_mode == FLAT_KEY) {
if ( i % 2 == 0 ) {
color = darkcolor.pixel;
current = &xftdarkcolor;
} else {
color = background.pixel;
current = &xftbackground;
}
XSetForeground(this->dpy, gc, color);
is_key ? DrawFilledPolygon(this->dpy, w, gc, scale, left, top, angle, rot_left, rot_top, t, l, b, r, corner_radius) : (void) 0;
RotateArc(left + l - 1 * pxl, top + t - 1 * pxl, 2 * corner_radius + LINE_WIDTH * pxl + 2 * pxl,
2 * corner_radius + LINE_WIDTH * pxl + 2 * pxl, 5760, 5759, angle,
rot_left, rot_top, &ax, &ay, &arcw, &arch, &arcs,
&arce);
XFillArc(this->dpy, w, gc, scale * ax, scale * ay, scale * arcw,
scale * arch, arcs, arce);
RotateArc(left + r - 2 * corner_radius - LINE_WIDTH * pxl, top + t - 1 * pxl,
2 * corner_radius + LINE_WIDTH * pxl, 2 * corner_radius + LINE_WIDTH * pxl + 2 * pxl,
0, 5759, angle, rot_left, rot_top, &ax, &ay, &arcw,
&arch, &arcs, &arce);
XFillArc(this->dpy, w, gc, scale * ax, scale * ay, scale * arcw,
scale * arch, arcs, arce);
RotateArc(left + r - 2 * corner_radius - LINE_WIDTH * pxl,
top + b - 2 * corner_radius - LINE_WIDTH * pxl,
2 * corner_radius + LINE_WIDTH * pxl, 2 * corner_radius + LINE_WIDTH * pxl,
17280, 5759, angle, rot_left, rot_top, &ax, &ay,
&arcw, &arch, &arcs, &arce);
XFillArc(this->dpy, w, gc, scale * ax, scale * ay, scale * arcw,
scale * arch, arcs, arce);
RotateArc(left + l - 1 * pxl, top + b - 2 * corner_radius - LINE_WIDTH * pxl,
2 * corner_radius + LINE_WIDTH * pxl + 2 * pxl, 2 * corner_radius + LINE_WIDTH * pxl,
11521, 5759, angle, rot_left, rot_top, &ax, &ay,
&arcw, &arch, &arcs, &arce);
XFillArc(this->dpy, w, gc, scale * ax, scale * ay, scale * arcw,
scale * arch, arcs, arce);
} else {
XSetForeground(this->dpy, gc, foreground.pixel);
current = &xftforeground;
RotatePoint(left + l + corner_radius, top + t, angle,
rot_left, rot_top, &ax, &ay);
RotatePoint(left + r - corner_radius, top + t, angle,
rot_left, rot_top, &bx, &by);
XDrawLine(this->dpy, w, gc, scale * (ax), scale * (ay), scale * (bx),
scale * (by));
RotateArc(left + l - 1 * pxl, top + t - 1 * pxl, 2 * corner_radius + LINE_WIDTH * pxl + 2 * pxl,
2 * corner_radius + LINE_WIDTH * pxl + 2 * pxl, 5760, 5759, angle,
rot_left, rot_top, &ax, &ay, &arcw, &arch, &arcs,
&arce);
XDrawArc(this->dpy, w, gc, scale * ax, scale * ay, scale * arcw,
scale * arch, arcs, arce);
RotatePoint(left + r, top + t + corner_radius, angle,
rot_left, rot_top, &ax, &ay);
RotatePoint(left + r, top + b - corner_radius, angle,
rot_left, rot_top, &bx, &by);
XDrawLine(this->dpy, w, gc, scale * (ax), scale * (ay), scale * (bx),
scale * (by));
RotateArc(left + r - 2 * corner_radius - LINE_WIDTH * pxl, top + t - 1 * pxl,
2 * corner_radius + LINE_WIDTH * pxl, 2 * corner_radius + LINE_WIDTH * pxl + 2 * pxl,
0, 5759, angle, rot_left, rot_top, &ax, &ay, &arcw,
&arch, &arcs, &arce);
XDrawArc(this->dpy, w, gc, scale * ax, scale * ay, scale * arcw,
scale * arch, arcs, arce);
RotatePoint(left + r - corner_radius, top + b, angle,
rot_left, rot_top, &ax, &ay);
RotatePoint(left + l + corner_radius, top + b, angle,
rot_left, rot_top, &bx, &by);
XDrawLine(this->dpy, w, gc, scale * (ax), scale * (ay), scale * (bx),
scale * (by));
RotateArc(left + r - 2 * corner_radius - LINE_WIDTH * pxl,
top + b - 2 * corner_radius - LINE_WIDTH * pxl,
2 * corner_radius + LINE_WIDTH * pxl, 2 * corner_radius + LINE_WIDTH * pxl,
17280, 5759, angle, rot_left, rot_top, &ax, &ay,
&arcw, &arch, &arcs, &arce);
XDrawArc(this->dpy, w, gc, scale * ax, scale * ay, scale * arcw,
scale * arch, arcs, arce);
RotatePoint(left + l, top + b - corner_radius, angle,
rot_left, rot_top, &ax, &ay);
RotatePoint(left + l, top + t + corner_radius, angle,
rot_left, rot_top, &bx, &by);
XDrawLine(this->dpy, w, gc, scale * (ax), scale * (ay), scale * (bx),
scale * (by));
RotateArc(left + l - 1 * pxl, top + b - 2 * corner_radius - LINE_WIDTH * pxl,
2 * corner_radius + LINE_WIDTH * pxl + 2 * pxl, 2 * corner_radius + LINE_WIDTH * pxl,
11521, 5759, angle, rot_left, rot_top, &ax, &ay,
&arcw, &arch, &arcs, &arce);
XDrawArc(this->dpy, w, gc, scale * ax, scale * ay, scale * arcw,
scale * arch, arcs, arce);
}
}
}
XFlush(this->dpy);
}
void
KbDrawDoodad(drawkb_p this, Drawable w, GC gc, /*XftFont *f, */unsigned int angle,
double scale, unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbDoodadPtr doodad)
{
XSetForeground(this->dpy, gc, lightcolor.pixel);
current = &xftlightcolor;
switch (doodad->any.type) {
case XkbOutlineDoodad:
KbDrawShape(this, w, gc, angle + doodad->shape.angle,
left + doodad->shape.left, top + doodad->shape.top,
scale, left + doodad->shape.left,
top + doodad->shape.top, _kb,
&_kb->geom->shapes[doodad->shape.shape_ndx],
&_kb->geom->colors[doodad->shape.color_ndx], False);
break;
case XkbSolidDoodad:
KbDrawShape(this, w, gc, angle + doodad->shape.angle,
left + doodad->shape.left, top + doodad->shape.top,
scale, left + doodad->shape.left,
top + doodad->shape.top, _kb,
&_kb->geom->shapes[doodad->shape.shape_ndx],
&_kb->geom->colors[doodad->shape.color_ndx], False);
break;
case XkbTextDoodad:
/* XftDrawString8(dw, current, NULL, scale * (left + doodad->text.left), scale * (top + doodad->text.top) + 6, (unsigned char *)doodad->text.text, strlen(doodad->text.text));*/
break;
case XkbIndicatorDoodad:
KbDrawShape(this, w, gc, angle + doodad->indicator.angle,
left + doodad->indicator.left,
top + doodad->indicator.top, scale,
left + doodad->indicator.left,
top + doodad->indicator.top, _kb,
&_kb->geom->shapes[doodad->indicator.shape_ndx],
&_kb->geom->colors[doodad->indicator.on_color_ndx],
False);
break;
case XkbLogoDoodad:
KbDrawShape(this, w, gc, angle + doodad->logo.angle,
left + doodad->logo.left, top + doodad->logo.top,
scale, left + doodad->logo.left,
top + doodad->logo.top, _kb,
&_kb->geom->shapes[doodad->logo.shape_ndx],
&_kb->geom->colors[doodad->logo.color_ndx], False);
break;
}
XSetForeground(this->dpy, gc, foreground.pixel);
current = &xftforeground;
}
void
KbDrawKey(drawkb_p this, Drawable w, GC gc, unsigned int angle,
unsigned int section_left, unsigned int section_top,
double scale, unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbKeyPtr key, key_data_t key_data, puticon_t PutIcon)
{
unsigned int fixed_num_keys;
unsigned long i;
char buf[1024]="";
int buf_n = 1023;
KbDrawShape(this, w, gc, angle, section_left, section_top, scale,
left, top, _kb,
&_kb->geom->shapes[key->shape_ndx],
&_kb->geom->colors[key->color_ndx], True);
XSetForeground(this->dpy, gc, foreground.pixel);
current = &xftforeground;
/* This is to work around an XKB apparent bug. */
fixed_num_keys = _kb->names->num_keys;
if (!fixed_num_keys)
fixed_num_keys = 256;
for (i = 0; i < fixed_num_keys; i++) {
char name[5] = "";
char glyph[256] = "";
char keystring[256] = "";
char *kss;
if (!strncmp(key->name.name, _kb->names->keys[i].name, 4)) {
strncpy(name, _kb->names->keys[i].name, 4);
KeySym ks;
ks = XkbKeycodeToKeysym(this->dpy, i, 0, 0);
kss = XKeysymToString(ks);
if (kss) {
strncpy(keystring, kss, 255);
kss = LookupKeylabelFromKeystring(kss);
if (!kss) continue;
strncpy(glyph, kss, 255);
XftFont *fs;
unsigned int tw;
double ax, ay;
if (this->IQF(XStringToKeysym(keystring), 0, buf, buf_n) == EXIT_SUCCESS) {
/* FIXME: Key label vertical position is miscalculated. */
fs = XLoadQueryScalableFont(this->dpy, 0, this->font, key_data.size);
if (strcmp(buf, "") != 0) {
int size = key_data.labelbox.x2 - key_data.labelbox.x1;
if (key_data.labelbox.y2 - key_data.labelbox.y1 - (fs->ascent + 1) * pxl < size)
size = key_data.labelbox.y2 - key_data.labelbox.y1 - (fs->ascent + 1) * pxl;
RotatePoint((left + key_data.labelbox.x2 - size),
(top + key_data.labelbox.y2 - size),
angle, section_left, section_top, &ax,
&ay);
PutIcon(w, scale*ax, scale*ay, scale*size, scale*size, buf);
/* KbDrawBounds(this->dpy, w, gc, angle, scale, left, top, _kb, &(key_data.labelbox)); */
}
RotatePoint(left + key_data.labelbox.x1,
(top + key_data.labelbox.y1 + fs->ascent / scale),
angle, section_left, section_top, &ax,
&ay);
XftDrawString8(dw, current, fs, scale*ax, scale*ay, (unsigned char *)glyph,
strlen(glyph));
} else {
if (this->painting_mode == FLAT_KEY) {
XSetForeground(this->dpy, gc, background.pixel);
current = &xftbackground;
} else {
XSetForeground(this->dpy, gc, lightcolor.pixel);
current = &xftlightcolor;
}
fs = XLoadQueryScalableFont(this->dpy, 0,
this->font,
key_data.size);
if (strlen(kss) == 1) {
tw = MyXftTextWidth(this->dpy, fs, glyph, strlen(glyph));
RotatePoint((left + (key_data.labelbox.x1 + key_data.labelbox.x2) / 2) -
tw / 2 / scale,
top + key_data.labelbox.y1 + (key_data.labelbox.y2 - key_data.labelbox.y1) * g_baseline,
angle, section_left, section_top, &ax,
&ay);
XftDrawString8(dw, current, fs, scale*ax, scale*ay, (unsigned char *)glyph,
1);
} else {
RotatePoint(left + key_data.labelbox.x1,
top + key_data.labelbox.y1 + (key_data.labelbox.y2 - key_data.labelbox.y1) * g_baseline,
angle, section_left, section_top, &ax,
&ay);
XftDrawString8(dw, current, fs, scale * (ax), scale * (ay),
(unsigned char *)kss, strlen(kss));
}
XftFontClose(this->dpy, fs);
XSetForeground(this->dpy, gc, foreground.pixel);
current = &xftforeground;
}
}
break;
}
}
}
void AdjustSize(drawkb_p this, XkbBoundsRec labelbox, const char *glyph, double initial_key_height_percent, double scale, int *size)
{
int labelbox_width = labelbox.x2 - labelbox.x1;
int labelbox_height = labelbox.y2 - labelbox.y1;
XftFont *fs;
this->debug (10, " --> AdjustSize (labelbox(x1=%d, y1=%d, x2=%d, y2=%d), glyph=%s, initial_key_height_percent=%lf, scale=%lf, size=%d\n", labelbox.x1, labelbox.y1, labelbox.x2, labelbox.y2, glyph, initial_key_height_percent, scale, *size);
if (!*size) {
*size = labelbox_height * initial_key_height_percent * scale;
fs = XLoadQueryScalableFont(this->dpy, 0, this->font, *size);
while (MyXftTextWidth(this->dpy, fs, glyph, strlen(glyph)) <= (int) labelbox_width*scale
&& fs->ascent <= labelbox_height*initial_key_height_percent*scale) {
XftFontClose(this->dpy, fs);
(*size)++;
fs = XLoadQueryScalableFont(this->dpy, 0, this->font, *size);
this->debug (10, "Iterating in %s:%d\n", __FILE__, __LINE__);
}
} else {
fs = XLoadQueryScalableFont(this->dpy, 0, this->font, *size);
}
this->debug (10, " ::: AdjustSize interim size value: %d\n", *size);
/* Reduce the *size point by point as less as possible. */
while (MyXftTextWidth(this->dpy, fs, glyph, strlen(glyph)) > (int) labelbox_width*scale) {
XftFontClose(this->dpy, fs);
(*size)--;
fs = XLoadQueryScalableFont(this->dpy, 0, this->font, *size);
this->debug (10, "Iterating in %s:%d\n", __FILE__, __LINE__);
}
XftFontClose(this->dpy, fs);
this->debug (10, " <-- AdjustSize final size value: %d\n", *size);
}
void
KbDrawRow(drawkb_p this, Drawable w, GC gc, unsigned int angle,
double scale, unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbRowPtr row, puticon_t PutIcon)
{
unsigned int i;
unsigned int next_piece = 0;
XkbBoundsRec labelbox;
// KbDrawBounds(this->dpy, w, gc, angle, scale, left + row->left, top + row->top, _kb, &row->bounds);
int size_bound = 0;
int size_unbound_char = 0;
int size_unbound_string = 0;
/* This is to work around an XKB apparent bug. */
unsigned int fixed_num_keys = _kb->names->num_keys;
if (!fixed_num_keys)
fixed_num_keys = 256;
unsigned int j;
key_data_t *key_data = NULL;
unsigned int key_data_n = 0;
for (j = 0; j < row->num_keys; j++) {
XkbKeyPtr key = &row->keys[j];
this->debug (4, "KbDrawRow: processing key j=%d\n ", j);
list_add_element (key_data, key_data_n, key_data_t);
memset(&(key_data[key_data_n-1]), 0, sizeof(key_data_t));
key_data[key_data_n-1].index = j;
for (i = 0; i < fixed_num_keys; i++) {
char name[5] = "";
char glyph[256] = "";
char keystring[256] = "";
char *kss;
if (strncmp(key->name.name, _kb->names->keys[i].name, 4) != 0)
continue;
strncpy(name, _kb->names->keys[i].name, 4);
KeySym ks;
ks = XkbKeycodeToKeysym(this->dpy, i, 0, 0);
kss = XKeysymToString(ks);
if (!kss)
continue;
strncpy(keystring, kss, 255);
kss = LookupKeylabelFromKeystring(kss);
if (!kss)
continue;
strncpy(glyph, kss, 255);
/* Calculate label + icon box bounds */
int labelbox_border = 0 / scale;
int labelbox_margin = 2 / scale;
XkbBoundsRec kr, *k = &kr;
if (this->painting_mode == FULL_SHAPE) {
XkbComputeShapeTop(&_kb->geom->shapes[key->shape_ndx], k);
} else if (this->painting_mode == BASE_OUTLINE_ONLY) {
k = &_kb->geom->shapes[key->shape_ndx].bounds;
labelbox_border = LINE_WIDTH * pxl;
} else if (this->painting_mode == FLAT_KEY) {
k = &_kb->geom->shapes[key->shape_ndx].bounds;
} else {
assert (0);
}
labelbox.x1 = k->x1 + labelbox_margin + labelbox_border;
labelbox.x2 = k->x2 - labelbox_margin - labelbox_border;
labelbox.y1 = k->y1 + labelbox_margin + labelbox_border;
labelbox.y2 = k->y2 - labelbox_margin - labelbox_border;
/* End calculate label + icon box bounds */
if (this->IQF(XStringToKeysym(keystring), 0, NULL, 0) == EXIT_SUCCESS) {
/* If this key is a bound key... */
AdjustSize(this, labelbox, glyph, 0.28, scale, &size_bound);
key_data[key_data_n-1].size = size_bound;
} else if (strlen(glyph) == 1) {
/* If this key is a single char unbound key... */
AdjustSize(this, labelbox, glyph, 0.9, scale, &size_unbound_char);
key_data[key_data_n-1].size = size_unbound_char;
} else {
/* This is a multiple char unbound key. */
labelbox.x1 += 4 / scale;
labelbox.x2 -= 4 / scale;
AdjustSize(this, labelbox, glyph, 0.25, scale, &size_unbound_string);
key_data[key_data_n-1].size = size_unbound_string;
}
memcpy(&(key_data[key_data_n-1].labelbox), &labelbox, sizeof(XkbBoundsRec));
key_data[key_data_n-1].glyph = glyph;
break;
}
}
for (i = 0; i < row->num_keys; i++) {
for (j = 0; j < key_data_n && key_data[j].index != i; j++);
assert(j < key_data_n);
if (!row->vertical) {
KbDrawKey(this, w, gc, angle, left, top, scale,
left + row->left + next_piece + row->keys[i].gap,
top + row->top,
_kb, &row->keys[i], key_data[i], PutIcon);
next_piece +=
_kb->geom->shapes[row->keys[i].shape_ndx].bounds.x2 + row->keys[i].gap;
} else {
KbDrawKey(this, w, gc,
angle, left, top, scale,
left + row->left, top + row->top + next_piece + row->keys[i].gap,
_kb, &row->keys[i], key_data[i], PutIcon);
next_piece +=
_kb->geom->shapes[row->keys[i].shape_ndx].bounds.y2 + row->keys[i].gap;
}
}
free(key_data);
}
void
KbDrawSection(drawkb_p this, Drawable w, GC gc, unsigned int angle,
double scale, unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbSectionPtr section, puticon_t PutIcon)
{
int i, p;
/* KbDrawBounds(dpy, w, gc, angle, scale, left + section->left, top + section->top, _kb, §ion->bounds); */
/* if (section->name) fprintf(stderr, "Drawing section: %s\n", XGetAtomName(dpy,
section->name)); */
for (i = 0; i < section->num_rows; i++) {
XkbComputeRowBounds(_kb->geom, section, §ion->rows[i]);
KbDrawRow(this, w, gc, angle + section->angle, scale,
left + section->left, top + section->top, _kb,
§ion->rows[i], PutIcon);
}
for (p = 0; p <= 255; p++) {
for (i = 0; i < section->num_doodads; i++) {
if (section->doodads[i].any.priority == p) {
KbDrawDoodad(this, w, gc, angle + section->angle, scale,
left + section->left, top + section->top, _kb,
§ion->doodads[i]);
}
}
}
}
void
KbDrawComponents(drawkb_p this, Drawable w, GC gc, unsigned int angle,
double scale, unsigned int left, unsigned int top,
XkbDescPtr _kb, XkbSectionPtr sections,
int sections_n, XkbDoodadPtr doodads, int doodads_n, puticon_t PutIcon)
{
int i, p;
/* FIXME: This algorithm REALLY NEEDS AND CRYING BEGS for optimization.
* Indexing sections and doodads into a binary or balanced tree would be
* the best.
*/
for (p = 0; p <= 255; p++) {
for (i = 0; i < sections_n; i++) {
if (sections[i].priority == p) {
KbDrawSection(this, w, gc, angle, scale, left,
top, _kb, §ions[i], PutIcon);
}
}
for (i = 0; i < doodads_n; i++) {
if (doodads[i].any.priority == p) {
KbDrawDoodad(this, w, gc, angle, scale, left,
top, _kb, &doodads[i]);
}
}
}
}
void drawkb_xlib_draw(drawkb_p this, Drawable d, GC gc, unsigned int width, unsigned int height, XkbDescPtr kbdesc, puticon_t PutIcon)
{
float scale;
Display *dpy = this->dpy;
dw = XftDrawCreate (dpy, d, DEFAULT_VISUAL(dpy), DEFAULT_COLORMAP(dpy));
XGCValues xgcv;
XGetGCValues(dpy, gc, GCForeground | GCBackground, &xgcv);
background.pixel = xgcv.background;
foreground.pixel = xgcv.foreground;
XQueryColor(dpy, DEFAULT_COLORMAP(dpy), &background);
XQueryColor(dpy, DEFAULT_COLORMAP(dpy), &foreground);
lightcolor.red = ((background.red - foreground.red) * 0.8) + foreground.red;
lightcolor.green = ((background.green - foreground.green) * 0.8) + foreground.green;
lightcolor.blue = ((background.blue - foreground.blue) * 0.8) + foreground.blue;
XAllocColor(dpy, DEFAULT_COLORMAP(dpy), &lightcolor);
darkcolor.red = ((background.red - 0) * 0.7);
darkcolor.green = ((background.green - 0) * 0.7);
darkcolor.blue = ((background.blue - 0) * 0.7);
XAllocColor(dpy, DEFAULT_COLORMAP(dpy), &darkcolor);
XRenderColor xr;
xr.red = background.red;
xr.green = background.green;
xr.blue = background.blue;
xr.alpha = 0xffff;
XftColorAllocValue(dpy, DEFAULT_VISUAL(dpy), DEFAULT_COLORMAP(dpy), &xr, &xftbackground);
xr.red = foreground.red;
xr.green = foreground.green;
xr.blue = foreground.blue;
xr.alpha = 0xffff;
XftColorAllocValue(dpy, DEFAULT_VISUAL(dpy), DEFAULT_COLORMAP(dpy), &xr, &xftforeground);
xr.red = darkcolor.red;
xr.green = darkcolor.green;
xr.blue = darkcolor.blue;
xr.alpha = 0xffff;
XftColorAllocValue(dpy, DEFAULT_VISUAL(dpy), DEFAULT_COLORMAP(dpy), &xr, &xftdarkcolor);
xr.red = lightcolor.red;
xr.green = lightcolor.green;
xr.blue = lightcolor.blue;
xr.alpha = 0xffff;
XftColorAllocValue(dpy, DEFAULT_VISUAL(dpy), DEFAULT_COLORMAP(dpy), &xr, &xftlightcolor);
XkbGeometryPtr kbgeom = kbdesc->geom;
/* Get what scale should drawkb work with, according to drawable's
* width and height. */
double scalew = (float) width / kbgeom->width_mm;
double scaleh = (float) height / kbgeom->height_mm;
/* Work with the smallest scale. */
if (scalew < scaleh) {
scale = scalew;
} else { /* scalew >= scaleh */
scale = scaleh;
}
/* Override scale for debugging purposes */
/*scale = 2;*/
int left = 0;
int top = 0;
int angle = 0;
/* Draw top-level rectangle */
XDrawRectangle(this->dpy, d, gc, left, top, scale * kbdesc->geom->width_mm,
scale * kbdesc->geom->height_mm);
/* Draw each component (section or doodad) of the top-level kbdesc->geometry, in
* priority order. Note that priority handling is left to the function. */
KbDrawComponents(this, d, gc, angle, scale, left, top, kbdesc,
kbdesc->geom->sections, kbdesc->geom->num_sections,
kbdesc->geom->doodads, kbdesc->geom->num_doodads, PutIcon);
XFlush(dpy);
}
/* Checks for font existance and tries to fallback if not. */
int Init_Font(drawkb_p this, const char *font)
{
if (!font) {
fprintf(stderr, "User didn't specify font.\n");
}
strncpy(this->font, font, 499);
/* Try 1: User drawkb_configured. */
if (this->font) {
/* FIXME: Validate font. */
XSetFontNameToScalable(this->font, this->font, 500);
XftFont *fs;
fs = XLoadQueryScalableFont(this->dpy, 0, this->font, 1000);
if (fs) {
return EXIT_SUCCESS;
}
fprintf(stderr, "Failed to initialize user configured font.\n");
}
/* FILLTHEGAP */
/* Try 2: Ask NETWM (like in a skin). */
/* Try 3: Fallback to XKB's. */
if (kbdesc->geom->label_font) {
XSetFontNameToScalable(kbdesc->geom->label_font, this->font, 500);
XftFont *fs;
fs = XLoadQueryScalableFont(this->dpy, 0, this->font, 1000);
if (fs) {
return EXIT_SUCCESS;
}
}
/* FILLTHEGAP */
/* Try 4: Ask for whatever ("*-iso8859-1" && !"*-symbol") font. */
return EXIT_FAILURE;
}
drawkb_p drawkb_xlib_create(Display *dpy, const char *font,
IQF_t IQF, painting_mode_t painting_mode, float scale, debug_t *debug, XkbDescPtr kbdesc,
int use_gradients)
{
drawkb_p this = (drawkb_p) malloc(sizeof(drawkb_t));
this->IQF = IQF;
this->painting_mode = painting_mode;
this->dpy = dpy;
this->debug = debug;
this->kbdesc = kbdesc;
this->use_gradients = use_gradients;
/* Init_Font needs Init_Geometry to succeed, because one of
* the fallback fonts is the XKB's specified font label, and
* therefore, geometry must be loaded. */
if (Init_Font(this, font) == EXIT_FAILURE)
{
fprintf(stderr, "Failed to initialize font: %s.\n"
"Possible causes are:\n"
" + You did not use the complete font name, as in\n"
" \"-*-bitstream vera sans-bold-r-*-*-*-*-*-*-*-*-*-*\"\n"
" + You did not quote the name and the name contains spaces.\n"
" + The font doesn't exist. Try using XftFont *sel to find a suitable "
"font.\n", font);
return NULL;
}
XftFont *fs;
fs = XLoadQueryScalableFont(this->dpy, 0, this->font, 1000);
if (!fs) {
fprintf(stderr, "superkb: Couldn't XLoadQueryScalableFont. This shouldn't have happened.\n");
return NULL;
}
g_baseline =
(float) fs->ascent / (fs->ascent +
fs->descent);
WorkaroundBoundsBug(dpy, kbdesc);
return this;
}
int drawkblibs_xlib_init(
drawkb_create_t *ret_create,
drawkb_draw_t *ret_draw)
{
*ret_create = drawkb_xlib_create;
*ret_draw = drawkb_xlib_draw;
return EXIT_SUCCESS;
}
superkb-0.23/drawkblibs/drawkblibs-xlib.h 0000664 0000000 0000000 00000001573 12210555441 0020473 0 ustar 00root root 0000000 0000000 /*
* drawkblibs-xlib.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* This is the actual implementation of drawkb by using X11 to render a
* keyboard onto an X11 drawable.
*
* This code is not by Superkb directly, but by drawkblib.c This allows
* drawkblib.c to provide multiple options to keyboard rendering.
*
* See drawkblib.h for details.
*
*/
#ifndef __DRAWKBLIBS_XLIB_H
#define __DRAWKBLIBS_XLIB_H
#include "drawkblibs.h"
int drawkb_xlib_create(Display *dpy, const char *imagelib, const char *font, IQF_t IQF, painting_mode_t painting_mode, float scale, XkbDescPtr kbdesc, int use_gradients);
void drawkb_xlib_draw(drawkb_p this, Drawable d, GC gc, unsigned int width, unsigned int height, XkbDescPtr kbdesc, puticon_t puticon);
int drawkblibs_xlib_init (
drawkb_create_t *ret_create,
drawkb_draw_t *ret_draw
);
#endif
superkb-0.23/drawkblibs/drawkblibs.h 0000664 0000000 0000000 00000002462 12210555441 0017535 0 ustar 00root root 0000000 0000000 /*
* drawkblibs.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* This header should be included by all implementation providers of drawkblib
* in order to comply and interoperate with the needed by drawkblibs.
*
*/
#ifndef __DRAWKBLIBS_H
#define __DRAWKBLIBS_H
#include
#include
#include
#include
#include "../debug.h"
typedef int (*IQF_t)(KeySym keysym, unsigned int state, char buf[], int buf_n);
typedef enum {
FULL_SHAPE,
BASE_OUTLINE_ONLY,
FLAT_KEY
} painting_mode_t;
typedef struct {
char font[500];
XftFont *fs;
Display *dpy;
IQF_t IQF;
painting_mode_t painting_mode;
debug_t *debug;
XkbDescPtr kbdesc;
int use_gradients;
} drawkb_t, *drawkb_p;
typedef int (puticon_t)(Drawable kbwin, int x, int y, int width, int height, const char *fn);
typedef drawkb_p (*drawkb_create_t)(Display *dpy, const char *font, IQF_t IQF, painting_mode_t painting_mode, float scale, debug_t debug, XkbDescPtr kbdesc, int use_gradients);
typedef void (*drawkb_draw_t)(drawkb_p this, Drawable d, GC gc, unsigned int width, unsigned int height, XkbDescPtr kbdesc, puticon_t puticon);
typedef int (*drawkblib_init_t)(
drawkb_create_t *ret_create,
drawkb_draw_t *ret_draw
);
#endif /* __DRAWKBLIBS_H */
superkb-0.23/extendedversioninfo.bash 0000775 0000000 0000000 00000001151 12210555441 0020032 0 ustar 00root root 0000000 0000000 #!/bin/bash
cat version.h | egrep -q '\+git'
if [ $? -eq 1 ]; then # Version is a release.
exit
fi
[ ! -z `which git` ] && git status &> /dev/null && {
LASTCOMMIT="`git log --oneline -1 | cut -b 1-7`"
CURRENTBRANCH="`git branch | grep '^\*' | cut -b 3-`"
[ -z "`git status --porcelain -uno`" ] || LOCALCHANGES="+local"
echo ':'${LASTCOMMIT}${LOCALCHANGES}'(b:'${CURRENTBRANCH}')'
exit
}
[ ! -z `which basename` ] && {
DIRNAME="`basename $PWD`"
if echo $DIRNAME | egrep -q '^superkb-[0-9a-f]{7}$'; then
echo ':'`echo $DIRNAME | sed -re 's/^superkb-//g'`'(snapshot)'
exit
fi
}
echo ':unidentified'
superkb-0.23/globals.h 0000664 0000000 0000000 00000000603 12210555441 0014703 0 ustar 00root root 0000000 0000000 /*
* globals.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
#ifndef __GLOBALS_H
#define __GLOBALS_H
/* Wrappers for easy dynamic array element adding and removing. */
#define list_add_element(x, xn, y) {x = (y *)realloc(x, (++(xn))*sizeof(y));}
#define list_rmv_element(x, xn, y) {x = (y *)realloc(x, (--(xn))*sizeof(y));}
#endif
superkb-0.23/imagelib.c 0000664 0000000 0000000 00000011754 12210555441 0015035 0 ustar 00root root 0000000 0000000 /*
* imagelib.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "imagelib.h"
#include "puticon/puticon.h"
#include "puticon/puticon-gdkpixbuf.h"
#include "puticon/puticon-imlib2.h"
#define STR(str) #str
#define ESTR(str) STR(str)
#ifndef PREFIX
#define PREFIX "/usr/local/"
#endif
#define LIB_PREFIX "/" ESTR(PREFIX) "/" ESTR(LIBDIRNAME) "/"
#ifndef WITH_GDKPIXBUF
#define pi_gdkpixbuf_init NULL
#endif
#ifndef WITH_IMLIB2
#define pi_imlib2_init NULL
#endif
imagelib_compiled_in_t imagelib_compiled_in[] = {
{ "gdkpixbuf", pi_gdkpixbuf_init },
{ "imlib2", pi_imlib2_init },
{ NULL, NULL }
};
struct {
imagelib_init_t InitImage;
imagelib_newimage_t NewImage;
imagelib_loadimage_t LoadImage;
imagelib_resizeimage_t ResizeImage;
imagelib_drawimage_t PaintImage;
imagelib_freeimage_t FreeImage;
} image;
void Imagelib_GetValues(char *buf, unsigned long buf_n)
{
imagelib_compiled_in_t *p;
if (buf == NULL) return;
strcpy(buf, "");
for (p = &imagelib_compiled_in[0]; p->code != NULL; p++)
{
if (p->init) {
strncat(buf, p->code, buf_n);
strncat(buf, " ", buf_n);
}
}
DIR *dir;
struct dirent *entry;
dir = opendir(LIB_PREFIX "superkb");
if (dir == NULL)
return;
while ((entry = readdir(dir))) {
if (strncmp(entry->d_name, "puticon-", 8) == 0
&& strncmp(&entry->d_name[strlen(entry->d_name)-3], ".so", 3) == 0) {
strncat(buf, entry->d_name+8, strlen(entry->d_name)-11 > buf_n ? buf_n : strlen(entry->d_name)-11);
strncat(buf, " ", buf_n);
}
}
}
int Init_Imagelib(Display *dpy, const char *userlib)
{
/* First, find an appropriate imagelib interface. */
/* ++ Try 1: Try loading user-specified lib (first compiled in, then
* with dlopen()). */
imagelib_compiled_in_t *p;
for (p = &imagelib_compiled_in[0]; p->code != NULL; p++)
{
if (strcmp(p->code, userlib) == 0 && p->init != NULL) {
p->init(dpy, &image.NewImage, &image.LoadImage, &image.ResizeImage,
&image.PaintImage, &image.FreeImage);
image.InitImage = p->init;
return EXIT_SUCCESS;
}
}
char *fn = malloc(strlen(LIB_PREFIX) + strlen("superkb/puticon-") + strlen(userlib)
+ strlen(".so") + 1);
strcpy(fn, LIB_PREFIX);
strcat(fn, "superkb/puticon-");
strcat(fn, userlib);
strcat(fn, ".so");
void *imagelib = dlopen(fn, RTLD_LAZY);
if (imagelib) {
// image.NewImage = dlsym(imagelib, "NewImage");
image.InitImage = (imagelib_init_t)(intptr_t) dlsym(imagelib, "Init");
// image.LoadImage = dlsym(imagelib, "LoadImage");
// image.ResizeImage = dlsym(imagelib, "ResizeImage");
// image.PaintImage = dlsym(imagelib, "PaintImage");
// image.FreeImage = dlsym(imagelib, "FreeImage");
if ((image.InitImage)(dpy, &image.NewImage, &image.LoadImage,
&image.ResizeImage, &image.PaintImage, &image.FreeImage) == EXIT_SUCCESS) {
return EXIT_SUCCESS;
}
} else {
fprintf(stderr, "Error loading imagelib %s: %s\n", userlib, dlerror());
}
free(fn);
/* ++ Try 2: Query X for WM and use try the best for it. */
/* It's not ready yet, though.
Atom actual_type;
int actual_format;
unsigned long nitems;
unsigned long bytes_after;
Window *prop;
unsigned char *s=NULL;
Window root_win = DefaultRootWindow(dpy);
Atom atom_net_supp;
atom_net_supp = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
XGetWindowProperty(dpy, root_win, atom_net_supp, 0, 128, False,
AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after,
(unsigned char **) &prop);
atom_net_supp = XInternAtom(dpy, "_NET_WM_NAME", False);
XGetWindowProperty(dpy, *prop, atom_net_supp, 0, 128, False,
AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after,
(unsigned char **) &s);
int i = 0;
void *hintinit;
int hintinit_success;
while ((hintinit = hints[i][HINTINIT]) != NULL) {
hintinit_success = hintinit(dpy);
if (hintinit_success == EXIT_SUCCESS)
break;
i++;
}
if (hintinit == NULL)
return EXIT_FAILURE;
hintwork = hints[i][HINTWORK];
*/
/* Try 3 should be checking for available image libs like gdk-pixbuf,
* imlib2, etc., but not libpng, libtiff... */
/* Try 4 should be checking for available format libs like libpng,
* libjpeg, etc., and use those. */
/* At the end, I _think_ xpm should be at least availble, so we will
* always return EXIT_SUCCESS. */
/* However, we don't know how to handle xpm files, so we return
* EXIT_FAILURE until this is fixed. */
return EXIT_FAILURE;
}
imagelib_image_t * NewImage()
{
return image.NewImage();
}
int LoadImage(imagelib_image_t *this, const char *fn)
{
return image.LoadImage(this, fn);
}
void ResizeImage(imagelib_image_t *this, int width, int height)
{
image.ResizeImage(this, width, height);
}
void DrawImage(imagelib_image_t *this, Drawable d, int x, int y)
{
image.PaintImage(this, d, x, y);
}
void FreeImage(imagelib_image_t *this)
{
image.FreeImage(this);
}
superkb-0.23/imagelib.h 0000664 0000000 0000000 00000001710 12210555441 0015031 0 ustar 00root root 0000000 0000000 /*
* imagelib.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* This code provides drawkblib-xlib with a way to render icons on the
* drawable it asks to. This allows it to draw the icons on bound keys.
*
* Multiple different codes may provide the functionality, and are located
* under puticon/ as are puticon-imlib2 and puticon-gdkpixbuf.
*
*/
#ifndef __IMAGELIB_H
#define __IMAGELIB_H
#include
#include "puticon/puticon.h"
typedef struct {
const char *code;
imagelib_init_t init;
} imagelib_compiled_in_t;
void Imagelib_GetValues(char *buf, unsigned long buf_n);
imagelib_image_t * NewImage();
int LoadImage(imagelib_image_t *this, const char *fn);
void ResizeImage(imagelib_image_t *this, int width, int height);
void DrawImage(imagelib_image_t *this, Drawable d, int left, int top);
void FreeImage(imagelib_image_t *this);
int Init_Imagelib(Display *dpy, const char *userlib);
#endif
superkb-0.23/main.c 0000664 0000000 0000000 00000035107 12210555441 0014206 0 ustar 00root root 0000000 0000000 /*
* main.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
/* Thanks to Natan "Whatah" Zohar for helping with tokenizer. */
#define _POSIX_C_SOURCE 2
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "superkb.h"
#include "imagelib.h"
#include "drawkblib.h"
#include "superkbrc.h"
#include "globals.h"
#include "debug.h"
#include "version.h"
#include "screeninfo.h"
#define WINH(i) (kbgeom->width_mm * scale[i])
#define WINV(i) (kbgeom->width_mm * scale[i])
superkb_p superkb;
struct sigaction action;
screeninfo_t *screens=NULL;
int screens_n=0;
Window *kbwin=NULL;
Pixmap *kbwin_backup=NULL;
GC *kbwin_gc=NULL;
config_t *config;
double *scale;
Window prev_kbwin_focus;
int prev_kbwin_revert;
Display *dpy;
drawkb_p draw1;
XkbDescPtr kbdesc;
XkbGeometryPtr kbgeom;
XColor background;
XColor foreground;
int fatal_error(const char * format, ...) {
va_list args;
va_start (args, format);
fprintf(stderr, format, args);
abort();
return 0;
}
int IconQuery(KeySym keysym, unsigned int state, char buf[], int buf_n)
{
unsigned int i;
for (i = 0; i < config->key_bindings_n; i++)
{
if (keysym == XkbKeycodeToKeysym(dpy, config->key_bindings[i].keycode, 0, 0) &&
state == config->key_bindings[i].state) {
if (config->key_bindings[i].icon != NULL) {
strncpy(buf, config->key_bindings[i].icon, buf_n);
} else {
strncpy(buf, "", buf_n);
}
return EXIT_SUCCESS;
}
}
return EXIT_FAILURE;
}
int PutIcon(Drawable kbwin, int x, int y, int width, int height, const char *fn)
{
void *i;
i = NewImage(fn);
if (i == NULL) {
perror("puticon");
return EXIT_FAILURE;
}
LoadImage(i, fn);
ResizeImage(i, width, height);
DrawImage(i, kbwin, x, y);
FreeImage(i);
return EXIT_SUCCESS;
}
void kbwin_event(Display * dpy, XEvent ev)
{
int i;
if (ev.type == Expose) {
/* drawkb_draw(dpy, kbwin[i], kbwin_gc[i], DisplayWidth(dpy, 0), DisplayHeight(dpy, 0), kbdesc);*/
for (i=0; i < screens_n; i++) {
XCopyArea(dpy, kbwin_backup[i], kbwin[i], kbwin_gc[i], 0, 0, WINH(i), WINV(i), 0, 0);
}
XFlush(dpy);
} else if (ev.type == VisibilityNotify &&
ev.xvisibility.state != VisibilityUnobscured) {
for (i=0; i < screens_n; i++) {
XRaiseWindow(dpy, kbwin[i]);
}
}
}
void kbwin_map(Display * dpy)
{
/* XGetInputFocus(dpy, &prev_kbwin_focus, &prev_kbwin_revert); */
int i;
for (i=0; i < screens_n; i++) {
XSetTransientForHint(dpy, kbwin[i], DefaultRootWindow(dpy));
XMapWindow(dpy, kbwin[i]);
XRaiseWindow(dpy, kbwin[i]);
}
}
void kbwin_unmap(Display * dpy)
{
int i;
for (i=0; i < screens_n; i++) {
XUnmapWindow(dpy, kbwin[i]);
}
/* XSetInputFocus(dpy, prev_kbwin_focus, prev_kbwin_revert, CurrentTime); */
}
int kbwin_init(Display * dpy)
{
/* Initialize Window and pixmap to back it up. */
XColor background;
XColor foreground;
background.red = config->backcolor.red;
background.green = config->backcolor.green;
background.blue = config->backcolor.blue;
foreground.red = config->forecolor.red;
foreground.green = config->forecolor.green;
foreground.blue = config->forecolor.blue;
XAllocColor(dpy, XDefaultColormap(dpy, 0), &background);
XAllocColor(dpy, XDefaultColormap(dpy, 0), &foreground);
XSetWindowAttributes attr;
attr.override_redirect = True;
/* Create one windows per screen. */
screeninfo_t *xsi;
int i;
kbwin = malloc(screens_n * sizeof(Window));
if (kbwin == NULL) {
perror("superkb: kbwin_init(): kbwin = malloc() failed");
return EXIT_FAILURE;
}
kbwin_backup = malloc(screens_n * sizeof(Pixmap));
if (kbwin == NULL) {
perror("superkb: kbwin_init(): kbwin_backup = malloc() failed");
return EXIT_FAILURE;
}
scale = malloc(screens_n * sizeof(double));
if (kbwin == NULL) {
perror("superkb: kbwin_init(): scale = malloc() failed");
return EXIT_FAILURE;
}
kbwin_gc = malloc(screens_n * sizeof(GC));
if (kbwin == NULL) {
perror("superkb: kbwin_init(): kbwin_gc = malloc() failed");
return EXIT_FAILURE;
}
for (i = 0; i < screens_n; i++) {
int winv;
int winh;
/* Just as little shortcut. */
xsi = &screens[i];
debug (3, "Preparing screen #%d: %d, %d, %d, %d\n", i, xsi->x_org, xsi->y_org, xsi->width, xsi->height);
/* Get what scale should drawkb work with, according to drawable's
* width and height. */
winv = xsi->height;
winh = xsi->width;
double scalew = (float) winh / kbgeom->width_mm;
double scaleh = (float) winv / kbgeom->height_mm;
/* Work with the smallest scale. */
if (scalew < scaleh) {
scale[i] = scalew;
} else { /* scalew >= scaleh */
scale[i] = scaleh;
}
winv = kbgeom->height_mm * scale[i];
winh = kbgeom->width_mm * scale[i];
kbwin[i] = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
(xsi->width - winh) / 2 + xsi->x_org,
(xsi->height - winv) / 2 + xsi->y_org, winh, winv,
0, 0, (background.pixel));
kbwin_gc[i] = XCreateGC(dpy, kbwin[i], 0, NULL);
XSetForeground(dpy, kbwin_gc[i], foreground.pixel);
XSetBackground(dpy, kbwin_gc[i], background.pixel);
XChangeWindowAttributes(dpy, kbwin[i], CWOverrideRedirect, &attr);
XSelectInput(dpy, kbwin[i], ExposureMask | VisibilityChangeMask);
draw1 = drawkb_create(dpy, config->drawkb_font, IconQuery, config->drawkb_painting_mode, scale[i], &debug, kbdesc, config->use_gradients);
if (draw1 == NULL) {
return EXIT_FAILURE;
}
kbwin_backup[i] = XCreatePixmap(dpy, kbwin[i], winh, winv, DefaultDepth(dpy, DefaultScreen(dpy)));
XSetForeground(dpy, kbwin_gc[i], background.pixel);
XFillRectangle(dpy, kbwin_backup[i], kbwin_gc[i], 0, 0, winh, winv);
XSetForeground(dpy, kbwin_gc[i], foreground.pixel);
XSetBackground(dpy, kbwin_gc[i], background.pixel);
drawkb_draw(draw1, kbwin_backup[i], kbwin_gc[i], winh, winv, kbdesc, PutIcon);
}
XFlush(dpy);
return EXIT_SUCCESS;
}
void __Superkb_Action(KeyCode keycode, unsigned int state)
{
unsigned int i;
char *argv[4] = { "sh", "-c", NULL, NULL };
for (i = 0; i < config->key_bindings_n; i++) {
if (config->key_bindings[i].keycode == keycode &&
config->key_bindings[i].state == state) {
switch (config->key_bindings[i].action_type) {
case AT_COMMAND:
if (fork() == 0) {
if (config->key_bindings[i].feedback_string) {
char *cmdline = malloc(strlen(config->feedback_handler) + strlen(config->key_bindings[i].feedback_string) + 4);
if (cmdline != NULL) {
strcpy (cmdline, config->feedback_handler);
strcat (cmdline, " ");
strcat (cmdline, config->key_bindings[i].feedback_string);
strcat (cmdline, " &");
system(cmdline);
}
}
argv[2] = config->key_bindings[i].action.command;
execvp(*argv, argv);
exit(EXIT_FAILURE);
}
break;
case AT_DOCUMENT:
if (fork() == 0) {
if (config->key_bindings[i].feedback_string) {
char *cmdline = malloc(strlen(config->feedback_handler) + strlen(config->key_bindings[i].feedback_string) + 4);
if (cmdline != NULL) {
strcpy (cmdline, config->feedback_handler);
strcat (cmdline, " ");
strcat (cmdline, config->key_bindings[i].feedback_string);
strcat (cmdline, " &");
system(cmdline);
}
}
char *cmdline = malloc(strlen(config->document_handler) + strlen(config->key_bindings[i].action.document) + 2);
if (cmdline != NULL) {
strcpy (cmdline, config->document_handler);
strcat (cmdline, " ");
strcat (cmdline, config->key_bindings[i].action.document);
argv[2] = cmdline;
execvp(*argv, argv);
}
exit(EXIT_FAILURE);
}
break;
case AT_FUNCTION:
if (fork() == 0) {
/* FIXME: Value should not be NULL. */
config->key_bindings[i].action.function(NULL);
exit(EXIT_SUCCESS);
}
}
}
}
}
void sighandler(int sig)
{
int chld_status;
int chld_p;
switch (sig) {
case SIGUSR1:
break;
case SIGCHLD:
chld_p = wait(&chld_status);
debug(6, "[chld] Got SIGCHLD. Process: %d. Status: %d\n", chld_p, chld_status);
break;
case SIGINT:
superkb_restore_auto_repeat(superkb);
signal(SIGINT, SIG_DFL);
kill(getpid(), SIGINT);
break;
}
}
void welcome_message() {
if (strcmp(config->welcome_cmd, "") != 0) {
char *cmdline = malloc(strlen(config->welcome_cmd)+3);
if (cmdline == NULL) {
perror("superkb: welcome_message(): malloc() failed");
return;
}
strcpy(cmdline, config->welcome_cmd);
strcat(cmdline, " &");
system(cmdline);
}
}
int main(int argc, char *argv[])
{
int cancel_after_ready = 0;
int c;
int errflg = 0;
int help = 0;
extern char *optarg;
extern int optind, optopt;
running_debug_level = 0;
while ((c = getopt(argc, argv, ":0d:hv")) != -1) {
switch(c) {
case '0':
cancel_after_ready++;
break;
case 'd':
/* FIXME: doesn't check if it is really an integer */
running_debug_level = atoi(optarg);
break;
case 'h':
/* FIXME: doesn't check if it is really an integer */
help++;
break;
case 'v':
printf("%s\n", VERSION VEXTRA);
exit(EXIT_SUCCESS);
break;
case ':':
/* -d level is optional, defaults to 1. */
if (optopt == 'd') {
running_debug_level++;
} else {
fprintf(stderr,
"superkb: option -%c requires an argument\n", optopt);
exit(EXIT_FAILURE);
}
break;
case '?':
fprintf(stderr, "superkb: unrecognized option: -%c\n", optopt);
exit(EXIT_FAILURE);
break;
}
}
if (errflg || help) {
printf("usage: superkb [options]\n");
printf("\n");
printf("Options:\n");
printf(" -0 Quit when Superkb is ready (for timing and debugging).\n");
printf(" -d level Show debug messages up to the specified verbosity level.\n");
printf(" -h Shows this help.\n");
printf(" -v Shows program version.\n");
printf("\n");
if (help)
exit(EXIT_SUCCESS);
else
exit(EXIT_FAILURE);
}
int status;
fprintf(stderr, "\nsuperkb " VERSION VEXTRA ": Welcome. This program is under development.\n\n"
"It's strongly recommended to set the following on xorg.conf:\n\n"
"| Section \"ServerFlags\"\n"
"| Option \"AllowDeactivateGrabs\" \"On\"\n"
"| Option \"AllowClosedownGrabs\" \"On\"\n"
"| EndSection\n\n"
"With these, if the program fails while drawing the keyboard, you "
" will be able\n"
"to kill it by pressing Ctrl-Alt-*, and restore Autorepeat with "
"'xset r on'.\n\n"
);
debug(1, "*** Debugging has been set to verbosity level %d.\n\n", running_debug_level);
/* Set SIGUSR1 handler. */
action.sa_handler = sighandler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
if (sigaction(SIGUSR1, &action, NULL) != 0) {
fprintf(stderr, "superkb: Error setting SIGUSR1 signal handler. "
"Quitting.\n");
return EXIT_FAILURE;
}
/* Set SIGCHLD handler. Needed to avoid zombie child processes. */
action.sa_handler = sighandler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
if (sigaction(SIGCHLD, &action, NULL) != 0) {
fprintf(stderr, "superkb: Error setting SIGCHLD signal handler. "
"Quitting.\n");
return EXIT_FAILURE;
}
/* Set SIGINT handler. Needed to restore autorepeat on Super keys. */
action.sa_handler = sighandler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
if (sigaction(SIGINT, &action, NULL) != 0) {
fprintf(stderr, "superkb: Error setting SIGINT signal handler. "
"Quitting.\n");
return EXIT_FAILURE;
}
/* Connect to display. */
dpy = XOpenDisplay(NULL);
if (dpy == NULL) {
fprintf(stderr, "superkb: Couldn't open display. Quitting.\n");
fprintf(stderr, "\nSuperkb must be run from inside the X Window System."
"\n");
return EXIT_FAILURE;
}
config = config_new(dpy);
setlocale(LC_ALL, "");
if (config == NULL) {
fprintf(stderr, "Superkb could not load configuration. Quitting.\n");
return EXIT_FAILURE;
}
if (config_load(config, dpy) == EXIT_FAILURE) {
fprintf(stderr, "\n");
fprintf(stderr, "== Make sure the .superkbrc file exists in your $HOME "
"directory. ==\n");
fprintf(stderr, "\n");
fprintf(stderr, "There is a sample configuration located at the "
"following URL:\n");
fprintf(stderr, "http://blog.alvarezp.org/files/superkbrc.sample "
"\n");
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
/* Init XKB extension. */
status = XkbQueryExtension(dpy, NULL, NULL, NULL, NULL, NULL);
if (status == False) {
fprintf(stderr, "superkb: Couldn't initialize XKB extension. "
"Quitting.\n");
return EXIT_FAILURE;
}
kbdesc = XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
if (kbdesc == NULL) {
fprintf(stderr, "superkb: Could not load keyboard information from "
"X. Quitting.\n");
fprintf(stderr, "\nIf using GNOME you might want to try adding a "
"keyboard layout and then\nremoving it, and making sure your "
"current layout is effectively selected as\ndefault.\n");
return EXIT_FAILURE;
}
status = XkbGetGeometry(dpy, kbdesc);
kbgeom = kbdesc->geom;
if (status != Success || kbgeom == NULL) {
fprintf(stderr, "superkb: Could not load keyboard geometry "
"information. Quitting.\n");
fprintf(stderr, "\nIf using GNOME you might want to try adding a "
"keyboard layout and then\nremoving it, and making sure your "
"default layout is effectively selected as\ndefault.\n");
return EXIT_FAILURE;
}
screeninfo_get_screens(dpy, &screens, &screens_n);
if (Init_Imagelib(dpy, config->drawkb_imagelib) == EXIT_FAILURE)
{
char vals[500] = "";
Imagelib_GetValues((char *) &vals, 499);
fprintf(stderr, "Failed to initialize image library: %s.\n\n"
"You might try any of the following as the value for IMAGELIB in\n"
"your $HOME/.superkbrc file: %s\n", config->drawkb_imagelib, vals);
return EXIT_FAILURE;
}
status = Init_drawkblib(config->drawkb_drawkblib);
if (status == EXIT_FAILURE) {
char vals[500] = "";
drawkblib_GetValues((char *) &vals, 499);
fprintf(stderr, "Failed to initialize drawkb library: %s.\n\n"
"You might try any of the following as the value for DRAWKBLIB in\n"
"your $HOME/.superkbrc file: %s\n", config->drawkb_drawkblib, vals);
return EXIT_FAILURE;
}
superkb = superkb_create();
superkb_kbwin_set(superkb, kbwin_init, kbwin_map, kbwin_unmap, kbwin_event);
status = superkb_init(superkb, dpy, "en", config->superkb_super1,
config->superkb_super2, config->drawkb_delay, __Superkb_Action, config->superkb_superkey_replay, config->superkb_superkey_release_cancels,
~config->squashed_states, &welcome_message);
if (status != EXIT_SUCCESS) {
return EXIT_FAILURE;
}
if (!cancel_after_ready)
superkb_start(superkb);
return EXIT_SUCCESS;
}
superkb-0.23/puticon/ 0000775 0000000 0000000 00000000000 12210555441 0014571 5 ustar 00root root 0000000 0000000 superkb-0.23/puticon/puticon-gdkpixbuf.c 0000664 0000000 0000000 00000003507 12210555441 0020404 0 ustar 00root root 0000000 0000000 /*
* puticon-gdkpixbuf.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
#include
#include
#include
#include
#include "puticon.h"
#ifndef WITH_GDKPIXBUF
#define pi_gdkpixbuf_init Init
#endif
imagelib_image_t *pi_gdkpixbuf_newimage()
{
imagelib_image_t *this = malloc(sizeof(imagelib_image_t));
if (this)
return this;
else
return NULL;
}
int pi_gdkpixbuf_loadimage(imagelib_image_t *this, const char *file)
{
this->original = gdk_pixbuf_new_from_file (file, NULL);
if (this->original)
return EXIT_SUCCESS;
else
return EXIT_FAILURE;
}
int pi_gdkpixbuf_resizeimage(imagelib_image_t *this, int width, int height)
{
this->scaled = gdk_pixbuf_scale_simple(this->original, width, height, GDK_INTERP_BILINEAR);
if (this->scaled)
return EXIT_SUCCESS;
else
return EXIT_FAILURE;
}
void pi_gdkpixbuf_paintimage(imagelib_image_t *this, Drawable d, int left, int top)
{
gdk_pixbuf_xlib_render_to_drawable_alpha(this->scaled, d, 0, 0, left, top, gdk_pixbuf_get_width(this->scaled), gdk_pixbuf_get_width(this->scaled), GDK_PIXBUF_ALPHA_FULL, 255, XLIB_RGB_DITHER_NORMAL, 0, 0);
}
void pi_gdkpixbuf_freeimage(imagelib_image_t *this)
{
g_object_unref(this->original);
g_object_unref(this->scaled);
free(this);
}
int pi_gdkpixbuf_init(Display *dpy,
imagelib_newimage_t *ret_new,
imagelib_loadimage_t *ret_load,
imagelib_resizeimage_t *ret_resize,
imagelib_drawimage_t *ret_draw,
imagelib_freeimage_t *ret_free)
{
/* Neither does gdk_pixbuf_xlib_init(). */
gdk_pixbuf_xlib_init(dpy, 0);
*ret_new = pi_gdkpixbuf_newimage;
*ret_load = pi_gdkpixbuf_loadimage;
*ret_resize = pi_gdkpixbuf_resizeimage;
*ret_draw = pi_gdkpixbuf_paintimage;
*ret_free = pi_gdkpixbuf_freeimage;
return EXIT_SUCCESS;
}
superkb-0.23/puticon/puticon-gdkpixbuf.h 0000664 0000000 0000000 00000002070 12210555441 0020403 0 ustar 00root root 0000000 0000000 /*
* puticon-gdkpixbuf.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* This is the actual implementation of puticon by using gdkpixbuf to render a
* an icon into an X11 drawable.
*
* This code is not by drawkblib-xlib directly, but by imagelib.c This allows
* imagelib.c to provide multiple options to image rendering.
*
* See drawkblibs/drawkblib-xlib.h and imagelib.h for details.
*
*/
#ifndef __PUTICON_GDKPIXBUF_PIXBUF_XLIB_H
#define __PUTICON_GDKPIXBUF_PIXBUF_XLIB_H
int pi_gdkpixbuf_newimage(imagelib_image_t *this);
int pi_gdkpixbuf_loadimage(imagelib_image_t *this, const char *file);
int pi_gdkpixbuf_resizeimage(imagelib_image_t *this, int width, int height);
void pi_gdkpixbuf_paintimage(imagelib_image_t *this, Drawable d, int left, int top);
void pi_gdkpixbuf_freeimage(imagelib_image_t *this);
int pi_gdkpixbuf_init(Display *dpy,
imagelib_newimage_t *ret_init,
imagelib_loadimage_t *ret_load,
imagelib_resizeimage_t *ret_resize,
imagelib_drawimage_t *ret_draw,
imagelib_freeimage_t *free);
#endif
superkb-0.23/puticon/puticon-imlib2.c 0000664 0000000 0000000 00000004457 12210555441 0017604 0 ustar 00root root 0000000 0000000 /*
* puticon-imlib2.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
#include
#include
#include "puticon.h"
#ifndef WITH_IMLIB2
#define pi_imlib2_init Init
#endif
int pi_imlib2_scaled_width;
int pi_imlib2_scaled_height;
imagelib_image_t *pi_imlib2_newimage()
{
imagelib_image_t *this = malloc(sizeof(imagelib_image_t));
if (this)
return this;
else
return NULL;
}
int pi_imlib2_loadimage(imagelib_image_t *this, const char *file)
{
this->original = imlib_load_image(file);
if (this->original)
return EXIT_SUCCESS;
else
return EXIT_FAILURE;
}
int pi_imlib2_resizeimage(imagelib_image_t *this, int width, int height)
{
this->scaled = imlib_create_image(width, height);
if (!this->scaled)
return EXIT_FAILURE;
// imlib_context_set_image(this->scaled);
// imlib_context_set_color(0, 0, 255, 0);
// imlib_image_fill_rectangle(0, 0, width, height);
// imlib_blend_image_onto_image(this->original, 0, 0, 0, imlib_image_get_width(), imlib_image_get_height(), 0, 0, width, height);
pi_imlib2_scaled_width = width;
pi_imlib2_scaled_height = height;
return EXIT_SUCCESS;
}
void pi_imlib2_paintimage(imagelib_image_t *this, Drawable d, int left, int top)
{
// imlib_context_set_image(this->scaled);
// imlib_context_set_drawable(d);
// imlib_render_image_on_drawable_at_size(left, top, imlib_image_get_width(), imlib_image_get_height());
imlib_context_set_image(this->original);
imlib_context_set_drawable(d);
imlib_render_image_on_drawable_at_size(left, top, pi_imlib2_scaled_width, pi_imlib2_scaled_height);
}
void pi_imlib2_freeimage(imagelib_image_t *this)
{
imlib_context_set_image(this->original);
imlib_free_image();
imlib_context_set_image(this->scaled);
imlib_free_image();
free(this);
}
int pi_imlib2_init(Display *dpy,
imagelib_newimage_t *ret_new,
imagelib_loadimage_t *ret_load,
imagelib_resizeimage_t *ret_resize,
imagelib_drawimage_t *ret_draw,
imagelib_freeimage_t *ret_free)
{
imlib_context_set_display(dpy);
imlib_context_set_visual(DefaultVisual(dpy, 0));
imlib_context_set_colormap(DefaultColormap(dpy, 0));
*ret_new = pi_imlib2_newimage;
*ret_load = pi_imlib2_loadimage;
*ret_resize = pi_imlib2_resizeimage;
*ret_draw = pi_imlib2_paintimage;
*ret_free = pi_imlib2_freeimage;
return EXIT_SUCCESS;
}
superkb-0.23/puticon/puticon-imlib2.h 0000664 0000000 0000000 00000002003 12210555441 0017572 0 ustar 00root root 0000000 0000000 /*
* puticon-imlib2.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* This is the actual implementation of puticon by using imblib2 to render a
* an icon into an X11 drawable.
*
* This code is not by drawkblib-xlib directly, but by imagelib.c This allows
* imagelib.c to provide multiple options to image rendering.
*
* See drawkblibs/drawkblib-xlib.h and imagelib.h for details.
*
*/
#ifndef __PUTICON_IMLIB2_H
#define __PUTICON_IMLIB2_H
int pi_imlib2_newimage(imagelib_image_t *this);
int pi_imlib2_loadimage(imagelib_image_t *this, const char *file);
int pi_imlib2_resizeimage(imagelib_image_t *this, int width, int height);
void pi_imlib2_paintimage(imagelib_image_t *this, Drawable d, int left, int top);
void pi_imlib2_freeimage(imagelib_image_t *this);
int pi_imlib2_init(Display *dpy,
imagelib_newimage_t *ret_init,
imagelib_loadimage_t *ret_load,
imagelib_resizeimage_t *ret_resize,
imagelib_drawimage_t *ret_draw,
imagelib_freeimage_t *free);
#endif
superkb-0.23/puticon/puticon.h 0000664 0000000 0000000 00000001764 12210555441 0016433 0 ustar 00root root 0000000 0000000 /*
* puticon.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* This header should be included by all implementation providers of puticon
* in order to comply and interoperate with the needed by imagelib.
*
*/
#ifndef __PUTICON_H
#define __PUTICON_H
#include
typedef struct {
void *original;
void *scaled;
} imagelib_image_t;
typedef imagelib_image_t * (*imagelib_newimage_t)();
typedef int (*imagelib_loadimage_t)(imagelib_image_t *this, const char *file);
typedef int (*imagelib_resizeimage_t)(imagelib_image_t *this, int width, int height);
typedef void (*imagelib_drawimage_t)(imagelib_image_t *this, Drawable w, int left, int top);
typedef void (*imagelib_freeimage_t)(imagelib_image_t *this);
typedef int (*imagelib_init_t)(Display *dpy,
imagelib_newimage_t *ret_init,
imagelib_loadimage_t *ret_load,
imagelib_resizeimage_t *ret_resize,
imagelib_drawimage_t *ret_draw,
imagelib_freeimage_t *free);
#endif /* __PUTICON_H */
superkb-0.23/sample-config/ 0000775 0000000 0000000 00000000000 12210555441 0015634 5 ustar 00root root 0000000 0000000 superkb-0.23/sample-config/superkbrc-gnome 0000664 0000000 0000000 00000001234 12210555441 0020662 0 ustar 00root root 0000000 0000000 IMAGELIB gdkpixbuf
FONT "-*-bitstream vera sans-bold-r-*-*-*-*-*-*-*-*-*-*"
BACKGROUND 59500 59500 59500
FOREGROUND 2000 2000 2000
KEY COMMAND "c" 0 /usr/bin/gcalctool /usr/share/icons/gnome/48x48/apps/gnome-calculator.png
KEY COMMAND "i" 0 /usr/bin/firefox /usr/share/pixmaps/mozilla-firefox.png
KEY COMMAND "n" 0 /usr/bin/gedit /usr/share/icons/gnome/48x48/apps/text-editor.png
KEY COMMAND "m" 0 /usr/bin/xmms /usr/share/icons/gnome/48x48/apps/gnome-media-player.png
KEY COMMAND "o" 0 /usr/bin/soffice /usr/share/icons/gnome/48x48/apps/openofficeorg-20-writer.png
KEY COMMAND "Home" 0 "/usr/bin/nautilus ." /usr/share/icons/gnome/48x48/filesystems/gnome-fs-home.png
superkb-0.23/sample-config/superkbrc-sample 0000664 0000000 0000000 00000000432 12210555441 0021035 0 ustar 00root root 0000000 0000000 IMAGELIB imlib2
FONT "-*-bitstream vera sans-bold-r-*-*-*-*-*-*-*-*-*-*"
BACKGROUND 27242 16191 11000
FOREGROUND 65535 65535 65535
KEY COMMAND "F9" 0 /usr/bin/opera /usr/share/opera/images/opera.xpm
KEY COMMAND "n" 0 /usr/bin/gedit /usr/share/icons/gnome/48x48/apps/text-editor.png
superkb-0.23/sample-config/superkbrc.bigsample 0000664 0000000 0000000 00000014022 12210555441 0021520 0 ustar 00root root 0000000 0000000 FEEDBACK_HANDLER "notify-send --urgency normal -t 2000 --icon='gtk-info' Superkb Launching\"
#WELCOME_CMD: Command to execute on Superkb start. It was intended to send a
# fixed welcome message on start, configured on /etc/superkbrc, but the user
# may override it with any other command, including an empty string.
#
#Example vlaues:
# WELCOME_CMD "notify-send 'Welcome to Superkb'"
# WELCOME_CMD "touch ~/.superkb-start-time"
# WELCOME_CMD ""
#
#Default value: "xmessage -buttons '' -center -timeout 5 Welcome to Superkb! To start, hold down any of your configured Super keys."
WELCOME_CMD "notify-send --urgency normal -t 5000 --icon='gtk-info' 'Welcome to Superkb' 'To start, hold down any of your configured Super keys.'"
#DELAY: Time (in seconds) the Super key must be pressed before showing
# the on-screen hints.
#
#Example vlaues:
# DELAY 0.5
# DELAY 1
#
#Default value: 0.5
DELAY 0.5
#DRAWKB_PAINTING_MODE: Selects the key shape mode to be used when painting
# the keyboard.
#
#Possible values:
# FULL_SHAPE = Draws all the available outlines, simulating the full physical
# key.
# BASE_OUTLINE_ONLY = Draws a hollow base outline using the foreground color.
# FLAT_KEY = Draws a filled dark base outline.
#
#Default value: FULL_SHAPE
DRAWKB_PAINTING_MODE FLAT_KEY
#SUPERKEY_REPLAY: Allows the Super key to be forwarded to the current window
# if it was pressed and released before the delay and if no action key was
# pressed.
#
#Possible values:
# 1 = Enables Super key replaying to the current window.
# 0 = Disables this behavior. Superkb steals the Super key for itself only.
#
#Default: 1
SUPERKEY_REPLAY 1
#SUPERKEY1_STRING and SUPERKEY1_CODE: Specify what the first Super key is to be.
# This is useful in laptops like the Thinkpad where there isn't a Windows key.
#
#Example values:
# SUPERKEY1_STRING F8
# SUPERKEY1_STRING Super_L
# SUPERKEY1_CODE 233
#
#Default value:
# SUPERKEY1_STRING Super_L
SUPERKEY1_STRING Super_L
#SUPERKEY2_STRING and SUPERKEY2_CODE: Specify what the second Super key is to
#be.
#
#Example values:
# SUPERKEY2_STRING F8
# SUPERKEY2_STRING Super_R
# SUPERKEY2_CODE 233
#
#Default value:
# SUPERKEY2_STRING Super_R
#SUPERKEY_RELEASE_CANCELS: Cancels whatever action is to be performed if the
# Super key is released before the bound key.
#
#Possible values:
# 0 = Actions will be done even if the Super key is released before the bound
# key.
# 1 = Releasing Super key will force ignoring of currently pressed bound keys.
#
#Default value: 0
SUPERKEY_RELEASE_CANCELS 0
#You can use either Cairo or Xlib for drawing the keyboard. This is controlled
#with DRAWKBLIB.
#
#You should change it if not using Cairo.
#
#Possible values:
# cairo
# xlib
#
#Default value: cairo
#Don't use the following unless you didn't include Cairo.
#
#FONT "-*-bitstream vera sans-bold-r-*-*-*-*-*-*-*-*-*-*"
#IMAGELIB imlib2
#BACKGROUND, FOREGROUND: Set the colors to use when drawing the keyboard.
#
#Syntax:
# FOREGROUND red_value green_value blue_value
# BACKGROUND red_value green_value blue_value
#
#The red, green and blue values can either be in the range 0 to 255, or
# 0 to 65535.
#
#Example values:
# FOREGROUND 255 255 255
# BACKGROUND 23 110 38
#
#Default values:
# BACKGROUND 40 40 40
# FOREGROUND 220 220 220
#FEEDBACK_STRINGS_AUTOQUOTE: Enable or disable single-quoting around feedback
#strings.
#
#The feedback string is the 6th parameter in KEY COMMAND. The string is simply
#appended to the FEEDBACK_HANDLER string and the result is run to generate the
#feedback announcement upon program launching.
#
#Previously it was needed to single quote multiple-word strings inside the
#double quotes "'like this'" in order to pass it as a single parameter to the
#shell. However, this behavior changed with FEEDBACK_STRINGS_AUTOQUOTE, which
#defaults to 1. Single quotes are automatically added (if not already there)
#and can be turned off by setting this value to 0.
#
#This value affects the rest of the configuration file and thus must be present
#before any KEY directive disired to be affected.
#
#Example values:
# FEEDBACK_STRINGS_AUTOQUOTE 1
# FEEDBACK_STRINGS_AUTOQUOTE 0
#
#Default value:
# FEEDBACK_STRINGS_AUTOQUOTE 1
#Icons files are really not that up to date.
KEY COMMAND "c" 0 /usr/bin/gcalctool /usr/share/icons/gnome/32x32/apps/accessories-calculator.png "Calculator"
KEY COMMAND "n" 0 /usr/bin/gedit /usr/share/icons/gnome/32x32/apps/text-editor.png "gedit"
KEY COMMAND "F10" 0 "/usr/bin/xchat" /usr/share/pixmaps/xchat.png "XChat"
KEY COMMAND "F12" 0 /usr/bin/gnome-terminal /usr/share/pixmaps/gnome-terminal.png "Terminal Emulator"
KEY COMMAND "Home" 0 "/usr/bin/nautilus /home/alvarezp" /usr/share/pixmaps/gnome-home.png "Home Folder"
KEY COMMAND "Print" 0 "/usr/bin/gnome-screenshot" /usr/share/icons/gnome/48x48/apps/applets-screenshooter.png "Screenshooter"
KEY COMMAND "g" 0 /usr/bin/gimp /usr/share/pixmaps/gnome-gimp.png "The Gimp"
KEY COMMAND "q" 0 /usr/bin/pidgin /usr/share/icons/hicolor/48x48/apps/pidgin.png "Pidgin"
KEY COMMAND "Insert" 0 /usr/bin/gmrun /usr/share/icons/gnome/32x32/actions/gnome-run.png "Application Launcher"
KEY COMMAND "Delete" 0 /usr/bin/gnome-system-monitor /usr/share/icons/gnome/32x32/apps/gnome-monitor.png "System Monitor"
KEY COMMAND "Pause" 0 /usr/bin/hal-device-manager /usr/share/icons/gnome/48x48/apps/hwbrowser.png "Hardware Browser"
KEY COMMAND "l" 0 "/usr/bin/gnome-screensaver-command --lock" /usr/share/icons/gnome/32x32/actions/gnome-lockscreen.png "Screen Locker"
KEY COMMAND "e" 0 "/usr/bin/evolution" /usr/share/icons/hicolor/32x32/apps/evolution.png "Evolution"
KEY COMMAND "F5" 0 "/usr/bin/soffice -writer" /usr/share/icons/hicolor/32x32/apps/openofficeorg23-writer.png "OpenOffice.org Writer"
KEY COMMAND "F6" 0 "/usr/bin/soffice -calc" /usr/share/icons/hicolor/32x32/apps/openofficeorg23-calc.png "OpenOffice.org Calc"
KEY COMMAND "F7" 0 "/usr/bin/soffice -impress" /usr/share/icons/hicolor/32x32/apps/openofficeorg23-impress.png "OpenOffice.org Impress"
KEY COMMAND "f" 0 "/usr/bin/dia" /usr/share/pixmaps/dia.xpm "Dia"
KEY COMMAND "i" 0 "/usr/bin/firefox" /usr/share/pixmaps/firefox.png "Firefox"
superkb-0.23/screeninfo-xinerama.c 0000664 0000000 0000000 00000004755 12210555441 0017224 0 ustar 00root root 0000000 0000000 /*
* screeninfo-xinerama.c
*
* Copyright (C) 2008, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
#include
#include
#include
#include
#include
#include "debug.h"
#include "screeninfo.h"
void screeninfo_get_screens(Display *dpy, screeninfo_t **screens, int *screens_n) {
XineramaScreenInfo *xinerama_screens=NULL;
int xinerama_screens_n=0;
Bool xinerama_queryextension_result;
Status xinerama_queryversion_result;
Bool xinerama_is_active;
int dummyint;
xinerama_queryextension_result = XineramaQueryExtension (dpy, &dummyint, &dummyint);
xinerama_queryversion_result = XineramaQueryVersion (dpy, &dummyint, &dummyint);
xinerama_is_active = XineramaIsActive(dpy);
if (xinerama_queryextension_result != True
|| xinerama_queryversion_result == 0
|| xinerama_is_active != True)
{
fprintf(stderr, "superkb: Xinerama extension not available! Falling back.\n");
*screens = (screeninfo_t *) malloc(sizeof(screeninfo_t));
*screens_n = 1;
screens[0]->screen_number = 0;
screens[0]->x_org = 0;
screens[0]->y_org = 0;
screens[0]->width = DisplayWidth(dpy, DefaultScreen(dpy));
screens[0]->height = DisplayHeight(dpy, DefaultScreen(dpy));
return;
}
xinerama_screens = XineramaQueryScreens (dpy, &xinerama_screens_n);
if (xinerama_screens_n == 0) {
fprintf(stderr, "superkb: Xinerama extension available, but query failed! Falling back.\n");
*screens = (screeninfo_t *) malloc(sizeof(screeninfo_t));
*screens_n = 1;
screens[0]->screen_number = 0;
screens[0]->x_org = 0;
screens[0]->y_org = 0;
screens[0]->width = DisplayWidth(dpy, DefaultScreen(dpy));
screens[0]->height = DisplayHeight(dpy, DefaultScreen(dpy));
return;
}
/* Everything went well */
debug(3, "[xs] Xinerama detected %d screens.\n", xinerama_screens_n);
int i;
for (i=0; i < xinerama_screens_n; i++) {
#define xsi ((xinerama_screens)[i])
debug (4, "[xs] Screen #%d: number=%d, x=%d, y=%d, w=%d, h=%d\n",
i, xsi.screen_number, xsi.x_org, xsi.y_org, xsi.width, xsi.height);
#undef xsi
}
/* We should dump all information from Xinerama to screeninfo. However,
* given the struct is the same (intentionally) we are going to simply
* memcpy() it. If the structure ever changes, this code should be
* definitely updated.
*/
*screens = malloc(sizeof(screeninfo_t)*xinerama_screens_n);
memcpy(*screens, xinerama_screens, sizeof(screeninfo_t)*xinerama_screens_n);
*screens_n = xinerama_screens_n;
}
superkb-0.23/screeninfo-xlib.c 0000664 0000000 0000000 00000001103 12210555441 0016336 0 ustar 00root root 0000000 0000000 /*
* screeninfo-xlib.c
*
* Copyright (C) 2008, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
#include
#include
#include "debug.h"
#include "screeninfo.h"
void screeninfo_get_screens(Display *dpy, screeninfo_t **screens, int *screens_n) {
*screens = (screeninfo_t *) malloc(sizeof(screeninfo_t));
*screens_n = 1;
screens[0]->screen_number = 0;
screens[0]->x_org = 0;
screens[0]->y_org = 0;
screens[0]->width = DisplayWidth(dpy, DefaultScreen(dpy));
screens[0]->height = DisplayHeight(dpy, DefaultScreen(dpy));
}
superkb-0.23/screeninfo.h 0000664 0000000 0000000 00000001202 12210555441 0015407 0 ustar 00root root 0000000 0000000 /*
* screeninfo.h
*
* Copyright (C) 2008, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* This code provides Superkb with a way to get information about the one
* or many monitors available on the system, in order to draw one keyboard
* per monitor instead of one big keyboard among all monitors.
*
* It does so by providing a function.
*/
#ifndef __SCREENINFO_H
#define __SCREENINFO_H
typedef struct {
int screen_number;
short x_org;
short y_org;
short width;
short height;
} screeninfo_t;
void screeninfo_get_screens(Display *dpy, screeninfo_t **xinerama_screens, int *screens_n);
#endif
superkb-0.23/superkb.1.inc 0000664 0000000 0000000 00000001575 12210555441 0015425 0 ustar 00root root 0000000 0000000 [synopsis]
superkb [options]
[=description]
Superkb is a keyboard-based application launcher based on a hotkey (the Super key by default) that allows for on-screen keyboard hints to be displayed if it is held long enough without calling any bound action. The hints will be shown in the form of icons in a keyboard.
System-wide configuration for Superkb is read from \fB/etc/superkbrc\fR. It can be extended with user-specific changes read from \fB$HOME/.superkbrc\fR.
[examples]
You should find sample files under \fB/usr/share/doc/superkb/sample-config\fR. Detailed description of the directives can be found online at the Wiki (see below).
[reporting bugs]
Bug tracker for Superkb is located at
.BR https://bugs.launchpad.net/superkb .
[more information]
The website for Superkb is located at
.B http://superkb.sf.net/
and
there is a documentation Wiki at
.BR http://superkb.org/wiki .
superkb-0.23/superkb.c 0000664 0000000 0000000 00000042707 12210555441 0014741 0 ustar 00root root 0000000 0000000 /*
* superkb.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
/* Superkb: This modules does all the key and event handling magic. */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "superkb.h"
#include "globals.h"
#include "debug.h"
#include "timeval.h"
int keygrab1_serial = -1;
int keygrab2_serial = -1;
int superkey1_grabfail = 0;
int superkey2_grabfail = 0;
void (*__Action)(KeyCode keycode, unsigned int state);
/* Start PRESSED KEYS STACK */
typedef struct pressed_keys_element {
int keycode;
int state;
} pressed_key_t;
pressed_key_t *pressed_keys = NULL;
int pressed_keys_n = 0;
void remove_from_pressed_key_stack(int keycode, int state)
{
int x;
int y;
for (x = pressed_keys_n-1; x >=0; x--) {
if (pressed_keys[x].keycode == keycode &&
pressed_keys[x].state == state) {
/* Item to be removed found. */
for (y = x; y < pressed_keys_n-1; y++) {
pressed_keys[y].keycode = pressed_keys[y+1].keycode;
pressed_keys[y].state = pressed_keys[y+1].state;
}
list_rmv_element(pressed_keys, pressed_keys_n, pressed_key_t);
}
}
}
void push_into_pressed_key_stack(int keycode, int state)
{
list_add_element(pressed_keys, pressed_keys_n, pressed_key_t);
pressed_keys[pressed_keys_n-1].keycode = keycode;
pressed_keys[pressed_keys_n-1].state = state;
}
void clear_pressed_key_stack() {
if (pressed_keys != NULL) {
free (pressed_keys);
pressed_keys = NULL;
}
pressed_keys_n = 0;
}
/* End PRESSED KEYS STACK */
/* This function is the same as XNextEvent but a timeout can be
* specified in "to". It's supposed to accept NULL for no timeout
* as the function works like a wrapper for select().
*
* It works by select()ing on XConnectionNumber(display) to wait either
* for incoming traffic or timeout. If the former is found, return the
* next event.
*
* RETURNS == 0 ? Timed out before getting an event.
* RETURNS < 0 ? Error. Useful to get EINTR. Return set to -errno.
* RETURNS > 0 ? Event catched.
*/
int
XNextEventWithTimeout(Display * display, XEvent * event_return,
struct timeval *to)
{
fd_set fd;
int r;
XFlush(display);
if (QLength(display) > 0) {
XNextEvent(display, event_return);
return 1;
}
FD_ZERO(&fd);
FD_SET(XConnectionNumber(display), &fd);
do {
r = select(FD_SETSIZE, &fd, NULL, NULL, to);
} while(r == -1 && errno == EINTR);
if (r == -1) {
/* Some error other than EINTR. */
return -errno;
}
if (r == 0) {
/* Timeout */
return r;
}
XNextEvent(display, event_return);
return 1;
}
enum to_index {
TO_CONFIG = 0,
TO_DRAWKB = 1
};
#define to_n 2
struct timeval to[to_n];
int saved_key1_autorepeat_mode = 0;
int saved_key2_autorepeat_mode = 0;
void superkb_restore_auto_repeat(superkb_p this) {
XKeyboardControl xkbc;
if (this->key1) {
xkbc.key = this->key1;
xkbc.auto_repeat_mode = saved_key1_autorepeat_mode;
XChangeKeyboardControl(this->dpy, KBAutoRepeatMode | KBKey, &xkbc);
}
if (this->key2) {
xkbc.key = this->key2;
xkbc.auto_repeat_mode = saved_key2_autorepeat_mode;
XChangeKeyboardControl(this->dpy, KBAutoRepeatMode | KBKey, &xkbc);
}
}
int display_generic_x_error(Display *dpy, XErrorEvent *xerrev) {
char buf[80];
XGetErrorText(dpy, xerrev->error_code, (char *) buf, sizeof (buf)-1);
fprintf(stderr, "X Error of failed request: %s\n", buf);
XGetErrorDatabaseText(dpy, "Xproto", "XError", "Unknown error", (char *) &buf, sizeof (buf)-1);
fprintf(stderr, " Major opcode of failed request: %d (%s)\n", xerrev->request_code, buf);
fprintf(stderr, " Serial number of failed request: %d\n", xerrev->minor_code);
fprintf(stderr, " Current serial number in output stream: %ld\n", xerrev->serial);
abort();
}
int xerror_handler(Display *dpy, XErrorEvent *xerrev) {
if (xerrev->serial == keygrab1_serial) {
superkey1_grabfail = 1;
} else if (xerrev->serial == keygrab2_serial) {
superkey2_grabfail = 1;
} else {
display_generic_x_error(dpy, xerrev);
}
return 0;
}
void one_superkey_used_friendly_warning(int number, const char *keyname) {
const char *ordinal;
if (number == 1)
ordinal = "first";
if (number == 2)
ordinal = "second";
fprintf(stderr,
"WARNING: Your %s configured Super key (%s) is already in\n"
" use by another program (usually Compiz). You may continue using Superkb\n"
" using your second Super key. You may want to try the following to avoid\n"
" this error:\n"
" * Load Superkb before the conflicting program by loading it right\n"
" at startup. (Under GNOME, use System > Startup Applications.)\n"
" * Unload or kill the conflicting program.\n"
" * Clear the configuration for the first Super key by adding\n"
" \"SUPERKEY%d_CODE 0\" in your $HOME/.superkbrc.)\n"
"\n", ordinal, keyname, number
);
}
int key_is_pressed (Display *dpy, KeyCode keycode)
{
char key_buffer [32];
XQueryKeymap(dpy, key_buffer);
return ( (key_buffer[keycode >> 3] >> (keycode & 0x07)) & 0x01 );
}
void superkb_start(superkb_p this)
{
XSynchronize(this->dpy, True);
XSetErrorHandler(xerror_handler);
/* Solicitar los eventos */
if (this->key1 != 0) {
keygrab1_serial = NextRequest(this->dpy);
XGrabKey(this->dpy, this->key1, AnyModifier, this->rootwin, True,
GrabModeAsync, GrabModeAsync);
}
if (this->key2 != 0) {
keygrab2_serial = NextRequest(this->dpy);
XGrabKey(this->dpy, this->key2, AnyModifier, this->rootwin, True,
GrabModeAsync, GrabModeAsync);
}
XSynchronize(this->dpy, False);
XSetErrorHandler(NULL);
int t1 = (this->key1 != 0);
int f1 = superkey1_grabfail;
int t2 = (this->key2 != 0);
int f2 = superkey2_grabfail;
if ((t1 && f1 && t2 && f2) || (t1 && f1 && !t2) || (t2 && f2 && !t1)) {
fprintf(stderr,
"ERROR: Some other program (usually Compiz or another Superkb) is already\n"
" using your Super keys. You may want to try either of the following:\n"
" * Load Superkb before the conflicting program by loading it right\n"
" at startup. (Under GNOME, use System > Startup Applications.)\n"
" * Unload or kill the conflicting program.\n"
" * Try a different set of Super keys. (Remember that Superkb supports\n"
" two Super keys; if you don't use the second one you must clear it\n"
" using \"SUPERKEY2_CODE 0\" in your $HOME/.superkbrc.)\n"
"\n"
);
abort();
}
if (t1 && t2 && !f1 && f2) {
one_superkey_used_friendly_warning(1, XKeysymToString(XkbKeycodeToKeysym(this->dpy, this->key1, 0, 0)));
}
if (t1 && t2 && f1 && !f2) {
one_superkey_used_friendly_warning(2, XKeysymToString(XkbKeycodeToKeysym(this->dpy, this->key2, 0, 0)));
}
XKeyboardState xkbs;
int x;
/* Save autorepeat previous state. Then turn off. */
XGetKeyboardControl(this->dpy, &xkbs);
saved_key1_autorepeat_mode = (xkbs.auto_repeats[(int) (this->key1/8)] & (1 << (this->key1 % 8))) > 0;
XGetKeyboardControl(this->dpy, &xkbs);
saved_key2_autorepeat_mode = (xkbs.auto_repeats[(int) (this->key2/8)] & (1 << (this->key2 % 8))) > 0;
/* FIXME: Autorepeat must be restored on end */
XKeyboardControl xkbc;
if (this->key1) {
xkbc.key = this->key1;
xkbc.auto_repeat_mode = AutoRepeatModeOff;
XChangeKeyboardControl(this->dpy, KBAutoRepeatMode | KBKey, &xkbc);
}
if (this->key2) {
xkbc.key = this->key2;
xkbc.auto_repeat_mode = AutoRepeatModeOff;
XChangeKeyboardControl(this->dpy, KBAutoRepeatMode | KBKey, &xkbc);
}
int ignore_release = 0;
int saved_autorepeat_mode = 0;
/* Counter, in case user presses both Supers and releases only one. */
int super_was_active = 0;
debug (2, "[ar] super_was_active has been initialized to %d.\n", super_was_active);
/* Initialize timeouts to be inactive. */
timerclear(&to[TO_DRAWKB]);
timerclear(&to[TO_CONFIG]);
(*this->welcome_message)();
fprintf(stderr,
"\n\n"
"Superkb is now running!\n"
"\n"
"Press and hold any of your configured Super keys to start using it.\n"
"\n"
);
while (1) {
struct timeval hold_start;
struct timeval hold_end;
XEvent ev;
int XNEWT_ret = 0;
int i;
int to_reason = 0;
int super_replay = 0;
XEvent event_save_for_replay;
Window event_saved_window;
/* Decide wether to use XNextEvent or my own XNextEventWithTimeout
* and do accordingly. If WithTimeout was used, substract the
* time actually elapsed to the set timeout. */
for (i = 0; i < to_n; i++) {
if (timerisset(&to[i])) {
to_reason = i;
break;
}
}
if (i == to_n) {
debug (4, "[xn] Calling XNextEventWithTimeout(this->dpy, &ev, NULL)\n");
XNEWT_ret = XNextEventWithTimeout(this->dpy, &ev, NULL);
} else {
gettimeofday(&hold_start, NULL);
for (i = to_reason + 1; i < to_n; i++) {
if (timerisset(&to[i])) {
if (timercmp(&to[i], &to[to_reason], <))
to_reason = i;
}
}
/* Man pages say that Linux select() modifies timeout where
* other implementations don't. We oughta save timeout and restore
* it after select().
*/
struct timeval timeout_save;
memcpy(&timeout_save, &to[to_reason], sizeof(struct timeval));
/* I hope select() takes proper care of negative timeouts.
* It happens sometimes.
*/
if (to[to_reason].tv_sec >= 0 &&
to[to_reason].tv_usec >= 0) {
debug (4, "[xn] Calling XNextEventWithTimeout(this->dpy, &ev, &to[to_reason]) to_reason = %d\n", to_reason);
XNEWT_ret = XNextEventWithTimeout(this->dpy, &ev, &to[to_reason]);
}
/* Restore. */
memcpy(&to[to_reason], &timeout_save, sizeof(struct timeval));
gettimeofday(&hold_end, NULL);
struct timeval hold_time;
/* Update all timers */
timersub(&hold_end, &hold_start, &hold_time);
for (i = 0; i < to_n; i++) {
if (timerisset(&to[i])) {
timersub(&to[i], &hold_time, &to[i]);
}
}
}
if (XNEWT_ret == -EINTR)
break;
if (XNEWT_ret == 0) {
/* Timed out */
if (to_reason == TO_CONFIG) {
debug(9, "[kc] Placeholder: key config window should pop up here.\n");
timerclear(&to[TO_CONFIG]);
ignore_release = 1;
int squashed_state = ev.xkey.state & this->state_mask;
remove_from_pressed_key_stack(ev.xkey.keycode, squashed_state);
}
if (to_reason == TO_DRAWKB) {
super_replay = 0;
timerclear(&to[TO_DRAWKB]);
/* Map Window. */
if (this->kbwin.map)
this->kbwin.map(this->dpy);
}
} else if (ev.xany.window != this->rootwin) {
this->kbwin.event(this->dpy, ev);
} else if (ev.xkey.keycode == this->key1
|| ev.xkey.keycode == this->key2) {
if (ev.type == KeyPress) {
ignore_release = 0;
debug(1, "[sk] Super key has been pressed, code: %d, name: %s.\n", ev.xkey.keycode,
XKeysymToString(XkbKeycodeToKeysym(this->dpy, ev.xkey.keycode, 0, 0)));
if (super_was_active++) {
super_replay = 0;
debug(2, "[sa] super_was_active increased to %d, not taking action.\n", super_was_active);
continue;
}
debug(2, "[sa] super_was_active increased to %d, taking action.\n", super_was_active);
super_replay = this->superkey_replay;
memcpy(&event_save_for_replay, &ev, sizeof(XEvent));
int revert_to_return;
XGetInputFocus(this->dpy, &event_saved_window, &revert_to_return);
XKeyboardState xkbs;
/* Save autorepeat previous state. Then turn off. */
XGetKeyboardControl(this->dpy, &xkbs);
saved_autorepeat_mode = xkbs.global_auto_repeat;
debug(1, "[ar] AutoRepeat state has been saved: %d.\n", saved_autorepeat_mode);
XKeyboardControl xkbc;
xkbc.auto_repeat_mode = AutoRepeatModeOff;
XChangeKeyboardControl(this->dpy, KBAutoRepeatMode, &xkbc);
debug(1, "[ar] AutoRepeat state has been turned off.\n");
/* Grab the keyboard. */
XGrabKeyboard(this->dpy, this->rootwin, False, GrabModeAsync,
GrabModeAsync, CurrentTime);
if (this->drawkb_delay > 0) {
to[TO_DRAWKB].tv_sec = (int) this->drawkb_delay;
to[TO_DRAWKB].tv_usec = (int) ((this->drawkb_delay - to[TO_DRAWKB].tv_sec) * 1000000);
} else {
/* Map Window. */
this->kbwin.map(this->dpy);
}
} else if (ev.type == KeyRelease) {
debug(1, "[sk] Super key has been released, code: %d, name: %s.\n", ev.xkey.keycode,
XKeysymToString(XkbKeycodeToKeysym(this->dpy, ev.xkey.keycode, 0, 0)));
if (--super_was_active) {
debug(2, "[sa] super_was_active decreased to %d, ignoring release.\n", super_was_active);
continue;
}
debug(2, "[sa] super_was_active decreased to %d, taking action.\n", super_was_active);
timerclear(&to[TO_DRAWKB]);
timerclear(&to[TO_CONFIG]);
if (super_replay) {
/* Since Xlib only supports Replaying a key before getting the next keyboard event,
* we can't really use XAllowEvents() to replay the Super key in case the user
* asked to. So we try XSendEvent() with the Press from the saved event on KeyPress,
* and the Release we are currently using.
*/
event_save_for_replay.xkey.window = event_saved_window;
ev.xkey.window = event_saved_window;
event_save_for_replay.xkey.subwindow = 0;
ev.xkey.subwindow = 0;
XSendEvent(this->dpy, event_saved_window, 1, KeyPressMask, &event_save_for_replay);
XSendEvent(this->dpy, event_saved_window, 1, KeyReleaseMask, &ev);
XSync(this->dpy, True);
debug(1, "[sr] Super key has been replayed\n");
}
/* Restore saved_autorepeat_mode. */
XKeyboardControl xkbc;
/*xkbc.auto_repeat_mode = saved_autorepeat_mode; */
xkbc.auto_repeat_mode = AutoRepeatModeOn;
XChangeKeyboardControl(this->dpy, KBAutoRepeatMode, &xkbc);
debug(1, "[ar] AutoRepeat has been restored to: %d\n", saved_autorepeat_mode);
XUngrabKeyboard(this->dpy, CurrentTime);
this->kbwin.unmap(this->dpy);
for (x = 0; x < pressed_keys_n; x++) {
__Action(pressed_keys[x].keycode, pressed_keys[x].state);
debug(1, "[ac] Due to Super key release, executed action for key code = %d, name: %s\n", pressed_keys[x].keycode,
XKeysymToString(XkbKeycodeToKeysym
(this->dpy, pressed_keys[x].keycode, 0, 0)));
}
clear_pressed_key_stack();
debug(1, "---------------------------------------------\n");
}
} else if (ev.type == KeyPress) {
debug(1, "[kp] A non-Super key was pressed.\n");
super_replay = 0;
to[TO_CONFIG].tv_sec = 3;
to[TO_CONFIG].tv_usec = 0;
debug(2, "[kp] TO_CONFIG timer set to 3 s.\n");
int squashed_state = ev.xkey.state & this->state_mask;
push_into_pressed_key_stack(ev.xkey.keycode, squashed_state);
debug(2, "[kp] Pushed key and state to stack: %d, %d\n", ev.xkey.keycode, squashed_state);
} else if ((ev.type == KeyRelease && !ignore_release &&
super_was_active > 0)) {
/* User might have asked for binding configuration, so ignore key
* release. That's what ignore_release is for.
*/
timerclear(&to[TO_CONFIG]);
int squashed_state = ev.xkey.state & this->state_mask;
if ( key_is_pressed (this->dpy, ev.xkey.keycode) ) {
/* Verifies that the key is indeed pressed and not just a
* KeyRelease generated X's AutoRepeat.
*/
remove_from_pressed_key_stack(ev.xkey.keycode, squashed_state);
continue;
}
__Action(ev.xkey.keycode, squashed_state);
debug(1, "[ac] Due to bound key release, executed action for key code = %d, name: %s\n", ev.xkey.keycode,
XKeysymToString(XkbKeycodeToKeysym
(this->dpy, ev.xkey.keycode, 0, 0)));
debug(2, " ... and because super_was_active value was > 0: %d\n", super_was_active);
remove_from_pressed_key_stack(ev.xkey.keycode, squashed_state);
debug(2, "[kp] Removed key and state to stack: %d, %d\n", ev.xkey.keycode, squashed_state);
} else {
/* According to manual, this should not be necessary. */
/* XAllowEvents(this->dpy, ReplayKeyboard, CurrentTime); */
}
}
}
void superkb_kbwin_set(superkb_p this,
int (*superkb_kbwin_init) (Display *),
void (*superkb_kbwin_map) (Display *),
void (*superkb_kbwin_unmap) (Display *),
void (*superkb_kbwin_event) (Display *, XEvent ev))
{
if (superkb_kbwin_init != NULL) {
this->kbwin.init = superkb_kbwin_init;
}
if (superkb_kbwin_map != NULL) {
this->kbwin.map = superkb_kbwin_map;
}
if (superkb_kbwin_unmap != NULL) {
this->kbwin.unmap = superkb_kbwin_unmap;
}
if (superkb_kbwin_event != NULL) {
this->kbwin.event = superkb_kbwin_event;
}
}
int
superkb_init(superkb_p this,
Display *display,
const char *kblayout, KeyCode key1, KeyCode key2,
double drawkb_delay,
void (*f)(KeyCode keycode, unsigned int state),
int superkey_replay,
int superkey_release_cancels,
int states_mask, void (*welcome_message)())
{
__Action = f;
this->dpy = display;
int r;
this->drawkb_delay = drawkb_delay;
this->superkey_replay = superkey_replay;
this->superkey_release_cancels = superkey_release_cancels;
this->state_mask = states_mask;
/* FIXME: Validate parameters. */
/* Set configuration values. Parameters should be already validated. */
strcpy(this->kblayout, kblayout);
this->key1 = key1;
this->key2 = key2;
this->rootwin = DefaultRootWindow(this->dpy);
this->dpy = display;
this->welcome_message = welcome_message;
/* Create the keyboard window. */
r = this->kbwin.init(this->dpy);
if (r == EXIT_FAILURE) {
perror("superkb: superkb_init(): kbwin.init() failed");
return EXIT_FAILURE;
}
XFlush(this->dpy);
return 0;
}
superkb_p superkb_create(void) {
superkb_p this = malloc(sizeof(superkb_t));
if (this == NULL) {
perror("superkb: superkb_create(): malloc() failed");
return NULL;
}
memset (this, 0, sizeof(superkb_t));
return this;
}
superkb-0.23/superkb.h 0000664 0000000 0000000 00000004021 12210555441 0014731 0 ustar 00root root 0000000 0000000 /*
* superkb.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* Provides Superkb with the mechanism to handle the keyboard. This includes:
* - handling of the hotkey (the one that triggers the keyboard display on
* the screen)
* - calling of the callback functions that actually launch the actions
* (application, document or whatever),
* - timer management (two at the moment):
* :: One that triggers the configuration program for an action key if
* held down for 3 seconds.
* :: The one that triggers the drawing of the keyboard.
*
* This code only does the handling of the keyboard. Every action is done by
* callbacks. This allows the module to be plugged out if needed.
*/
#ifndef __SUPERKB_H
#define __SUPERKB_H
#include
#include
#include
#include
#include
typedef struct {
int (*init) (Display *);
void (*map) (Display *);
void (*unmap) (Display *);
void (*event) (Display *, XEvent ev);
} kbwin_t, *kbwin_p;
typedef struct {
KeyCode key1;
KeyCode key2;
double drawkb_delay;
Display *dpy;
Window rootwin;
int superkey_replay;
int superkey_release_cancels;
kbwin_t kbwin;
char kblayout[3];
int state_mask;
void (*welcome_message)();
} superkb_t, *superkb_p;
void superkb_start(superkb_p this);
superkb_p superkb_create(void);
void superkb_restore_auto_repeat(superkb_p this);
int superkb_init(superkb_p this,
Display *display,
const char *kblayout, KeyCode key1, KeyCode key2,
double drawkb_delay,
void (*f)(KeyCode keycode, unsigned int state),
int superkey_replay,
int superkey_release_cancels,
int states_mask,
void (*welcome_message)());
void superkb_kbwin_set(superkb_p this,
int (*superkb_kbwin_init) (Display *),
void (*superkb_kbwin_map) (Display *),
void (*superkb_kbwin_unmap) (Display *),
void (*superkb_kbwin_event) (Display *, XEvent ev));
#endif /* __SUPERKB_H */
superkb-0.23/superkbrc.c 0000664 0000000 0000000 00000046516 12210555441 0015270 0 ustar 00root root 0000000 0000000 /*
* conf.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* Some code by Nathan "Whatah" Zohar.
*/
#include
#include
#include
#include
#include
#include "superkbrc.h"
#include "globals.h"
#define CONFIG_FILENAME ".superkbrc"
#define CONFIG_DEFAULT_SUPERKB_SUPER1 XKeysymToKeycode(dpy, XStringToKeysym("Super_L"));
#define CONFIG_DEFAULT_SUPERKB_SUPER2 XKeysymToKeycode(dpy, XStringToKeysym("Super_R"));
#define CONFIG_DEFAULT_SQUASHED_STATES 82
#define CONFIG_DEFAULT_DRAWKB_DELAY 0.5
#define CONFIG_DEFAULT_DRAWKB_FONT "Sans Bold"
#define CONFIG_DEFAULT_DRAWKB_IMAGELIB "imlib2"
#define CONFIG_DEFAULT_DRAWKB_DRAWKBLIB "cairo"
#define CONFIG_DEFAULT_DRAWKB_BACKCOLOR_RED 12700
#define CONFIG_DEFAULT_DRAWKB_BACKCOLOR_GREEN 12700
#define CONFIG_DEFAULT_DRAWKB_BACKCOLOR_BLUE 12700
#define CONFIG_DEFAULT_DRAWKB_FORECOLOR_RED 56100
#define CONFIG_DEFAULT_DRAWKB_FORECOLOR_GREEN 56100
#define CONFIG_DEFAULT_DRAWKB_FORECOLOR_BLUE 56100
#define CONFIG_DEFAULT_DRAWKB_USE_GRADIENTS 1
#define CONFIG_DEFAULT_DOCUMENT_HANDLER "gnome-open"
#define CONFIG_DEFAULT_SUPERKB_SUPERKEY_REPLAY 1
#define CONFIG_DEFAULT_FEEDBACK_HANDLER "xmessage -buttons '' -center -timeout 2 Launching "
#define CONFIG_DEFAULT_SUPERKB_SUPERKEY_RELEASE_CANCELS 0
#define CONFIG_DEFAULT_DRAWKB_PAINTING_MODE FLAT_KEY
#define CONFIG_DEFAULT_WELCOME_CMD "xmessage -buttons '' -center -timeout 5 Welcome to Superkb! To start, hold down any of your configured Super keys."
int cver = 0;
config_t * __config;
Display * __dpy;
void
config_add_binding_command(Display *dpy, config_t *this, KeySym keysym, unsigned int state,
enum action_type action_type, const char *command,
const char *icon, const char *feedback_string)
{
debug(5, "[bc] Binding command: %d, %s, %s\n", keysym, command, feedback_string);
list_add_element(this->key_bindings, this->key_bindings_n, struct key_bindings);
this->key_bindings[this->key_bindings_n - 1].keycode =
XKeysymToKeycode(dpy, keysym);
this->key_bindings[this->key_bindings_n - 1].state = state;
this->key_bindings[this->key_bindings_n - 1].action_type = action_type;
this->key_bindings[this->key_bindings_n - 1].action.command = malloc(strlen(command)+1);
strcpy(this->key_bindings[this->key_bindings_n - 1].action.command, command);
if (icon != NULL) {
this->key_bindings[this->key_bindings_n - 1].icon = malloc(strlen(icon)+1);
strcpy(this->key_bindings[this->key_bindings_n - 1].icon, icon);
} else {
this->key_bindings[this->key_bindings_n - 1].icon = NULL;
}
if (feedback_string != NULL) {
this->key_bindings[this->key_bindings_n - 1].feedback_string = malloc(strlen(feedback_string)+1);
strcpy(this->key_bindings[this->key_bindings_n - 1].feedback_string, feedback_string);
} else {
this->key_bindings[this->key_bindings_n - 1].feedback_string = NULL;
}
}
void
config_add_binding_document(Display *dpy, config_t *this, KeySym keysym, unsigned int state,
enum action_type action_type, const char *document,
const char *icon, const char *feedback_string)
{
list_add_element(this->key_bindings, this->key_bindings_n, struct key_bindings);
this->key_bindings[this->key_bindings_n - 1].keycode =
XKeysymToKeycode(dpy, keysym);
this->key_bindings[this->key_bindings_n - 1].state = state;
this->key_bindings[this->key_bindings_n - 1].action_type = action_type;
this->key_bindings[this->key_bindings_n - 1].action.document = malloc(strlen(document)+1);
strcpy(this->key_bindings[this->key_bindings_n - 1].action.document, document);
if (icon != NULL) {
this->key_bindings[this->key_bindings_n - 1].icon = malloc(strlen(icon)+1);
strcpy(this->key_bindings[this->key_bindings_n - 1].icon, icon);
} else {
this->key_bindings[this->key_bindings_n - 1].icon = NULL;
}
if (feedback_string != NULL) {
this->key_bindings[this->key_bindings_n - 1].feedback_string = malloc(strlen(feedback_string)+1);
strcpy(this->key_bindings[this->key_bindings_n - 1].feedback_string, feedback_string);
} else {
this->key_bindings[this->key_bindings_n - 1].feedback_string = NULL;
}
}
void
config_add_binding(Display *dpy, config_t *this, enum action_type binding_type, KeySym keysym, unsigned int state,
enum action_type action_type, const char *content,
const char *icon, const char *feedback_string, int autoquote)
{
char *feedback_string_quoted = (char *)feedback_string;
int already_quoted = 0;
if (feedback_string != NULL) {
if (feedback_string[0] == '\'' && feedback_string[strlen(feedback_string) - 1] == '\'') {
debug(4, "[aq] Already quoted: %s\n", feedback_string);
already_quoted = 1;
} else {
debug(4, "[aq] Will try to quote: %s\n", feedback_string);
}
}
if (autoquote && !already_quoted && feedback_string != NULL) {
feedback_string_quoted = malloc(strlen(feedback_string) + 3);
if (feedback_string_quoted) {
strcpy(feedback_string_quoted, "'");
strcat(feedback_string_quoted, feedback_string);
strcat(feedback_string_quoted, "'");
debug(4, "[aq] New quoted string: %s\n", feedback_string_quoted);
} else {
feedback_string_quoted = (char *)feedback_string;
debug(4, "[aq] Could not get memory for new string. Falling back: %s\n", feedback_string_quoted);
}
}
switch (binding_type) {
case AT_DOCUMENT:
debug(4, "[aq] AT_DOCUMENT: %s, %s\n", feedback_string_quoted, icon);
config_add_binding_document(dpy, this, keysym, state, AT_DOCUMENT, content, icon, feedback_string_quoted);
break;
case AT_COMMAND:
debug(4, "[aq] AT_COMMAND: %s, %s\n", feedback_string_quoted, icon);
config_add_binding_command(dpy, this, keysym, state, AT_COMMAND, content, icon, feedback_string_quoted);
break;
default:
break;
}
}
/* lets us know if the line is blank or not */
int empty(char *string, int size) {
int i;
for (i = 0; i < size; i++) {
if (!isspace(string[i])) {
return 0;
}
}
return 1;
}
/** Return address of next word in buf and update *wordLength
* to the length of that word. Return NULL if there is no such
* word.
*
* A word is defined as all the chars from buf until one in delim and
* and until the next item in delim. (it strips whitespace out of the word)
*
* If the first character is a double quote, then it will search for the
* next double quote as a delimiter.
**/
const char *next_word(const char *buf, int *wordLength, const char* delim) {
char c = *buf;
int i = 0; /* Word length counter */
int j = 0; /* Leading whitespace counter */
while (strchr(delim, c) != NULL && c != '\0') {
c = buf[j++];
}
if (j > 0) j--;
if (buf[j] == '\0') return NULL;
if (buf[j] == '"') {
c = buf[++j];
i = j;
while (c != '"' && c != '\0') {
c = buf[++i];
}
i++;
} else {
i = j;
while (strchr(delim, c) == NULL) {
c = buf[i++];
}
}
*wordLength = --i - j;
return buf + j;
}
/** Read next line (terminated by `\n` or EOF) from in into dynamically
* allocated buffer buf having size *bufSize. The line is terminated
* by a NUL ('\0') character. The terminating newline is not
* included. If buf is not large enough to contain
* the line then it is reallocated and the new size stored in *bufSize.
* The return value is a pointer to the start of the buffer containing
* the line. Sets *isEof to non-zero on EOF. Aborts with an
* error message on error.
**/
char *get_line(FILE *in, char *buf, int *bufSize, int *isEof) {
char c;
int i = 0;
if (*bufSize == 0) *bufSize = 1;
buf = realloc(buf, *bufSize * sizeof(char));
while((c = fgetc(in)) != EOF && (c != '\n')) {
if (i >= (*bufSize) - 1) {
buf = realloc(buf, sizeof(char) * *bufSize * 2);
*bufSize *= 2;
}
buf[i++] = c;
}
if (c == EOF) {
*isEof = 1;
}
if (ferror(in)) {
perror("superkb: ");
exit(EXIT_FAILURE);
}
buf[i] = 0;
*bufSize = i;
return buf;
}
/* Reads line and updates **c to reflect the configuration of that line */
void handle_line(char *line, int linesize) {
static int autoquote = 1;
char *comment;
/* We zero out anything past a '#', including the '#', for commenting */
if ((comment = strchr(line, '#')) != NULL) {
*comment = 0;
linesize = (comment - line);
}
/* Sanity Checks */
if (linesize == 0) return;
if (empty(line, linesize)) return;
/* Tokenize the line by whitespace, filling token_array with tok_index
* number of items. */
int wordlength;
char **token_array = malloc(sizeof(*token_array));
char *token;
char *token_item;
int tok_size;
int tok_index;
int q;
wordlength = -1;
token = line;
tok_index = 0;
tok_size = 1;
while ((token = (char *) next_word(token + wordlength + 1, &wordlength, " \v\t\r")) != NULL) {
if (tok_size <= tok_index) {
token_array = realloc(token_array, tok_size * 2 * sizeof(*token_array));
tok_size *= 2;
}
/* Need to end each token with a null, so add 1 to the wordlength and NULL it */
token_item = malloc(sizeof(*token_item) * wordlength + 1);
/* copy the token into our newly allocated space */
memcpy(token_item, token, wordlength);
token_item[wordlength] = 0;
/* pop it into the array */
token_array[tok_index++] = token_item;
if (token + wordlength >= line + linesize) {
break;
}
}
/* Finished tokenizing */
/* (Octavio) Interpretation */
if (!strcmp(token_array[0], "CVER"))
{
int input;
/* FIXME: This will accept strings like '2a'. Though it will fallback
* correctly to '2', it might not be what the user wants. It should
* spit back a warning or an error.
*/
input = atoi(token_array[1]);
if (input > 0) {
fprintf(stderr, "Ignoring bad CVER: %d\n", atoi(token_array[1]));
}
} else if (cver == 0) {
if (!strcmp(token_array[0], "DELAY") && tok_index == 2) {
__config->drawkb_delay = atof(token_array[1]);
return;
}
if (!strcmp(token_array[0], "FONT") && tok_index == 2) {
strncpy(__config->drawkb_font, token_array[1], 500);
return;
}
if (!strcmp(token_array[0], "IMAGELIB") && tok_index == 2) {
strncpy(__config->drawkb_imagelib, token_array[1], 500);
return;
}
if (!strcmp(token_array[0], "DRAWKBLIB") && tok_index == 2) {
strncpy(__config->drawkb_drawkblib, token_array[1], 500);
return;
}
if (!strcmp(token_array[0], "DOCUMENT_HANDLER") && tok_index == 2) {
strncpy(__config->document_handler, token_array[1], 500);
return;
}
if (!strcmp(token_array[0], "SUPERKEY1_STRING") && tok_index == 2) {
__config->superkb_super1 = XKeysymToKeycode(__dpy, XStringToKeysym(token_array[1]));
return;
}
if (!strcmp(token_array[0], "SUPERKEY2_STRING") && tok_index == 2) {
__config->superkb_super2 = XKeysymToKeycode(__dpy, XStringToKeysym(token_array[1]));
return;
}
if (!strcmp(token_array[0], "SUPERKEY1_CODE") && tok_index == 2) {
__config->superkb_super1 = atoi(token_array[1]);
return;
}
if (!strcmp(token_array[0], "SUPERKEY2_CODE") && tok_index == 2) {
__config->superkb_super2 = atoi(token_array[1]);
return;
}
if (!strcmp(token_array[0], "SQUASHED_STATES") && tok_index == 2) {
__config->squashed_states = atoi(token_array[1]);
return;
}
if (!strcmp(token_array[0], "BACKGROUND") && tok_index == 4) {
__config->backcolor.red = atoi(token_array[1]);
__config->backcolor.green = atoi(token_array[2]);
__config->backcolor.blue = atoi(token_array[3]);
if (__config->backcolor.red <= 255 &&
__config->backcolor.green <= 255 &&
__config->backcolor.blue <= 255) {
__config->backcolor.red *= 256;
__config->backcolor.green *= 256;
__config->backcolor.blue *= 256;
}
return;
}
if (!strcmp(token_array[0], "FOREGROUND") && tok_index == 4) {
__config->forecolor.red = atoi(token_array[1]);
__config->forecolor.green = atoi(token_array[2]);
__config->forecolor.blue = atoi(token_array[3]);
if (__config->forecolor.red <= 255 &&
__config->forecolor.green <= 255 &&
__config->forecolor.blue <= 255) {
__config->forecolor.red *= 256;
__config->forecolor.green *= 256;
__config->forecolor.blue *= 256;
}
return;
}
if (!strcmp(token_array[0], "SUPERKEY_REPLAY") && tok_index == 2) {
if (!strcmp(token_array[1], "1"))
__config->superkb_superkey_replay = 1;
else if (!strcmp(token_array[1], "0"))
__config->superkb_superkey_replay = 0;
else fprintf(stderr, "superkb: SUPERKEY_REPLAY value must be 1 or 0.\n");
return;
}
if (!strcmp(token_array[0], "FEEDBACK_STRINGS_AUTOQUOTE") && tok_index == 2) {
if (!strcmp(token_array[1], "1"))
autoquote = 1;
else if (!strcmp(token_array[1], "0"))
autoquote = 0;
else fprintf(stderr, "superkb: FEEDBACK_STRINGS_AUTOQUOTE must be 1 or 0.\n");
return;
}
if (!strcmp(token_array[0], "SUPERKEY_RELEASE_CANCELS") && tok_index == 2) {
if (!strcmp(token_array[1], "1"))
__config->superkb_superkey_release_cancels = 1;
else if (!strcmp(token_array[1], "0"))
__config->superkb_superkey_release_cancels = 0;
else fprintf(stderr, "superkb: SUPERKEY_RELEASE_CANCELS value must be 1 or 0.\n");
return;
}
if (!strcmp(token_array[0], "DRAWKB_PAINTING_MODE") && tok_index == 2) {
if (!strcmp(token_array[1], "FULL_SHAPE"))
__config->drawkb_painting_mode = FULL_SHAPE;
else if (!strcmp(token_array[1], "BASE_OUTLINE_ONLY"))
__config->drawkb_painting_mode = BASE_OUTLINE_ONLY;
else if (!strcmp(token_array[1], "FLAT_KEY"))
__config->drawkb_painting_mode = FLAT_KEY;
else fprintf(stderr, "superkb: DRAWKB_PAINTING_MODE value must be one of: FULL_SHAPE, BASE_OUTLINE_ONLY, FLAT_KEY.\n");
return;
}
if (!strcmp(token_array[0], "FEEDBACK_HANDLER") && tok_index == 2) {
strncpy(__config->feedback_handler, token_array[1], 500);
return;
}
if (!strcmp(token_array[0], "WELCOME_CMD") && tok_index == 2) {
strncpy(__config->welcome_cmd, token_array[1], 500);
return;
}
if (!strcmp(token_array[0], "USE_GRADIENTS") && tok_index == 2) {
if (!strcmp(token_array[1], "1"))
__config->use_gradients = 1;
else if (!strcmp(token_array[1], "0"))
__config->use_gradients = 0;
else fprintf(stderr, "superkb: USE_GRADIENTS value must be 1 or 0.\n");
return;
}
/* FIXME: There might not exist token_array[1]. */
if (!strcmp(token_array[0], "KEY")
&& !strcmp(token_array[1], "COMMAND")
&& (tok_index == 6 || tok_index == 7))
{
/* FIXME: Key validation missing. */
/* Check if file exists */
char *validated_param;
FILE *filecheck;
filecheck = fopen (token_array[5], "r");
if (filecheck == NULL) {
validated_param = NULL;
fprintf(stderr, "superkb: Specified icon file does not exist: %s\n",
token_array[5]);
} else {
fclose (filecheck);
validated_param = (char *) token_array[5];
}
config_add_binding(__dpy, __config, AT_COMMAND,
XStringToKeysym(token_array[2]), atoi(token_array[3]),
AT_COMMAND, token_array[4], validated_param, tok_index == 7 ? token_array[6] : NULL, autoquote);
} else if (!strcmp(token_array[0], "KEY")
&& !strcmp(token_array[1], "DOCUMENT")
&& (tok_index == 6 || tok_index == 7))
{
/* FIXME: Key validation missing. */
/* Check if file exists */
char *validated_param;
FILE *filecheck;
filecheck = fopen (token_array[5], "r");
if (filecheck == NULL) {
validated_param = NULL;
fprintf(stderr, "superkb: Specified icon file does not exist: %s\n",
token_array[5]);
} else {
fclose (filecheck);
validated_param = (char *) token_array[5];
}
config_add_binding(__dpy, __config, AT_DOCUMENT,
XStringToKeysym(token_array[2]), atoi(token_array[3]),
AT_DOCUMENT, token_array[4], validated_param, tok_index == 7 ? token_array[6] : NULL, autoquote);
} else {
fprintf(stderr, "Ignoring invalid config line: '[%s]", token_array[0]);
for (q = 1; q < tok_index; q++) {
fprintf(stderr, " [%s]", token_array[q]);
}
fprintf(stderr, "'\n");
}
}
/* Free our allocated memory */
/* iterate through the token_array freeing everything */
for (q = 0; q < tok_index; q++) {
free(token_array[q]);
}
free(token_array);
return;
}
int parse_config(FILE *file) {
char *buf = malloc(sizeof(*buf));
if (buf == NULL) {
perror("superkb: parse_config(): buf = malloc() failed");
return EXIT_FAILURE;
}
int *bufSize = malloc(sizeof(*bufSize));
if (bufSize == NULL) {
perror("superkb: parse_config(): bufSize = malloc() failed");
return EXIT_FAILURE;
}
int *eof = malloc(sizeof(*eof));
if (eof == NULL) {
perror("superkb: parse_config(): eof = malloc() failed");
return EXIT_FAILURE;
}
*bufSize = 1;
*eof = 0;
while (*eof == 0) {
buf = get_line(file, buf, bufSize, eof);
handle_line(buf, *bufSize);
free(buf);
buf=NULL;
}
return EXIT_SUCCESS;
}
config_t * config_new (Display *dpy)
{
config_t *this;
this = malloc(sizeof(config_t));
if (this == NULL) {
perror("superkb: config_new(): malloc() failed");
return NULL;
}
/* Initialize everything */
this->key_bindings = NULL;
this->key_bindings_n = 0;
this->drawkb_delay = CONFIG_DEFAULT_DRAWKB_DELAY;
strcpy(this->drawkb_font, CONFIG_DEFAULT_DRAWKB_FONT);
strcpy(this->drawkb_imagelib, CONFIG_DEFAULT_DRAWKB_IMAGELIB);
strcpy(this->drawkb_drawkblib, CONFIG_DEFAULT_DRAWKB_DRAWKBLIB);
this->superkb_super1 = CONFIG_DEFAULT_SUPERKB_SUPER1;
this->superkb_super2 = CONFIG_DEFAULT_SUPERKB_SUPER2;
this->backcolor.red = CONFIG_DEFAULT_DRAWKB_BACKCOLOR_RED;
this->backcolor.green = CONFIG_DEFAULT_DRAWKB_BACKCOLOR_GREEN;
this->backcolor.blue = CONFIG_DEFAULT_DRAWKB_BACKCOLOR_BLUE;
this->forecolor.red = CONFIG_DEFAULT_DRAWKB_FORECOLOR_RED;
this->forecolor.green = CONFIG_DEFAULT_DRAWKB_FORECOLOR_GREEN;
this->forecolor.blue = CONFIG_DEFAULT_DRAWKB_FORECOLOR_BLUE;
this->use_gradients = CONFIG_DEFAULT_DRAWKB_USE_GRADIENTS;
strcpy(this->document_handler, CONFIG_DEFAULT_DOCUMENT_HANDLER);
this->superkb_superkey_replay = CONFIG_DEFAULT_SUPERKB_SUPERKEY_REPLAY;
strcpy(this->feedback_handler, CONFIG_DEFAULT_FEEDBACK_HANDLER);
this->superkb_superkey_release_cancels = CONFIG_DEFAULT_SUPERKB_SUPERKEY_RELEASE_CANCELS;
this->drawkb_painting_mode = CONFIG_DEFAULT_DRAWKB_PAINTING_MODE;
this->squashed_states = CONFIG_DEFAULT_SQUASHED_STATES;
strcpy(this->welcome_cmd, CONFIG_DEFAULT_WELCOME_CMD);
return this;
}
void config_destroy (config_t *this)
{
free(this);
}
int config_load(config_t *this, Display *dpy)
{
__dpy = dpy;
__config = this;
int system_config_read = 0;
int user_config_read = 0;
/* Override current configuration with system-wide settings. */
FILE *fd;
fd = fopen("/etc/superkbrc", "r");
if (fd) {
system_config_read = 0;
if (parse_config(fd) == EXIT_SUCCESS) {
system_config_read = 1;
} else {
perror("config_load(): parse_config(system) failed");
}
fclose(fd);
}
/* Read configuration from user file. */
char *home = getenv("HOME");
char *file;
if (home) {
file = malloc(strlen(home) + strlen("/" CONFIG_FILENAME)+1);
if (!file) {
fprintf(stderr, "superkb: Not enough memory to open a file. Very "
"weird. Quitting.\n");
return EXIT_FAILURE;
}
strcpy(file, home);
strcat(file, "/" CONFIG_FILENAME);
} else {
file = CONFIG_FILENAME;
}
fd = fopen(file, "r");
if (fd) {
user_config_read = 0;
if (parse_config(fd) == EXIT_SUCCESS) {
user_config_read = 1;
} else {
perror("config_load(): parse_config(user) failed");
}
fclose(fd);
}
if (!user_config_read && !system_config_read) {
fprintf(stderr, "superkb: Couldn't read any configuration file. Quitting.\n");
fprintf(stderr, " System-wide configuration file should be at /etc/superkbrc.\n");
fprintf(stderr, " User local configuration file should be at $HOME/.superkbrc.\n");
}
return EXIT_SUCCESS;
}
superkb-0.23/superkbrc.h 0000664 0000000 0000000 00000003166 12210555441 0015267 0 ustar 00root root 0000000 0000000 /*
* conf.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
* Provides Superkb with a way to read its initial configuration from a file.
*
* It does so by providing config_load(), but be sure to call config_new()
* to allocate the configuration structure.
*
*/
#ifndef __CONFIG_H
#define __CONFIG_H
#include
#include "drawkblib.h"
enum action_type {
AT_COMMAND = 1,
AT_FUNCTION,
AT_DOCUMENT
};
/* key_bindings is a dynamic list of keybindings */
struct key_bindings {
KeyCode keycode; /* Like in XKeyEvent. */
unsigned int state; /* Like in XKeyEvent. */
unsigned int statemask;
enum action_type action_type;
union {
void (*function)(void *p);
char *command;
char *document;
} action;
char *icon;
char *feedback_string;
/* FIXME: Implement startup notification. */
/* FIXME: Implement tooltips. */
};
typedef struct {
struct key_bindings *key_bindings;
unsigned int key_bindings_n;
double drawkb_delay;
char drawkb_font[500];
char drawkb_imagelib[500];
char drawkb_drawkblib[500];
KeyCode superkb_super1;
KeyCode superkb_super2;
struct {
int red;
int green;
int blue;
} backcolor;
struct {
int red;
int green;
int blue;
} forecolor;
int use_gradients;
char document_handler[500];
int superkb_superkey_replay;
char feedback_handler[500];
int superkb_superkey_release_cancels;
painting_mode_t drawkb_painting_mode;
int squashed_states;
char welcome_cmd[500];
} config_t;
int config_load(config_t *config, Display *dpy);
config_t * config_new (Display *dpy);
#endif
superkb-0.23/timeval.c 0000664 0000000 0000000 00000001374 12210555441 0014722 0 ustar 00root root 0000000 0000000 /*
* timeval.c
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
/* timeval.c: This provides with some timeval functions if not provided
* by the system.
*/
#include "timeval.h"
#ifndef _GNU_SOURCE
void
timersub(struct timeval *a, struct timeval *b, struct timeval *res)
{
if (a->tv_usec >= b->tv_usec) {
res->tv_usec = a->tv_usec - b->tv_usec;
res->tv_sec = a->tv_sec - b->tv_sec;
} else {
res->tv_usec = a->tv_usec - b->tv_usec + 1000000;
res->tv_sec = a->tv_sec - b->tv_sec - 1;
}
}
int
timerisset(struct timeval *tv)
{
return ((tv->tv_sec != 0) || (tv->tv_usec != 0));
}
void
timerclear(struct timeval *tv)
{
tv->tv_sec = 0;
tv->tv_usec = 0;
}
#endif /* #ifndef _GNU_SOURCE */
superkb-0.23/timeval.h 0000664 0000000 0000000 00000001172 12210555441 0014723 0 ustar 00root root 0000000 0000000 /*
* timeval.h
*
* Copyright (C) 2006, Octavio Alvarez Piza.
* License: GNU General Public License v2.
*
*/
/* timeval.h: This provides with some timeval functions if not provided
* by the system.
*/
#ifndef __TIMEVAL_H
#define __TIMEVAL_H
#ifndef _GNU_SOURCE
#include
void
timersub(struct timeval *a, struct timeval *b, struct timeval *res);
int
timerisset(struct timeval *tv);
void
timerclear(struct timeval *tv);
#define timercmp(a, b, CMP) \
(((a)->tv_sec == (b)->tv_sec) ? \
((a)->tv_usec CMP (b)->tv_usec) \
: ((a)->tv_sec CMP (b)->tv_sec))
#endif /* #ifndef _GNU_SOURCE */
#endif
superkb-0.23/version.h 0000664 0000000 0000000 00000000027 12210555441 0014745 0 ustar 00root root 0000000 0000000 #define VERSION "0.23"