Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Import sources to have something to work with |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
15eae1e8e6d2c5f44cb7d45393ec8257 |
| User & Date: | KhazAkar 2019-06-20 16:42:23.150 |
Context
|
2019-06-20
| ||
| 17:26 | Delete old, insanely made, build system check-in: 544f8a0572 user: KhazAkar tags: trunk | |
| 16:42 | Import sources to have something to work with check-in: 15eae1e8e6 user: KhazAkar tags: trunk | |
| 16:23 | initial empty check-in check-in: a6b737c603 user: KhazAkar tags: trunk | |
Changes
Added DISTRIBUTORS.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | Distributors ============ This file only applies to those who wish to distribute wmii in any form. The conditions herein do not apply to end users in any manner whatsoever. License Terms ============= wmii is licensed under the liberal MIT License. This license allows for free modification and distribution of the source code, so long as credit is given to the author. To this end, the LICENSE file, or an equivalent statement of its contents, MUST be distributed with any significant binary or source portions of this software. The file SHOULD be included with the software's documentation. The default installation sequence provides for this. Note that this condition only applies to distribution, and that the end user is under no obligation to keep or install a copy of the LICENSE file. Note also that this software may be sub-licensed under more restrictive terms, though the original LICENSE text MUST remain. The wmii Name ============= The following conditions apply to any distribution which uses the name wmii. These conditions apply only to wmii name, and not to its source code or any other included materials. When in doubt about any of these conditions or other matters of packaging or distribution, please contact the wmii mailing lists at <dev@suckless.org> or Kris Maglione <maglione.k@gmail.com>. The conditions herein MAY be contravened by any more lenient distribution terms agreed upon by the latter, which SHOULD replace this file in the form of a PGP signed permissions notice. Version Strings --------------- Any binary distribution of wmii MUST have a properly set VERSION string. This is the string printed by the 'wmii' binary when invoked with the '-v' flag. This string may normally be set in 'mk/wmii.mk'. Unmodified builds from the Mercurial tree automatically set this string based on the Mercurial local revision number, so long as the 'hg' command is present and properly functioning. Any version which is an official release, alpha, or beta, MUST contain the release version. Alpha and beta releases MUST be proceeded directly by "a" or "b" followed by the alpha or beta number respectively. wmii 4.0, Alpha 3, for instance, MUST be formatted as 4.0a3 Any version which is not an official release or snapshot MUST contain the Mercurial local revision number or changeset hash in its version string. The local revision number MUST be within 5 revisions of the equivalent changeset in the official canonical repositories at http://hg.suckless.org/ and http://wmii.googlecode.com/. This SHOULD be formatted as hgXXXX, where XXXX is the decimal revision number. The version string of any official snapshot release MUST, if it does not contain Mercurial revision information as above, contain the date of the snapshot in the form YYYYMMDD, and SHOULD contain the word snap or snapshot. The version string of a snapshot MAY contain the version name of a full release that the snapshot is expected to precede, but it MUST be either directly preceded, or directly followed by, the word 'pre', optionally separated by a non-alphanumeric character, including -~_,./. Modifications ------------- Any binary distribution which is modified in any non-trivial way MUST signify the modifications in its name or version string. This DOES NOT include minor patches to improve consistency with the rest of the system, including changing the default terminal emulator, POSIX-compliant shell, or installation prefix. Source form distribution MAY include non-trivial patches without such modifications, provided that the user is made clearly aware of them at build or install time and/or prompted in some way to enable or disable them. |
Added FAQ.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
wmii 3.10
@@ If you're reading this file before it's been installed,
@@ substitute the following directories for their placeholders.
@@ @DOCDIR@ doc/
@@ @EXAMPLES@ examples/
@@ @LOCALCONF@ ~/.wmii or ~/.wmii-hg (if this is a snapshot)
@@ @ALTDOC@ alternative_wmiircs/
@@
Frequently Asked Questions
==========================
1. I've just upgraded and something doesn't work.
-------------------------------------------------
If you compiled wmii yourself, please try again from a clean source
tree. If wmii still fails, try deleting or renaming your old
configuration files. If this fails, see questions #2.
2. I've read all of the docs, but I still need help.
----------------------------------------------------
You can get support[1] in the #suckless irc channel on irc.oftc.net, or
you can subscribe to the mailing list by sending an email to
dev+subscribe@suckless.org. You can also browse or search the
mailing list archives[2] at Gmane.
3. I think I've found a bug.
----------------------------
You can report bugs at the issue tracker at the Google Code
project[3]. Please be sure to search for your problem before you
open a new issue.
4. How do I get a list of keyboard shortcuts?
---------------------------------------------
The default keyboard shortcuts are listed in both the wmii(1)
manpage and in the user guide[4]. You can also get a list of all
current keyboard shortcuts at any time by selecting 'showkeys' from
the actions menu (M-a).
5. How do I customize wmii? How do I change my keyboard shortcuts?
------------------------------------------------------------------
You can customize wmii by editing its configuration script. If
you're using the stock wmiirc configuration script, you can add key
bindings and change your theme by editing @LOCALCONF@/wmiirc_local.
See @EXAMPLES@/wmiirc_local for more information. You should also be
sure to read wmii(1) and the user guide[4].
6. I've heard I can do my configuration in any language?
--------------------------------------------------------
While wmii is driven by a sh(1) script by default, it ships with
configuration scripts in several other languages, and more still are
available elsewhere on the web. See @ALTDOC@/README for more
information.
7. I've made some changes to my configuration. How do I reload it?
------------------------------------------------------------------
You can rerun your wmiirc script from the actions menu at any time.
If you're running the stock wmiirc, just select wmiirc. If you're
running the python wmiirc (and haven't moved it to
@LOCALCONF@/wmiirc), type python/wmiirc, and so on.
8. How do I restart wmii without killing X?
-------------------------------------------
You can either run 'exec wmii' from the actions menu or write
'exec wmii' to the /ctl virtual file.
9. Why is there space around my terminal windows?
-------------------------------------------------
Your terminal has asked to only be resized in certain increments,
and there's not enough space for another row. `wmii` is forced to
compromise and leave blank space around it. If you'd rather wmii to
ignore the terminal's request, write 'incmode ignore'[5] to the /ctl
virtual file. Note, though, that this will prevent `wmii`'s normal
behavior of trying to keep these increment gaps as small as
possible, and will therefore result in more wasted space than
otherwise.
10. On FreeBSD, using p9p[6], I get an error about not being able to open /dev/fd/7.
------------------------------------------------------------------------------------
You need to mount fdescfs on /dev/fd. See the BUGS section of rc(1)
for details.
11. How do I set a background image?
------------------------------------
This isn't the job of a window manager. You can set the background
with a third party tool, such as wmsetbg, Esetbg, feh, qiv,
xsetroot, etc.
12. How do I enable sequential shortcuts (like in ratpoison)?
or How do I use wmii with emacs? The shortcuts collide!
-------------------------------------------------------------
Some applications make extensive use of the Alt key. The preferred
solution is to use the Windows, Apple, or Penguin key in its place.
It's assigned the identifier Mod4 on most systems. Set the
following in wmiirc_local:
MODKEY=Mod4
Alternatively, you can use key chains, so you're required to press a
certain key combination before wmii accepts its shortcuts:
MODKEY=Control-i,
13. How do I find out the names of keys to define keyboard shorcuts?
--------------------------------------------------------------------
The easiest way is to run wikeyname(1) and type the key you want to
bind.
[1] http://suckless.org/community
[2] http://dir.gmane.org/gmane.comp.misc.suckless
[3] http://wmii.googlecode.com/
[4] @DOCDIR@/wmii.pdf
[5] For more information, see wmii(1).
[6] http://plan9.us
|
Added LICENSE.
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | Copyright © 2006-2010 Kris Maglione <maglione.k@gmail.com> Copyright © 2003-2006 Anselm R Garbe <anselm@garbe.us> Portions Copyright © 2002 by Lucent Technologies. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
Added Makefile.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
ROOT=.
include $(ROOT)/mk/hdr.mk
include $(ROOT)/mk/wmii.mk
DIRS = \
doc \
examples \
man \
lib \
cmd \
rc \
alternative_wmiircs
DOCS = FAQ \
LICENSE \
README.md
deb-dep:
IFS=', '; \
apt-get -qq install build-essential $$(sed -n 's/([^)]*)//; s/^Build-Depends: \(.*\)/\1/p' debian/control)
DISTRO = unstable
deb:
$(ROOT)/util/genchangelog wmii-hg $(VERSION) $(DISTRO)
dpkg-buildpackage -rfakeroot -b -nc
[ -d .hg ] && hg revert debian/changelog || true
include $(ROOT)/mk/dir.mk
|
Added NEWS.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
3.10b1:
* /colrules widths may now be specified in pixels.
* /tagrules has been replaced with the more general /rules
* The format of the bar files has changed.
* Add witray system tray program.
* Floating clients can be collapsed by clicking their layout boxes.
* Dock windows act more like dock windows.
* The FocusFloating and FocusColumn events have been removed.
* The tag '!' is no longer special.
* Xft is now loaded on demand.
3.9.2:
* Fixed some managed move bugs.
* Work around mawk bug that broke wmiirc.
3.9.1:
* Workaround a dash 0.5.6 bug that broke wmiirc.
* Noticably speed-up python wmiirc startup.
* Disable static linking which breaks wmiir in glibc 2.12.
3.9:
* wmii9menu is now Xinerama aware.
* Install READMEs to $(PREFIX)/share/doc/wmii/.
* Documentation updates. Add wmiir.1, wmii9menu.1.
* Allow dragging floating clients from anywhere in their titlebars.
* Allow specifying screen in area specs.
* Change default $MODKEY to Mod4.
* Minor changes to pygmi.events API.
* Allow client to follow tag change in python wmiirc.
* Update /tag/*/index to be more useful on Xinerama.
* Add showkeys action to shell and python wmiirc.
* Restore windows from floating layer to their original Xinerama screen.
* Hide bar on non-primary Xinerama screens.
* Allow resizing of rightmost and leftmost column dividers.
3.9a2:
* Add Suraj's Rumai-based wmiirc.
* Move rc.wmii to alternative_wmiircs/plan9port/wmiirc.
* Install wmii.pdf to $(PREFIX)/share/doc/.
* Focus windows regardless of whether they form a new group.
* Update selection and execution of wmiirc: no more magic.
* Update wmii.1
* Add alternative_wmiircs READMEs.
3.9a1:
* Add new wmii guide. See doc/wmii.pdf
* Allow for programmable completion in wimenu.
* Use pkg-config globally.
* Add Xft (antialiased font) support.
* Add python wmiirc/9P client library
* Allow bindings to work regardless of caps lock.
* Add M-f fullscreen toggle key binding.
* Augment /client/*/ctl Fullscreen command.
* Allow setting of increment display from /ctl.
* Show a client's extra tags in its titlebar.
* Darken background when floating area selected.
* Allow bar on top or bottom.
* Allow for wmiirc_local.
* Add grow and nudge commands to /tag/*/ctl.
* Cascade windows when the floating layer fills.
* Support alpha-transparant windows.
* Add regex tag support.
* It is now possible to float/unfloat windows with the mouse.
* Make the bar Xdnd aware; DND between views is now possible. Fixed some window raising/moving bugs.
* Add a notification bar.
* Improved floating mouse resizing.
* Improved mouse move/resize support for managed mode.
* Better return from floating/fullscreen to managed mode.
* Allow comments (#.*\n) in rules and ctl files.
* Add /client/*/ctl ‘slay’ command.
* Detect unresponsive clients on ‘kill’.
* Draw titlebars of floating clients differently.
* Add wihack: LD_PRELOAD hack to set window properties of programs:
* Respect window groups
* Add ‘Kill’ to client right-click menu
* wmii9menu now takes similar args to wimenu
* Document grow/nudge commands.
* Add wimenu with history and caret support
* Add wistrut. Undocumented, not built by default.
* EWMH strut support.
* Basic EWMH support.
* Better fullscreen support.
* XRandR support.
* Xinerama support.
2008-08-25:
* libixp version 97 now required
* Stack and max modes now affect floating clients:
- max: Collapsed clients disappear, all clients disappear
when managed layer is selected.
- stack: All clients but selected are collapsed.
* Adobe's Flash plugin's fullscreen mode now works.
* Some annoying focus bugs are fixed.
|
Added PKGBUILD.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
pkgname=(wmii-hg python-pyxp-hg python-pygmi-hg)
pkgver=2755
pkgrel=1
pkgdesc="The latest hg pull of wmii, a lightweight, dynamic window manager for X11"
url="http://wmii.suckless.org"
license=(MIT)
arch=(i686 x86_64)
makedepends=(mercurial python "libixp-hg>="$(sed -rn <mk/wmii.mk 's/.*IXP_NEEDAPI=([0-9]+).*/\1/p'))
options=(!strip)
source=()
FORCE_VER=$(hg log -r . --template {rev})
_make() {
cd $startdir
make PREFIX=/usr \
PYPREFIX=--prefix=/usr \
ETC=/etc \
DESTDIR="$pkgdir" \
"$@"
}
build() {
_make "${flags[@]}" || return 1
}
package_wmii-hg() {
depends=(libx11 libxinerama libxrandr)
optdepends=("plan9port: for use of the alternative plan9port wmiirc" \
"${pkgname[2]}: for use of the alternative Python wmiirc" \
"ruby-rumai: for use of the alternative Ruby wmiirc" \
"libxft: for anti-aliased font support")
provides=(wmii)
conflicts=(wmii)
_make install PYMODULES= || return 1
install -m644 -D ./debian/file/wmii.desktop "$pkgdir/etc/X11/sessions/wmii.desktop"
install -m644 -D ./LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
}
package_python-pyxp-hg() {
pkgdesc="Python 9P client library"
arch=(any)
depends=(python)
_make -C alternative_wmiircs/python pyclean pyxp.install
}
package_python-pygmi-hg() {
pkgdesc="Python wmii interaction library"
arch=(any)
depends=(python-pyxp-hg)
_make -C alternative_wmiircs/python pyclean pygmi.install
}
|
Added README.md.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
[](https://travis-ci.org/0intro/wmii)
[](https://scan.coverity.com/projects/0intro-wmii)
Abstract
--------
wmii is a dynamic window manager for X11. It supports classic and
tiled window management with extended keyboard, mouse, and 9P-based[1]
remote control. It consists of the wmii(1) window manager and the
wmiir(1) the remote access utility.
Requirements
------------
In order to build wmii you need the Xlib header files and libixp.
xmessage is used by the default scripts. Libixp, if not provided, can
be obtained from http://libs.suckless.org/. On debian, you should be
able to obtain all dependencies by running `make deb-dep`. Python is
recommended for more advanced configurations.
Installation
------------
First, edit config.mk to match your local setup.
To build, simply run:
make
To install, run the following, as root if necessary:
make install
On debian, you should only have to run `make deb` to create a debian
package. No further configuration should be necessary.
Running wmii
------------
Add the following line to your .xinitrc to start wmii using startx:
until wmii; do :; done
In order to connect wmii to a specific display, make sure that the
DISPLAY environment variable is set correctly. For example:
DISPLAY=:1 wmii
This will start wmii on display :1.
Configuration
-------------
The configuration of wmii is done by customizing the rc script wmiirc,
which remotely controls the window manager and handles various events.
The main wmiirc script lives in @GLOBALCONF@ while wmiirc_local goes
in @LOCALCONF@.
More advanced versions of wmiirc are provided in python and ruby.
For more information on them, see alternative_wmiircs/README.
Credits
-------
The following people have contributed especially to wmii in various
ways:
- Christoph Wegscheider <christoph dot wegscheider at wegi dot net>
- Georg Neis <gn at suckless dot org>
- Uwe Zeisberger <zeisberg at informatik dot uni-freiburg dot de>
- Uriel <uriel99 at gmail dot com>
- Scot Doyle <scot at scotdoyle dot com>
- Sebastian Hartmann <seb dot wmi at gmx dot de>
- Bernhard Leiner <bleiner at gmail dot com>
- Jonas Domeij <jonas dot domeij at gmail dot com>
- Vincent <10 dot 50 at free dot fr>
- Oliver Kopp <olly at flupp dot de>
- Sebastian Roth <sebastian dot roth at gmail dot com>
- Nico Golde <nico at ngolde dot de>
- Steve Hoffman <steveh at g2switchworks dot com>
- Christof Musik <christof at senfdax dot de>
- Steffen Liebergeld <perl at gmx dot org>
- Tobias Walkowiak <wal at ivu dot de>
- Sander van Dijk <a dot h dot vandijk at gmail dot com>
- Salvador Peiro <saoret dot one at gmail dot com>
- Anthony Martin <ality at pbrane dot org>
- Icarus Sparry <wmii at icarus dot freeuk dot com>
- Norman Golisz <norman dot golisz at arcor dot de>
- Stefano K. Lee <wizinblack at gmail dot com >
- Stefan Tibus <sjti at gmx dot net>
- Neptun <neptun at gmail dot com>
- Daniel Wäber <_wabu at web dot de>
References
----------
[1] http://9p.cat-v.org
[2] http://plan9.us
|
Added TODO.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | BUGS * collapsed clients outside stacked mode don't always uncollapse when they receive focus * various qiv brokenness * dosbox won't grab the mouse 4.0 * Opaque managed moves. I know I've argued against it, but it may be doable. * Clicking layout boxes should do useful things. * Collapse/uncollapse frames with the keyboard. * Open modes (to replace colmodes). * Resizable managed area. Maybe. Struts seem to do everything this might. * New dmenu, with real cursor; snarfable. |
Added alternative_wmiircs/Makefile.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | ROOT=.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk BIN = $(GLOBALCONF) DIRS = python \ plan9port \ ruby DOCS = README DOCDIR = $(DOC)/alternative_wmiircs include $(ROOT)/mk/dir.mk |
Added alternative_wmiircs/README.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Alternative wmiirc scripts
==========================
This folder contains alternative implementations of wmii's rc
scripts. Each folder contains a different implementation,
described below, including its own README, wmiirc script, and
possibly other suppporting files and libraries. These scripts
are installed along with wmii to $(ETC) as defined in config.mk.
It usually suffices to start the included `wmiirc` script at
wmii startup. Invoking wmii with the flag '-r python/wmiirc',
for instance, will start the python implementation.
Alternatively, if you use a session manager, you can add this
line to @LOCALCONF@/wmiirc (which must be executable):
wmiir xwrite /ctl spawn python/wmiirc
Index
------------- ----------------------------------------------------
python/ A pure Python wmiirc implementation.
plan9port/ A Plan 9 Port/rc shell based wmiirc implementation
ruby/ A pure-ruby wmiirc implementation, by Suraj Kurapati
|
Added alternative_wmiircs/plan9port/Makefile.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | ROOT=../.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk DOCS = README EXECS = wmiirc DIR = $(GLOBALCONF)/plan9port DOCDIR = $(DOC)/alternative_wmiircs/plan9port |
Added alternative_wmiircs/plan9port/README.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | plan9port wmiirc ================ This directory contains a Plan 9 based wmiirc script. This script was traditionally the default wmiirc for wmii, but has been moved for portability reasons. To run this script, either Plan 9 from User Space[1] (plan9port for short) or 9base[2] is required. Modifications can be placed in @LOCALCONF@/wmiirc_local.rc, which must be executable. |
Added alternative_wmiircs/plan9port/wmiirc.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
#!/bin/sh -f
test $#* '=' 0 || {
p="$PATH"
which rc >/dev/null || PATH="$PLAN9:$p"
which rc >/dev/null || PATH="/usr/local/plan9/bin:$p"
which rc >/dev/null || PATH="/usr/local/9/bin:$p"
which rc >/dev/null || PATH="/opt/plan9/bin:$p"
which rc >/dev/null || PATH="/opt/9/bin:$p"
which rc >/dev/null || PATH="/usr/plan9/bin:$p"
which rc >/dev/null || PATH="/usr/9/bin:$p"
exec rc $0
}
cd
scriptname=$0
oldpath=$path; path=($PLAN9/bin $path)
. wmii.rc wmiirc # Include utility functions
# WMII Configuration
# Keys
MODKEY=Mod4
UP=k
DOWN=j
LEFT=h
RIGHT=l
# Bars
noticetimeout=5
noticebar=/rbar/!notice
# Theme
wmiifont='drift,-*-fixed-*-*-*-*-9-*-*-*-*-*-*-*'
wmiifont='-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*'
wmiinormcol=('#000000' '#c1c48b' '#81654f')
wmiifocuscol=('#000000' '#81654f' '#000000')
wmiibackground='#333333'
wmiifloatbackground='#222222'
fn setbackground { xsetroot -solid $* }
# Programs
WMII_TERM=(xterm)
# Column Rules
wmiir write /colrules <<!
/gimp/ -> 17+83+41
/.*/ -> 62+38 # Golden Ratio
!
# Tagging Rules
wmiir write /rules <<!
# Apps with system tray icons like to their main windows
# Give them permission.
/^Pidgin:/ allow=+activate
# MPlayer and VLC don't float by default, but should.
/MPlayer|VLC/ floating=on
# ROX puts all of its windows in the same group, so they open
# with the same tags. Disable grouping for ROX Filer.
/^ROX-Filer:/ group=0
!
# Status Bar Info
fn status {
echo -n label `{uptime | sed 's/.*://; s/, / /g'} '|' \
`{date} }
# Generic overridable startup details
fn startup { witray & }
# End Configuration
# For the time being, this file follows the lisp bracing
# convention. i.e.:
# if(frob this) {
# frob that
# if(frob theother) {
# unfrob this
# unfrob that}}
# Comments welcome.
confpath=`{echo $WMII_CONFPATH | sed 'y/:/ /'}
# Events
fn sigexit {
rm -f $progs_file
wi_cleankeys}
fn Event-CreateTag {
echo colors $wmiinormcol $wi_newline label $* | wmiir create /lbar/$"*}
fn Event-DestroyTag {
wmiir remove /lbar/$"*}
fn Event-FocusTag {
wmiir xwrite /lbar/$"* colors $wmiifocuscol}
fn Event-UnfocusTag {
wmiir xwrite /lbar/$"* colors $wmiinormcol}
fn Event-UrgentTag {
shift
wmiir xwrite /lbar/$"* label '*'$"*}
fn Event-NotUrgentTag {
shift
wmiir xwrite /lbar/$"* label $"*}
fn Event-AreaFocus {
if(~ $1 '~')
setbackground $wmiifloatbackground
if not
setbackground $wmiibackground }
fn Event-Unresponsive {
client = $1; shift
@{
msg = 'The following client is not responding. What would you like to do?'
resp = `{wihack -transient $client \
xmessage -nearmouse -buttons Kill,Wait -print \
$msg $wi_newline '' `{wmiir read /client/$client/label}}
if(~ $resp Kill)
wmiir xwrite /client/$client/ctl slay
}&}
fn Event-Notice {
wmiir xwrite $noticebar label $wi_arg
/bin/kill $xpid >[2]/dev/null # Let's hope this isn't reused...
{ sleep $noticetimeout; wmiir xwrite $noticebar ' ' }& # Bug...
xpid = $apid}
fn Event-LeftBar^(Click DND) {
shift; wmiir xwrite /ctl view $*}
fn ClientMenu-3-Delete {
wmiir xwrite /client/$1/ctl kill}
fn ClientMenu-3-Kill {
wmiir xwrite /client/$1/ctl slay}
fn ClientMenu-3-Fullscreen {
wmiir xwrite /client/$1/ctl Fullscreen on}
fn Event-ClientMouseDown {
wi_fnmenu Client $2 $1 &}
fn LBarMenu-3-Delete {
tag=$1; clients=`{wmiir read /tag/$tag/index | awk '/[^#]/{print $2}'}
for(c in $clients) {
if(~ $tag `{wmiir read /client/$c/tags})
wmiir xwrite /client/$c/ctl kill
if not
wmiir xwrite /client/$c/tags -$tag}
if(~ $tag `{wi_seltag}) {
newtag = `{wi_tags | awk -v't='$tag '
$1 == t { if(!l) getline l
print l
exit }
{ l = $0 }'}
wmiir xwrite /ctl view $newtag}}
fn Event-LeftBarMouseDown {
wi_fnmenu LBar $* &}
# Actions
fn Action-exec {
wmiir xwrite /ctl exec $*}
fn Action-quit {
wmiir xwrite /ctl quit}
fn Action-rehash {
comm -23 <{ls `{namespace}^/proglist.* >[2]/dev/null | awk -F'.' '{print $NF}'} \
<{ps | awk '{print $2}'} |
while(id=`{read})
rm `{namespace}^/proglist.$id
wi_proglist $PATH >$progs_file}
fn Action-showkeys {
echo $wmiikeyhelp | xmessage -file -
}
fn Action-status {
flag x -; flag r -
if(wmiir remove /rbar/status >[2]/dev/null)
sleep 2
echo colors $wmiinormcol | wmiir create /rbar/status
while(status | wmiir write /rbar/status)
sleep 1
}
# Source Variables, &c
if(~ $0 ('' */)wmiirc_local.rc)
wi_notice This file should not be named wmiirc_local.rc
if not
. `{wi_script -f wmiirc_local.rc}
echo colors $wmiinormcol | wmiir create $noticebar
startup
# Key Bindings
_keys = `{wi_getfuns Key}
fn keygroup {
wmiikeyhelp = $wmiikeyhelp ^ $wi_newline ^ ' ' ^ $"* ^ $wi_newline}
fn key {
help=$1; shift
key=()
for(k) {
if(! ~ $k $_keys) {
ifs=() { wmiikeyhelp = `{
printf "%s %- 20s %s\n" $wmiikeyhelp $k $help}}
key = ($key Key-$k)}}
~ $#key 0}
keygroup Moving around
key 'Select the client to the left' $MODKEY-$LEFT || fn $key {
wmiir xwrite /tag/sel/ctl select left}
key 'Select the client to the right' $MODKEY-$RIGHT || fn $key {
wmiir xwrite /tag/sel/ctl select right}
key 'Select the client below' $MODKEY-$DOWN || fn $key {
wmiir xwrite /tag/sel/ctl select down}
key 'Select the client above' $MODKEY-$UP || fn $key {
wmiir xwrite /tag/sel/ctl select up}
key 'Toggle between floating and managed layers' $MODKEY-space || fn $key {
wmiir xwrite /tag/sel/ctl select toggle}
keygroup Moving through stacks
key 'Select the stack below' $MODKEY-Control-$DOWN || fn $key {
wmiir xwrite /tag/sel/ctl select down stack}
key 'Select the stack above' $MODKEY-Control-$UP || fn $key {
wmiir xwrite /tag/sel/ctl select up stack}
keygroup Moving clients around
key 'Move selected client to the left' $MODKEY-Shift-$LEFT || fn $key {
wmiir xwrite /tag/sel/ctl send sel left}
key 'Move selected client to the right' $MODKEY-Shift-$RIGHT || fn $key {
wmiir xwrite /tag/sel/ctl send sel right}
key 'Move selected client down' $MODKEY-Shift-$DOWN || fn $key {
wmiir xwrite /tag/sel/ctl send sel down}
key 'Move selected client up' $MODKEY-Shift-$UP || fn $key {
wmiir xwrite /tag/sel/ctl send sel up}
key 'Toggle selected client between floating and managed layers' $MODKEY-Shift-space || fn $key {
wmiir xwrite /tag/sel/ctl send sel toggle}
keygroup Client actions
key 'Toggle selected client''s fullsceen state' $MODKEY-f || fn $key {
wmiir xwrite /client/sel/ctl Fullscreen toggle}
key 'Close client' $MODKEY-Shift-c || fn $key {
wmiir xwrite /client/sel/ctl kill}
keygroup Changing column modes
key 'Set column to default mode' $MODKEY-d || fn $key {
wmiir xwrite /tag/sel/ctl colmode sel default-max}
key 'Toggle between floating and managed layers' $MODKEY-s || fn $key {
wmiir xwrite /tag/sel/ctl colmode sel stack-max}
key 'Set column to max mode' $MODKEY-m || fn $key {
wmiir xwrite /tag/sel/ctl colmode sel stack+max}
keygroup Running programs
key 'Open wmii actions menu' $MODKEY-a || fn $key {
Action `{wi_actions | wimenu -h $hist.action -n $histlen} &}
key 'Open program menu' $MODKEY-p || fn $key {
ifs=() { cmd = `{wimenu -h $hist.prog -n $histlen <$progs_file} }
wi_runcmd $cmd & }
key 'Launch a terminal' $MODKEY-Return || fn $key {
wi_runcmd $WMII_TERM &}
keygroup Other
key 'Toggle all other key bindings' $MODKEY-Control-t || fn $key {
switch(`{wmiir read /keys | wc -l}) {
case 0 1
wmiir xwrite /keys $keys
wmiir xwrite /ctl grabmod $MODKEY
case *
ifs=() { keys=`{wmiir read /keys} }
wmiir xwrite /keys $MODKEY-Control-t
wmiir xwrite /ctl grabmod Mod3
}}
keygroup Tag actions
key 'Change to another tag' $MODKEY-t || fn $key {
tag=`{wi_tags | wimenu -h $hist.tag -n 50} && wmiir xwrite /ctl view $tag &}
key 'Retag the selected client' $MODKEY-Shift-t || fn $key {
sel=`{wi_selclient} {
tag=`{wi_tags | wimenu -h $hist.tag -n 50} && wmiir xwrite /client/$sel/tags $tag } &}
key 'Move to the next tag' $MODKEY-n || fn $key {
wmiir xwrite /ctl view `{wi_tags | wi_nexttag}}
key 'Move to the previous tag' $MODKEY-b || fn $key {
wmiir xwrite /ctl view `{wi_tags | sort -r | wi_nexttag}}
key 'Move to the numbered view' $MODKEY-^`{seq 0 9} || fn $key {
wmiir xwrite /ctl view `{echo $1 | sed 's/.*-//'}}
key 'Retag selected client with the numbered tag' Shift-$MODKEY-^`{seq 0 9} || fn $key {
wmiir xwrite /client/sel/tags `{echo $1 | sed 's/.*-//'}}
# WM Configuration
wmiir write /ctl <<!
grabmod $MODKEY
border 2
font $wmiifont
focuscolors $wmiifocuscol
normcolors $wmiinormcol
!
setbackground $wmiibackground
# Source Overrides
Action overridekeys
# Misc Setup
progs_file=`{namespace}^/proglist.$pid
hist=`{echo $WMII_CONFPATH | sed 's,:.*,/,'}^/history
histlen=5000
Action status &
Action rehash &
# Tag Bar Setup
ifs=$wi_newline {
rc -c 'wmiir rm /lbar/^$*' >[2]/dev/null \
`{comm -23 <{wmiir ls /lbar} \
<{wi_tags}}
seltag=`{wi_seltag}
for(tag in `{wi_tags}) {{
if(~ $tag $seltag)
echo colors $wmiifocuscol $wi_newline label $tag
if not
echo colors $wmiinormcol $wi_newline label $tag
} | wmiir create /lbar/$tag}}
wi_eventloop
|
Added alternative_wmiircs/python/Makefile.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ROOT=../.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk PYMODULES = pyxp pygmi DOCS = README EXECS = wmiirc TEXT = wmiirc.py DIR = $(GLOBALCONF)/python DOCDIR = $(DOC)/alternative_wmiircs/python include $(ROOT)/mk/python.mk |
Added alternative_wmiircs/python/README.
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Python wmiirc ============= This directory contains a pure Python implementation of wmiirc. The two included libraries, pyxp and pygmi, are a 9P client and wmii filesystem utility module, respectively. To use this library, simply copy the contents of this direcctory to @LOCALCONF@. To customize it, either modify wmiirc.py directly, or create wmii_local.py and store your modifications there. The latter approach is preferable in that future modifications to wmiirc.py can usually be painlessly integrated. The documentation is sparse, but wmiirc.py should serve as a fairly comprehensive example. |
Added alternative_wmiircs/python/pygmi.py.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/usr/bin/env python
from distutils.core import setup
setup(name='pygmi',
version='0.2',
description='Python wmii interaction library',
author='Kris Maglione',
author_email='maglione.k@gmail.com',
url='http://wmii.suckless.org',
packages=['pygmi'],
license='MIT',
)
|
Added alternative_wmiircs/python/pygmi/__init__.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import os
import sys
from pyxp.asyncclient import Client
if 'WMII_ADDRESS' in os.environ:
client = Client(os.environ['WMII_ADDRESS'])
else:
client = Client(namespace='wmii')
confpath = os.environ.get('WMII_CONFPATH', '%s/.wmii' % os.environ['HOME']).split(':')
shell = os.environ['SHELL']
sys.path += confpath
from pygmi.util import *
from pygmi.event import *
from pygmi.fs import *
from pygmi.menu import *
from pygmi.monitor import *
from pygmi import util, event, fs, menu, monitor
__all__ = (fs.__all__ + monitor.__all__ + event.__all__ +
menu.__all__ + util.__all__ +
('client', 'confpath', 'shell'))
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pygmi/event.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
import os
import re
import sys
import traceback
import pygmi
from pygmi.util import prop
from pygmi import monitor, client, curry, call, program_list, _
__all__ = ('keys', 'events', 'Match')
class Match(object):
"""
A class used for matching events based on simple patterns.
"""
def __init__(self, *args):
"""
Creates a new Match object based on arbitrary arguments
which constitute a match pattern. Each argument matches an
element of the original event. Arguments are matched based
on their type:
_: Matches anything
set: Matches any string equal to any of its elements
list: Matches any string equal to any of its elements
tuple: Matches any string equal to any of its elements
Additionally, any type with a 'search' attribute matches if
that callable attribute returns True given element in
question as its first argument.
Any other object matches if it compares equal to the
element.
"""
self.args = args
self.matchers = []
for a in args:
if a is _:
a = lambda k: True
elif isinstance(a, basestring):
a = a.__eq__
elif isinstance(a, (list, tuple, set)):
a = (lambda ary: (lambda k: k in ary))(a)
elif hasattr(a, 'search'):
a = a.search
else:
a = str(a).__eq__
self.matchers.append(a)
def match(self, string):
"""
Returns true if this object matches an arbitrary string when
split on ascii spaces.
"""
ary = string.split(' ', len(self.matchers))
if all(m(a) for m, a in zip(self.matchers, ary)):
return ary
def flatten(items):
"""
Given an iterator which returns (key, value) pairs, returns a
new iterator of (k, value) pairs such that every list- or
tuple-valued key in the original sequence yields an individual
pair.
Example: flatten({(1, 2, 3): 'foo', 4: 'bar'}.items()) ->
(1, 'foo'), (2: 'foo'), (3: 'foo'), (4: 'bar')
"""
for k, v in items:
if isinstance(k, (list, tuple)):
for key in k:
yield key, v
else:
yield k, v
class Events():
"""
A class to handle events read from wmii's '/event' file.
"""
def __init__(self):
"""
Initializes the event handler
"""
self.events = {}
self.eventmatchers = {}
self.alive = True
def dispatch(self, event, args=''):
"""
Distatches an event to any matching event handlers.
The handler which specifically matches the event name will
be called first, followed by any handlers with a 'match'
method which matches the event name concatenated to the args
string.
Param event: The name of the event to dispatch.
Param args: The single arguments string for the event.
"""
try:
if event in self.events:
self.events[event](args)
for matcher, action in self.eventmatchers.iteritems():
ary = matcher.match(' '.join((event, args)))
if ary is not None:
action(*ary)
except Exception, e:
try:
traceback.print_exc(sys.stderr)
except:
pass
def loop(self):
"""
Enters the event loop, reading lines from wmii's '/event'
and dispatching them, via #dispatch, to event handlers.
Continues so long as #alive is True.
"""
keys.mode = 'main'
for line in client.readlines('/event'):
if not self.alive:
break
self.dispatch(*line.split(' ', 1))
self.alive = False
def bind(self, items={}, **kwargs):
"""
Binds a number of event handlers for wmii events. Keyword
arguments other than 'items' are added to the 'items' dict.
Handlers are called by #loop when a matching line is read
from '/event'. Each handler is called with, as its sole
argument, the string read from /event with its first token
stripped.
Param items: A dict of action-handler pairs to bind. Passed
through pygmi.event.flatten. Keys with a 'match' method,
such as pygmi.event.Match objects or regular expressions,
are matched against the entire event string. Any other
object matches if it compares equal to the first token of
the event.
"""
kwargs.update(items)
for k, v in flatten(kwargs.iteritems()):
if hasattr(k, 'match'):
self.eventmatchers[k] = v
else:
self.events[k] = v
def event(self, fn):
"""
A decorator which binds its wrapped function, as via #bind,
for the event which matches its name.
"""
self.bind({fn.__name__: fn})
events = Events()
class Keys(object):
"""
A class to manage wmii key bindings.
"""
def __init__(self):
"""
Initializes the class and binds an event handler for the Key
event, as via pygmi.event.events.bind.
Takes no arguments.
"""
self.modes = {}
self.modelist = []
self.mode = 'main'
self.defs = {}
events.bind(Key=self.dispatch)
def _add_mode(self, mode):
if mode not in self.modes:
self.modes[mode] = {
'name': mode,
'desc': {},
'groups': [],
'keys': {},
'import': {},
}
self.modelist.append(mode)
mode = property(lambda self: self._mode,
doc="The current mode for which to dispatch keys")
@mode.setter
def mode(self, mode):
self._add_mode(mode)
self._mode = mode
self._keys = dict((k % self.defs, v) for k, v in
self.modes[mode]['keys'].items() +
self.modes[mode]['import'].items());
if hasattr(self, 'defs'):
client.write('/keys', '\n'.join(self._keys.keys()) + '\n')
@prop(doc="Returns a short help text describing the bound keys in all modes")
def help(self):
return '\n\n'.join(
('Mode %s\n' % mode['name']) +
'\n\n'.join((' %s\n' % str(group or '')) +
'\n'.join(' %- 20s %s' % (key % self.defs,
mode['keys'][key].__doc__)
for key in mode['desc'][group])
for group in mode['groups'])
for mode in (self.modes[name]
for name in self.modelist))
def bind(self, mode='main', keys=(), import_={}):
"""
Binds a series of keys for the given 'mode'. Keys may be
specified as a dict or as a sequence of tuple values and
strings.
In the latter case, documentation may be interspersed with
key bindings. Any value in the sequence which is not a tuple
begins a new key group, with that value as a description.
A tuple with two values is considered a key-value pair,
where the value is the handler for the named key. A
three valued tuple is considered a key-description-value
tuple, with the same semantics as above.
Each key binding is interpolated with the values of
#defs, as if processed by (key % self.defs)
Param mode: The name of the mode for which to bind the keys.
Param keys: A sequence of keys to bind.
Param import_: A dict specifying keys which should be
imported from other modes, of the form
{ 'mode': ['key1', 'key2', ...] }
"""
self._add_mode(mode)
mode = self.modes[mode]
group = None
def add_desc(key, desc):
if group not in mode['desc']:
mode['desc'][group] = []
mode['groups'].append(group)
if key not in mode['desc'][group]:
mode['desc'][group].append(key);
if isinstance(keys, dict):
keys = keys.iteritems()
for obj in keys:
if isinstance(obj, tuple) and len(obj) in (2, 3):
if len(obj) == 2:
key, val = obj
desc = ''
elif len(obj) == 3:
key, desc, val = obj
mode['keys'][key] = val
add_desc(key, desc)
val.__doc__ = str(desc)
else:
group = obj
def wrap_import(mode, key):
return lambda k: self.modes[mode]['keys'][key](k)
for k, v in flatten((v, k) for k, v in import_.iteritems()):
mode['import'][k % self.defs] = wrap_import(v, k)
def dispatch(self, key):
"""
Dispatches a key event for the current mode.
Param key: The key spec for which to dispatch.
"""
mode = self.modes[self.mode]
if key in self._keys:
return self._keys[key](key)
keys = Keys()
class Actions(object):
"""
A class to represent user-callable actions. All methods without
leading underscores in their names are treated as callable actions.
"""
def __getattr__(self, name):
if name.startswith('_') or name.endswith('_'):
raise AttributeError()
if hasattr(self, name + '_'):
return getattr(self, name + '_')
cmd = pygmi.find_script(name)
if not cmd:
raise AttributeError()
return lambda args='': call(pygmi.shell, '-c', '$* %s' % args, '--', cmd,
background=True)
def _call(self, args):
"""
Calls a method named for the first token of 'args', with the
rest of the string as its first argument. If the method
doesn't exist, a trailing underscore is appended.
"""
a = args.split(' ', 1)
if a:
getattr(self, a[0])(*a[1:])
@prop(doc="Returns the names of the public methods callable as actions, with trailing underscores stripped.")
def _choices(self):
return sorted(
program_list(pygmi.confpath) +
[re.sub('_$', '', k) for k in dir(self)
if not re.match('^_', k) and callable(getattr(self, k))])
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pygmi/fs.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 |
import collections
from datetime import datetime, timedelta
import re
from pyxp import *
from pyxp.client import *
from pygmi import *
from pygmi.util import prop
__all__ = ('wmii', 'Tags', 'Tag', 'Area', 'Frame', 'Client',
'Button', 'Colors', 'Color', 'Toggle', 'Always', 'Never')
spacere = re.compile(r'\s')
sentinel = {}
def tounicode(obj):
if isinstance(obj, str):
return obj.decode('UTF-8')
return unicode(obj)
class utf8(object):
def __str__(self):
return unicode(self).encode('utf-8')
@apply
class Toggle(utf8):
def __unicode__(self):
return unicode(self.__class__.__name__)
@apply
class Always(Toggle.__class__):
pass
@apply
class Never(Toggle.__class__):
pass
def constrain(min, max, val):
return min if val < min else max if val > max else val
class Map(collections.Mapping):
def __init__(self, cls, *args):
self.cls = cls
self.args = args
def __repr__(self):
return 'Map(%s%s)' % (self.cls.__name__, (', %s' % ', '.join(map(repr, self.args)) if self.args else ''))
def __getitem__(self, item):
ret = self.cls(*(self.args + (item,)))
if not ret.exists:
raise KeyError('no such %s %s' % (self.cls.__name__.lower(), repr(item)))
return ret
def __len__(self):
return len(iter(self))
def __keys__(self):
return [v for v in self.cls.all(*self.args)]
def __iter__(self):
return (v for v in self.cls.all(*self.args))
def iteritems(self):
return ((v, self.cls(*(self.args + (v,)))) for v in self.cls.all(*self.args))
def itervalues(self):
return (self.cls(*(self.args + (v,))) for v in self.cls.all(*self.args))
class Ctl(object):
"""
An abstract class to represent the 'ctl' files of the wmii filesystem.
Instances act as live, writable dictionaries of the settings represented
in the file.
Abstract roperty ctl_path: The path to the file represented by this
control.
Property ctl_hasid: When true, the first line of the represented
file is treated as an id, rather than a key-value pair. In this
case, the value is available via the 'id' property.
Property ctl_types: A dict mapping named dictionary keys to two valued
tuples, each containing a decoder and encoder function for the
property's plain text value.
"""
ctl_types = {}
ctl_hasid = False
ctl_open = 'aopen'
ctl_file = None
def __eq__(self, other):
if self.ctl_hasid and isinstance(other, Ctl) and other.ctl_hasid:
return self.id == other.id
return False
def __init__(self):
self.cache = {}
def ctl(self, *args):
"""
Arguments are joined by ascii spaces and written to the ctl file.
"""
def next(file):
if file:
self.ctl_file = file
file.awrite(u' '.join(map(tounicode, args)))
if self.ctl_file:
return next(self.ctl_file)
getattr(client, self.ctl_open)(self.ctl_path, callback=next, mode=OWRITE)
def __getitem__(self, key):
for line in self.ctl_lines():
key_, rest = line.split(' ', 1)
if key_ == key:
if key in self.ctl_types:
return self.ctl_types[key][0](rest)
return rest
raise KeyError()
def __hasitem__(self, key):
return key in self.keys()
def __setitem__(self, key, val):
assert '\n' not in key
self.cache[key] = val
if key in self.ctl_types:
if self.ctl_types[key][1] is None:
raise NotImplementedError('%s: %s is not writable' % (self.ctl_path, key))
val = self.ctl_types[key][1](val)
self.ctl(key, val)
def get(self, key, default=sentinel):
"""
Gets the instance's dictionary value for 'key'. If the key doesn't
exist, 'default' is returned. If 'default' isn't provided and the key
doesn't exist, a KeyError is raised.
"""
try:
return self[key]
except KeyError, e:
if default is not self.sentinel:
return default
raise e
def set(self, key, val):
"""
Sets the dictionary value for 'key' to 'val', as self[key] = val
"""
self[key] = val
def keys(self):
return [line.split(' ', 1)[0]
for line in self.ctl_lines()]
def iteritems(self):
return (tuple(line.split(' ', 1))
for line in self.ctl_lines())
def items(self):
return [tuple(line.split(' ', 1))
for line in self.ctl_lines()]
def ctl_lines(self):
"""
Returns the lines of the ctl file as a tuple, with the first line
stripped if #ctl_hasid is set.
"""
lines = tuple(client.readlines(self.ctl_path))
if self.ctl_hasid:
lines = lines[1:]
return lines
_id = None
@prop(doc="If #ctl_hasid is set, returns the id of this ctl file.")
def id(self):
if self._id is None and self.ctl_hasid:
return self.name_read(client.read(self.ctl_path).split('\n', 1)[0])
return self._id
class Dir(Ctl):
"""
An abstract class representing a directory in the wmii filesystem with a
ctl file and sub-objects.
Abstract property base_path: The path directly under which all objects
represented by this class reside. e.g., /client, /tag
"""
ctl_hasid = True
name_read = unicode
name_write = unicode
def __init__(self, id):
"""
Initializes the directory object.
Param id: The id of the object in question. If 'sel', the object
dynamically represents the selected object, even as it
changes. In this case, #id will return the actual ID of the
object.
"""
super(Dir, self).__init__()
if isinstance(id, Dir):
id = id.id
if id != 'sel':
self._id = self.name_read(id)
def __eq__(self, other):
return (self.__class__ == other.__class__ and
self.id == other.id)
class ctl_property(object):
"""
A class which maps instance properties to ctl file properties.
"""
def __init__(self, key):
self.key = key
def __get__(self, dir, cls):
return dir.get(self.key, None)
def __set__(self, dir, val):
dir[self.key] = val
class toggle_property(ctl_property):
"""
A class which maps instance properties to ctl file properties. The
values True and False map to the strings "on" and "off" in the
filesystem.
"""
props = {
'on': True,
'off': False,
'toggle': Toggle,
'always': Always,
'never': Never
}
def __get__(self, dir, cls):
val = dir[self.key]
if val in self.props:
return self.props[val]
return val
def __set__(self, dir, val):
for k, v in self.props.iteritems():
if v == val:
val = k
break
dir[self.key] = val
class file_property(object):
"""
A class which maps instance properties to files in the directory
represented by this object.
"""
def __init__(self, name, writable=False):
self.name = name
self.writable = writable
def __get__(self, dir, cls):
return client.read('%s/%s' % (dir.path, self.name))
def __set__(self, dir, val):
if not self.writable:
raise NotImplementedError('File %s is not writable' % self.name)
return client.awrite('%s/%s' % (dir.path, self.name),
str(val))
@prop(doc="The path to this directory's ctl file")
def ctl_path(self):
return '%s/ctl' % self.path
@prop(doc="The path to this directory")
def path(self):
return '%s/%s' % (self.base_path, self.name_write(self._id or 'sel'))
@prop(doc="True if the given object exists in the wmii filesystem")
def exists(self):
return bool(client.stat(self.path))
@classmethod
def all(cls):
"""
Returns all of the objects that exist for this type of directory.
"""
return (cls.name_read(s.name)
for s in client.readdir(cls.base_path)
if s.name != 'sel')
@classmethod
def map(cls, *args):
return Map(cls, *args)
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__,
repr(self._id or 'sel'))
class Client(Dir):
"""
A class which represents wmii clients. Maps to the directories directly
below /client.
"""
base_path = '/client'
ctl_types = {
'group': (lambda s: int(s, 16), str),
'pid': (int, None),
}
@staticmethod
def name_read(name):
if isinstance(name, int):
return name
try:
return int(name, 16)
except:
return unicode(name)
name_write = lambda self, name: name if isinstance(name, basestring) else '%#x' % name
allow = Dir.ctl_property('allow')
fullscreen = Dir.toggle_property('fullscreen')
group = Dir.ctl_property('group')
pid = Dir.ctl_property('pid')
tags = Dir.ctl_property('tags')
urgent = Dir.toggle_property('urgent')
label = Dir.file_property('label', writable=True)
props = Dir.file_property('props')
def kill(self):
"""Politely asks a client to quit."""
self.ctl('kill')
def slay(self):
"""Forcibly severs a client's connection to the X server."""
self.ctl('slay')
class liveprop(object):
def __init__(self, get):
self.get = get
self.attr = str(self)
def __get__(self, area, cls):
if getattr(area, self.attr, sentinel) is not sentinel:
return getattr(area, self.attr)
return self.get(area)
def __set__(self, area, val):
setattr(area, self.attr, val)
class Area(object):
def __init__(self, tag, ord, screen='sel', offset=sentinel, width=sentinel, height=sentinel, frames=sentinel):
self.tag = tag
if ':' in str(ord):
screen, ord = ord.split(':', 2)
self.ord = str(ord)
self.screen = str(screen)
self.offset = offset
self.width = width
self.height = height
self.frames = frames
def prop(key):
@liveprop
def prop(self):
for area in self.tag.index:
if str(area.ord) == str(self.ord):
return getattr(area, key)
return prop
offset = prop('offset')
width = prop('width')
height = prop('height')
frames = prop('frames')
@property
def spec(self):
if self.screen is not None:
return '%s:%s' % (self.screen, self.ord)
return self.ord
@property
def mode(self):
for k, v in self.tag.iteritems():
if k == 'colmode':
v = v.split(' ')
if v[0] == self.ord:
return v[1]
@mode.setter
def mode(self, val):
self.tag['colmode %s' % self.spec] = val
def grow(self, dir, amount=None):
self.tag.grow(self, dir, amount)
def nudge(self, dir, amount=None):
self.tag.nudge(self, dir, amount)
class Frame(object):
live = False
def __init__(self, client, area=sentinel, ord=sentinel, offset=sentinel, height=sentinel):
self.client = client
self.ord = ord
self.offset = offset
self.height = height
@property
def width(self):
return self.area.width
def prop(key):
@liveprop
def prop(self):
for area in self.tag.index:
for frame in area.frames:
if frame.client == self.client:
return getattr(frame, key)
return prop
offset = prop('area')
offset = prop('ord')
offset = prop('offset')
height = prop('height')
def grow(self, dir, amount=None):
self.area.tag.grow(self, dir, amount)
def nudge(self, dir, amount=None):
self.area.tag.nudge(self, dir, amount)
class Tag(Dir):
base_path = '/tag'
@classmethod
def framespec(cls, frame):
if isinstance(frame, Frame):
frame = frame.client
if isinstance(frame, Area):
frame = (frame.ord, 'sel')
if isinstance(frame, Client):
if frame._id is None:
return 'sel sel'
return 'client %s' % frame.id
elif isinstance(frame, basestring):
return frame
else:
return '%s %s' % tuple(map(str, frame))
def dirspec(cls, dir):
if isinstance(dir, tuple):
dir = ' '.join(dir)
return dir
@property
def selected(self):
return tuple(self['select'].split(' '))
@selected.setter
def selected(self, frame):
if not isinstance(frame, basestring) or ' ' not in frame:
frame = self.framespec(frame)
self['select'] = frame
@property
def selclient(self):
for k, v in self.iteritems():
if k == 'select' and 'client' in v:
return Client(v.split(' ')[1])
return None
@selclient.setter
def selclient(self, val):
self['select'] = self.framespec(val)
@property
def selcol(self):
return Area(self, self.selected[0])
@property
def index(self):
areas = []
for l in (l.split(' ')
for l in client.readlines('%s/index' % self.path)
if l):
if l[0] == '#':
m = re.match(r'(?:(\d+):)?(\d+|~)', l[1])
if m.group(2) == '~':
area = Area(tag=self, screen=m.group(1), ord=l[1], width=l[2],
height=l[3], frames=[])
else:
area = Area(tag=self, screen=m.group(1) or 0,
height=None, ord=m.group(2), offset=l[2], width=l[3],
frames=[])
areas.append(area)
i = 0
else:
area.frames.append(
Frame(client=Client(l[1]), area=area, ord=i,
offset=l[2], height=l[3]))
i += 1
return areas
def delete(self):
id = self.id
for a in self.index:
for f in a.frames:
if f.client.tags == id:
f.client.kill()
else:
f.client.tags = '-%s' % id
if self == Tag('sel'):
Tags.instance.select(Tags.instance.next())
def select(self, frame, stack=False):
self['select'] = '%s %s' % (
self.framespec(frame),
stack and 'stack' or '')
def send(self, src, dest, stack=False, cmd='send'):
if isinstance(src, tuple):
src = ' '.join(src)
if isinstance(src, Frame):
src = src.client
if isinstance(src, Client):
src = src._id or 'sel'
if isinstance(dest, tuple):
dest = ' '.join(dest)
self[cmd] = '%s %s' % (src, dest)
def swap(self, src, dest):
self.send(src, dest, cmd='swap')
def nudge(self, frame, dir, amount=None):
frame = self.framespec(frame)
self['nudge'] = '%s %s %s' % (frame, dir, str(amount or ''))
def grow(self, frame, dir, amount=None):
frame = self.framespec(frame)
self['grow'] = '%s %s %s' % (frame, dir, str(amount or ''))
class Color(utf8):
def __init__(self, colors):
if isinstance(colors, Color):
colors = colors.rgb
elif isinstance(colors, basestring):
match = (re.match(r'^#(..)(..)(..)((?:..)?)$', colors) or
re.match(r'^rgba:(..)/(..)/(..)/(..)$', colors))
colors = tuple(int(match.group(group), 16) for group in range(1, 4))
if match.group(4):
colors += int(match.group(4), 16),
def toint(val):
if isinstance(val, float):
val = int(255 * val)
assert 0 <= val <= 255
return val
self.rgb = tuple(map(toint, colors))
def __getitem__(self, key):
if isinstance(key, basestring):
key = {'red': 0, 'green': 1, 'blue': 2}[key]
return self.rgb[key]
@property
def hex(self):
if len(self.rgb) > 3:
return 'rgba:%02x/%02x/%02x/%02x' % self.rgb
return '#%02x%02x%02x' % self.rgb
def __unicode__(self):
if len(self.rgb) > 3:
return 'rgba(%d, %d, %d, %d)' % self.rgb
return 'rgb(%d, %d, %d)' % self.rgb
def __repr__(self):
return 'Color(%s)' % repr(self.rgb)
class Colors(utf8):
def __init__(self, foreground=None, background=None, border=None):
vals = foreground, background, border
self.vals = tuple(map(Color, vals))
def __iter__(self):
return iter(self.vals)
def __list__(self):
return list(self.vals)
def __tuple__(self):
return self.vals
@classmethod
def from_string(cls, val):
return cls(*val.split(' '))
def __getitem__(self, key):
if isinstance(key, basestring):
key = {'foreground': 0, 'background': 1, 'border': 2}[key]
return self.vals[key]
def __unicode__(self):
return ' '.join(c.hex for c in self.vals)
def __repr__(self):
return 'Colors(%s, %s, %s)' % tuple(repr(c.rgb) for c in self.vals)
class Button(Ctl):
sides = {
'left': 'lbar',
'right': 'rbar',
}
ctl_types = {
'colors': (Colors.from_string, lambda c: str(Colors(*c))),
}
ctl_open = 'acreate'
colors = Dir.ctl_property('colors')
label = Dir.ctl_property('label')
def __init__(self, side, name, colors=None, label=None):
super(Button, self).__init__()
self.side = side
self.name = name
self.base_path = self.sides[side]
self.ctl_path = '%s/%s' % (self.base_path, self.name)
self.ctl_file = None
if colors or label:
self.create(colors, label)
def create(self, colors=None, label=None):
if not self.ctl_file:
self.ctl_file = client.create(self.ctl_path, ORDWR)
if colors:
self.colors = colors
if label:
self.label = label
def remove(self):
if self.ctl_file:
self.ctl_file.aremove()
self.ctl_file = None
@property
def exists(self):
return bool(self.file.stat() if self.file else client.stat(self.ctl_path))
@classmethod
def all(cls, side):
return (s.name
for s in client.readdir(cls.sides[side])
if s.name != 'sel')
@classmethod
def map(cls, *args):
return Map(cls, *args)
class Rules(collections.MutableMapping, utf8):
_items = ()
def __init__(self, path, rules=None):
self.path = path
if rules:
self.setitems(rules)
_quotere = re.compile(ur'(\\(.)|/)')
@classmethod
def quoteslash(cls, str):
return cls._quotere.sub(lambda m: m.group(0) if m.group(2) else r'\/', str)
__get__ = lambda self, obj, cls: self
def __set__(self, obj, val):
self.setitems(val)
def __getitem__(self, key):
for k, v in self.iteritems():
if k == key:
return v
raise KeyError()
def __setitem__(self, key, val):
items = [(k, v) for k, v in self.iteritems() if k != key]
items.append((key, val))
self.setitems(items)
def __delitem__(self, key):
self.setitems((k, v) for k, v in self.iteritems() if k != key)
def __len__(self):
return len(tuple(self.iteritems()))
def __iter__(self):
return (k for k, v in self.iteritems())
def __list__(self):
return list(iter(self))
def __tuple__(self):
return tuple(iter(self))
def append(self, item):
self.setitems(self + (item,))
def __add__(self, items):
return tuple(self.iteritems()) + tuple(items)
def rewrite(self):
client.awrite(self.path, unicode(self))
def setitems(self, items):
self._items = [(k, v if isinstance(v, Rule) else Rule(self, k, v))
for (k, v) in items]
self.rewrite()
def __unicode__(self):
return u''.join(unicode(value) for (key, value) in self.iteritems()) or u'\n'
def iteritems(self):
return iter(self._items)
def items(self):
return list(self._items())
class Rule(collections.MutableMapping, utf8):
_items = ()
parent = None
@classmethod
def quotekey(cls, key):
if key.endswith('_'):
key = key[:-1]
return key.replace('_', '-')
@classmethod
def quotevalue(cls, val):
if val is True: return "on"
if val is False: return "off"
if val in (Toggle, Always, Never):
return unicode(val).lower()
return tounicode(val)
def __get__(self, obj, cls):
return self
def __set__(self, obj, val):
self.setitems(val)
def __init__(self, parent, key, items={}):
self.key = key
self._items = []
self.setitems(items.iteritems() if isinstance(items, dict) else items)
self.parent = parent
def __getitem__(self, key):
for k, v in reversed(self._items):
if k == key:
return v
raise KeyError()
def __setitem__(self, key, val):
items = [(k, v) for k, v in self.iteritems() if k != key]
items.append((key, val))
self.setitems(items)
def __delitem__(self, key):
self.setitems([(k, v) for k, v in self.iteritems() if k != key])
def __len__(self):
return len(self._items)
def __iter__(self):
return iter(self._items)
def __list__(self):
return list(iter(self))
def __tuple__(self):
return tuple(iter(self))
def append(self, item):
self.setitems(self + (item,))
def __add__(self, items):
return tuple(self.iteritems()) + tuple(items)
def setitems(self, items):
items = list(items)
assert not any('=' in key or
spacere.search(self.quotekey(key)) or
spacere.search(self.quotevalue(val)) for (key, val) in items)
self._items = items
if self.parent:
self.parent.rewrite()
def __unicode__(self):
return u'/%s/ %s\n' % (
Rules.quoteslash(self.key),
u' '.join(u'%s=%s' % (self.quotekey(k), self.quotevalue(v))
for (k, v) in self.iteritems()))
def iteritems(self):
return iter(self._items)
def items(self):
return list(self._items)
@apply
class wmii(Ctl):
ctl_path = '/ctl'
ctl_types = {
'normcolors': (Colors.from_string, lambda c: str(Colors(*c))),
'focuscolors': (Colors.from_string, lambda c: str(Colors(*c))),
'border': (int, str),
}
clients = Client.map()
tags = Tag.map()
lbuttons = Button.map('left')
rbuttons = Button.map('right')
rules = Rules('/rules')
class Tags(object):
PREV = []
NEXT = []
def __init__(self, normcol=None, focuscol=None):
self.ignore = set()
self.tags = {}
self.sel = None
self.normcol = normcol
self.focuscol = focuscol
self.lastselect = datetime.now()
for t in wmii.tags:
self.add(t)
for b in wmii.lbuttons.itervalues():
if b.name not in self.tags:
b.remove()
self.focus(Tag('sel').id)
self.mru = [self.sel.id]
self.idx = -1
Tags.instance = self
def add(self, tag):
self.tags[tag] = Tag(tag)
self.tags[tag].button = Button('left', tag, self.normcol or wmii.cache['normcolors'], tag)
def delete(self, tag):
self.tags.pop(tag).button.remove()
def focus(self, tag):
self.sel = self.tags[tag]
self.sel.button.colors = self.focuscol or wmii.cache['focuscolors']
def unfocus(self, tag):
self.tags[tag].button.colors = self.normcol or wmii.cache['normcolors']
def set_urgent(self, tag, urgent=True):
self.tags[tag].button.label = urgent and '*' + tag or tag
def next(self, reverse=False):
tags = [t for t in wmii.tags if t not in self.ignore]
tags.append(tags[0])
if reverse:
tags.reverse()
for i in range(0, len(tags)):
if tags[i] == self.sel.id:
return tags[i+1]
return self.sel
def select(self, tag, take_client=None):
def goto(tag):
if take_client:
# Make a new instance in case this is Client('sel'),
# which would cause problems given 'sel' changes in the
# process.
client = Client(take_client.id)
sel = Tag('sel').id
client.tags = '+%s' % tag
wmii['view'] = tag
if tag != sel:
client.tags = '-%s' % sel
else:
wmii['view'] = tag
if tag is self.PREV:
if self.sel.id not in self.ignore:
self.idx -= 1
elif tag is self.NEXT:
self.idx += 1
else:
if isinstance(tag, Tag):
tag = tag.id
goto(tag)
if tag not in self.ignore:
if self.idx < -1:
self.mru = self.mru[:self.idx + 1]
self.idx = -1
if self.mru and datetime.now() - self.lastselect < timedelta(seconds=.5):
self.mru[self.idx] = tag
elif tag != self.mru[-1]:
self.mru.append(tag)
self.mru = self.mru[-10:]
self.lastselect = datetime.now()
return
self.idx = constrain(-len(self.mru), -1, self.idx)
goto(self.mru[self.idx])
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pygmi/menu.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
from threading import Thread
from pygmi.util import call
__all__ = 'Menu', 'ClickMenu'
def inthread(name, args, action, **kwargs):
fn = lambda: call(*args, **kwargs)
if not action:
return fn()
t = Thread(target=lambda: action(fn()))
t.name += '-%s' % name
t.daemon = True
t.start()
class Menu(object):
def __init__(self, choices=(), action=None,
histfile=None, nhist=None):
self.choices = choices
self.action = action
self.histfile = histfile
self.nhist = nhist
def __call__(self, choices=None):
if choices is None:
choices = self.choices
if callable(choices):
choices = choices()
args = ['wimenu']
if self.histfile:
args += ['-h', self.histfile]
if self.nhist:
args += ['-n', self.nhist]
return inthread('Menu', map(str, args), self.action, input='\n'.join(choices))
call = __call__
class ClickMenu(object):
def __init__(self, choices=(), action=None,
histfile=None, nhist=None):
self.choices = choices
self.action = action
self.prev = None
def __call__(self, choices=None):
if choices is None:
choices = self.choices
if callable(choices):
choices = choices()
args = ['wmii9menu']
if self.prev:
args += ['-i', self.prev]
args += ['--'] + list(choices)
return inthread('ClickMenu', map(str, args), self.action)
call = __call__
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pygmi/monitor.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
from threading import Lock, Timer
from pygmi import client
from pygmi.fs import *
__all__ = 'monitors', 'defmonitor', 'Monitor'
monitors = {}
def defmonitor(*args, **kwargs):
"""
Defines a new monitor to appear in wmii's bar based on
the wrapped function. Creates a new Monitor object,
initialized with *args and **kwargs. The wrapped function
is assigned to the 'action' keyword argument for the
Monitor, its name is assigned to the 'name' argument.
The new monitor is added to the 'monitors' dict in this
module.
"""
def monitor(fn):
kwargs['action'] = fn
if not args and 'name' not in kwargs:
kwargs['name'] = fn.__name__
monitor = Monitor(*args, **kwargs)
monitors[monitor.name] = monitor
return monitor
if args and callable(args[0]):
fn = args[0]
args = args[1:]
return monitor(fn)
return monitor
class Monitor(object):
"""
A class to manage status monitors for wmii's bar. The bar item
is updated on a fixed interval based on the values returned
by the 'action' method.
Property active: When true, the monitor is updated at regular
intervals. When false, monitor is hidden.
Property name: The name of the monitor, which acts as the name
of the bar in wmii's filesystem.
Property interval: The update interval, in seconds.
Property side: The side of the bar on which to place the monitor.
Property action: A function of no arguments which returns the
value of the monitor. Called at each update interval.
May return a string, a tuple of (Color, string), or None
to hide the monitor for one iteration.
"""
side = 'right'
interval = 1.0
define = classmethod(defmonitor)
def __init__(self, name=None, interval=None, side=None,
action=None, colors=None, label=None):
"""
Initializes the new monitor. For parameter values, see the
corresponding property values in the class's docstring.
Param colors: The initial colors for the monitor.
Param label: The initial label for the monitor.
"""
if side:
self.side = side
if name:
self.name = name
if interval:
self.interval = interval
if action:
self.action = action
self.lock = Lock()
self.timer = None
self.button = Button(self.side, self.name, colors, label)
self.tick()
def tick(self):
"""
Called internally at the interval defined by #interval.
Calls #action and updates the monitor based on the result.
"""
if self.timer and monitors.get(self.name, None) is not self:
return
if self.active:
label = self.getlabel()
if isinstance(label, basestring):
label = None, label
with self.lock:
if self.active:
if label is None:
self.button.remove()
else:
self.button.create(*label)
self.timer = Timer(self.interval, self.tick)
self.timer.name = 'Monitor-Timer-%s' % self.name
self.timer.daemon = True
self.timer.start()
def getlabel(self):
"""
Calls #action and returns the result, ignoring any
exceptions.
"""
try:
return self.action(self)
except Exception:
return None
_active = True
@property
def active(self):
return self._active
@active.setter
def active(self, val):
with self.lock:
self._active = bool(val)
if val:
self.tick()
else:
self.button.remove()
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pygmi/util.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
from functools import partial, update_wrapper, wraps
import os
import signal
import subprocess
import pygmi
__all__ = 'call', 'message', 'program_list', 'curry', 'find_script', '_', 'prop'
def _():
pass
def call(*args, **kwargs):
background = kwargs.pop('background', False)
stdin = subprocess.PIPE if not background else open('/dev/null', 'r')
pipe = subprocess.PIPE if not background else None
input = kwargs.pop('input', None)
p = subprocess.Popen(args, stdin=stdin, stdout=pipe, stderr=pipe,
preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL),
cwd=os.environ['HOME'], close_fds=True, **kwargs)
if not background:
return p.communicate(input)[0].rstrip('\n')
def message(message):
args = ['xmessage', '-file', '-'];
font = pygmi.wmii['font']
if not font.startswith('xft:'):
args += ['-fn', font.split(',')[0]]
call(*args, input=message)
def program_list(path):
names = set()
for d in path:
try:
for f in os.listdir(d):
p = '%s/%s' % (d, f)
if (f not in names and os.access(p, os.X_OK) and
os.path.isfile(p)):
names.add(f)
except Exception:
pass
return sorted(names)
def curry(func, *args, **kwargs):
if _ in args:
blank = [i for i in range(0, len(args)) if args[i] is _]
@wraps(func)
def curried(*newargs, **newkwargs):
ary = list(args)
for k, v in zip(blank, newargs):
ary[k] = v
ary = tuple(ary) + newargs[len(blank):]
return func(*ary, **dict(kwargs, **newkwargs))
else:
curried = update_wrapper(partial(func, *args, **kwargs), func)
curried.__name__ += '__curried__'
return curried
def find_script(name):
for path in pygmi.confpath:
if os.access('%s/%s' % (path, name), os.X_OK):
return '%s/%s' % (path, name)
def prop(**kwargs):
def prop_(wrapped):
kwargs['fget'] = wrapped
return property(**kwargs)
return prop_
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pyxp.py.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/usr/bin/env python
from distutils.core import setup
setup(name='pyxp',
version='0.2',
description='Python 9P client library',
author='Kris Maglione',
author_email='maglione.k@gmail.com',
url='http://wmii.suckless.org',
packages=['pyxp'],
license='MIT',
)
|
Added alternative_wmiircs/python/pyxp/__init__.py.
> > > > > > > | 1 2 3 4 5 6 7 | from pyxp.client import Client from pyxp.dial import dial from pyxp.types import Qid, Stat VERSION = '9P2000' # vim:se sts=4 sw=4 et: |
Added alternative_wmiircs/python/pyxp/asyncclient.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
from pyxp import client, fcall
from pyxp.client import *
from functools import wraps
def send(iter, val, default=None):
try:
return iter.send(val)
except StopIteration:
return default
def awithfile(fn):
@wraps(fn)
def wrapper(self, path, *args, **kwargs):
gen = fn(self, *args, **kwargs)
callback, fail, mode = next(gen)
def cont(file):
send(gen, file)
self.aopen(path, cont, fail=fail or callback, mode=mode)
return wrapper
def requestchain(fn):
@wraps(fn)
def wrapper(self, *args, **kwargs):
gen = fn(self, *args, **kwargs)
callback, fail = next(gen)
def cont(val):
data = gen.send(val)
if isinstance(data, fcall.Fcall):
self._dorpc(data, cont, fail or callback)
else:
Client.respond(callback, data)
cont(None)
return wrapper
class Client(client.Client):
ROOT_FID = 0
def _awalk(fn):
@wraps(fn)
@requestchain
def wrapper(self, *args, **kwargs):
gen = fn(self, *args, **kwargs)
path, callback, fail = next(gen)
path = self._splitpath(path)
fid = self._getfid()
ofid = ROOT_FID
def fail_(resp, exc, tb):
if ofid != ROOT_FID:
self._aclunk(fid)
self.respond(fail or callback, resp, exc, tb)
yield callback, fail_
while path:
wname = path[:fcall.MAX_WELEM]
path = path[fcall.MAX_WELEM:]
resp = yield fcall.Twalk(fid=ofid, newfid=fid, wname=wname)
ofid = fid
resp = fid
while resp is not None:
resp = yield send(gen, resp)
return wrapper
_file = property(lambda self: File)
@_awalk
def _aopen(self, path, mode, fcall, callback, fail=None, origpath=None):
path = self._splitpath(path)
fcall.fid = yield path, callback, fail
resp = yield fcall
yield self._file(self, origpath or '/'.join(path), resp, fcall.fid, mode,
cleanup=lambda: self._aclunk(fcall.fid))
def aopen(self, path, callback=True, fail=None, mode=OREAD):
assert callable(callback)
self._aopen(path, mode, fcall.Topen(mode=mode), callback, fail)
def acreate(self, path, callback=True, fail=None, mode=OREAD, perm=0):
path = self._splitpath(path)
name = path.pop()
self._aopen(path, mode,
fcall.Tcreate(mode=mode, name=name, perm=perm),
callback if callable(callback) else lambda resp: resp and resp.close(),
fail, origpath='/'.join(path + [name]))
@_awalk
def aremove(self, path, callback=True, fail=None):
yield fcall.Tremove(fid=(yield path, callback, fail))
@_awalk
def astat(self, path, callback, fail=None):
resp = yield fcall.Tstat(fid=(yield path, callback, fail))
yield resp.stat
@awithfile
def aread(self, callback, fail=None, count=None, offset=None, buf=''):
file = yield callback, fail, OREAD
file.aread(callback, fail, count, offset, buf)
@awithfile
def awrite(self, data, callback=True, fail=None, offset=None):
file = yield callback, fail, OWRITE
file.awrite(data, callback, fail, offset)
@awithfile
def areadlines(self, callback):
file = yield callback, fail, OREAD
file.areadlines(callback)
class File(client.File):
@requestchain
def stat(self, callback, fail=None):
yield callback, fail
resp = yield fcall.Tstat()
yield resp.stat
@requestchain
def aread(self, callback, fail=None, count=None, offset=None, buf=''):
yield callback, fail
setoffset = offset is None
if count is None:
count = self.iounit
if offset is None:
offset = self.offset
res = []
while count > 0:
n = min(count, self.iounit)
count -= n
resp = yield fcall.Tread(offset=offset, count=n)
res.append(resp.data)
offset += len(resp.data)
if len(resp.data) == 0:
break
if setoffset:
self.offset = offset
yield ''.join(res)
def areadlines(self, callback):
class ctxt:
last = None
def cont(data, exc, tb):
res = True
if data:
lines = data.split('\n')
if ctxt.last:
lines[0] = ctxt.last + lines[0]
for i in range(0, len(lines) - 1):
res = callback(lines[i])
if res is False:
return
ctxt.last = lines[-1]
self.aread(cont)
else:
if ctxt.last:
callback(ctxt.last)
callback(None)
self.aread(cont)
@requestchain
def awrite(self, data, callback=True, fail=None, offset=None):
yield callback, fail
setoffset = offset is None
if offset is None:
offset = self.offset
off = 0
while off < len(data):
n = min(len(data), self.iounit)
resp = yield fcall.Twrite(offset=offset, data=data[off:off+n])
off += resp.count
offset += resp.count
if setoffset:
self.offset = offset
yield off
@requestchain
def aremove(self, callback=True, fail=None):
yield callback, fail
yield fcall.Tremove()
self.close()
yield True
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pyxp/client.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
# Copyright (C) 2009 Kris Maglione
import operator
import os
import re
import sys
from threading import *
import traceback
import pyxp
from pyxp import fcall, fields
from pyxp.mux import Mux
from pyxp.types import *
if os.environ.get('NAMESPACE', None):
namespace = os.environ['NAMESPACE']
else:
try:
namespace = '/tmp/ns.%s.%s' % (
os.environ['USER'],
re.sub(r'\.0$', '', os.environ['DISPLAY']))
except Exception:
pass
NAMESPACE = namespace
OREAD = 0x00
OWRITE = 0x01
ORDWR = 0x02
OEXEC = 0x03
OEXCL = 0x04
OTRUNC = 0x10
OREXEC = 0x20
ORCLOSE = 0x40
OAPPEND = 0x80
ROOT_FID = 0
class ProtocolException(Exception):
pass
class RPCError(Exception):
pass
class Client(object):
ROOT_FID = 0
@staticmethod
def respond(callback, data, exc=None, tb=None):
if hasattr(callback, 'func_code'):
callback(*(data, exc, tb)[0:callback.func_code.co_argcount])
elif callable(callback):
callback(data)
def __enter__(self):
return self
def __exit__(self, *args):
self._cleanup()
def __init__(self, conn=None, namespace=None, root=None):
if not conn and namespace:
conn = 'unix!%s/%s' % (NAMESPACE, namespace)
try:
self.lastfid = ROOT_FID
self.fids = set()
self.lock = RLock()
def process(data):
return fcall.Fcall.unmarshall(data)[1]
self.mux = Mux(conn, process, maxtag=256)
resp = self._dorpc(fcall.Tversion(version=pyxp.VERSION, msize=65535))
if resp.version != pyxp.VERSION:
raise ProtocolException, "Can't speak 9P version '%s'" % resp.version
self.msize = resp.msize
self._dorpc(fcall.Tattach(fid=ROOT_FID, afid=fcall.NO_FID,
uname=os.environ['USER'], aname=''))
if root:
path = self._splitpath(root)
resp = self._dorpc(fcall.Twalk(fid=ROOT_FID,
newfid=ROOT_FID,
wname=path))
except Exception:
traceback.print_exc(sys.stdout)
if getattr(self, 'mux', None):
self.mux.fd.close()
raise
def _cleanup(self):
try:
for f in self.files:
f.close()
finally:
self.mux.fd.close()
self.mux = None
def _dorpc(self, req, callback=None, error=None):
def doresp(resp):
if isinstance(resp, fcall.Rerror):
raise RPCError, "%s[%d] RPC returned error: %s" % (
req.__class__.__name__, resp.tag, resp.ename)
if req.type != resp.type ^ 1:
raise ProtocolException, "Missmatched RPC message types: %s => %s" % (
req.__class__.__name__, resp.__class__.__name__)
return resp
def next(mux, resp):
try:
res = doresp(resp)
except Exception, e:
self.respond(error or callback, None, e, None)
else:
self.respond(callback, res)
if not callback:
return doresp(self.mux.rpc(req))
self.mux.rpc(req, next)
def _splitpath(self, path):
if isinstance(path, list):
return path
return [v for v in path.split('/') if v != '']
def _getfid(self):
with self.lock:
if self.fids:
return self.fids.pop()
self.lastfid += 1
return self.lastfid
def _putfid(self, fid):
with self.lock:
self.fids.add(fid)
def _aclunk(self, fid, callback=None):
def next(resp, exc, tb):
if resp:
self._putfid(fid)
self.respond(callback, resp, exc, tb)
self._dorpc(fcall.Tclunk(fid=fid), next)
def _clunk(self, fid):
try:
self._dorpc(fcall.Tclunk(fid=fid))
finally:
self._putfid(fid)
def _walk(self, path):
fid = self._getfid()
ofid = ROOT_FID
while True:
self._dorpc(fcall.Twalk(fid=ofid, newfid=fid,
wname=path[0:fcall.MAX_WELEM]))
path = path[fcall.MAX_WELEM:]
ofid = fid
if len(path) == 0:
break
@apply
class Res:
def __enter__(res):
return fid
def __exit__(res, exc_type, exc_value, traceback):
if exc_type:
self._clunk(fid)
return Res
_file = property(lambda self: File)
def _open(self, path, mode, fcall, origpath=None):
resp = None
with self._walk(path) as nfid:
fid = nfid
fcall.fid = fid
resp = self._dorpc(fcall)
def cleanup():
self._aclunk(fid)
file = self._file(self, origpath or '/'.join(path), resp, fid, mode, cleanup)
return file
def open(self, path, mode=OREAD):
path = self._splitpath(path)
return self._open(path, mode, fcall.Topen(mode=mode))
def create(self, path, mode=OREAD, perm=0):
path = self._splitpath(path)
name = path.pop()
return self._open(path, mode, fcall.Tcreate(mode=mode, name=name, perm=perm),
origpath='/'.join(path + [name]))
def remove(self, path):
path = self._splitpath(path)
with self._walk(path) as fid:
self._dorpc(fcall.Tremove(fid=fid))
def stat(self, path):
path = self._splitpath(path)
try:
with self._walk(path) as fid:
resp = self._dorpc(fcall.Tstat(fid= fid))
st = resp.stat
self._clunk(fid)
return st
except RPCError:
return None
def read(self, path, *args, **kwargs):
with self.open(path) as f:
return f.read(*args, **kwargs)
def readlines(self, path, *args, **kwargs):
with self.open(path) as f:
for l in f.readlines(*args, **kwargs):
yield l
def readdir(self, path, *args, **kwargs):
with self.open(path) as f:
for s in f.readdir(*args, **kwargs):
yield s
def write(self, path, *args, **kwargs):
with self.open(path, OWRITE) as f:
return f.write(*args, **kwargs)
class File(object):
def __enter__(self):
return self
def __exit__(self, *args):
self.close()
def __init__(self, client, path, fcall, fid, mode, cleanup):
self.lock = RLock()
self.client = client
self.path = path
self.fid = fid
self._cleanup = cleanup
self.mode = mode
self.iounit = fcall.iounit
self.qid = fcall.qid
self.closed = False
self.offset = 0
def __del__(self):
if not self.closed:
self._cleanup()
def _dorpc(self, fcall, async=None, error=None):
if hasattr(fcall, 'fid'):
fcall.fid = self.fid
return self.client._dorpc(fcall, async, error)
def stat(self):
resp = self._dorpc(fcall.Tstat())
return resp.stat
def read(self, count=None, offset=None, buf=''):
if count is None:
count = self.iounit
res = []
with self.lock:
offs = self.offset
if offset is not None:
offs = offset
while count > 0:
n = min(count, self.iounit)
count -= n
resp = self._dorpc(fcall.Tread(offset=offs, count=n))
data = resp.data
offs += len(data)
res.append(data)
if len(data) < n:
break
if offset is None:
self.offset = offs
return ''.join(res)
def readlines(self):
last = None
while True:
data = self.read()
if not data:
break
lines = data.split('\n')
if last:
lines[0] = last + lines[0]
last = None
for i in range(0, len(lines) - 1):
yield lines[i]
last = lines[-1]
if last:
yield last
def write(self, data, offset=None):
if offset is None:
offset = self.offset
off = 0
with self.lock:
offs = self.offset
if offset is not None:
offs = offset
while off < len(data):
n = min(len(data), self.iounit)
resp = self._dorpc(fcall.Twrite(offset=offs,
data=data[off:off+n]))
off += resp.count
offs += resp.count
if resp.count < n:
break
if offset is None:
self.offset = offs
return off
def readdir(self):
if not self.qid.type & Qid.QTDIR:
raise Exception, "Can only call readdir on a directory"
off = 0
while True:
data = self.read(self.iounit, off)
if not data:
break
off += len(data)
for s in Stat.unmarshall_list(data):
yield s
def close(self):
assert not self.closed
self.closed = True
try:
self._cleanup()
except:
pass
self.tg = None
self.fid = None
self.client = None
self.qid = None
def remove(self):
try:
self._dorpc(fcall.Tremove())
finally:
self.close()
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pyxp/dial.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
from socket import *
__all__ = 'dial',
def dial_unix(address):
sock = socket(AF_UNIX, SOCK_STREAM, 0)
sock.connect(address)
return sock
def dial_tcp(host):
host = host.split('!')
if len(host) != 2:
return
host, port = host
res = getaddrinfo(host, port, AF_INET, SOCK_STREAM, 0, AI_PASSIVE)
for family, socktype, protocol, name, addr in res:
try:
sock = socket(family, socktype, protocol)
sock.connect(addr)
return sock
except error:
if sock:
sock.close()
def dial(address):
proto, address = address.split('!', 1)
if proto == 'unix':
return dial_unix(address)
elif proto == 'tcp':
return dial_tcp(address)
else:
raise Exception('invalid protocol')
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pyxp/fcall.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
from pyxp.messages import MessageBase, Message
from pyxp.fields import *
from types import Qid, Stat
__all__ = 'Fcall',
NO_FID = 1<<32 - 1
MAX_WELEM = 16
class FcallBase(MessageBase):
idx = 99
def __new__(cls, name, bases, attrs):
new_cls = super(FcallBase, cls).__new__(cls, name, bases, attrs)
new_cls.type = FcallBase.idx
if new_cls.type > 99:
new_cls.types[new_cls.type] = new_cls
FcallBase.idx += 1
return new_cls
class Fcall(Message):
__metaclass__ = FcallBase
types = {}
def response(self, *args, **kwargs):
assert self.type % 2 == 0, "No respense type for response fcalls"
kwargs['tag'] = self.tag
return self.types[self.type + 1]()
@classmethod
def unmarshall(cls, data, offset=0):
res = super(Fcall, cls).unmarshall(data, offset)
if cls.type < 100:
res = cls.types[res[1].type].unmarshall(data, offset)
return res
size = Size(4, 4)
type = Int(1)
tag = Int(2)
class Tversion(Fcall):
msize = Int(4)
version = String()
class Rversion(Fcall):
msize = Int(4)
version = String()
class Tauth(Fcall):
afid = Int(4)
uname = String()
aname = String()
class Rauth(Fcall):
aqid = Qid.field()
class Tattach(Fcall):
fid = Int(4)
afid = Int(4)
uname = String()
aname = String()
class Rattach(Fcall):
qid = Qid.field()
class Terror(Fcall):
def __init__(self):
raise Exception("Illegal 9P tag 'Terror' encountered")
class Rerror(Fcall):
ename = String()
class Tflush(Fcall):
oldtag = Int(2)
class Rflush(Fcall):
pass
class Twalk(Fcall):
fid = Int(4)
newfid = Int(4)
wname = Array(2, String())
class Rwalk(Fcall):
wqid = Array(2, Qid.field())
class Topen(Fcall):
fid = Int(4)
mode = Int(1)
class Ropen(Fcall):
qid = Qid.field()
iounit = Int(4)
class Tcreate(Fcall):
fid = Int(4)
name = String()
perm = Int(4)
mode = Int(1)
class Rcreate(Fcall):
qid = Qid.field()
iounit = Int(4)
class Tread(Fcall):
fid = Int(4)
offset = Int(8)
count = Int(4)
class Rread(Fcall):
data = Data(4)
class Twrite(Fcall):
fid = Int(4)
offset = Int(8)
data = Data(4)
class Rwrite(Fcall):
count = Int(4)
class Tclunk(Fcall):
fid = Int(4)
class Rclunk(Fcall):
pass
class Tremove(Tclunk):
pass
class Rremove(Fcall):
pass
class Tstat(Tclunk):
pass
class Rstat(Fcall):
sstat = Size(2)
stat = Stat.field()
class Twstat(Rstat):
pass
class Rwstat(Fcall):
pass
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pyxp/fields.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
from datetime import datetime
import operator
class Field(object):
idx = 0
def __init__(self):
Field.idx += 1
self.id = Field.idx
def repr(self):
return self.__class__.__name__
def __repr__(self):
if hasattr(self, 'name'):
return '<Field %s "%s">' % (self.repr(), self.name)
return super(Field, self).__repr__()
class Int(Field):
encoders = {}
decoders = {}
@classmethod
def encoder(cls, n):
if n not in cls.encoders:
exec ('def enc(n):\n' +
' assert n == n & 0x%s, "Arithmetic overflow"\n' +
' return "".join((%s,))'
) % ('ff' * n,
','.join('chr((n >> %d) & 0xff)' % (i * 8)
for i in range(0, n)))
cls.encoders[n] = enc
return cls.encoders[n]
@classmethod
def decoder(cls, n):
if n not in cls.decoders:
cls.decoders[n] = eval('lambda data, offset: ' +
'|'.join('ord(data[offset + %d]) << %d' % (i, i * 8)
for i in range(0, n)))
return cls.decoders[n]
def __init__(self, size):
super(Int, self).__init__()
self.size = size
self.encode = self.encoder(size)
self.decode = self.decoder(size)
if self.__class__ == Int:
self.marshall = self.encode
def unmarshall(self, data, offset):
return self.size, self.decode(data, offset)
def marshall(self, val):
return self.encode(val)
def repr(self):
return '%s(%d)' % (self.__class__.__name__, self.size)
class Size(Int):
def __init__(self, size, extra=0):
super(Size, self).__init__(size)
self.extra = extra
def marshall(self, val):
return lambda vals, i: self.encode(
reduce(lambda n, i: n + len(vals[i]),
range(i + 1, len(vals)),
self.extra))
class Date(Int):
def __init__(self):
super(Date, self).__init__(4)
def unmarshall(self, data, offset):
val = self.decode(data, offset)
return 4, datetime.fromtimestamp(val)
def marshall(self, val):
return self.encode(int(val.strftime('%s')))
class Data(Int):
def __init__(self, size=2):
super(Data, self).__init__(size)
def unmarshall(self, data, offset):
n = self.decode(data, offset)
offset += self.size
assert offset + n <= len(data), "String too long to unpack"
return self.size + n, data[offset:offset + n]
def marshall(self, val):
if isinstance(val, unicode):
val = val.encode('UTF-8')
return [self.encode(len(val)), val]
# Note: Py3K strings are Unicode by default. They can't store binary
# data.
class String(Data):
def unmarshall(self, data, offset):
off, val = super(String, self).unmarshall(data, offset)
return off, val.decode('UTF-8')
def marshall(self, val):
if isinstance(val, str):
# Check for valid UTF-8
str.decode('UTF-8')
else:
val = val.encode('UTF-8')
return super(String, self).marshall(val)
class Array(Int):
def __init__(self, size, spec):
super(Array, self).__init__(size)
self.spec = spec
def unmarshall(self, data, offset):
start = offset
n = self.decode(data, offset)
offset += self.size
res = []
for i in range(0, n):
size, val = self.spec.unmarshall(data, offset)
if isinstance(val, list):
res += val
else:
res.append(val)
offset += size
return offset - start, res
def marshall(self, vals):
res = [self.encode(len(vals))]
for val in vals:
val = self.spec.marshall(val)
if isinstance(val, list):
res += val
else:
res.append(val)
return res
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pyxp/messages.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
from pyxp.fields import *
class MessageBase(type):
idx = 0
def __new__(cls, name, bases, attrs):
fields = []
fieldmap = {}
for k, v in attrs.items():
if isinstance(v, Field):
attrs[k] = None
fields.append(v)
fieldmap[k] = v
v.name = k
fields.sort(lambda a, b: cmp(a.id, b.id))
new_cls = super(MessageBase, cls).__new__(cls, name, bases, attrs)
map = getattr(new_cls, 'fieldmap', {})
map.update(fieldmap)
new_cls.fields = getattr(new_cls, 'fields', ()) + tuple(fields)
new_cls.fieldmap = map
for f in fields:
f.message = new_cls
return new_cls
class Message(object):
__metaclass__ = MessageBase
def __init__(self, *args, **kwargs):
if args:
args = dict(zip((f.name for f in self.fields), args))
args.update(kwargs)
kwargs = args;
for k, v in kwargs.iteritems():
assert k in self.fieldmap, "Invalid keyword argument"
setattr(self, k, v)
@classmethod
def field(cls):
class MessageField(Field):
def repr(self):
return cls.__name__
def unmarshall(self, data, offset):
return cls.unmarshall(data, offset)
def marshall(self, val):
return val.marshall()
return MessageField()
@classmethod
def unmarshall(cls, data, offset=0):
vals = {}
start = offset
for field in cls.fields:
size, vals[field.name] = field.unmarshall(data, offset)
offset += size
return offset - start, cls(**vals)
def marshall(self):
res = []
callbacks = []
for field in self.fields:
val = field.marshall(getattr(self, field.name, None))
if callable(val):
callbacks.append((val, len(res)))
if isinstance(val, list):
res += val
else:
res.append(val)
for fn, i in reversed(callbacks):
res[i] = fn(res, i)
return res
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pyxp/mux.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# Derived from libmux, available in Plan 9 under /sys/src/libmux
# under the following terms:
#
# Copyright (C) 2003-2006 Russ Cox, Massachusetts Institute of Technology
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
import os
import sys
import traceback
from pyxp import fields
from pyxp.dial import dial
from threading import *
Condition = Condition().__class__
__all__ = 'Mux',
class Mux(object):
def __init__(self, con, process, flush=None, mintag=0, maxtag=1<<16 - 1):
self.lock = RLock()
self.tagcond = Condition(self.lock)
self.outlock = RLock()
self.inlock = RLock()
self.process = process
self.flush = flush
self.wait = {}
self.free = set(range(mintag, maxtag))
self.mintag = mintag
self.maxtag = maxtag
self.muxer = None
self.async_mux = Queue(self.mux)
self.async_dispatch = Queue(self.async_dispatch)
if isinstance(con, basestring):
con = dial(con)
self.fd = con
if self.fd is None:
raise Exception("No connection")
def mux(self, rpc):
with self.lock:
try:
rpc.waiting = True
while self.muxer and self.muxer != rpc and rpc.data is None:
rpc.wait()
if rpc.data is None:
assert self.muxer in (rpc, None)
self.muxer = rpc
try:
self.lock.release()
while rpc.data is None:
data = self.recv()
if data is None:
raise Exception("unexpected eof")
self.dispatch(data)
finally:
self.lock.acquire()
self.electmuxer()
except Exception:
traceback.print_exc(sys.stderr)
if rpc.tag in self.wait:
self.wait.pop(rpc.tag)
if self.flush:
self.flush(self, rpc.data)
raise
return rpc.data
def rpc(self, dat, async=None):
rpc = self.newrpc(dat, async)
if async:
self.async_mux.push(rpc)
else:
return self.mux(rpc)
def async_dispatch(self, rpc):
rpc.async(self, rpc.data)
def electmuxer(self):
for rpc in self.wait.itervalues():
if self.muxer != rpc and rpc.waiting:
self.muxer = rpc
rpc.notify()
return
self.muxer = None
def dispatch(self, dat):
with self.lock:
rpc = self.wait.get(dat.tag, None)
if rpc:
self.puttag(rpc)
rpc.dispatch(dat)
elif False:
print "bad rpc tag: %u (no one waiting on it)" % dat.tag
def gettag(self, r):
tag = 0
while not self.free:
self.tagcond.wait()
tag = self.free.pop()
if tag in self.wait:
raise Exception("nwait botch")
self.wait[tag] = r
r.tag = tag
r.orig.tag = r.tag
return r.tag
def puttag(self, rpc):
if rpc.tag in self.wait:
del self.wait[rpc.tag]
self.free.add(rpc.tag)
self.tagcond.notify()
def send(self, dat):
data = ''.join(dat.marshall())
n = self.fd.send(data)
return n == len(data)
def recv(self):
def readn(fd, n):
data = ''
while len(data) < n:
try:
s = fd.recv(n - len(data))
if len(s) == 0:
raise Exception('unexpected end of file')
data += s
except os.error, e:
if e.errno != os.errno.EINTR:
raise e
return data
try:
with self.inlock:
data = readn(self.fd, 4)
if data:
nmsg = fields.Int.decoders[4](data, 0)
data += readn(self.fd, nmsg - 4)
return self.process(data)
except Exception, e:
print e.__class__.__name__
print repr(e)
traceback.print_exc(sys.stderr)
return None
def newrpc(self, dat, async=None):
rpc = Rpc(self, dat, async)
tag = None
with self.lock:
self.gettag(rpc)
if rpc.tag >= 0 and self.send(dat):
return rpc
with self.lock:
self.puttag(rpc)
class Rpc(Condition):
def __init__(self, mux, data, async=None):
super(Rpc, self).__init__(mux.lock)
self.mux = mux
self.orig = data
self.data = None
self.async = async
self.waiting = False
def __repr__(self):
return '<Rpc tag=%s orig=%s data=%s async=%s waiting=%s>' % tuple(map(repr, (self.tag, self.orig, self.data, self.async, self.waiting)))
def dispatch(self, data=None):
self.data = data
self.notify()
if callable(self.async):
self.mux.async_dispatch(self)
class Queue(Thread):
_id = 1
def __init__(self, op):
super(Queue, self).__init__(name='Queue-%d-%s' % (Queue._id, repr(op)))
Queue._id += 1
self.cond = Condition()
self.op = op
self.queue = []
self.daemon = True
def __call__(self, item):
return self.push(item)
def push(self, item):
with self.cond:
self.queue.append(item)
if not self.is_alive():
self.start()
self.cond.notify()
def pop(self, item):
with self.cond:
if item in self.queue:
self.queue.remove(item)
return True
return False
def run(self):
self.cond.acquire()
while True:
while self.queue:
item = self.queue.pop(0)
self.cond.release()
try:
self.op(item)
except Exception, e:
traceback.print_exc(sys.stderr)
self.cond.acquire()
self.cond.wait()
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/pyxp/types.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
from pyxp.messages import Message
from pyxp.fields import *
__all__ = 'Qid', 'Stat'
class Qid(Message):
QTFILE = 0x00
QTLINK = 0x01
QTSYMLINK = 0x02
QTTMP = 0x04
QTAUTH = 0x08
QTMOUNT = 0x10
QTEXCL = 0x20
QTAPPEND = 0x40
QTDIR = 0x80
type = Int(1)
version = Int(4)
path = Int(8)
class Stat(Message):
DMDIR = 0x80000000
DMAPPEND = 0x40000000
DMEXCL = 0x20000000
DMMOUNT = 0x10000000
DMAUTH = 0x08000000
DMTMP = 0x04000000
DMSYMLINK = 0x02000000
DMDEVICE = 0x00800000
DMNAMEDPIPE = 0x00200000
DMSOCKET = 0x00100000
DMSETUID = 0x00080000
DMSETGID = 0x00040000
@classmethod
def unmarshall_list(cls, data, offset=0):
while offset < len(data):
n, stat = cls.unmarshall(data, offset)
offset += n
yield stat
size = Size(2)
type = Int(2)
dev = Int(4)
qid = Qid.field()
mode = Int(4)
atime = Date()
mtime = Date()
length = Int(8)
name = String()
uid = String()
gid = String()
muid = String()
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/python/wmiirc.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
#!/usr/bin/env @PYTHON@
import os, sys
path = []
for p in os.environ.get("WMII_CONFPATH", "").split(':'):
path += [p, p + '/python']
sys.path = path + sys.path
from pygmi import events
import wmiirc
events.loop()
|
Added alternative_wmiircs/python/wmiirc.py.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
import datetime
import operator
import os
import re
import sys
import traceback
from threading import Thread, Timer
import pygmi
from pygmi import *
from pygmi import event
identity = lambda k: k
# Begin Configuration
#
# Note: This file loads ~/.wmii/wmiirc_local.py if it exists.
# Configuration should be placed in that file, and this file
# left unmodified, if possible. wmiirc_local should import
# wmiirc or any other modules it needs.
#
# Do *not* copy this file to wmiirc_local.py lest you want it
# executed twice.
# Keys
keys.defs = dict(
mod='Mod4',
left='h',
down='j',
up='k',
right='l')
# Bars
noticetimeout=5
noticebar=('right', '!notice')
# Theme
background = '#333333'
floatbackground='#222222'
wmii['font'] = 'drift,-*-fixed-*-*-*-*-9-*-*-*-*-*-*-*'
wmii['normcolors'] = '#000000', '#c1c48b', '#81654f'
wmii['focuscolors'] = '#000000', '#81654f', '#000000'
wmii['grabmod'] = keys.defs['mod']
wmii['border'] = 2
def setbackground(color):
call('xsetroot', '-solid', color, background=True)
setbackground(background)
terminal = 'wmiir', 'setsid', '@TERMINAL@'
pygmi.shell = os.environ.get('SHELL', 'sh')
tray = 'witray',
@defmonitor
def load(self):
return wmii.cache['normcolors'], re.sub(r'^.*: ', '', call('uptime')).replace(', ', ' ')
@defmonitor
def time(self):
return wmii.cache['focuscolors'], datetime.datetime.now().strftime('%c')
wmii.rules = (
# Apps with system tray icons like to their main windows
# Give them permission.
(ur'^Pidgin:', dict(allow='+activate')),
# MPlayer and VLC don't float by default, but should.
(ur'MPlayer|VLC', dict(floating=True)),
# ROX puts all of its windows in the same group, so they open
# with the same tags. Disable grouping for ROX Filer.
(ur'^ROX-Filer:', dict(group=0)),
)
def unresponsive_client(client):
msg = 'The following client is not responding. What would you like to do?'
resp = call('wihack', '-transient', str(client.id),
'xmessage', '-nearmouse', '-buttons', 'Kill,Wait', '-print',
'%s\n %s' % (msg, client.label))
if resp == 'Kill':
client.slay()
# End Configuration
client.awrite('/event', 'Start wmiirc')
tags = Tags()
events.bind({
('Quit', Match('Start', 'wmiirc')): lambda *a: sys.exit(),
'CreateTag': tags.add,
'DestroyTag': tags.delete,
'FocusTag': tags.focus,
'UnfocusTag': tags.unfocus,
'UrgentTag': lambda args: tags.set_urgent(args.split()[1], True),
'NotUrgentTag': lambda args: tags.set_urgent(args.split()[1], False),
'AreaFocus': lambda args: (args == '~' and
(setbackground(floatbackground), True) or
setbackground(background)),
'Unresponsive': lambda args: Thread(target=unresponsive_client,
args=(Client(args),)).start(),
'Notice': lambda args: notice.show(args),
'ScreenChange': lambda args: wmii.ctl('wipescreens'),
Match(('LeftBarClick', 'LeftBarDND'), 1): lambda e, b, tag: tags.select(tag),
Match('LeftBarClick', 4): lambda *a: tags.select(tags.next(True)),
Match('LeftBarClick', 5): lambda *a: tags.select(tags.next()),
Match('LeftBarMouseDown', 3): lambda e, n, tag: clickmenu((
('Delete', lambda t: Tag(t).delete()),
), (tag,)),
Match('ClientMouseDown', _, 3): lambda e, client, n: clickmenu((
('Delete', lambda c: Client(c).kill()),
('Kill', lambda c: Client(c).slay()),
('Fullscreen', lambda c: Client(c).set('Fullscreen', 'on')),
), (client,)),
Match('ClientClick', _, 4): lambda e, c, n: Tag('sel').select('up'),
Match('ClientClick', _, 5): lambda e, c, n: Tag('sel').select('down'),
})
@apply
class Actions(event.Actions):
def rehash(self, args=''):
program_menu.choices = program_list(os.environ['PATH'].split(':'))
def showkeys(self, args=''):
message(keys.help)
def quit(self, args=''):
wmii.ctl('quit')
def eval_(self, args=''):
exec args
def exec_(self, args=''):
wmii['exec'] = args
def exit(self, args=''):
client.awrite('/event', 'Quit')
program_menu = Menu(histfile='%s/history.progs' % confpath[0], nhist=5000,
action=curry(call, 'wmiir', 'setsid',
pygmi.shell, '-c', background=True))
action_menu = Menu(histfile='%s/history.actions' % confpath[0], nhist=500,
choices=lambda: Actions._choices,
action=Actions._call)
tag_menu = Menu(histfile='%s/history.tags' % confpath[0], nhist=100,
choices=lambda: sorted(tags.tags.keys()))
def clickmenu(choices, args):
ClickMenu(choices=(k for k, v in choices),
action=lambda choice: dict(choices).get(choice, identity)(*args)
).call()
class Notice(Button):
def __init__(self):
super(Notice, self).__init__(*noticebar, colors=wmii.cache['normcolors'])
self.timer = None
self.show(' ')
def tick(self):
self.create(wmii.cache['normcolors'], ' ')
def write(self, notice):
client.awrite('/event', 'Notice %s' % notice.replace('\n', ' '))
def show(self, notice):
if self.timer:
self.timer.cancel()
self.create(wmii.cache['normcolors'], notice)
self.timer = Timer(noticetimeout, self.tick)
self.timer.start()
notice = Notice()
keys.bind('main', (
"Moving around",
('%(mod)s-%(left)s', "Select the client to the left",
lambda k: Tag('sel').select('left')),
('%(mod)s-%(right)s', "Select the client to the right",
lambda k: Tag('sel').select('right')),
('%(mod)s-%(up)s', "Select the client above",
lambda k: Tag('sel').select('up')),
('%(mod)s-%(down)s', "Select the client below",
lambda k: Tag('sel').select('down')),
('%(mod)s-space', "Toggle between floating and managed layers",
lambda k: Tag('sel').select('toggle')),
"Moving through stacks",
('%(mod)s-Control-%(up)s', "Select the stack above",
lambda k: Tag('sel').select('up', stack=True)),
('%(mod)s-Control-%(down)s', "Select the stack below",
lambda k: Tag('sel').select('down', stack=True)),
"Moving clients around",
('%(mod)s-Shift-%(left)s', "Move selected client to the left",
lambda k: Tag('sel').send(Client('sel'), 'left')),
('%(mod)s-Shift-%(right)s', "Move selected client to the right",
lambda k: Tag('sel').send(Client('sel'), 'right')),
('%(mod)s-Shift-%(up)s', "Move selected client up",
lambda k: Tag('sel').send(Client('sel'), 'up')),
('%(mod)s-Shift-%(down)s', "Move selected client down",
lambda k: Tag('sel').send(Client('sel'), 'down')),
('%(mod)s-Shift-space', "Toggle selected client between floating and managed layers",
lambda k: Tag('sel').send(Client('sel'), 'toggle')),
"Client actions",
('%(mod)s-f', "Toggle selected client's fullsceen state",
lambda k: Client('sel').set('Fullscreen', 'toggle')),
('%(mod)s-Shift-c', "Close client",
lambda k: Client('sel').kill()),
"Changing column modes",
('%(mod)s-d', "Set column to default mode",
lambda k: setattr(Tag('sel').selcol, 'mode', 'default-max')),
('%(mod)s-s', "Set column to stack mode",
lambda k: setattr(Tag('sel').selcol, 'mode', 'stack-max')),
('%(mod)s-m', "Set column to max mode",
lambda k: setattr(Tag('sel').selcol, 'mode', 'stack+max')),
"Running programs",
('%(mod)s-a', "Open wmii actions menu",
lambda k: action_menu()),
('%(mod)s-p', "Open program menu",
lambda k: program_menu()),
('%(mod)s-Return', "Launch a terminal",
lambda k: call(*terminal, background=True)),
"Tag actions",
('%(mod)s-t', "Change to another tag",
lambda k: tags.select(tag_menu())),
('%(mod)s-Shift-t', "Retag the selected client",
lambda k: setattr(Client('sel'), 'tags', tag_menu())),
('%(mod)s-n', "Move to the view to the left",
lambda k: tags.select(tags.next())),
('%(mod)s-b', "Move to the view to the right",
lambda k: tags.select(tags.next(True))),
('%(mod)s-Shift-n', "Move to the view to the left, take along current client",
lambda k: tags.select(tags.next(), take_client=Client('sel'))),
('%(mod)s-Shift-b', "Move to the view to the right, take along current client",
lambda k: tags.select(tags.next(True), take_client=Client('sel'))),
('%(mod)s-i', "Move to the newer tag in the tag stack",
lambda k: tags.select(tags.NEXT)),
('%(mod)s-o', "Move to the older tag in the tag stack",
lambda k: tags.select(tags.PREV)),
('%(mod)s-Shift-i', "Move to the newer tag in the tag stack, take along current client",
lambda k: tags.select(tags.NEXT, take_client=Client('sel'))),
('%(mod)s-Shift-o', "Move to the older tag in the tag stack, take along current client",
lambda k: tags.select(tags.PREV, take_client=Client('sel'))),
))
def bind_num(i):
keys.bind('main', (
"Tag actions",
('%%(mod)s-%d' % i, "Move to view '%d'" % i,
lambda k: tags.select(str(i))),
('%%(mod)s-Shift-%d' % i, "Retag selected client with tag '%d'" % i,
lambda k: setattr(Client('sel'), 'tags', i)),
))
map(bind_num, range(0, 10))
keys.bind('main', (
"Changing modes",
('%(mod)s-Control-r', "Enter resize mode",
lambda k: setattr(keys, 'mode', 'resize')),
('%(mod)s-Control-t', "Enter passthrough mode",
lambda k: setattr(keys, 'mode', 'passthrough')),
));
keys.bind('passthrough', (
"Changing modes",
('%(mod)s-Control-t', "Leave passthrough mode",
lambda k: setattr(keys, 'mode', 'main')),
));
keys.bind('resize', (
('Escape', "Leave resize mode",
lambda k: setattr(keys, 'mode', 'main')),
), import_={'main': ('%(mod)s-%(left)s', '%(mod)s-%(right)s',
'%(mod)s-%(up)s', '%(mod)s-%(down)s',
'%(mod)s-Space')})
def addresize(mod, desc, cmd, *args):
keys.bind('resize', (
(mod + '%(left)s', "%s selected client to the left" % desc,
lambda k: Tag('sel').ctl(cmd, 'sel sel', 'left',
*args)),
(mod + '%(right)s', "%s selected client to the right" % desc,
lambda k: Tag('sel').ctl(cmd, 'sel sel', 'right',
*args)),
(mod + '%(up)s', "%s selected client up" % desc,
lambda k: Tag('sel').ctl(cmd, 'sel sel', 'up',
*args)),
(mod + '%(down)s', "%s selected client down" % desc,
lambda k: Tag('sel').ctl(cmd, 'sel sel', 'down',
*args)),
));
addresize('', 'Grow', 'grow')
addresize('Control-', 'Shrink', 'grow', '-1')
addresize('Shift-', 'Nudge', 'nudge')
Thread(target=lambda: Actions.rehash()).start()
if not os.environ.get('WMII_NOPLUGINS', ''):
dirs = filter(curry(os.access, _, os.R_OK),
('%s/plugins' % dir for dir in confpath))
files = filter(re.compile(r'\.py$').search,
reduce(operator.add, map(os.listdir, dirs), []))
for f in ['wmiirc_local'] + ['plugins.%s' % file[:-3] for file in files]:
try:
__import__(f)
except Exception, e:
traceback.print_exc(sys.stdout)
call(*tray, background=True)
# vim:se sts=4 sw=4 et:
|
Added alternative_wmiircs/ruby/HISTORY.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
= 2006-09-30
* Included 1.1.0 release of Ruby-IXP.
= 2006-09-29
* Fixed bug in toggle_maximize method (in rc.rb) due
to accessing a nonexistent file in IXP file system.
Thanks to Christian von Mueffling for reporting this bug.
* Fixed problem with reading
index (Wmii::Client#index) of
currently selected client.
* Wmii.find_client now accepts a variable number of places to be searched.
= 2006-09-28
* Added number_view_buttons method (in rc.rb) which numbers
the view buttons displayed on the bar, from left to right.
= 2006-09-27
* Included two main concurrency fixes for Ruby-IXP.
= 2006-09-24
* Added two-stage event handling,
to minimize the number of events
missed while processing an event.
= 2006-09-23
* Fixed event & status bar loop. It was forgotten when I transitioned
to the new Ixp::Node#method_missing behavior on 2006-09-22.
Thanks to Fredrik Ternerot for reporting this bug.
* When selecting views based on their first letter: if more than one
view matches, then they are cycled (adapted from Fredrik Ternerot).
* Added focus_view_matching method in rc.rb.
* Fixed errors that occurred when the tile and
diamond arrangements were applied to empty views.
= 2006-09-22
* Ixp::Node#method_missing now only dereferences files. Also,
the ! notation has been removed, as you can see below.
>> Wmii.fs.bar.status
=> #<Ixp::Node:0xb7b5940c @path="/bar/status">
>> Wmii.fs.bar.status.read
=> ["colors", "data"]
>> Wmii.fs.bar.status.data
=> "Fri Sep 22 18:46:11 PDT 2006 | 0.06 0.10 0.08 | 531M 100% /home"
>> Wmii.fs.bar.status.data!
=> #<Ixp::Node:0xb7b377e4 @path="/bar/status/data!">
= 2006-09-21
* Fix some forgotten changes from show_menu() returning *nil*.
* Exception error message (xmessage) now lets you restart *wmiirc*.
* Updated event loop to generate less 9P traffic.
= 2006-09-20
* Included code from upcoming Ruby-IXP 1.1.0 release.
* Ixp::Node#method_missing now only dereferences a node
if the method is suffixed with an exclamation mark.
* show_menu now returns *nil* if nothing was chosen.
* Updated event loop for {wmii-3.1's /event overload bug
fix}[http://wmii.de/pipermail/wmii/2006-September/002718.html].
* Added explicit termination of already running instances
in *wmiirc* via Process.kill and `ps`, instead of using
/event as a means of coordinating said task.
= 2006-09-19
* Included Ruby-IXP 1.0.3 release.
* Added Ixp::Node#open method to reduce 9P traffic.
* Added ability to fetch a sub-node
via Ixp::Node#method_missing, while
not dereferencing it (reading its
contents if it is a file), by adding
an exclamation to the file name.
For example, consider the following output in *wmiish*.
>> Wmii.fs.bar.status.data
=> "Tue Sep 19 10:50:41 PDT 2006 | 0.30 0.43 0.29 | 1.7G 98% /home"
>> Wmii.fs.bar.status.data!
=> #<Ixp::Node:0xb7bf1f18 @path="/bar/status/data">
* *wmiirc* no longer automatically resumes from error. Instead,
it throws you a terminal and shows you the error details so
you have a chance to fix it and restart *wmiirc* yourself.
= 2006-09-18
* Included Ruby-IXP 1.0.2 release.
= 2006-09-17
* Added Wmii::View#empty? and Wmii::Area#empty? methods.
* change_tag_from_menu now returns the chosen tag.
* Included Ruby-IXP 1.0.1 release.
= 2006-09-16
* Fixed toggling of maximization
of currently focused client,
via toggle_maximize in rc.rb.
Thanks to Fredrik Ternerot for reporting this bug.
= 2006-09-15
* Added Wmii.get_view and Wmii.get_client
methods, to further minimize hard-coded
IXP file system paths. This will make it
easier to upgrade to wmii-4 later on.
* Fixed ruby-ixp to be internally buffered for Ixp#read.
* Event loop now uses Ixp#read instead of *wmiir*.
* Already running configurations now correctly
exit when another instance starts up.
= 2006-09-14
* Added ability to swap current client with the
currently focused client in any other column.
= 2006-09-13
* Reverted to *wmiir* for event loop, because
Ixp#read isn't internally buffered!
* Changed Wmii::View#each to Wmii::View#each_column because
floating area isn't a column (it doesn't have /mode file).
* Added shortcuts for setting layouts of all columns in current view.
* Added shortcuts for selection of current column.
* Fixed ability to terminate multiple clients.
= 2006-09-12
* Event loop now uses Ixp#read instead of *wmiir*.
* Already running configurations now correctly
exit when another instance starts up.
* Added Wmii::View#diamond! -- a diamond-shaped automated client arrangement.
* Added Wmii::Area#length= for setting number of clients in a column.
= 2006-09-11
* Added exception logging and recovery mechanism.
* wmiirc is now split into a loader
file (wmiirc) and a configuration
file (wmiirc-config.rb), just
like in the ruby-wmii project.
* IXPException' are no longer hidden away inside Ixp.
* Moved support for destructive area-operations
from Wmii#with_selection into Array#each so
that it is generally available.
= 2006-09-10
* Added wmiish--an interactive Ruby shell for controlling wmii.
* Lots of major refactoring in Ixp and Wmii.
* Moved utility methods from wmiirc into rc.rb.
= 2006-09-09
* Cleaned up IXP abstraction... now
multiple levels of method_missing
works, and so does self[sub_path]
* Wmii#with_selection now supports destructive area-operations.
* Update for compliance with new unique-client-id in filesystem patch.
= 2006-08-31
* Added facility which sends the selection
to temporary view or switches back again.
= 2006-08-30
* Add Wmii#with_selection method for operating on all clients in selection.
|
Added alternative_wmiircs/ruby/LICENSE.
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | (the ISC license) Copyright 2006 Suraj N. Kurapati <sunaku@gmail.com> Copyright 2007 Kris Maglione <jg@suckless.org> Copyright 2007 Nick Stenning <nick@whiteink.com> Copyright 2009 Daniel Wäber <waeber@inf.fu-berlin.de> Copyright 2009 Michael Andrus <centyx@centyx.net> Copyright 2009 Simon Hafner <hafnersimon@gmail.com> Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
Added alternative_wmiircs/ruby/Makefile.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | ROOT=../.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk DOCS = README \ HISTORY \ LICENSE EXECS = wmiirc TEXT = config.rb \ config.yaml DIR = $(GLOBALCONF)/ruby DOCDIR = $(DOC)/alternative_wmiircs/ruby |
Added alternative_wmiircs/ruby/README.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
This is a modified version of sunaku's wmiirc, designed for
his Rumai Ruby module. Minor configuration changes, namely to
the color scheme and default key bindings, as well as the
configuration search path, exist in this version. Builtin mpd
support has also been removed. Also added is support for
string interpolation in key bindings, as should be apparent in
the included config.yaml.
In particular, not that there is no need to copy any files to
@LOCALCONF@ other than config.yaml. The script will happily load
the requisite files from their default install location. They
can be loaded either by involing wmii as follows:
wmiir -r ruby/wmiirc
or running the following after startup:
wmiir xwrite /ctl spawn ruby/wmiirc
The rumai gem is still required, as noted below.
The original readme appears below unmodified:
sunaku's Ruby wmiirc
====================
This is my wmii configuration, described in these articles:
http://wmii.suckless.org/alternative_wmiirc_scripts
http://snk.tuxfamily.org/lib/rumai/
http://article.gmane.org/gmane.comp.window-managers.wmii/1704
http://snk.tuxfamily.org/web/2006-07-01-wmii-3-1-configuration-in-ruby.html
Dependencies:
wmii 3.6 or newer (preferably wmii-hg)
Ruby 1.8.6 or newer
RubyGems 1.3.1 or newer
Installation:
# library
gem install rumai # required
gem install librmpd # optional
# install
mv @LOCALCONF@ @LOCALCONF@.backup
git clone git://github.com/sunaku/wmiirc.git @LOCALCONF@
# choose
cd @LOCALCONF@
git checkout --track -b CHOICE origin/CHOICE # choices are:
+--------+------------------------------------------------+
| CHOICE | DESCRIPTION |
+--------+------------------------------------------------+
| dvorak | sunaku's personal configuration; DSK friendly! |
| qwerty | QWERTY port of sunaku's personal configuration |
| strict | port of the default wmiirc shipped with wmii |
| master | barebones template for starting from scratch |
+--------+------------------------------------------------+
# run
@LOCALCONF@/wmiirc
Documentation:
# see list of all key bindings
egrep '^ +\$\{\w+\}' @LOCALCONF@/config.yaml
# read the configuration file
less @LOCALCONF@/config.yaml
Configuration:
Edit @LOCALCONF@/config.yaml to your liking.
Run @LOCALCONF@/wmiirc to apply your changes.
Contribution:
Fork this project on GitHub and send pull requests.
Questions:
Send me an e-mail (see LICENSE for my address).
|
Added alternative_wmiircs/ruby/config.rb.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 |
# DSL for wmiirc configuration.
#--
# Copyright protects this work.
# See LICENSE file for details.
#++
require 'shellwords'
require 'pathname'
require 'yaml'
require 'rubygems'
gem 'rumai', '~> 3'
require 'rumai'
include Rumai
class Handler < Hash
def initialize
super {|h,k| h[k] = [] }
end
##
# If a block is given, registers a handler
# for the given key and returns the handler.
#
# Otherwise, executes all handlers registered for the given key.
#
def handle key, *args, &block
if block
self[key] << block
elsif key? key
self[key].each do |block|
block.call(*args)
end
end
block
end
end
EVENTS = Handler.new
ACTIONS = Handler.new
KEYS = Handler.new
##
# If a block is given, registers a handler
# for the given event and returns the handler.
#
# Otherwise, executes all handlers for the given event.
#
def event *a, &b
EVENTS.handle(*a, &b)
end
##
# Returns a list of registered event names.
#
def events
EVENTS.keys
end
##
# If a block is given, registers a handler for
# the given action and returns the handler.
#
# Otherwise, executes all handlers for the given action.
#
def action *a, &b
ACTIONS.handle(*a, &b)
end
##
# Returns a list of registered action names.
#
def actions
ACTIONS.keys
end
##
# If a block is given, registers a handler for
# the given keypress and returns the handler.
#
# Otherwise, executes all handlers for the given keypress.
#
def key *a, &b
KEYS.handle(*a, &b)
end
##
# Returns a list of registered action names.
#
def keys
KEYS.keys
end
##
# Shows a menu (where the user must press keys on their keyboard to
# make a choice) with the given items and returns the chosen item.
#
# If nothing was chosen, then nil is returned.
#
# ==== Parameters
#
# [prompt]
# Instruction on what the user should enter or choose.
#
def key_menu choices, prompt = nil
words = ['dmenu', '-fn', CONFIG['display']['font']]
# show menu at the same location as the status bar
words << '-b' if CONFIG['display']['bar'] == 'bottom'
words.concat %w[-nf -nb -sf -sb].zip(
[
CONFIG['display']['color']['normal'],
CONFIG['display']['color']['focus'],
].map {|c| c.to_s.split[0,2] }.flatten
).flatten
words.push '-p', prompt if prompt
command = words.shelljoin
IO.popen(command, 'r+') do |menu|
menu.puts choices
menu.close_write
choice = menu.read
choice unless choice.empty?
end
end
##
# Shows a menu (where the user must click a menu
# item using their mouse to make a choice) with
# the given items and returns the chosen item.
#
# If nothing was chosen, then nil is returned.
#
# ==== Parameters
#
# [choices]
# List of choices to display in the menu.
#
# [initial]
# The choice that should be initially selected.
#
# If this choice is not included in the list
# of choices, then this item will be made
# into a makeshift title-bar for the menu.
#
def click_menu choices, initial = nil
words = ['wmii9menu']
if initial
words << '-i'
unless choices.include? initial
initial = "<<#{initial}>>:"
words << initial
end
words << initial
end
words.concat choices
command = words.shelljoin
choice = `#{command}`.chomp
choice unless choice.empty?
end
##
# Shows a key_menu() containing the given
# clients and returns the chosen client.
#
# If nothing was chosen, then nil is returned.
#
# ==== Parameters
#
# [prompt]
# Instruction on what the user should enter or choose.
#
# [clients]
# List of clients to present as choices to the user.
#
# If this parameter is not specified,
# its default value will be a list of
# all currently available clients.
#
def client_menu prompt = nil, clients = Rumai.clients
choices = []
clients.each_with_index do |c, i|
choices << "%d. [%s] %s" % [i, c[:tags].read, c[:label].read.downcase]
end
if target = key_menu(choices, prompt)
clients[target.scan(/\d+/).first.to_i]
end
end
##
# Returns the basenames of executable files present in the given directories.
#
def find_programs *dirs
dirs.flatten.
map {|d| Pathname.new(d).expand_path.children rescue [] }.flatten.
map {|f| f.basename.to_s if f.file? and f.executable? }.compact.uniq.sort
end
##
# Launches the command built from the given words in the background.
#
def launch *words
command = words.shelljoin
system "#{command} &"
end
##
# A button on a bar.
#
class Button < Thread
##
# Creates a new button at the given node and updates its label
# according to the given refresh rate (measured in seconds). The
# given block is invoked to calculate the label of the button.
#
# The return value of the given block can be either an
# array (whose first item is a wmii color sequence for the
# button, and the remaining items compose the label of the
# button) or a string containing the label of the button.
#
# If the given block raises a standard exception, then that will be
# rescued and displayed (using error colors) as the button's label.
#
def initialize fs_bar_node, refresh_rate, &button_label
raise ArgumentError, 'block must be given' unless block_given?
super(fs_bar_node) do |button|
while true
label =
begin
Array(button_label.call)
rescue Exception => e
LOG.error e
[CONFIG['display']['color']['error'], e]
end
# provide default color
unless label.first =~ /(?:#[[:xdigit:]]{6} ?){3}/
label.unshift CONFIG['display']['color']['normal']
end
button.create unless button.exist?
button.write label.join(' ')
sleep refresh_rate
end
end
end
##
# Refreshes the label of this button.
#
alias refresh wakeup
end
##
# Loads the given YAML configuration file.
#
def load_config config_file
Object.const_set :CONFIG, YAML.load_file(config_file)
# script
eval CONFIG['script']['before'].to_s, TOPLEVEL_BINDING,
"#{config_file}:script:before"
# display
fo = ENV['WMII_FONT'] = CONFIG['display']['font']
fc = ENV['WMII_FOCUSCOLORS'] = CONFIG['display']['color']['focus']
nc = ENV['WMII_NORMCOLORS'] = CONFIG['display']['color']['normal']
settings = {
'font' => fo,
'focuscolors' => fc,
'normcolors' => nc,
'border' => CONFIG['display']['border'],
'bar on' => CONFIG['display']['bar'],
'colmode' => CONFIG['display']['column']['mode'],
'grabmod' => CONFIG['control']['grab'],
}
begin
fs.ctl.write settings.map {|pair| pair.join(' ') }.join("\n")
rescue Rumai::IXP::Error => e
#
# settings that are not supported in a particular wmii version
# are ignored, and those that are supported are (silently)
# applied. but a "bad command" error is raised nevertheless!
#
warn e.inspect
warn e.backtrace.join("\n")
end
launch 'xsetroot', '-solid', CONFIG['display']['background']
# column
fs.colrules.write CONFIG['display']['column']['rule']
# client
event 'CreateClient' do |client_id|
client = Client.new(client_id)
unless defined? @client_tags_by_regexp
@client_tags_by_regexp = CONFIG['display']['client'].map {|hash|
k, v = hash.to_a.first
[eval(k, TOPLEVEL_BINDING, "#{config_file}:display:client"), v]
}
end
if label = client.props.read rescue nil
catch :found do
@client_tags_by_regexp.each do |regexp, tags|
if label =~ regexp
client.tags = tags
throw :found
end
end
# force client onto current view
begin
client.tags = curr_tag
client.focus
rescue
# ignore
end
end
end
end
# status
action 'status' do
fs.rbar.clear
unless defined? @status_button_by_name
@status_button_by_name = {}
@status_button_by_file = {}
@on_click_by_status_button = {}
CONFIG['display']['status'].each_with_index do |hash, position|
name, defn = hash.to_a.first
# buttons appear in ASCII order of their IXP file name
file = "#{position}-#{name}"
button = eval(
"Button.new(fs.rbar[#{file.inspect}], #{defn['refresh']}) { #{defn['content']} }",
TOPLEVEL_BINDING, "#{config_file}:display:status:#{name}"
)
@status_button_by_name[name] = button
@status_button_by_file[file] = button
# mouse click handler
if code = defn['click']
@on_click_by_status_button[button] = eval(
"lambda {|mouse_button| #{code} }", TOPLEVEL_BINDING,
"#{config_file}:display:status:#{name}:click"
)
end
end
end
@status_button_by_name.each_value {|b| b.refresh }
end
##
# Returns the status button associated with the given name.
#
# ==== Parameters
#
# [name]
# Either the the user-defined name of
# the status button or the basename
# of the status button's IXP file.
#
def status_button name
@status_button_by_name[name] || @status_button_by_file[name]
end
##
# Refreshes the content of the status button with the given name.
#
# ==== Parameters
#
# [name]
# Either the the user-defined name of
# the status button or the basename
# of the status button's IXP file.
#
def status name
if button = status_button(name)
button.refresh
end
end
##
# Invokes the mouse click handler for the given mouse
# button on the status button that has the given name.
#
# ==== Parameters
#
# [name]
# Either the the user-defined name of
# the status button or the basename
# of the status button's IXP file.
#
# [mouse_button]
# The identification number of
# the mouse button (as defined
# by X server) that was clicked.
#
def status_click name, mouse_button
if button = status_button(name) and
handle = @on_click_by_status_button[button]
then
handle.call mouse_button.to_i
end
end
# control
action 'reload' do
# reload this wmii configuration
reload_config
end
action 'rehash' do
# scan for available programs and actions
@programs = find_programs(ENV['PATH'].squeeze(':').split(':'))
end
# kill all currently open clients
action 'clear' do
# firefox's restore session feature does not
# work unless the whole process is killed.
system 'killall firefox firefox-bin thunderbird thunderbird-bin'
# gnome-panel refuses to die by any other means
system 'killall -s TERM gnome-panel'
Thread.pass until clients.each do |c|
begin
c.focus # XXX: client must be on current view in order to be killed
c.kill
rescue
# ignore
end
end.empty?
end
# kill the window manager only; do not touch the clients!
action 'kill' do
fs.ctl.write 'quit'
end
# kill both clients and window manager
action 'quit' do
action 'clear'
action 'kill'
end
event 'Unresponsive' do |client_id|
client = Client.new(client_id)
IO.popen('xmessage -nearmouse -file - -buttons Kill,Wait -print', 'w+') do |f|
f.puts 'The following client is not responding.', ''
f.puts client.inspect
f.puts client.label.read
f.puts '', 'What would you like to do?'
f.close_write
if f.read.chomp == 'Kill'
client.slay
end
end
end
event 'Notice' do |*argv|
unless defined? @notice_mutex
require 'thread'
@notice_mutex = Mutex.new
end
Thread.new do
# prevent notices from overwriting each other
@notice_mutex.synchronize do
button = fs.rbar['!notice']
button.create unless button.exist?
# display the notice
message = argv.join(' ')
LOG.info message # also log it in case the user is AFK
button.write "#{CONFIG['display']['color']['notice']} #{message}"
# clear the notice
sleep [1, CONFIG['display']['notice'].to_i].max
button.remove
end
end
end
%w[key action event].each do |param|
if settings = CONFIG['control'][param]
settings.each do |name, code|
if param == 'key'
# expand ${...} expressions in shortcut key sequences
name = name.gsub(/\$\{(.+?)\}/) { CONFIG['control'][$1] }
end
eval "#{param}(#{name.inspect}) {|*argv| #{code} }",
TOPLEVEL_BINDING, "#{config_file}:control:#{param}:#{name}"
end
end
end
# script
action 'status'
action 'rehash'
eval CONFIG['script']['after'].to_s, TOPLEVEL_BINDING,
"#{config_file}:script:after"
end
##
# Reloads the entire wmii configuration.
#
def reload_config
LOG.info 'reload'
exec $0
end
|
Added alternative_wmiircs/ruby/config.yaml.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 |
#
# High-level wmii configuration.
#
# Ruby code in this file has access
# to a CONFIG constant which contains
# the data in this configuration file.
#
#--
# Copyright protects this work.
# See LICENSE file for details.
#++
##
# Program preferences.
#
program:
terminal: @TERMINAL@
browser: firefox
editor: mousepad
filer: thunar
##
# Appearance settings.
#
display:
##
# Where to display the horizontal status bar?
#
# Possible choices are "top" and "bottom".
#
bar: bottom
##
# The font to use in all text drawn by wmii.
#
font: -*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*
##
# Thickness of client border (measured in pixels).
#
border: 1
##
# Number of seconds a notice should be displayed.
#
notice: 5
##
# Color schemes for everything drawn by wmii.
#
# <scheme>: "<text> <background> <border>"
#
# You can find more color schemes here:
#
# http://wmii.suckless.org/scripts_n_snips/themes
#
color:
normal: "#000000 #c1c48b #81654f"
focus: "#000000 #81654f #000000"
error: "#000000 #81654f #000000"
notice: "#000000 #a1956d #413328"
success: "#000000 #c1c48b #81654f"
##
# Color of desktop background.
#
background: "#333333"
##
# Settings for columns drawn by wmii.
#
# mode: <the wmii "colmode" setting>
# rule: <the wmii "colrules" setting>
#
column:
mode: default
rule: |
/gimp/ -> 17+83+41
/.*/ -> 62+38 # Golden Ratio
##
# Mapping of clients to views they must appear on.
#
# - <client props regular expression> : <tags to apply>
#
# These mappings are processed in top-to-bottom order.
# Processing stops after the first matching mapping is applied.
#
client:
- /MPlayer|VLC/ : ~
##
# Self-refreshing buttons on the status bar.
#
# - <button name>:
# refresh: <number of seconds to wait before refreshing the content>
# content: <Ruby code whose result is displayed as the content>
# click: <Ruby code to handle mouse clicks on the status button.
# This code has access to a "mouse_button" variable which is
# an integer representing the mouse button that was clicked.>
#
# You can refresh a particular status button in Ruby using:
#
# status "your button name"
#
# The horizontal order in which these buttons appear on the status
# bar reflects the vertical order in which they are defined below.
#
status:
- system_load:
refresh: 10
content: |
load_averages = File.read('/proc/loadavg').split.first(3)
current_load = load_averages.first.to_f
# visually indicate the intensity of system load
color = case
when current_load > 3.0 then CONFIG['display']['color']['error']
when current_load > 1.5 then CONFIG['display']['color']['notice']
end
[color, *load_averages]
- clock:
refresh: 5
content: Time.now.to_s
##
# Interaction settings.
#
control:
##
# The wmii "grabmod" setting.
#
grab: Mod4
##
# Key sequence prefixes.
#
mod: Mod4
move: Mod4-Shift
swap: Mod4-w
view: Mod4-v
group: Mod4-g
##
# Direction keys.
#
up: k
down: j
left: h
right: l
##
# Sequence keys.
#
prev: b
next: n
##
# Key bindings.
#
# <key sequence>: <Ruby code to execute>
#
# A key sequence may contain ${...} expressions which
# are replaced with the value corresponding to '...'
# in the 'control' section of this configuration file.
#
# For example, if the 'control' section of
# this configuration file appeared like this:
#
# control:
# foo: Mod4
# bar: y
#
# and the following key sequence was used:
#
# ${foo}-${bar},${bar}
#
# then after ${...} expression replacement,
# that key sequence would appear like this:
#
# Mod4-y,y
#
key:
#---------------------------------------------------------------------------
# focus
#---------------------------------------------------------------------------
${mod}-${up}: | # focus above client
curr_view.select(:up) rescue nil
${mod}-${down}: | # focus below client
curr_view.select(:down) rescue nil
${mod}-${left}: | # focus left client
curr_view.select(:left) rescue nil
${mod}-${right}: | # focus right client
curr_view.select(:right) rescue nil
${mod}-space: | # focus floating area (toggle)
curr_view.select(:toggle)
${mod}-${prev}: | # focus previous view
prev_view.focus
${mod}-${next}: | # focus next view
next_view.focus
# focus the view whose index or name equals the pressed number
${mod}-1: focus_view tags[0] || 1
${mod}-2: focus_view tags[1] || 2
${mod}-3: focus_view tags[2] || 3
${mod}-4: focus_view tags[3] || 4
${mod}-5: focus_view tags[4] || 5
${mod}-6: focus_view tags[5] || 6
${mod}-7: focus_view tags[6] || 7
${mod}-8: focus_view tags[7] || 8
${mod}-9: focus_view tags[8] || 9
${mod}-0: focus_view tags[9] || 10
# focus the view whose name begins with the pressed alphabet
${view},a: t = tags.grep(/^a/i).first and focus_view(t)
${view},b: t = tags.grep(/^b/i).first and focus_view(t)
${view},c: t = tags.grep(/^c/i).first and focus_view(t)
${view},d: t = tags.grep(/^d/i).first and focus_view(t)
${view},e: t = tags.grep(/^e/i).first and focus_view(t)
${view},f: t = tags.grep(/^f/i).first and focus_view(t)
${view},g: t = tags.grep(/^g/i).first and focus_view(t)
${view},h: t = tags.grep(/^h/i).first and focus_view(t)
${view},i: t = tags.grep(/^i/i).first and focus_view(t)
${view},j: t = tags.grep(/^j/i).first and focus_view(t)
${view},k: t = tags.grep(/^k/i).first and focus_view(t)
${view},l: t = tags.grep(/^l/i).first and focus_view(t)
${view},m: t = tags.grep(/^m/i).first and focus_view(t)
${view},n: t = tags.grep(/^n/i).first and focus_view(t)
${view},o: t = tags.grep(/^o/i).first and focus_view(t)
${view},p: t = tags.grep(/^p/i).first and focus_view(t)
${view},q: t = tags.grep(/^q/i).first and focus_view(t)
${view},r: t = tags.grep(/^r/i).first and focus_view(t)
${view},s: t = tags.grep(/^s/i).first and focus_view(t)
${view},t: t = tags.grep(/^t/i).first and focus_view(t)
${view},u: t = tags.grep(/^u/i).first and focus_view(t)
${view},v: t = tags.grep(/^v/i).first and focus_view(t)
${view},w: t = tags.grep(/^w/i).first and focus_view(t)
${view},x: t = tags.grep(/^x/i).first and focus_view(t)
${view},y: t = tags.grep(/^y/i).first and focus_view(t)
${view},z: t = tags.grep(/^z/i).first and focus_view(t)
#---------------------------------------------------------------------------
# move
#---------------------------------------------------------------------------
${move}-${up}: | # move grouping toward the top
grouping.each {|c| c.send(:up) rescue nil }
${move}-${down}: | # move grouping toward the bottom
grouping.each {|c| c.send(:down) rescue nil }
${move}-${left}: | # move grouping toward the left
grouping.each {|c| c.send(:left) rescue nil }
${move}-${right}: | # move grouping toward the right
grouping.each {|c| c.send(:right) rescue nil }
${move}-space: | # move grouping to floating area (toggle)
grouping.each {|c| c.send(:toggle) rescue nil }
${move}-t: | # move grouping to chosen view
#
# Changes the tag (according to a menu choice) of
# each grouped client and returns the chosen tag.
#
# The +tag -tag idea is from Jonas Pfenniger:
#
# http://zimbatm.oree.ch/articles/2006/06/15/wmii-3-and-ruby
#
choices = tags.map {|t| [t, "+#{t}", "-#{t}"] }.flatten
if target = key_menu(choices, 'tag as:')
grouping.each {|c| c.tags = target }
end
# move grouping to the view whose index or name equals the pressed number
${move}-1: grouping.each {|c| c.tags = tags[0] || 1 }
${move}-2: grouping.each {|c| c.tags = tags[1] || 2 }
${move}-3: grouping.each {|c| c.tags = tags[2] || 3 }
${move}-4: grouping.each {|c| c.tags = tags[3] || 4 }
${move}-5: grouping.each {|c| c.tags = tags[4] || 5 }
${move}-6: grouping.each {|c| c.tags = tags[5] || 6 }
${move}-7: grouping.each {|c| c.tags = tags[6] || 7 }
${move}-8: grouping.each {|c| c.tags = tags[7] || 8 }
${move}-9: grouping.each {|c| c.tags = tags[8] || 9 }
${move}-0: grouping.each {|c| c.tags = tags[9] || 10 }
#---------------------------------------------------------------------------
# group
#---------------------------------------------------------------------------
${group},g: | # toggle current client from grouping
curr_client.group!
${group},c: | # add clients in current area to grouping
curr_area.group
${group},Shift-c: | # remove clients in current area from grouping
curr_area.ungroup
${group},f: | # add clients in floating area to grouping
Area.floating.group
${group},Shift-f: | # remove clients in floating area from grouping
Area.floating.ungroup
${group},m: | # add clients in managed areas to grouping
curr_view.managed_areas.each {|a| a.group }
${group},Shift-m: | # remove clients in managed areas from grouping
curr_view.managed_areas.each {|a| a.ungroup }
${group},v: | # add clients in current view to grouping
curr_view.group
${group},Shift-v: | # remove clients in current view from grouping
curr_view.ungroup
${group},i: | # invert the grouping in the current view
curr_view.group!
${group},Shift-i: | # invert the grouping in all views
Rumai.group!
${group},n: | # remove all clients everywhere from grouping
Rumai.ungroup
#---------------------------------------------------------------------------
# swap
#---------------------------------------------------------------------------
${swap},${up}: | # swap with above client
curr_client.swap(:up) rescue nil
${swap},${down}: | # swap with below client
curr_client.swap(:down) rescue nil
${swap},${left}: | # swap with left client
curr_client.swap(:left) rescue nil
${swap},${right}: | # swap with right client
curr_client.swap(:right) rescue nil
# swap current client with the column whose index equals the pressed number
${swap},1: curr_client.swap 1
${swap},2: curr_client.swap 2
${swap},3: curr_client.swap 3
${swap},4: curr_client.swap 4
${swap},5: curr_client.swap 5
${swap},6: curr_client.swap 6
${swap},7: curr_client.swap 7
${swap},8: curr_client.swap 8
${swap},9: curr_client.swap 9
${swap},0: curr_client.swap 10
#---------------------------------------------------------------------------
# client
#---------------------------------------------------------------------------
${mod}-f: | # zoom client to fullscreen (toggle)
curr_client.fullscreen!
${mod}-Shift-c: | # kill the current client
curr_client.kill
#---------------------------------------------------------------------------
# column
#---------------------------------------------------------------------------
${mod}-d: | # apply equal-spacing layout to current column
curr_area.layout = 'default-max'
${mod}-s: | # apply stacked layout to current column
curr_area.layout = 'stack-max'
${mod}-m: | # apply maximized layout to current column
curr_area.layout = 'stack+max'
#---------------------------------------------------------------------------
# menu
#---------------------------------------------------------------------------
${mod}-a: | # run internal action chosen from a menu
if choice = key_menu(actions, 'run action:')
action choice
end
${mod}-p: | # run external program chosen from a menu
if choice = key_menu(@programs, 'run program:')
launch choice
end
${mod}-t: | # focus view chosen from a menu
if choice = key_menu(tags, 'show view:')
focus_view choice
end
#---------------------------------------------------------------------------
# launcher
#---------------------------------------------------------------------------
${mod}-Return: | # launch a terminal
#
# Launch a new terminal and set its
# working directory to be the same
# as the currently focused terminal.
#
work = ENV['HOME']
label = curr_client.label.read rescue ''
# iterate in reverse order because
# paths are usually at end of label
label.split(' ').reverse_each do |s|
path = File.expand_path(s)
if File.exist? path
unless File.directory? path
path = File.dirname(path)
end
work = path
break
end
end
require 'fileutils'
FileUtils.cd work do
launch CONFIG['program']['terminal']
end
##
# Event handlers.
#
# <event name>: <Ruby code to execute>
#
# The Ruby code has access to an "argv" variable which
# is a list of arguments that were passed to the event.
#
event:
CreateTag: |
tag = argv[0]
but = fs.lbar[tag]
but.create unless but.exist?
but.write "#{CONFIG['display']['color']['normal']} #{tag}"
DestroyTag: |
tag = argv[0]
but = fs.lbar[tag]
but.remove if but.exist?
FocusTag: |
tag = argv[0]
but = fs.lbar[tag]
but.write "#{CONFIG['display']['color']['focus']} #{tag}" if but.exist?
UnfocusTag: |
tag = argv[0]
but = fs.lbar[tag]
but.write "#{CONFIG['display']['color']['normal']} #{tag}" if but.exist?
UrgentTag: |
tag = argv[1]
but = fs.lbar[tag]
but.write "#{CONFIG['display']['color']['notice']} #{tag}" if but.exist?
NotUrgentTag: |
tag = argv[1]
but = fs.lbar[tag]
color = curr_view.id == tag ? 'focus' : 'normal'
but.write "#{CONFIG['display']['color'][color]} #{tag}" if but.exist?
LeftBarClick: &LeftBarClick |
mouse_button, view_id = argv
if mouse_button == '1' # primary button
focus_view view_id
end
##
# allows the user to drag a file over a
# view button and activate that view while
# still holding on to their dragged file!
#
LeftBarDND: *LeftBarClick
RightBarClick: |
status_click *argv.reverse
ClientMouseDown: |
client_id, mouse_button = argv
if mouse_button == '3' # secondary button
client = Client.new(client_id)
case click_menu %w[stick group fullscreen kill slay], 'client'
when 'stick' then client.stick!
when 'group' then client.group!
when 'fullscreen' then client.fullscreen!
when 'kill' then client.kill
when 'slay' then client.slay
end
end
##
# Internal scripts.
#
# <action name>: <Ruby code to execute>
#
action:
##
# Arbitrary logic.
#
# script:
# before: <Ruby code to execute before processing this file>
# after: <Ruby code to execute after processing this file>
#
script:
before:
after:
|
Added alternative_wmiircs/ruby/wmiirc.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
#!/usr/bin/env ruby
#
# Bootloader for wmii configuration.
#
#--
# Copyright protects this work.
# See LICENSE file for details.
#++
# create a logger to aid debugging
require 'logger'
LOG = Logger.new(__FILE__ + '.log', 5)
class << LOG
# emulate IO.write
alias write <<
def flush
# ignore
end
end
# capture standard output in logger
$stdout = $stderr = LOG
begin
LOG.info 'birth'
# load configuration library
def find_config file
base_dirs = ENV['WMII_CONFPATH'].to_s.split(/:+/)
ruby_dirs = base_dirs.map {|dir| File.join(dir, 'ruby') }
Dir["{#{base_dirs.zip(ruby_dirs).join(',')}}/#{file}"].first
end
require find_config('config.rb')
# terminate any existing wmiirc
fs.event.write 'Start wmiirc'
event 'Start' do |arg|
exit if arg == 'wmiirc'
end
# apply user configuration
load_config find_config('config.yaml')
# setup tag bar (buttons that correspond to views)
fs.lbar.clear
tags.each {|t| event 'CreateTag', t }
event 'FocusTag', curr_tag
# register key bindings
fs.keys.write keys.join("\n")
event('Key') {|*a| key(*a) }
# the main event loop
fs.event.each_line do |line|
line.split("\n").each do |call|
name, args = call.split(' ', 2)
argv = args.to_s.split(' ')
event name, *argv
end
end
rescue SystemExit
# ignore it; the program wants to terminate
rescue Exception => e
LOG.error e
# allow the user to rescue themselves
system '@TERMINAL@ &'
IO.popen('xmessage -nearmouse -file - -buttons Recover,Ignore -print', 'w+') do |f|
f.puts e.inspect, e.backtrace
f.close_write
if f.read.chomp == 'Recover'
reload_config
end
end
ensure
LOG.info 'death'
end
|
Added cmd/Makefile.
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ROOT=.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk wmiir.c: $(ROOT)/mk/wmii.mk DIRS = menu \ strut \ tray \ wmii \ x11 TARG = wihack \ wmii.rc \ wmii.sh \ wmiir LIBS += $(LIBS9) $(LIBIXP) include $(ROOT)/mk/many.mk include $(ROOT)/mk/dir.mk |
Added cmd/menu/Makefile.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ROOT= ../.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk main.c: $(ROOT)/mk/wmii.mk bindings.c: keys.txt Makefile ( echo "char binding_spec[] ="; \ sed 's/.*/ "&\\n"/' keys.txt; \ echo " ;" ) >$@ TARG = wimenu HFILES= dat.h fns.h TAGFILES= dat.h $(ROOT)/include/*.h $(ROOT)/include/stuff/*.h PACKAGES += $(X11PACKAGES) LIB = $(LIBS9) $(LIBIXP) LIBS += -lm OBJ = main \ caret \ history \ menu \ keys \ bindings include $(ROOT)/mk/one.mk |
Added cmd/menu/caret.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
#include "dat.h"
#include <ctype.h>
#include <string.h>
#include "fns.h"
static int
iswordrune(Rune r) {
if(isalpharune(r))
return 1;
return r < 0x80 && (r == '_' || isdigit(r));
}
static char*
prev_rune(char *start, char *p, Rune *r) {
*r = 0;
if(p == start)
return p;
while(p > start && (*(--p)&0xC0) == 0x80)
;
chartorune(r, p);
return p;
}
static char*
next_rune(char *p, Rune *r) {
int i;
*r = 0;
if(!*p)
return p;
i = chartorune(r, p);
return p + i;
}
void
caret_set(int start, int end) {
int len;
len = input.end - input.string;
start = max(0, min(len, start));
input.pos = input.string + start;
if(end < 0)
input.pos_end = nil;
else
input.pos_end = input.string + max(start, end);
}
char*
caret_find(int dir, int type) {
char *end;
char *next, *p;
Rune r;
int res;
p = input.pos;
if(dir == FORWARD) {
end = input.end;
switch(type) {
case LINE:
return end;
case WORD:
chartorune(&r, p);
res = iswordrune(r);
while(next=next_rune(p, &r), r && iswordrune(r) == res && !isspacerune(r))
p = next;
while(next=next_rune(p, &r), r && isspacerune(r))
p = next;
return p;
case CHAR:
return next_rune(p, &r);
}
}
else if(dir == BACKWARD) {
end = input.string;
switch(type) {
case LINE:
return end;
case WORD:
while(next=prev_rune(end, p, &r), r && isspacerune(r))
p = next;
prev_rune(end, p, &r);
res = iswordrune(r);
while(next=prev_rune(end, p, &r), r && iswordrune(r) == res && !isspacerune(r))
p = next;
return p;
case CHAR:
return prev_rune(end, p, &r);
}
}
input.pos_end = nil;
return input.pos;
}
void
caret_move(int dir, int type) {
input.pos = caret_find(dir, type);
input.pos_end = nil;
}
void
caret_delete(int dir, int type) {
char *pos, *p;
int n;
if(input.pos_end)
p = input.pos_end;
else
p = caret_find(dir, type);
pos = input.pos;
if(p == input.end)
input.end = pos;
else {
if(p < pos) {
pos = p;
p = input.pos;
}
n = input.end - p;
memmove(pos, p, n);
input.pos = pos;
input.end = pos + n;
}
*input.end = '\0';
input.pos_end = nil;
}
void
caret_insert(char *s, bool clear) {
int pos, end, len, size;
if(s == nil)
return;
if(clear) {
input.pos = input.string;
input.end = input.string;
}else if(input.pos_end)
caret_delete(0, 0);
len = strlen(s);
pos = input.pos - input.string;
end = input.end - input.string;
size = input.size;
if(input.size == 0)
input.size = 1;
while(input.size < end + len + 1)
input.size <<= 2;
if(input.size != size)
input.string = erealloc(input.string, input.size);
input.pos = input.string + pos;
input.end = input.string + end + len;
*input.end = '\0';
memmove(input.pos + len, input.pos, end - pos);
memmove(input.pos, s, len);
input.pos += len;
input.pos_end = nil;
}
|
Added cmd/menu/dat.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
#define _XOPEN_SOURCE 600
#define IXP_P9_STRUCTS
#define IXP_NO_P9_
#include <fmt.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ixp.h>
#include <stuff/x.h>
#include <stuff/util.h>
#ifndef EXTERN
# define EXTERN extern
#endif
enum {
FORWARD,
BACKWARD,
LINE,
WORD,
CHAR,
CARET_LAST,
};
enum {
LACCEPT,
LBACKWARD,
LCHAR,
LCOMPLETE,
LDELETE,
LFIRST,
LFORWARD,
LHISTORY,
LKILL,
LLAST,
LLINE,
LLITERAL,
LNEXT,
LNEXTPAGE,
LPASTE,
LPREV,
LPREVPAGE,
LREJECT,
LWORD,
};
typedef struct Item Item;
struct Item {
char* string;
char* retstring;
Item* next_link;
Item* next;
Item* prev;
int len;
int width;
};
EXTERN struct {
char* string;
char* end;
char* pos;
char* pos_end;
int size;
char* filter;
int filter_start;
} input;
EXTERN struct {
Window* win;
Image* buf;
char* prompt;
int height;
int rows;
bool ontop;
Rectangle itemr;
Point arrow;
} menu;
extern char binding_spec[];
EXTERN IxpServer srv;
EXTERN struct {
Item* all;
Item* first;
Item* start;
Item* end;
Item* sel;
int maxwidth;
} match;
Font* font;
CTuple cnorm;
CTuple csel;
EXTERN Item hist;
EXTERN Item* histsel;
EXTERN int itempad;
EXTERN int result;
EXTERN char* (*find)(const char*, const char*);
EXTERN int (*compare)(const char*, const char*, size_t);
|
Added cmd/menu/fns.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /* caret.c */ void caret_delete(int, int); char* caret_find(int, int); void caret_insert(char*, bool); void caret_move(int, int); void caret_set(int, int); /* history.c */ void history_dump(const char*, int); char* history_search(int, char*, int); /* main.c */ void debug(int, const char*, ...); Item* filter_list(Item*, char*); void update_filter(bool); void update_input(void); /* menu.c */ void menu_draw(void); void menu_init(void); void menu_show(void); /* keys.c */ void parse_keys(char*); char** find_key(char*, long); int getsym(char*); |
Added cmd/menu/history.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
#include "dat.h"
#include <assert.h>
#include <bio.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "fns.h"
static void
splice(Item *i) {
if(i->next != nil)
i->next->prev = i->prev;
if(i->prev != nil)
i->prev->next = i->next;
}
char*
history_search(int dir, char *string, int n) {
Item *i;
if(dir == FORWARD) {
if(histsel == &hist)
return hist.string;
for(i=histsel->next; i != hist.next; i=i->next)
if(!i->string || !compare(i->string, string, n)) {
histsel = i;
return i->string;
}
return string;
}
assert(dir == BACKWARD);
if(histsel == &hist) {
free(hist.string);
hist.string = estrdup(input.string);
}
for(i=histsel->prev; i != &hist; i=i->prev)
if(!compare(i->string, string, n)) {
histsel = i;
return i->string;
}
return string;
}
void
history_dump(const char *path, int max) {
static char *items[20];
static char *tmp;
Biobuf b;
Item *h, *first;
int i, n, fd;
SET(first);
if(fork() != 0)
return;
tmp = smprint("%s.XXXXXX", path);
fd = mkstemp(tmp);
if(fd < 0) {
fprint(2, "%s: Can't create temporary history file %q: %r\n", argv0, path);
_exit(1);
}
hist.string = input.string;
n = 0;
hist.next->prev = nil;
for(h=&hist; h; h=h->prev) {
for(i=0; i < nelem(items); i++)
if(items[i] && !strcmp(h->string, items[i])) {
splice(h);
goto next;
}
items[n++ % nelem(items)] = h->string;
first = h;
if(!max || n >= max)
break;
next:
continue;
}
Binit(&b, fd, OWRITE);
hist.next = nil;
for(h=first; h; h=h->next)
if(Bprint(&b, "%s\n", h->string) < 0) {
unlink(tmp);
fprint(2, "%s: Can't write temporary history file %q: %r\n", argv0, path);
_exit(1);
}
Bterm(&b);
rename(tmp, path);
_exit(0);
}
|
Added cmd/menu/keys.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
#include "dat.h"
#include <ctype.h>
#include <strings.h>
#include <unistd.h>
#include "fns.h"
typedef struct Key Key;
struct Key {
Key* next;
long mask;
char* key;
char** action;
};
static Key* bindings;
static int numlock;
/*
* To do: Find my red black tree implementation.
*/
void
parse_keys(char *spec) {
static char *lines[1024];
static char *words[16];
Key *k;
char *p, *line;
int mask;
int i, nlines, nwords;
if(!numlock)
numlock = numlockmask();
nlines = tokenize(lines, nelem(lines), spec, '\n');
for(i=0; i < nlines; i++) {
line = lines[i];
p = strchr(line, '#');
if(p)
*p = '\0';
nwords = stokenize(words, nelem(words) - 1, line, " \t");
words[nwords] = nil;
if(!words[0])
continue;
if(parsekey(words[0], &mask, &p)) {
k = emallocz(sizeof *k);
k->key = p;
k->mask = mask;
k->action = strlistdup(words + 1);
k->next = bindings;
bindings = k;
}
}
}
char**
find_key(char *key, long mask) {
Key *k;
/* Horrible hack. */
if(!strcmp(key, "ISO_Left_Tab"))
key = "Tab";
mask &= ~(numlock | LockMask) & ((1<<8) - 1);
for(k=bindings; k; k=k->next)
if(!strcasecmp(k->key, key) && k->mask == mask)
return k->action;
return nil;
}
/* sed 's/"([^"]+)"/L\1/g' | tr 'a-z' 'A-Z' */
/* awk '{$1=""; print}' keys.txt | perl -e '$_=lc join "", <>; print join "\n", m/(\w+)/g;' | sort -u | sed 's:.*: "&",:' */
char *symtab[] = {
"accept",
"backward",
"char",
"complete",
"delete",
"first",
"forward",
"history",
"kill",
"last",
"line",
"literal",
"next",
"nextpage",
"paste",
"prev",
"prevpage",
"reject",
"word",
};
static int
_bsearch(char *s, char **tab, int ntab) {
int i, n, m, cmp;
if(s == nil)
return -1;
n = ntab;
i = 0;
while(n) {
m = n/2;
cmp = strcasecmp(s, tab[i+m]);
if(cmp == 0)
return i+m;
if(cmp < 0 || m == 0)
n = m;
else {
i += m;
n = n-m;
}
}
return -1;
}
int
getsym(char *s) {
return _bsearch(s, symtab, nelem(symtab));
}
|
Added cmd/menu/keys.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | Control-j Accept Control-m Accept Return Accept Control-Shift-j Accept literal Control-Shift-m Accept literal Shift-Return Accept literal Escape Reject Control-Bracketleft Reject Left Backward char Control-b Backward char Right Forward char Control-f Forward char Mod1-b Backward word Mod1-f Forward word Control-a Backward line Control-e Forward line Control-p History backward Up History backward Control-n History forward Down History forward Backspace Kill char Control-h Kill char Control-Backspace Kill word Control-w Kill word Control-u Kill line Control-k Delete line Tab Complete next Control-i Complete next Mod1-l Complete next Mod1-p Paste PRIMARY Shift-Tab Complete prev Control-Shift-i Complete prev Mod1-h Complete prev Prior Complete prevpage Mod1-k Complete prevpage Next Complete nextpage Mod1-j Complete nextpage Home Complete first Mod1-g Complete first End Complete last Mod1-Shift-g Complete last |
Added cmd/menu/main.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#define EXTERN
#include "dat.h"
#include <X11/Xproto.h>
#include <locale.h>
#include <strings.h>
#include <unistd.h>
#include <bio.h>
#include <stuff/clientutil.h>
#include "fns.h"
#define link _link
static const char version[] = "wimenu-"VERSION", "COPYRIGHT"\n";
static Biobuf* cmplbuf;
static Biobuf* inbuf;
static bool alwaysprint;
static char* cmdsep;
static int screen_hint;
static void
usage(void) {
fprint(2, "usage: %s -i [-a <address>] [-h <history>] [-p <prompt>] [-r <rows>] [-s <screen>]\n", argv0);
fprint(2, " See manual page for full usage details.\n");
exit(1);
}
static int
errfmt(Fmt *f) {
return fmtstrcpy(f, ixp_errbuf());
}
static inline void
splice(Item *i) {
i->next->prev = i->prev;
i->prev->next = i->next;
}
static inline void
link(Item *i, Item *j) {
i->next = j;
j->prev = i;
}
static Item*
populate_list(Biobuf *buf, bool hist) {
Item ret;
Item *i;
char *p;
bool stop;
stop = !hist && !isatty(buf->fid);
ret.next_link = nil;
i = &ret;
while((p = Brdstr(buf, '\n', true))) {
if(stop && p[0] == '\0')
break;
i->next_link = emallocz(sizeof *i);
i = i->next_link;
i->string = p;
i->retstring = p;
if(cmdsep && (p = strstr(p, cmdsep))) {
*p = '\0';
i->retstring = p + strlen(cmdsep);
}
if(!hist) {
i->len = strlen(i->string);
i->width = textwidth_l(font, i->string, i->len) + itempad;
match.maxwidth = max(i->width, match.maxwidth);
}
}
return ret.next_link;
}
static void
check_competions(IxpConn *c) {
char *s;
s = Brdstr(cmplbuf, '\n', true);
if(!s) {
ixp_hangup(c);
return;
}
input.filter_start = strtol(s, nil, 10);
match.all = populate_list(cmplbuf, false);
update_filter(false);
menu_draw();
}
Item*
filter_list(Item *i, char *filter) {
static Item exact;
Item start, substr;
Item *exactp, *startp, *substrp;
Item **ip;
char *p;
int len;
len = strlen(filter);
exactp = &exact;
startp = &start;
substrp = &substr;
for(; i; i=i->next_link)
if((p = find(i->string, filter))) {
ip = &substrp;
if(p == i->string)
if(strlen(p) == len)
ip = &exactp;
else
ip = &startp;
link(*ip, i);
*ip = i;
}
link(substrp, &exact);
link(startp, &substr);
link(exactp, &start);
splice(&substr);
splice(&start);
splice(&exact);
return exact.next;
}
void
update_input(void) {
if(alwaysprint) {
write(1, input.string, input.pos - input.string);
write(1, "\n", 1);
write(1, input.pos, input.end - input.pos);
write(1, "\n", 1);
}
}
void
update_filter(bool print) {
char *filter;
filter = input.string + min(input.filter_start, input.pos - input.string);
if(input.pos < input.end)
filter = freelater(estrndup(filter, input.pos - filter));
match.sel = nil;
match.first = match.start = filter_list(match.all, filter);
if(print)
update_input();
}
enum { PointerScreen = -1 };
void
init_screens(void) {
Rectangle *rects;
Point p;
int i, n;
rects = xinerama_screens(&n);
if(screen_hint >= 0 && screen_hint < n)
i = screen_hint;
else {
/* Pick the screen with the pointer, for now. Later,
* try for the screen with the focused window first.
*/
p = querypointer(&scr.root);
for(i=0; i < n; i++)
if(rect_haspoint_p(rects[i], p))
break;
if(i == n)
i = 0;
}
scr.rect = rects[i];
menu_show();
}
ErrorCode ignored_xerrors[] = {
{ 0, BadWindow },
{ X_GetAtomName, BadAtom },
};
int
main(int argc, char *argv[]) {
static char *address;
static char *histfile;
static char *keyfile;
static bool nokeys;
Item *item;
int i;
long ndump;
setlocale(LC_ALL, "");
fmtinstall('r', errfmt);
quotefmtinstall();
screen_hint = PointerScreen;
find = strstr;
compare = strncmp;
ndump = -1;
ARGBEGIN{
case 'a':
address = EARGF(usage());
break;
case 'c':
alwaysprint = true;
break;
case 'h':
histfile = EARGF(usage());
break;
case 'i':
find = strcasestr;
compare = strncasecmp;
break;
case 'K':
nokeys = true;
case 'k':
keyfile = EARGF(usage());
break;
case 'n':
ndump = strtol(EARGF(usage()), nil, 10);
break;
case 'p':
menu.prompt = EARGF(usage());
break;
case 'r':
menu.rows = strtol(EARGF(usage()), nil, 10);
break;
case 's':
screen_hint = strtol(EARGF(usage()), nil, 10);
break;
case 'S':
cmdsep = EARGF(usage());
break;
case 'v':
lprint(1, "%s", version);
return 0;
default:
usage();
}ARGEND;
if(argc)
usage();
initdisplay();
xext_init();
if(!isatty(0))
menu_init();
client_init(address);
srv.preselect = event_preselect;
ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, event_fdclosed);
menu.ontop = !strcmp(readctl("/ctl", "bar "), "on top");
client_readconfig(&cnorm, &csel, &font);
itempad = (font->height & ~1) + font->pad.min.x + font->pad.max.x;
cmplbuf = Bfdopen(0, OREAD);
match.all = populate_list(cmplbuf, false);
if(!isatty(cmplbuf->fid))
ixp_listen(&srv, cmplbuf->fid, inbuf, check_competions, nil);
caret_insert("", true);
update_filter(false);
if(!nokeys)
parse_keys(binding_spec);
if(keyfile) {
i = open(keyfile, O_RDONLY);
if(read(i, buffer, sizeof(buffer)) > 0)
parse_keys(buffer);
}
histsel = &hist;
link(&hist, &hist);
if(histfile && (inbuf = Bopen(histfile, OREAD))) {
item = filter_list(populate_list(inbuf, true), "");
if(item->string) {
link(item->prev, &hist);
link(&hist, item);
}
Bterm(inbuf);
}
if(menu.win == nil)
menu_init();
init_screens();
i = ixp_serverloop(&srv);
if(i)
fprint(2, "%s: error: %r\n", argv0);
XCloseDisplay(display);
if(ndump >= 0 && histfile && result == 0)
history_dump(histfile, ndump);
return result;
}
|
Added cmd/menu/menu.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
#include "dat.h"
#include <ctype.h>
#include <strings.h>
#include <unistd.h>
#include "fns.h"
static Handlers handlers;
static int promptw;
void
menu_init(void) {
WinAttr wa;
wa.event_mask = ExposureMask | KeyPressMask;
menu.win = createwindow(&scr.root, Rect(-1, -1, 1, 1), scr.depth, InputOutput,
&wa, CWEventMask);
if(scr.xim)
menu.win->xic = XCreateIC(scr.xim,
XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, menu.win->xid,
XNFocusWindow, menu.win->xid,
nil);
changeprop_long(menu.win, Net("WM_WINDOW_TYPE"), "ATOM", (long[]){ TYPE("MENU") }, 1);
changeprop_string(menu.win, "_WMII_TAGS", "sel");
changeprop_textlist(menu.win, "WM_CLASS", "STRING", (char*[3]){ "wimenu", "wimenu" });
sethandler(menu.win, &handlers);
mapwin(menu.win);
int i = 0;
while(!grabkeyboard(menu.win)) {
if(i++ > 1000)
fatal("can't grab keyboard");
usleep(1000);
}
}
void
menu_show(void) {
Rectangle r;
if(menu.prompt)
promptw = textwidth(font, menu.prompt) + itempad;
r = textextents_l(font, "<", 1, nil);
menu.arrow = Pt(Dy(r) + itempad/2, Dx(r) + itempad/2);
menu.height = labelh(font);
freeimage(menu.buf);
menu.buf = allocimage(Dx(scr.rect),
!!menu.rows * 2 * menu.arrow.y + (menu.rows + 1) * menu.height,
menu.win->depth);
mapwin(menu.win);
raisewin(menu.win);
menu_draw();
}
/* I'd prefer to use ⌃ and ⌄, but few fonts support them. */
static void
drawarrow(Image *img, Rectangle r, int up, Color *col) {
Point p[3], pt;
pt = Pt(menu.arrow.x - itempad/2, menu.arrow.y - itempad/2 & ~1);
p[1] = Pt(r.min.x + Dx(r)/2, up ? r.min.y + itempad/4 : r.max.y - itempad/4);
p[0] = Pt(p[1].x - pt.x/2, up ? p[1].y + pt.y : p[1].y - pt.y);
p[2] = Pt(p[1].x + pt.x/2, p[0].y);
drawpoly(img, p, nelem(p), CapProjecting, 1, col);
}
static Rectangle
slice(Rectangle *rp, int x, int y) {
Rectangle r;
r = *rp;
if(x) rp->min.x += x, r.max.x = min(rp->min.x, rp->max.x);
if(y) rp->min.y += y, r.max.y = min(rp->min.y, rp->max.y);
return r;
}
static bool
nextrect(Item *i, Rectangle *rp, Rectangle *src) {
Rectangle r;
if(menu.rows)
r = slice(src, 0, menu.height);
else
r = slice(src, i->width, 0);
return (Dx(*src) >= 0 && Dy(*src) >= 0) && (*rp = r, 1);
}
void
menu_draw(void) {
Rectangle barr, extent, itemr, inputr, r, r2;
Item *item;
int inputw, offset;
barr = r2 = Rect(0, 0, Dx(menu.win->r), menu.height);
inputw = max(match.maxwidth + textwidth_l(font, input.string, min(input.filter_start, strlen(input.string))),
max(itempad + textwidth(font, input.string),
Dx(barr) / 3));
/* Calculate items box, w/ and w/o arrows */
if(menu.rows) {
menu.itemr = barr;
menu.itemr.max.y += Dy(barr) * (menu.rows - 1);
if(menu.ontop)
menu.itemr = rectaddpt(menu.itemr, Pt(0, Dy(barr)));
itemr = menu.itemr;
if(match.start != match.first)
menu.itemr = rectaddpt(menu.itemr, Pt(0, menu.arrow.y));
}
else {
itemr = r2;
slice(&itemr, inputw + promptw, 0);
menu.itemr = Rect(itemr.min.x + menu.arrow.x, itemr.min.y,
itemr.max.x - menu.arrow.x, itemr.max.y);
}
fill(menu.buf, menu.buf->r, &cnorm.bg);
/* Draw items */
item = match.start, r2 = menu.itemr;
nextrect(item, &r, &r2);
do {
match.end = item;
if(item->string)
fillstring(menu.buf, font, r, West, item->string,
(item == match.sel ? &csel : &cnorm), 0);
item = item->next;
} while(item != match.first && nextrect(item, &r, &r2));
/* Adjust dimensions for arrows/number of items */
if(menu.rows)
itemr.max.y = r.max.y + (match.end->next != match.first ? menu.arrow.y : 0);
else
itemr.max.x = r.max.x + menu.arrow.x;
if(menu.rows && !menu.ontop)
barr = rectaddpt(barr, Pt(0, itemr.max.y));
/* Draw indicators */
if(!menu.rows && match.start != match.first)
drawstring(menu.buf, font, itemr, West, "<", &cnorm.fg);
if(!menu.rows && match.end->next != match.first)
drawstring(menu.buf, font, itemr, East, ">", &cnorm.fg);
if(menu.rows && match.start != match.first)
drawarrow(menu.buf, itemr, 1, &cnorm.fg);
if(menu.rows && match.end->next != match.first)
drawarrow(menu.buf, itemr, 0, &cnorm.fg);
/* Draw prompt */
r2 = barr;
if(menu.prompt)
drawstring(menu.buf, font, slice(&r2, promptw, 0),
West, menu.prompt, &cnorm.fg);
/* Border input/horizontal items */
border(menu.buf, r2, 1, &cnorm.border);
/* Draw input */
inputr = slice(&r2, inputw, 0);
drawstring(menu.buf, font, inputr, West, input.string, &cnorm.fg);
/* Draw cursor */
extent = textextents_l(font, input.string, input.pos - input.string, &offset);
r2 = insetrect(inputr, 2);
r2.min.x = inputr.min.x - extent.min.x + offset + font->pad.min.x + itempad/2 - 1;
r2.max.x = r2.min.x + 1;
fill(menu.buf, r2, &cnorm.border);
/* Reshape window */
r = scr.rect;
if(menu.ontop)
r.max.y = r.min.y + itemr.max.y;
else
r.min.y = r.max.y - barr.max.y;
reshapewin(menu.win, r);
/* Border window */
r = rectsubpt(r, r.min);
border(menu.buf, r, 1, &cnorm.border);
copyimage(menu.win, r, menu.buf, ZP);
}
static Item*
pagestart(Item *i) {
Rectangle r, r2;
r = menu.itemr;
nextrect(i, &r2, &r);
while(i->prev != match.first->prev && nextrect(i->prev, &r2, &r))
i = i->prev;
return i;
}
static void
selectitem(Item *i) {
if(i != match.sel) {
caret_set(input.filter_start, input.pos - input.string);
caret_insert(i->string, 0);
match.sel = i;
if(i == match.start->prev)
match.start = pagestart(i);
if(i == match.end->next)
match.start = i;
}
}
static void
paste(void *aux, char *str) {
if(str)
caret_insert(str, false);
menu_draw();
}
static bool
kdown_event(Window *w, void *aux, XKeyEvent *e) {
char **action, **p;
char *key;
char buf[128];
int num, status;
KeySym ksym;
if(XFilterEvent((XEvent*)e, w->xid))
return false;
status = XLookupBoth;
if(w->xic)
num = Xutf8LookupString(w->xic, e, buf, sizeof buf - 1, &ksym, &status);
else
num = XLookupString(e, buf, sizeof buf - 1, &ksym, nil);
if(status != XLookupChars && status != XLookupKeySym && status != XLookupBoth)
return false;
if(status == XLookupKeySym || status == XLookupBoth) {
key = XKeysymToString(ksym);
if(IsKeypadKey(ksym))
if(ksym == XK_KP_Enter)
ksym = XK_Return;
else if(ksym >= XK_KP_0 && ksym <= XK_KP_9)
ksym = (ksym - XK_KP_0) + XK_0;
if(IsFunctionKey(ksym)
|| IsMiscFunctionKey(ksym)
|| IsKeypadKey(ksym)
|| IsPrivateKeypadKey(ksym)
|| IsPFKey(ksym))
return false;
action = find_key(key, e->state);
}
if(status == XLookupChars || action == nil || action[0] == nil) {
if(num && !iscntrl(buf[0])) {
buf[num] = '\0';
caret_insert(buf, false);
update_filter(true);
menu_draw();
}
}
else {
long mask = 0;
# define have(val) !!(mask & (1 << val))
for(p=action+1; *p; p++)
mask |= 1 << getsym(*p);
int amount = (
have(LCHAR) ? CHAR :
have(LWORD) ? WORD :
have(LLINE) ? LINE :
-1);
switch(getsym(action[0])) {
default:
return false;
case LHISTORY:
num = input.pos - input.string;
amount = have(LBACKWARD) ? BACKWARD : FORWARD;
caret_insert(history_search(amount, input.string, num), true);
input.pos = input.string + num;
update_filter(true);
break;
case LKILL:
caret_delete(BACKWARD, amount);
update_filter(true);
break;
case LDELETE:
caret_delete(FORWARD, amount);
update_filter(true);
break;
case LACCEPT:
srv.running = false;
if(!have(LLITERAL) && !match.sel && match.start->retstring)
if(input.filter_start == 0 && input.pos == input.end)
selectitem(match.start);
if(!have(LLITERAL) && match.sel && !strcmp(input.string, match.sel->string))
lprint(1, "%s", match.sel->retstring);
else
lprint(1, "%s", input.string);
break;
case LBACKWARD:
caret_move(BACKWARD, amount);
update_input();
break;
case LCOMPLETE:
if(have(LNEXT))
selectitem(match.sel ? match.sel->next : match.first);
else if(have(LPREV))
selectitem((match.sel ? match.sel : match.start)->prev);
else if(have(LFIRST)) {
match.start = match.first;
selectitem(match.start);
}
else if(have(LLAST))
selectitem(match.first->prev);
else if(have(LNEXTPAGE))
selectitem(match.end->next);
else if(have(LPREVPAGE)) {
match.start = pagestart(match.start->prev);
selectitem(match.start);
}
break;
case LFORWARD:
caret_move(FORWARD, amount);
update_input();
break;
case LPASTE:
getselection(action[1] ? action[1] : "PRIMARY", paste, nil);
break;
case LREJECT:
srv.running = false;
result = 1;
break;
}
menu_draw();
}
return false;
}
static bool
expose_event(Window *w, void *aux, XExposeEvent *e) {
USED(w);
menu_draw();
return false;
}
static Handlers handlers = {
.expose = expose_event,
.kdown = kdown_event,
};
|
Added cmd/strut/Makefile.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ROOT= ../.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk main.c: $(ROOT)/mk/wmii.mk TARG = wistrut HFILES= dat.h fns.h PACKAGES += $(X11PACKAGES) LIB = $(LIBS9) LIBS += -lm OBJ = main \ ewmh \ win include $(ROOT)/mk/one.mk |
Added cmd/strut/dat.h.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <fmt.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <stuff/x.h>
#include <stuff/util.h>
#ifndef EXTERN
# define EXTERN extern
#endif
enum { DAuto, DHorizontal, DVertical };
EXTERN Handlers handlers;
EXTERN int direction;
|
Added cmd/strut/ewmh.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <limits.h>
#include <string.h>
#include "fns.h"
enum {
Left, Right, Top, Bottom,
LeftMin, LeftMax,
RightMin, RightMax,
TopMin, TopMax,
BottomMin, BottomMax,
Last
};
void
ewmh_getstrut(Window *w, Rectangle struts[4]) {
long *strut;
ulong n;
memset(struts, 0, sizeof struts);
n = getprop_long(w, Net("WM_STRUT_PARTIAL"), "CARDINAL",
0L, &strut, Last);
if(n != Last) {
free(strut);
n = getprop_long(w, Net("WM_STRUT"), "CARDINAL",
0L, &strut, 4L);
if(n != 4) {
free(strut);
return;
}
strut = erealloc(strut, Last * sizeof *strut);
strut[LeftMin] = strut[RightMin] = 0;
strut[LeftMax] = strut[RightMax] = INT_MAX;
strut[TopMin] = strut[BottomMin] = 0;
strut[TopMax] = strut[BottomMax] = INT_MAX;
}
struts[Left] = Rect(0, strut[LeftMin], strut[Left], strut[LeftMax]);
struts[Right] = Rect(-strut[Right], strut[RightMin], 0, strut[RightMax]);
struts[Top] = Rect(strut[TopMin], 0, strut[TopMax], strut[Top]);
struts[Bottom] = Rect(strut[BottomMin], -strut[Bottom], strut[BottomMax], 0);
free(strut);
}
void
ewmh_setstrut(Window *w, Rectangle struts[4]) {
long strut[Last];
int i;
strut[LeftMin] = struts[Left].min.y;
strut[Left] = struts[Left].max.x;
strut[LeftMax] = struts[Left].max.y;
strut[RightMin] = struts[Right].min.y;
strut[Right] = -struts[Right].min.x;
strut[RightMax] = struts[Right].max.y;
strut[TopMin] = struts[Top].min.x;
strut[Top] = struts[Top].max.y;
strut[TopMax] = struts[Top].max.x;
strut[BottomMin] = struts[Bottom].min.x;
strut[Bottom] = -struts[Bottom].min.y;
strut[BottomMax] = struts[Bottom].max.x;
for(i=0; i<Last; i++)
if(strut[i] < 0)
strut[i] = 0;
changeprop_long(w, Net("WM_STRUT_PARTIAL"), "CARDINAL", strut, nelem(strut));
}
|
Added cmd/strut/fns.h.
> > > > > > | 1 2 3 4 5 6 | void restrut(Window*); void ewmh_getstrut(Window*, Rectangle[4]); void ewmh_setstrut(Window*, Rectangle[4]); |
Added cmd/strut/main.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#define EXTERN
#include "dat.h"
#include <X11/Xproto.h>
#include <locale.h>
#include <string.h>
#include <time.h>
#include "fns.h"
static Window* testwin;
static ulong testtime[2];
static const char version[] = "wistrut-"VERSION", "COPYRIGHT"\n";
static void manage(ulong);
static void
usage(void) {
fatal("usage: %s [-HV] <window|class>...\n", argv0);
}
static void
search_wins(char *pattern) {
ulong *wins;
ulong n, num;
int i;
char **class;
Reprog *regexp;
Window *win;
regexp = regcomp(pattern);
num = getprop_ulong(&scr.root, "_NET_CLIENT_LIST", "WINDOW", 0L, &wins, 1024L);
for(i = 0; i < num; i++) {
win = window(wins[i]);
n = getprop_textlist(win, "WM_CLASS", &class);
bufclear();
bufprint("%s:%s:%s",
(n > 0 ? class[0] : "<nil>"),
(n > 1 ? class[1] : "<nil>"),
freelater(windowname(win)));
freestringlist(class);
if(regexec(regexp, buffer, nil, 0))
manage(wins[i]);
}
free(wins);
}
static Window
findframe(Window *w) {
XWindow *children;
XWindow xw, par, root;
Window ret = {0, };
uint n;
xw = w->xid;
for(par=w->xid; par != scr.root.xid; ) {
xw = par;
XQueryTree(display, xw, &root, &par, &children, &n);
XFree(children);
}
ret.type = WWindow;
ret.xid = xw;
ret.parent = &scr.root;
return ret;
}
static void
getwinsize(Window *win) {
int x, y;
uint w, h;
XWindow root;
uint border, depth;
XGetGeometry(display, win->xid, &root,
&x, &y, &w, &h,
&border, &depth);
win->r = rectaddpt(Rect(0, 0, w, h),
Pt(x+border, y+border));
}
static bool
managable(ulong xid) {
ulong *ret;
ulong n;
bool retval;
n = getprop_ulong(window(xid), "_WMII_STRUT", "WINDOW", 0L, &ret, 1L);
if(n < 0)
retval = true;
else {
if(ret[0] == xid)
retval = ret[0] != testtime[0] || ret[1] != testtime[1];
else
retval = managable(ret[0]);
}
free(ret);
return retval;
}
static void
manage(ulong xid) {
Window *frame;
Window *win;
if(!managable(xid))
return;
win = emallocz(sizeof *win);
frame = emalloc(sizeof *frame);
win->type = WWindow;
win->xid = xid;
*frame = findframe(win);
frame->aux = win;
getwinsize(frame);
restrut(frame);
sethandler(frame, &handlers);
selectinput(frame, StructureNotifyMask);
changeprop_ulong(frame, "_WMII_STRUT", "WINDOW", testtime, nelem(testtime));
}
int
main(int argc, char *argv[]) {
ulong win;
char *s;
setlocale(LC_CTYPE, "");
fmtinstall('E', fmtevent);
ARGBEGIN{
case 'H':
direction = DHorizontal;
break;
case 'V':
direction = DVertical;
break;
case 'v':
lprint(1, "%s", version);
return 0;
default:
usage();
}ARGEND;
initdisplay();
testwin = createwindow(&scr.root, Rect(0, 0, 1, 1), 0,
InputOnly, nil, 0);
testtime[0] = testwin->xid;
testtime[1] = time(nil);
while(argc) {
s = ARGF();
if(getulong(s, &win))
manage(win);
else
search_wins(s);
}
changeprop_ulong(testwin, "_WMII_STRUT", "WINDOW", testtime, nelem(testtime));
if(windowmap.nmemb > 0)
event_loop();
XCloseDisplay(display);
return 0;
}
|
Added cmd/strut/win.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <string.h>
#include "fns.h"
void
restrut(Window *frame) {
enum { Left, Right, Top, Bottom };
Rectangle strut[4];
Rectangle r;
r = frame->r;
memset(strut, 0, sizeof strut);
if(Dx(r) < Dx(scr.rect)/2 && direction != DVertical) {
if(r.min.x <= scr.rect.min.x) {
strut[Left] = r;
strut[Left].min.x = 0;
strut[Left].max.x -= scr.rect.min.x;
}
if(r.max.x >= scr.rect.max.x) {
strut[Right] = r;
strut[Right].min.x -= scr.rect.max.x;
strut[Right].max.x = 0;
}
}
if(Dy(r) < Dy(scr.rect)/2 && direction != DHorizontal) {
if(r.min.y <= scr.rect.min.y) {
strut[Top] = r;
strut[Top].min.y = 0;
strut[Top].max.y -= scr.rect.min.y;
}
if(r.max.y >= scr.rect.max.y) {
strut[Bottom] = r;
strut[Bottom].min.y -= scr.rect.max.y;
strut[Bottom].max.y = 0;
}
}
/* Choose the struts which take up the least space.
* Not ideal.
*/
if(Dy(strut[Top])) {
if(Dx(strut[Left]))
if(Dy(strut[Top]) < Dx(strut[Left]))
strut[Left] = ZR;
else
strut[Top] = ZR;
if(Dx(strut[Right]))
if(Dy(strut[Top]) < Dx(strut[Right]))
strut[Right] = ZR;
else
strut[Top] = ZR;
}
if(Dy(strut[Bottom])) {
if(Dx(strut[Left]))
if(Dy(strut[Bottom]) < Dx(strut[Left]))
strut[Left] = ZR;
else
strut[Bottom] = ZR;
if(Dx(strut[Right]))
if(Dy(strut[Bottom]) < Dx(strut[Right]))
strut[Right] = ZR;
else
strut[Bottom] = ZR;
}
#if 0
#define pstrut(name) \
if(!eqrect(strut[name], ZR)) \
fprint(2, "strut["#name"] = %R\n", strut[name])
pstrut(Left);
pstrut(Right);
pstrut(Top);
pstrut(Bottom);
#endif
ewmh_setstrut(frame->aux, strut);
}
static bool
config_event(Window *frame, void *aux, XConfigureEvent *ev) {
frame->r = rectaddpt(Rect(ev->x, ev->y, ev->width, ev->height),
Pt(ev->border_width, ev->border_width));
restrut(frame);
return false;
}
static bool
destroy_event(Window *w, void *aux, XDestroyWindowEvent *ev) {
USED(ev);
sethandler(w, nil);
event_looprunning = windowmap.nmemb > 0;
return false;
}
Handlers handlers = {
.config = config_event,
.destroy = destroy_event,
};
|
Added cmd/tray/Makefile.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ROOT= ../.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk main.c: $(ROOT)/mk/wmii.mk TARG = witray HFILES= dat.h fns.h selection.h PACKAGES += $(X11PACKAGES) LIB = $(LIBS9) $(LIBIXP) LIBS += -lm OBJ = \ client \ ewmh \ main \ selection \ tray \ xembed include $(ROOT)/mk/one.mk |
Added cmd/tray/client.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
#include <string.h>
static Handlers handlers;
static void client_cleanup(XEmbed*);
void
client_manage(XWindow w) {
Client **cp;
Client *c;
WinAttr wa;
int size;
c = emallocz(sizeof *c);
c->w.type = WWindow;
c->w.xid = w;
c->w.aux = c;
Dprint("client_manage(%W)\n", &c->w);
traperrors(true);
XAddToSaveSet(display, w);
c->xembed = xembed_swallow(tray.win, &c->w, client_cleanup);
if(traperrors(false)) {
fprint(2, "client_manage(0x%ulx): Caught error.\n", w);
xembed_disown(c->xembed);
return;
}
wa.background_pixel = pixelvalue(&scr.root, &tray.selcolors.bg);
size = max(tray.iconsize / 4, 4);
c->indicator = createwindow(tray.win, Rect(0, 0, size, size), scr.depth,
InputOutput, &wa, CWBackPixel);
setborder(c->indicator, 1, &tray.selcolors.border);
sethandler(&c->w, &handlers);
for(cp=&tray.clients; *cp; cp=&(*cp)->next)
;
*cp = c;
tray_update();
}
void
client_disown(Client *c) {
Dprint("client_disown(%W)\n", &c->w);
xembed_disown(c->xembed);
}
static void
client_cleanup(XEmbed *e) {
Client **cp;
Client *c;
c = e->w->aux;
if (c->indicator)
destroywindow(c->indicator);
for(cp=&tray.clients; *cp; cp=&(*cp)->next)
if(*cp == c) {
*cp = c->next;
break;
}
cleanupwindow(&c->w);
free(c);
tray_update();
}
Client*
client_find(Window *w) {
Client *c;
for(c=tray.clients; c; c=c->next)
if(&c->w == w)
return c;
return nil;
}
void
message_cancel(Client *c, long id) {
Message *m, **mp;
for(mp=&c->message; (m = *mp) && m->id != id; mp=&m->next)
;
if(m) {
*mp = m->next;
free(m->msg.data);
free(m);
}
}
bool
client_hasmessage(Client *c) {
Message *m;
for(m=c->message; m; m=m->next)
if(m->msg.pos == m->msg.end)
return true;
return false;
}
void
client_opcode(Client *c, long message, long l1, long l2, long l3) {
Message *m, **mp;
Dprint("client_opcode(%p, %s, %ulx, %ulx, %ulx)\n",
c,
message == TrayRequestDock ? "TrayRequestDock" :
message == TrayBeginMessage ? "TrayBeginMessage" :
message == TrayCancelMessage ? "TrayCancelMessage" :
sxprint("%lx", message),
l1, l2, l3);
if(message == TrayBeginMessage)
message_cancel(c, l1);
else if(message == TrayBeginMessage) {
if(l2 > 5 * 1024) /* Don't bother with absurdly large messages. */
return;
m = emallocz(sizeof *m);
m->timeout = l1;
m->msg = ixp_message(emallocz(l2), l2, MsgPack);
m->id = l3;
/* Add the message to the end of the queue. */
for(mp=&c->message; *mp; mp=&(*mp)->next)
;
*mp = m;
}
}
void
client_message(Client *c, long type, int format, ClientMessageData* data) {
Message *m;
if(format == 8 && type == NET("SYSTEM_TRAY_MESSAGE_DATA")) {
/* Append the data to the last incomplete message. */
for(m = c->message; m && m->msg.pos >= m->msg.end; m++)
;
if(m) {
memcpy(m->msg.pos, data, min(20, m->msg.end - m->msg.pos));
m->msg.pos += min(20, m->msg.end - m->msg.pos);
}
}
}
static bool
config_event(Window *w, void *aux, XConfigureEvent *e) {
Client *c;
c = aux;
if(false)
movewin(c->indicator, addpt(w->r.min, Pt(1, 1)));
return false;
}
static bool
configreq_event(Window *w, void *aux, XConfigureRequestEvent *e) {
Dprint("configreq_event(%W)\n", w);
/* This seems, sadly, to be necessary. */
tray_update();
return false;
}
static bool
map_event(Window *w, void *aux, XMapEvent *e) {
Dprint("client map_event(%W)\n", w);
w->mapped = true;
tray_update();
return false;
}
static bool
unmap_event(Window *w, void *aux, XUnmapEvent *e) {
Dprint("client map_event(%W)\n", w);
tray_update();
return false;
}
static bool
reparent_event(Window *w, void *aux, XReparentEvent *e) {
Dprint("client reparent_event(%W)\n", w);
return false;
}
static Handlers handlers = {
.config = config_event,
.configreq = configreq_event,
.map = map_event,
.unmap = unmap_event,
.reparent = reparent_event,
};
|
Added cmd/tray/dat.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
#include <fmt.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <ixp.h>
#include <stuff/x.h>
#include <stuff/util.h>
#include "selection.h"
#ifndef EXTERN
# define EXTERN extern
#endif
enum { OAuto, OHorizontal, OVertical };
enum XEmbedFlags {
XEmbedMapped = (1 << 0),
};
enum TrayOpcodes {
TrayRequestDock,
TrayBeginMessage,
TrayCancelMessage,
};
typedef struct Client Client;
typedef struct Message Message;
typedef struct XEmbed XEmbed;
struct Client {
Client* next;
XEmbed* xembed;
Window w;
Window* indicator;
Message* message;
};
struct Message {
Message* next;
long id;
ulong timeout;
IxpMsg msg;
};
struct XEmbed {
Window* w;
Window* owner;
void (*cleanup)(XEmbed*);
int version;
ulong flags;
};
EXTERN IxpServer srv;
EXTERN char** program_args;
EXTERN int debug;
EXTERN struct {
Window* win;
Image* pixmap;
Client* clients;
Selection* selection;
char* tags;
Rectangle r;
ulong iconsize;
ulong padding;
long edge;
int orientation;
Font* font;
CTuple selcolors;
CTuple normcolors;
} tray;
|
Added cmd/tray/ewmh.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <limits.h>
#include <string.h>
#include "fns.h"
enum {
Left, Right, Top, Bottom,
LeftMin, LeftMax,
RightMin, RightMax,
TopMin, TopMax,
BottomMin, BottomMax,
Last
};
void
ewmh_setstrut(Window *w, Rectangle struts[4]) {
long strut[Last];
int i;
strut[LeftMin] = struts[Left].min.y;
strut[Left] = struts[Left].max.x;
strut[LeftMax] = struts[Left].max.y;
strut[RightMin] = struts[Right].min.y;
strut[Right] = -struts[Right].min.x;
strut[RightMax] = struts[Right].max.y;
strut[TopMin] = struts[Top].min.x;
strut[Top] = struts[Top].max.y;
strut[TopMax] = struts[Top].max.x;
strut[BottomMin] = struts[Bottom].min.x;
strut[Bottom] = -struts[Bottom].min.y;
strut[BottomMax] = struts[Bottom].max.x;
for(i=0; i<Last; i++)
if(strut[i] < 0)
strut[i] = 0;
changeprop_long(w, Net("WM_STRUT_PARTIAL"), "CARDINAL", strut, nelem(strut));
}
|
Added cmd/tray/fns.h.
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | void cleanup(Selection*); Client* client_find(Window*); bool client_hasmessage(Client*); void client_disown(Client*); void client_manage(XWindow); void client_message(Client*, long, int, ClientMessageData*); void client_opcode(Client*, long, long, long, long); void ewmh_setstrut(Window*, Rectangle[4]); int main(int, char*[]); void message(Selection*, XClientMessageEvent*); void message_cancel(Client*, long); void restrut(Window*, int); void tray_init(void); void tray_resize(Rectangle); void tray_update(void); void xembed_disown(XEmbed*); XEmbed* xembed_swallow(Window*, Window*, void (*)(XEmbed*)); #define Debug if(debug) #define Dprint Debug print |
Added cmd/tray/main.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#define EXTERN
#include "dat.h"
#include <X11/Xproto.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <stuff/clientutil.h>
#include <sys/signal.h>
#include "fns.h"
static const char version[] = "witray-"VERSION", "COPYRIGHT"\n";
static int exitsignal;
static struct sigaction sa;
static void
usage(void) {
fprint(2, "usage: %s [-a <address>] [-NESW] [-HVn] [-p <padding>] [-s <iconsize>] [-t tags]\n"
" %s -v\n", argv0, argv0);
exit(1);
}
static int
errfmt(Fmt *f) {
return fmtstrcpy(f, ixp_errbuf());
}
static void
cleanup_handler(int signal) {
sa.sa_handler = SIG_DFL;
sigaction(signal, &sa, nil);
selection_release(tray.selection);
srv.running = false;
switch(signal) {
case SIGINT:
case SIGTERM:
sa.sa_handler = cleanup_handler;
sigaction(SIGALRM, &sa, nil);
alarm(1);
default:
exitsignal = signal;
break;
case SIGALRM:
raise(SIGTERM);
}
}
static void
init_traps(void) {
sa.sa_flags = 0;
sa.sa_handler = cleanup_handler;
sigaction(SIGINT, &sa, nil);
sigaction(SIGTERM, &sa, nil);
sigaction(SIGQUIT, &sa, nil);
sigaction(SIGHUP, &sa, nil);
sigaction(SIGUSR1, &sa, nil);
sigaction(SIGUSR2, &sa, nil);
}
void
cleanup(Selection *s) {
USED(s);
while(tray.clients)
client_disown(tray.clients);
tray.selection = nil;
srv.running = false;
}
void
message(Selection *s, XClientMessageEvent *ev) {
Window *w;
Client *c;
USED(s);
Dprint("message(%A) 0x%lx\n", ev->message_type, ev->window);
Dprint("\t0x%lx, 0x%lx, 0x%ulx, 0x%ulx, 0x%ulx\n",
ev->data.l[0], ev->data.l[1], ev->data.l[2], ev->data.l[3], ev->data.l[4]);
w = findwin(ev->window);
if(w == nil)
return;
if(w == tray.selection->owner) {
if(ev->message_type == NET("SYSTEM_TRAY_OPCODE") && ev->format == 32)
if(ev->data.l[1] == TrayRequestDock)
client_manage(ev->data.l[2]);
return;
}
if((c = client_find(w))) {
if(ev->message_type == NET("SYSTEM_TRAY_OPCODE") && ev->format == 32)
client_opcode(w->aux, ev->data.l[1], ev->data.l[2], ev->data.l[3], ev->data.l[4]);
else
client_message(w->aux, ev->message_type, ev->format, (ClientMessageData*)&ev->data);
return;
}
}
ErrorCode ignored_xerrors[] = {
{ 0, BadWindow },
{ X_GetAtomName, BadAtom },
};
int
main(int argc, char *argv[]) {
static char* address;
bool steal;
program_args = argv;
setlocale(LC_CTYPE, "");
fmtinstall('r', errfmt);
fmtinstall('E', fmtevent);
steal = true;
tray.orientation = OHorizontal;
tray.tags = "/./";
tray.padding = 1;
ARGBEGIN{
case 'N':
tray.edge = (tray.edge & ~South) | North;
break;
case 'S':
tray.edge = (tray.edge & ~North) | South;
break;
case 'E':
tray.edge = (tray.edge & ~West) | East;
break;
case 'W':
tray.edge = (tray.edge & ~East) | West;
break;
case 'H':
tray.orientation = OHorizontal;
break;
case 'V':
tray.orientation = OVertical;
break;
case 'n':
steal = false;
break;
case 'p':
if(!getulong(EARGF(usage()), &tray.padding))
usage();
tray.padding = max(1, min(10, (int)tray.padding));
break;
case 's':
if(!getulong(EARGF(usage()), &tray.iconsize))
usage();
tray.iconsize = max(1, (int)tray.iconsize);
break;
case 't':
tray.tags = EARGF(usage());
break;
case 'a':
address = EARGF(usage());
break;
case 'D':
debug++;
break;
case 'v':
lprint(1, "%s", version);
return 0;
default:
usage();
}ARGEND;
if(argc)
usage();
init_traps();
initdisplay();
srv.preselect = event_preselect;
ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, event_fdclosed);
event_updatextime();
tray.selection = selection_manage(sxprint(Net("SYSTEM_TRAY_S%d"), scr.screen),
event_xtime, message, cleanup, steal);
if(tray.selection == nil)
fatal("Another system tray is already running.");
if(tray.selection->oldowner)
lprint(1, "%s: Replacing currently running system tray.\n", argv0);
xext_init();
tray_init();
client_init(address);
if(tray.edge == 0)
tray.edge = West | (!strcmp(readctl("/ctl", "bar on "), "top") ? North : South);
client_readconfig(&tray.normcolors, &tray.selcolors, &tray.font);
if(tray.iconsize == 0) /* Default to wmii's bar size. */
tray.iconsize = labelh(tray.font) - 2 * tray.padding;
srv.running = true;
ixp_serverloop(&srv);
if(tray.selection)
selection_release(tray.selection);
XCloseDisplay(display);
if(exitsignal)
raise(exitsignal);
return 0;
}
|
Added cmd/tray/selection.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
static Handlers selection_handlers;
static Handlers steal_handlers;
static Selection*
_selection_create(char *selection, ulong time,
void (*request)(Selection*, XSelectionRequestEvent*),
void (*cleanup)(Selection*),
bool lazy) {
Selection *s;
if(time == 0)
time = event_xtime;
s = emallocz(sizeof *s);
s->owner = createwindow(&scr.root, Rect(0, 0, 1, 1), 0,
InputOnly, nil, 0);
s->owner->aux = s;
s->request = request;
s->cleanup = cleanup;
s->time_start = time;
sethandler(s->owner, &selection_handlers);
if (!lazy) {
XSetSelectionOwner(display, xatom(selection), s->owner->xid, time);
/*
* There is a race here that ICCCM doesn't mention. It's
* possible that we've gained and lost the selection in this
* time, and a client's sent us a selection request. We're
* required to reply to it, but since we're destroying the
* window, we'll never hear about it. Since ICCCM doesn't
* mention it, we assume that other clients behave likewise,
* and therefore clients must be prepared to deal with such
* behavior regardless.
*/
if(XGetSelectionOwner(display, xatom(selection)) != s->owner->xid) {
destroywindow(s->owner);
free(s);
return nil;
}
}
s->selection = estrdup(selection);
return s;
}
Selection*
selection_create(char *selection, ulong time,
void (*request)(Selection*, XSelectionRequestEvent*),
void (*cleanup)(Selection*)) {
return _selection_create(selection, time, request, cleanup, false);
}
static void
_selection_manage(Selection *s) {
if (s->oldowner) {
Dprint("[selection] Grabbing.\n");
XSetSelectionOwner(display, xatom(s->selection), s->owner->xid, s->time_start);
if(XGetSelectionOwner(display, xatom(s->selection)) != s->owner->xid) {
selection_release(s);
return;
}
}
Dprint("[selection] Notifying.\n");
clientmessage(&scr.root, "MANAGER", SubstructureNotifyMask|StructureNotifyMask, 32,
(ClientMessageData){ .l = {s->time_start, xatom(s->selection), s->owner->xid} });
}
static void
timeout(long timer, void *v) {
Selection *s;
s = v;
Dprint("[selection] Done waiting. Killing 0x%ulx.\n", s->oldowner);
s->timer = 0;
XKillClient(display, s->oldowner);
sync();
}
Selection*
selection_manage(char *selection, ulong time,
void (*message)(Selection*, XClientMessageEvent*),
void (*cleanup)(Selection*),
bool steal) {
Selection *s;
Window *w;
XWindow old;
if((old = XGetSelectionOwner(display, xatom(selection)))) {
if (!steal)
return nil;
w = emallocz(sizeof *w);
w->type = WWindow;
w->xid = old;
selectinput(w, StructureNotifyMask);
/* Hack for broken Qt systray implementation. If it
* finds a new system tray running when the old one
* dies, it never selects the StructureNotify mask
* on it, and therefore never disassociates from it,
* and completely ignores any future MANAGER
* messages it receives.
*/
XSetSelectionOwner(display, xatom(selection), 0, time);
}
s = _selection_create(selection, time, nil, cleanup, old);
if(s) {
s->message = message;
s->oldowner = old;
if(!old)
_selection_manage(s);
else {
Dprint("[selection] Waiting for old owner %W to die...\n", w);
pushhandler(w, &steal_handlers, s);
s->timer = ixp_settimer(&srv, 2000, timeout, s);
}
}
return s;
}
void
selection_release(Selection *s) {
if(s->cleanup)
s->cleanup(s);
if(!s->time_end)
XSetSelectionOwner(display, xatom(s->selection), None, s->time_start);
destroywindow(s->owner);
free(s->selection);
free(s);
}
static void
selection_notify(Selection *s, XSelectionRequestEvent *ev, bool success) {
XSelectionEvent notify;
notify.type = SelectionNotify;
notify.requestor = ev->requestor;
notify.selection = ev->selection;
notify.target = ev->target;
notify.property = success ? ev->property : None;
notify.time = ev->time;
sendevent(window(ev->requestor), false, 0L, ¬ify);
}
static bool
message_event(Window *w, void *aux, XClientMessageEvent *ev) {
Selection *s;
s = aux;
if(s->message)
s->message(s, ev);
return false;
}
static bool
selectionclear_event(Window *w, void *aux, XSelectionClearEvent *ev) {
Selection *s;
USED(w, ev);
Dprint("[selection] Lost selection\n");
s = aux;
s->time_end = ev->time;
selection_release(s);
return false;
}
static bool
selectionrequest_event(Window *w, void *aux, XSelectionRequestEvent *ev) {
Selection *s;
s = aux;
if(ev->property == None)
ev->property = ev->target; /* Per ICCCM §2.2. */
Dprint("[selection] Request: %A\n", ev->target);
if(ev->target == xatom("TIMESTAMP")) {
/* Per ICCCM §2.6.2. */
changeprop_ulong(window(ev->requestor),
atomname(ev->property), "TIMESTAMP",
&s->time_start, 1);
selection_notify(s, ev, true);
return false;
}
if(s->request)
s->request(s, ev);
else
selection_notify(s, ev, false);
return false;
}
static Handlers selection_handlers = {
.message = message_event,
.selectionclear = selectionclear_event,
.selectionrequest = selectionrequest_event,
};
static bool
destroy_event(Window *w, void *aux, XDestroyWindowEvent *e) {
Selection *s;
Dprint("[selection] Old owner is dead.\n");
s = aux;
if(s->timer)
ixp_unsettimer(&srv, s->timer);
s->timer = 0;
_selection_manage(s);
s->oldowner = 0;
return false;
}
static Handlers steal_handlers = {
.destroy = destroy_event,
};
|
Added cmd/tray/selection.h.
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
typedef struct Selection Selection;
struct Selection {
Window* owner;
char* selection;
ulong time_start;
ulong time_end;
void (*cleanup)(Selection*);
void (*message)(Selection*, XClientMessageEvent*);
void (*request)(Selection*, XSelectionRequestEvent*);
long timer;
ulong oldowner;
};
Selection* selection_create(char*, ulong, void (*)(Selection*, XSelectionRequestEvent*), void (*)(Selection*));
Selection* selection_manage(char*, ulong, void (*)(Selection*, XClientMessageEvent*), void (*)(Selection*), bool);
void selection_release(Selection*);
|
Added cmd/tray/tray.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <string.h>
#include <strings.h>
#include "fns.h"
static Handlers handlers;
static Handlers root_handlers;
void
restrut(Window *w, int orientation) {
enum { Left, Right, Top, Bottom };
Rectangle strut[4];
Rectangle r;
r = w->r;
memset(strut, 0, sizeof strut);
if(Dx(r) < Dx(scr.rect)/2 && orientation != OHorizontal) {
if(r.min.x <= scr.rect.min.x) {
strut[Left] = r;
strut[Left].min.x = 0;
strut[Left].max.x -= scr.rect.min.x;
}
if(r.max.x >= scr.rect.max.x) {
strut[Right] = r;
strut[Right].min.x -= scr.rect.max.x;
strut[Right].max.x = 0;
}
}
if(Dy(r) < Dy(scr.rect)/2 && orientation != OVertical) {
if(r.min.y <= scr.rect.min.y) {
strut[Top] = r;
strut[Top].min.y = 0;
strut[Top].max.y -= scr.rect.min.y;
}
if(r.max.y >= scr.rect.max.y) {
strut[Bottom] = r;
strut[Bottom].min.y -= scr.rect.max.y;
strut[Bottom].max.y = 0;
}
}
#if 0
#define pstrut(name) \
if(!eqrect(strut[name], ZR)) \
fprint(2, "strut["#name"] = %R\n", strut[name])
pstrut(Left);
pstrut(Right);
pstrut(Top);
pstrut(Bottom);
#endif
ewmh_setstrut(w, strut);
}
void
tray_init(void) {
WinAttr wa;
XWMHints hints = { 0, };
wa.background_pixmap = None;
wa.bit_gravity = NorthEastGravity;
wa.border_pixel = 0;
wa.event_mask = ExposureMask
| ButtonPressMask
| ButtonReleaseMask
| StructureNotifyMask
| SubstructureNotifyMask
/* Disallow clients reconfiguring themselves. */
| SubstructureRedirectMask;
tray.win = createwindow(&scr.root, Rect(0, 0, 1, 1), scr.depth, InputOutput,
&wa, CWBackPixmap
| CWBitGravity
| CWEventMask);
sethandler(tray.win, &handlers);
pushhandler(&scr.root, &root_handlers, nil);
selectinput(&scr.root, scr.root.eventmask | PropertyChangeMask);
changeprop_string(tray.win, "_WMII_TAGS", tray.tags);
changeprop_ulong(tray.win, "XdndAware", "ATOM", (ulong[1]){ 5 }, 1);
changeprop_ulong(tray.selection->owner, Net("SYSTEM_TRAY_VISUAL"), "VISUALID",
&scr.visual->visualid, 1);
changeprop_long(tray.win, Net("WM_WINDOW_TYPE"), "ATOM",
(long[1]){ TYPE("DOCK") }, 1);
changeprop_string(tray.win, Net("WM_NAME"), "witray");
changeprop_textlist(tray.win, "WM_NAME", "STRING",
(char*[2]){ "witray", nil });
changeprop_textlist(tray.win, "WM_CLASS", "STRING",
(char*[3]){ "witray", "witray", nil });
changeprop_textlist(tray.win, "WM_COMMAND", "STRING", program_args);
hints.flags = InputHint;
hints.input = false;
XSetWMHints(display, tray.win->xid, &hints);
tray_resize(tray.win->r);
}
static void
tray_unmap(void) {
unmapwin(tray.win);
sendevent(&scr.root, false, SubstructureNotifyMask,
&(XUnmapEvent){
.type = UnmapNotify,
.event = scr.root.xid,
.window = tray.win->xid
});
}
static void
tray_draw(Rectangle r) {
int borderwidth;
if(!tray.pixmap)
return;
borderwidth = 1;
r = rectsetorigin(r, ZP);
border(tray.pixmap, r, borderwidth, &tray.selcolors.border);
r = insetrect(r, borderwidth);
fill(tray.pixmap, r, &tray.selcolors.bg);
XClearWindow(display, tray.win->xid);
}
void
tray_resize(Rectangle r) {
WinHints hints;
Image *oldimage;
WinAttr wa;
hints = ZWinHints;
hints.position = true;
hints.min = hints.max = Pt(Dx(r), Dy(r));
hints.grav = Pt(tray.edge & East ? 0 :
tray.edge & West ? 2 : 1,
tray.edge & North ? 0 :
tray.edge & South ? 2 : 1);
/* Not necessary, since we specify fixed size, but... */
// hints.base = Pt(2, 2);
// hints.inc = Pt(tray.iconsize, tray.iconsize);
sethints(tray.win, &hints);
if(!eqrect(tray.win->r, r)) {
oldimage = tray.pixmap;
tray.pixmap = allocimage(Dx(r), Dy(r), tray.win->depth);
tray_draw(r);
wa.background_pixmap = tray.pixmap->xid;
setwinattr(tray.win, &wa, CWBackPixmap);
freeimage(oldimage);
}
tray.r = r;
tray.win->r = ZR; /* Force the configure event. */
reshapewin(tray.win, r);
restrut(tray.win, tray.orientation);
}
void
tray_update(void) {
Rectangle r;
Point p, offset, padding;
Client *c;
r = Rect(0, 0, tray.iconsize, tray.iconsize);
padding = Pt(tray.padding, tray.padding);
offset = padding;
Dprint("tray_update()\n");
for(c=tray.clients; c; c=c->next) {
if(c->w.mapped) {
reshapewin(&c->w, rectaddpt(r, offset));
/* This seems, sadly, to be necessary. */
sendevent(&c->w, false, StructureNotifyMask, &(XEvent){
.xconfigure = {
.type = ConfigureNotify,
.event = c->w.xid,
.window = c->w.xid,
.above = None,
.x = c->w.r.min.x,
.y = c->w.r.min.y,
.width = Dx(c->w.r),
.height = Dy(c->w.r),
.border_width = 0,
}
});
movewin(c->indicator, addpt(offset, Pt(2, 2)));
if(tray.orientation == OHorizontal)
offset.x += tray.iconsize + tray.padding;
else
offset.y += tray.iconsize + tray.padding;
}
if(c->w.mapped && client_hasmessage(c))
mapwin(c->indicator);
else
unmapwin(c->indicator);
}
if(eqpt(offset, padding))
tray_unmap();
else {
if(tray.orientation == OHorizontal)
offset.y += tray.iconsize + tray.padding;
else
offset.x += tray.iconsize + tray.padding;
r = Rpt(ZP, offset);
p = subpt(scr.rect.max, r.max);
if(tray.edge & East)
p.x = 0;
if(tray.edge & North)
p.y = 0;
tray_resize(rectaddpt(r, p));
mapwin(tray.win);
}
tray_draw(tray.win->r);
}
static bool
config_event(Window *w, void *aux, XConfigureEvent *ev) {
USED(aux);
if(ev->send_event) {
/*
* Per ICCCM §4.2.3, the window manager sends
* synthetic configure events in the root coordinate
* space when it changes the window configuration.
* This code assumes wmii's generous behavior of
* supplying all relevant members in every configure
* notify event.
*/
w->r = rectaddpt(rectsetorigin(Rect(0, 0, ev->width, ev->height),
Pt(ev->x, ev->y)),
Pt(ev->border_width, ev->border_width));
restrut(w, tray.orientation);
}
return false;
}
static bool
expose_event(Window *w, void *aux, XExposeEvent *ev) {
USED(w, aux, ev);
tray_draw(tray.win->r);
return false;
}
typedef struct Dnd Dnd;
struct Dnd {
ulong source;
ulong dest;
long data[4];
Point p;
bool have_actions;
};
static Dnd dnd;
#define Point(l) Pt((ulong)(l) >> 16, (ulong)(l) & 0xffff)
#define Long(p) ((long)(((ulong)(p).x << 16) | (ulong)(p).y))
#define sendmessage(...) BLOCK( \
Dprint("(%W) %s 0x%ulx, 0x%ulx, 0x%ulx, 0x%ulx, 0x%ulx\n", __VA_ARGS__); \
sendmessage(__VA_ARGS__); \
)
static void
dnd_updatestatus(ulong dest) {
if(dest == dnd.dest)
return;
if(dnd.dest && dnd.dest != ~0UL)
sendmessage(window(dnd.dest), "XdndLeave", tray.win->xid, 0, 0, 0, 0);
dnd.dest = dest;
if(dest)
sendmessage(window(dest), "XdndEnter", tray.win->xid,
dnd.data[0], dnd.data[1], dnd.data[2], dnd.data[3]);
else
sendmessage(window(dnd.source), "XdndStatus", tray.win->xid, (1<<1),
Long(tray.win->r.min), (Dx(tray.win->r)<<16) | Dy(tray.win->r), 0UL);
}
static void
copyprop_long(Window *src, Window *dst, char *atom, char *type, long max) {
long *data;
long n;
/* Round trip. Really need to switch to XCB. */
if((n = getprop_long(src, atom, type, 0, &data, max)))
changeprop_long(dst, atom, type, data, n);
free(data);
}
static void
copyprop_char(Window *src, Window *dst, char *atom, char *type, long max) {
uchar *data;
ulong actual, n;
int format;
n = getprop(src, atom, type, &actual, &format, 0, &data, max);
if(n > 0 && format == 8 && xatom(type) == actual)
changeprop_char(dst, atom, type, (char*)data, n);
free(data);
}
static bool
message_event(Window *w, void *aux, XClientMessageEvent *e) {
Client *c;
long *l;
Rectangle r;
Point p;
ulong msg;
msg = e->message_type;
l = e->data.l;
Dprint("ClientMessage: %A\n", msg);
if(e->format == 32)
Dprint("\t0x%ulx, 0x%ulx, 0x%ulx, 0x%ulx, 0x%ulx\n",
l[0], l[1], l[2], l[3], l[4]);
if(msg == xatom("XdndEnter")) {
if(e->format != 32)
return false;
dnd = (Dnd){0};
dnd.dest = ~0UL;
dnd.source = l[0];
bcopy(&l[1], dnd.data, sizeof dnd.data);
copyprop_long(window(dnd.source), tray.win, "XdndSelection", "ATOM", 128);
if(l[1] & 0x01)
copyprop_long(window(dnd.source), tray.win, "XdndTypeList", "ATOM", 128);
return false;
}else
if(msg == xatom("XdndLeave")) {
if(e->format != 32)
return false;
dnd.source = 0UL;
if(dnd.dest)
sendmessage(window(dnd.dest), "XdndLeave", tray.win->xid, l[1], 0, 0, 0);
return false;
}else
if(msg == xatom("XdndPosition")) {
if(e->format != 32)
return false;
if(!dnd.have_actions && l[4] == xatom("XdndActionAsk")) {
dnd.have_actions = true;
copyprop_long(window(dnd.source), tray.win, "XdndActionList", "ATOM", 16);
copyprop_char(window(dnd.source), tray.win, "XdndActionDescription", "ATOM", 16 * 32);
}
dnd.p = subpt(Point(l[2]), tray.win->r.min);
for(c=tray.clients; c; c=c->next)
if(rect_haspoint_p(c->w.r, dnd.p)) {
dnd_updatestatus(c->w.xid);
sendmessage(&c->w, "XdndPosition", tray.win->xid, l[1], l[2], l[3], l[4]);
return false;
}
dnd_updatestatus(0UL);
return false;
}else
if(msg == xatom("XdndStatus")) {
if(e->format != 32)
return false;
if(l[0] != dnd.dest)
return false;
for(c=tray.clients; c; c=c->next)
if(c->w.xid == dnd.dest) {
p = Point(l[2]);
r = Rpt(p, addpt(p, Point(l[3])));
r = rect_intersection(r, rectaddpt(c->w.r, tray.win->r.min));
sendmessage(window(dnd.source), "XdndStatus", tray.win->xid, l[1],
Long(r.min), (Dx(r)<<16) | Dy(r), l[4]);
break;
}
return false;
}else
if(msg == xatom("XdndDrop") || msg == xatom("XdndFinished")) {
if(e->format != 32)
return false;
for(c=tray.clients; c; c=c->next)
if(c->w.xid == dnd.dest) {
sendmessage(&c->w, atomname(msg),
tray.win->xid, l[1], l[2], 0L, 0L);
break;
}
return false;
}
return true;
}
static Handlers handlers = {
.message = message_event,
.config = config_event,
.expose = expose_event,
};
static bool
property_event(Window *w, void *aux, XPropertyEvent *ev) {
if(ev->atom == NET("CURRENT_DESKTOP"))
tray_resize(tray.r);
Debug if(ev->atom == NET("CURRENT_DESKTOP"))
print("property_event(_NET_CURRENT_DESKTOP)\n");
return false;
}
static Handlers root_handlers = {
.property = property_event,
};
|
Added cmd/tray/xembed.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
#define DEAD ~0UL
enum { XEmbedVersion = 0 };
enum XEmbedMessage {
XEmbedEmbeddedNotify,
XEmbedWindowActivate,
XEmbedWindowDeactivate,
XEmbedRequestFocus,
XEmbedFocusIn,
XEmbedFocusOut,
XEmbedFocusNext,
XEmbedFocusPrev,
XEmbedModalityOn = 10,
XEmbedModalityOff,
XEmbedRegisterAccelerator,
XEmbedUnregisterAccelerator,
XEmbedActivateAccelerator,
};
enum XEmbedFocusDetail {
XEmbedFocusCurrent,
XEmbedFocusFirst,
XEmbedFocusLast,
};
static Handlers handlers;
static void xembed_updateinfo(XEmbed*);
static void xembed_sendmessage(XEmbed*, long, long, long, long);
XEmbed*
xembed_swallow(Window *parent, Window *client, void (*cleanup)(XEmbed*)) {
XEmbed *xembed;
xembed = emallocz(sizeof *xembed);
xembed->w = client;
xembed->owner = parent;
xembed->cleanup = cleanup;
selectinput(client, client->eventmask | PropertyChangeMask | StructureNotifyMask);
pushhandler(client, &handlers, xembed);
reparentwindow(client, parent, ZP);
xembed_updateinfo(xembed);
xembed_sendmessage(xembed, XEmbedEmbeddedNotify, 0, parent->xid, min(XEmbedVersion, xembed->version));
return xembed;
}
void
xembed_disown(XEmbed *xembed) {
pophandler(xembed->w, &handlers);
if(xembed->flags != DEAD) {
reparentwindow(xembed->w, &scr.root, ZP);
unmapwin(xembed->w);
}
if(xembed->cleanup)
xembed->cleanup(xembed);
free(xembed);
}
static void
xembed_updateinfo(XEmbed *xembed) {
ulong *res;
int n;
n = getprop_ulong(xembed->w, "_XEMBED_INFO", "_XEMBED_INFO", 0, &res, 2);
xembed->flags = 0UL;
if(n >= 2) {
xembed->version = res[0];
xembed->flags = res[1];
}
else {
/* Deal with a Qt system tray replacement bug. */
xembed->flags = XEmbedMapped;
}
free(res);
Dprint("xembed_updateinfo(0x%ulx) XEmbedMapped=%s\n",
xembed->w,
xembed->flags & XEmbedMapped ? "true" : "false");
if(xembed->flags & XEmbedMapped)
mapwin(xembed->w);
else
unmapwin(xembed->w);
}
static void
xembed_sendmessage(XEmbed *xembed, long message, long detail, long data1, long data2) {
traperrors(true);
sendmessage(xembed->w, "_XEMBED", event_xtime, message, detail, data1, data2);
traperrors(false);
}
static bool
destroy_event(Window *w, void *aux, XDestroyWindowEvent *ev) {
XEmbed *xembed;
xembed = aux;
xembed->flags = DEAD;
xembed_disown(xembed);
return false;
}
static bool
property_event(Window *w, void *aux, XPropertyEvent *ev) {
XEmbed *xembed;
Dprint("property_event(%W, %p, %A)\n",
w, aux, ev->atom);
xembed = aux;
if(ev->atom == xatom("_XEMBED_INFO"))
xembed_updateinfo(xembed);
return false;
}
static bool
reparent_event(Window *w, void *aux, XReparentEvent *ev) {
XEmbed *xembed;
xembed = aux;
if(ev->parent != xembed->owner->xid) {
xembed->flags = DEAD;
xembed_disown(xembed);
}
return false;
}
static Handlers handlers = {
.destroy = destroy_event,
.property = property_event,
.reparent = reparent_event,
};
|
Added cmd/wihack.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#!/bin/sh -f
unset WMII_HACK_TRANSIENT WMII_HACK_TYPE WMII_HACK_TAGS
usage() {
echo 1>&2 Usage: \
"$0 [-transient <window>] [-type <window_type>[,...]] [-tags <tags>] <command> [<arg> ...]"
exit 1
}
checkarg='[ ${#@} -gt 0 ] || usage'
export WMII_HACK_TIME=$(date +%s)
while [ ${#@} -gt 0 ]
do
case $1 in
-transient)
shift; eval $checkarg
export WMII_HACK_TRANSIENT=$1
shift;;
-type)
shift; eval $checkarg
export WMII_HACK_TYPE=$1
shift;;
-tags)
shift; eval $checkarg
export WMII_HACK_TAGS=$1
shift;;
-*)
usage;;
*)
break;;
esac
done
eval $checkarg
if [ ! -u "`which $1`" -a ! -g "`which $1`" ]
then
export LD_PRELOAD="@LIBDIR@/libwmii_hack.so"
else
unset WMII_HACK_TRANSIENT WMII_HACK_TYPE WMII_HACK_TAGS
fi
exec "$@"
|
Added cmd/wmii.rc.rc.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# For the time being, this file follows the lisp bracing
# convention. i.e.:
# if(frob this) {
# frob that
# if(frob theother) {
# unfrob this
# unfrob that}}
wmiiscript=$1
wmiikeys=()
wmiikeyhelp=''
wi_newline='
'
echo Start $wmiiscript | wmiir write /event >[2]/dev/null \
|| exit write
if(~ $scriptname '')
scriptname=$wmiiscript
# Blech.
if(! test -x $PLAN9/bin/read)
fn read { sh -c 'read -r x || exit 1; echo $x' }
fn wi_atexit {}
fn sigexit {
wi_atexit
}
fn wi_fatal {
echo $scriptname: Fatal: $*
exit fatal
}
fn wi_notice {
xmessage $scriptname: Notice: $*
}
fn wi_readctl { wmiir read /ctl | sed -n 's/^'$1' (.*)/\1/p' }
wmiifont=`{wi_readctl font}
wmiinormcol=`{wi_readctl normcolors}
wmiifocuscol=`{wi_readctl focuscolors}
fn wi_fnmenu {
group=$1^Menu-$2 last=$group^_last fns=`{wi_getfuns $group} {
shift 2
if(! ~ $#fns 0) {
res = `{wmii9menu -i $"($last) $fns} \
if(! ~ $res '') {
($last) = $res
$group-$res $*}}}
}
fn wi_fn-p {
rc -c 'whatis '$1 >[2]/dev/null | grep -s '^fn '
}
fn wi_proglist {
ifs=: { wmiir proglist -- `{echo -n $*} | sort | uniq }
}
fn wi_actions {
{ wi_proglist $WMII_CONFPATH
wi_getfuns Action
} | sort | uniq
}
fn wi_script {
noprog=true prog=() {
if(~ $1 -f) {
shift
noprog=/dev/null
}
prog = `{rc -c 'path=$confpath whatis '$1 >[2]/dev/null \
| grep -v '^fn |=' || echo $noprog}
shift; echo $prog $*}
}
fn wi_initkeys {
ifs=() {
wmiikeys = `{wmiir read /keys} {
mykeys = `{comm -23 \
<{wi_getfuns Key | sort | uniq} \
<{echo $wmiikeys | sort | uniq}}
{echo $wmiikeys; wi_getfuns Key} \
| sort | uniq \
| wmiir write /keys }}
fn wi_atexit {
wi_cleankeys
}
}
fn wi_cleankeys {
ifs=() {
wmiikeys = `{wmiir read /keys} {
comm -23 <{echo $wmiikeys | sort | uniq} \
<{echo $mykeys} \
| wmiir write /keys }}
}
fn wi_runcmd { @{
rfork ns
path=$oldpath
if(~ $1 -t) {
shift
* = (wihack -tags `{wmiir read /tag/sel/ctl | sed 1q} $*) }
fn `{env | 9 sed -n 's/^fn#([^=]+).*/\1/p'}
mykeys=()
if(! ~ $* '')
eval exec $* & }
}
fn wi_getfuns {
env | sed -n 's/^fn#'^$1^'-([^=]+).*/\1/p' | sort | uniq
}
for(i in Key Event Action '*Menu')
fns=`{wi_getfuns $i} {
if(! ~ $fns '')
fn $i-^$fns}
fn wi_tags {
wmiir ls /tag | sed 's,/,,; /^sel$/d'
}
fn wi_seltag {
wmiir read /tag/sel/ctl | sed 1q
}
fn wi_selclient {
wmiir read /client/sel/ctl | sed 1q
}
fn wi_nexttag {
awk -v 'curtag='^`{wi_seltag} '
NR==1 {first = $0}
$0==curtag { if(getline) print $0; else print first; exit }'
}
fn wi_eventloop {
wi_initkeys
{
if(~ $1 -i)
cat
if not
wmiir read /event
} | while(ifs=$wi_newline{wi_event=`{read}}) {
ifs=$wi_newline{
wi_arg=`{echo $wi_event | sed 's/^[^ ]+ //'}}
* = `{echo $wi_event}
event = $1; shift
Event-$"event $*
} >[2]/dev/null </dev/null
true
}
fn Event-Key {
Key-$1 $1
}
fn Event-Quit {
exit
}
fn Event-Start {
if(~ $1 $wmiiscript)
exit
}
fn Action {
cmd=$1 action=Action-$"cmd { shift
if(! ~ $cmd '') {
if(wi_fn-p $action)
$action $*
if not
wi_runcmd `{wi_script $cmd} $*
}
}
}
|
Added cmd/wmii.sh.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
[ -z "$scriptname" ] && scriptname="$wmiiscript"
echo Start $wmiiscript | wmiir write /event 2>/dev/null ||
exit 1
wi_newline='
'
_wi_script() {
# Awk script to mangle key/event/action definition spec
# into switch-case functions and lists of the cases. Also
# generates a simple key binding help text based on KeyGroup
# clauses and comments that appear on key lines.
#
# Each clause (Key, Event, Action) generates a function of the
# same name which executes the indented text after the matching
# clause. Clauses are selected based on the first argument passed
# to the mangled function. Additionally, a variable is created named
# for the plouralized version of the clause name (Keys, Events,
# Actions) which lists each case value. These are used for actions
# menus and to write wmii's /keys file.
cat <<'!'
BEGIN {
arg[1] = "Nop"
narg = 1;
body = "";
keyhelp = ""
}
function quote(s) {
gsub(/'/, "'\\''", s)
return "'" s "'"
}
function addevent() {
var = arg[1] "s"
for(i=2; i <= narg; i++) {
if(body == "")
delete a[arg[1],arg[i]]
else
a[arg[1],arg[i]] = body
if(i == 2) {
# There's a bug here. Can you spot it?
gsub("[^a-zA-Z_0-9]", "_", arg[2]);
body = sprintf("%s %s \"$@\"", arg[1], arg[2])
}
}
}
/^(Key)Group[ \t]/ {
sub(/^[^ \t]+[ \t]+/, "")
keyhelp = keyhelp "\n " $0 "\n"
}
/^(Event|Key|Action|Menu)[ \t]/ {
addevent()
split($0, tmp, /[ \t]+#[ \t]*/)
narg = split(tmp[1], arg)
if(arg[1] == "Key" && tmp[2])
for (i=2; i <= narg; i++)
keyhelp = keyhelp sprintf(" %-20s %s\n",
arg[i], tmp[2])
body = ""
}
/^[ \t]/ {
sub(/^( |\t)/, "")
body = body"\n"$0
}
END {
addevent()
for(k in a) {
split(k, b, SUBSEP)
c[b[1]] = c[b[1]] b[2] "\n"
if(body != "")
d[b[1]] = d[b[1]] quote(b[2]) ")" a[k] "\n;;\n"
}
for(k in c)
printf "%ss=%s\n", k, quote(c[k])
for(k in d) {
printf "%s() {\n", k
printf " %s=$1; shift\n", tolower(k)
printf "case $%s in\n%s\n*) return 1\nesac\n", tolower(k), d[k]
printf "}\n"
}
print "KeysHelp=" quote(keyhelp)
}
!
}
_wi_text() {
eval "cat <<!
$( (test ! -t 0 && cat; for a; do eval "$a"; done) | sed '/^[ ]/s/\([$`\\]\)/\\\1/g')
!
"
}
_wi_events=""
wi_events() {
eval=""; [ "$1" = -e ] && eval=1 && shift
_wi_events="$(_wi_text "$@")
$_wi_events"
# -n "$eval" ] && printf %s "$_wi_events" | awk "$(_wi_script)" >&2
[ -n "$eval" ] && eval "$(printf %s "$_wi_events" | awk "$(_wi_script)")"
}
wi_events <<'!'
Event Key
Key "$@"
!
wi_fatal() {
echo $scriptname: Fatal: $*
exit 1
}
wi_notice() {
xmessage $scriptname: Notice: $*
}
wi_readctl() {
wmiir read /ctl | sed -n 's/^'$1' //p'
}
wmiifont="$(wi_readctl font)"
wmiinormcol="$(wi_readctl normcolors)"
wmiifocuscol="$(wi_readctl focuscolors)"
wi_fnmenu() {
group="$1-$2"; shift 2
_last="$(echo $group|tr - _)_last"
eval "last=\"\$$_last\""
res=$(set -- $(echo "$Menus" | awk -v "s=$group" 'BEGIN{n=length(s)}
substr($1,1,n) == s{print substr($1,n+2)}')
[ $# != 0 ] && wmii9menu -i "$last" "$@")
if [ -n "$res" ]; then
eval "$_last="'"$res"'
Menu $group-$res "$@"
fi
}
wi_proglist() {
wmiir proglist -- $(echo $* | sed 'y/:/ /') | sort | uniq
}
wi_actions() {
{ wi_proglist $WMII_CONFPATH
echo -n "$Actions"
} | sort | uniq
}
wi_runconf() {
sflag=""; if [ "$1" = -s ]; then sflag=1; shift; fi
which="$(which which)"
prog=$(PATH="$WMII_CONFPATH" "$which" -- $1 2>/dev/null); shift
if [ -n "$prog" ]; then
if [ -z "$sflag" ]
then "$prog" "$@"
else . "$prog"
fi
else return 1
fi
}
wi_script() {
_noprog=true
if [ "$1" = -f ]; then
shift
_noprog=/dev/null
fi
which=$(which which)
_prog=$(PATH="$WMII_CONFPATH" $which $1 || echo $_noprog); shift
shift; echo "$_prog $*"
}
wi_runcmd() {
if [ "$1" = -t ]; then
shift
set -- wihack -tags $(wmiir read /tag/sel/ctl | sed 1q) "$*"
fi
eval exec "$*" &
}
wi_tags() {
wmiir ls /tag | sed 's,/,,; /^sel$/d'
}
wi_seltag() {
wmiir read /tag/sel/ctl | sed 1q | tr -d '\012'
}
wi_selclient() {
wmiir read /client/sel/ctl | sed 1q | tr -d '\012'
}
wi_nexttag() {
awk -v curtag=$(wi_seltag) '
NR==1 {first = $0}
$0==curtag { if(getline) print $0; else print first; exit }'
}
wi_eventloop() {
echo "$Keys" | wmiir write /keys
if [ "$1" = -i ]
then cat
else wmiir read /event
fi |
while read wi_event; do
IFS="$wi_newline"
wi_arg=$(echo "$wi_event" | sed 's/^[^ ]* //')
unset IFS
set -- $wi_event
event=$1; shift
[ "$event" = Start -a "$1" = "$wmiiscript" ] &&
exit
Event $event "$@"
done
true
}
action() {
action=$1; shift
if [ -n "$action" ]; then
set +x
Action $action "$@" \
|| wi_runconf $action "$@"
fi
}
|
Added cmd/wmii/Makefile.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | ROOT= ../.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk main.c: $(ROOT)/mk/wmii.mk TARG = wmii HFILES = dat.h fns.h TAGFILES = dat.h PACKAGES += $(X11PACKAGES) xext xrandr xrender xinerama LIB = $(LIBIXP) $(LIBS9) LIBS += -lm OBJ = area \ bar \ backtrace \ client \ column \ div \ error \ event \ ewmh \ float \ frame \ fs \ key \ layout \ main \ message \ mouse \ print \ root \ rule \ screen \ stack \ utf \ view \ xdnd include $(ROOT)/mk/one.mk |
Added cmd/wmii/area.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <math.h>
#include <limits.h>
#include "fns.h"
Client*
area_selclient(Area *a) {
if(a && a->sel)
return a->sel->client;
return nil;
}
int
area_idx(Area *a) {
View *v;
Area *ap;
uint i;
v = a->view;
if(a->floating)
return -1;
i = 1;
for(ap=v->areas[a->screen]; a != ap; ap=ap->next)
i++;
return i;
}
static Rectangle
area_rect(void *v) {
Area *a;
a = v;
return a->r;
}
Area*
area_find(View *v, Rectangle r, int dir, bool wrap) {
static Vector_ptr vec;
Area *a;
int s;
vec.n = 0;
foreach_column(v, s, a)
vector_ppush(&vec, a);
return findthing(r, dir, &vec, area_rect, wrap);
}
int
afmt(Fmt *f) {
Area *a;
a = va_arg(f->args, Area*);
if(a == nil)
return fmtstrcpy(f, "<nil>");
if(a->floating)
return fmtstrcpy(f, "~");
if(a->screen > 0 || (f->flags & FmtSharp))
return fmtprint(f, "%d:%d", a->screen, area_idx(a));
return fmtprint(f, "%d", area_idx(a));
}
char*
area_name(Area *a) {
if(a == nil)
return "<nil>";
if(a->floating)
return "~";
return sxprint("%d", area_idx(a));
}
Area*
area_create(View *v, Area *pos, int scrn, uint width) {
static ushort id = 1;
int i, j;
uint minwidth, index;
int numcols;
Area *a;
assert(!pos || pos->screen == scrn);
SET(index);
if(v->areas) { /* Creating a column. */
minwidth = column_minwidth();
index = pos ? area_idx(pos) : 0;
numcols = 0;
for(a=v->areas[scrn]; a; a=a->next)
numcols++;
/* TODO: Need a better sizing/placing algorithm. */
if(width == 0) {
if(numcols >= 0) {
width = view_newcolwidth(v, scrn, index);
if(width == 0)
width = Dx(v->r[scrn]) / (numcols + 1);
}
else
width = Dx(v->r[scrn]);
}
if(width < minwidth)
width = minwidth;
minwidth = numcols * minwidth + minwidth;
if(minwidth > Dx(v->r[scrn]))
return nil;
i = minwidth - Dx(v->pad[scrn]) - Dx(v->r[scrn]);
if(i > 0 && Dx(v->pad[scrn])) {
j = min(i/2, v->pad[scrn].min.x);
v->pad[scrn].min.x -= j;
v->pad[scrn].max.x += i - j;
}
view_scale(v, scrn, Dx(v->r[scrn]) - width);
}
a = emallocz(sizeof *a);
a->view = v;
a->screen = scrn;
a->id = id++;
a->floating = !v->floating;
if(a->floating)
a->mode = Coldefault;
else
a->mode = def.colmode;
a->frame = nil;
a->sel = nil;
a->r = v->r[scrn];
a->r.min.x = 0;
a->r.max.x = width;
if(a->floating) {
v->floating = a;
a->screen = -1;
}
else if(pos) {
a->next = pos->next;
a->prev = pos;
}
else {
a->next = v->areas[scrn];
v->areas[scrn] = a;
}
if(a->prev)
a->prev->next = a;
if(a->next)
a->next->prev = a;
if(v->sel == nil && !a->floating)
area_focus(a);
if(!a->floating)
event("CreateColumn %ud\n", index);
return a;
}
void
area_destroy(Area *a) {
Area *newfocus;
View *v;
int idx;
v = a->view;
if(a->frame)
die("destroying non-empty area");
if(v->revert == a)
v->revert = nil;
if(v->oldsel == a)
v->oldsel = nil;
idx = area_idx(a);
if(a->prev && !a->prev->floating)
newfocus = a->prev;
else
newfocus = a->next;
/* Can only destroy the floating area when destroying a
* view---after destroying all columns.
*/
assert(!a->floating || !v->areas[0]);
if(a->prev)
a->prev->next = a->next;
else if(!a->floating)
v->areas[a->screen] = a->next;
else
v->floating = nil;
if(a->next)
a->next->prev = a->prev;
if(newfocus && v->sel == a)
area_focus(newfocus);
view_arrange(v);
event("DestroyArea %d\n", idx);
free(a);
}
void
area_moveto(Area *to, Frame *f) {
Area *from;
assert(to->view == f->view);
if(f->client->fullscreen >= 0 && !to->floating)
return;
from = f->area;
if(from == to)
return;
area_detach(f);
/* Temporary kludge. */
if(!to->floating
&& to->floating != from->floating
&& !eqrect(f->colr, ZR))
column_attachrect(to, f, f->colr);
else
area_attach(to, f);
}
void
area_setsel(Area *a, Frame *f) {
View *v;
v = a->view;
/* XXX: Stack. */
for(; f && f->collapsed && f->anext; f=f->anext)
;
for(; f && f->collapsed && f->aprev; f=f->aprev)
;
if(a == v->sel && f)
frame_focus(f);
else
a->sel = f;
}
void
area_attach(Area *a, Frame *f) {
f->area = a;
if(a->floating)
float_attach(a, f);
else
column_attach(a, f);
view_arrange(a->view);
event("AreaAttach %s %a %#C\n", a->view->name, a, f->client);
if(btassert("4 full", a->frame && a->sel == nil))
a->sel = a->frame;
}
void
area_detach(Frame *f) {
View *v;
Area *a;
a = f->area;
v = a->view;
event("AreaDetach %s %a %#C\n", v->name, a, f->client);
if(a->floating)
float_detach(f);
else
column_detach(f);
if(v->sel->sel == nil && v->floating->sel)
if(!v->floating->sel->client->nofocus)
v->sel = v->floating;
view_arrange(v);
}
void
area_focus(Area *a) {
Frame *f;
View *v;
Area *old_a;
v = a->view;
f = a->sel;
old_a = v->sel;
if(!a->floating && view_fullscreen_p(v, a->screen))
return;
v->sel = a;
if(!a->floating) {
v->selcol = area_idx(a);
v->selscreen = a->screen;
}
if(a != old_a)
v->oldsel = nil;
if(old_a && a->floating != old_a->floating) {
v->revert = old_a;
if(v->floating->max)
view_update(v);
}
if(v == selview) {
move_focus(old_a->sel, f);
client_focus(f ? f->client : nil);
if(a != old_a)
event("AreaFocus %a\n", a);
}
}
|
Added cmd/wmii/backtrace.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <bio.h>
#include <plan9.h>
#undef nelem
#include <stuff/util.h>
#include "debug.h"
#ifdef __linux__
# define PROGTXT "exe"
#else
# define PROGTXT "file"
#endif
static void
_backtrace(int pid, char *btarg) {
char *proc, *spid, *gdbcmd;
int fd[3], p[2];
int status, cmdfd;
gdbcmd = estrdup("/tmp/gdbcmd.XXXXXX");
if(pipe(p) < 0)
goto done;
closeexec(p[0]);
cmdfd = mkstemp(gdbcmd);
if(cmdfd < 0)
goto done;
fprint(cmdfd, "bt %s\n", btarg);
fprint(cmdfd, "detach\n");
close(cmdfd);
fd[0] = open("/dev/null", O_RDONLY);
fd[1] = p[1];
fd[2] = dup(2);
proc = sxprint("/proc/%d/" PROGTXT, pid);
spid = sxprint("%d", pid);
if(spawn3l(fd, "gdb", "gdb", "-batch", "-x", gdbcmd, proc, spid, nil) < 0) {
unlink(gdbcmd);
goto done;
}
Biobuf bp;
char *s;
Binit(&bp, p[0], OREAD);
while((s = Brdstr(&bp, '\n', 1))) {
Dprint(DStack, "%s\n", s);
free(s);
}
unlink(gdbcmd);
done:
free(gdbcmd);
kill(pid, SIGKILL);
waitpid(pid, &status, 0);
}
void
backtrace(char *btarg) {
int pid;
/* Fork so we can backtrace the child. Keep this stack
* frame minimal, so the trace is fairly clean.
*/
Debug(DStack)
switch(pid = fork()) {
case -1:
return;
case 0:
kill(getpid(), SIGSTOP);
_exit(0);
default:
_backtrace(pid, btarg);
break;
}
}
|
Added cmd/wmii/bar.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
static Handlers handlers;
#define foreach_bar(s, b) \
for(int __bar_n=0; __bar_n < nelem((s)->bar); __bar_n++) \
for((b)=(s)->bar[__bar_n]; (b); (b)=(b)->next)
void
bar_init(WMScreen *s) {
WinAttr wa;
if(s->barwin && (s->barwin->depth == 32) == s->barwin_rgba)
return;
s->brect = s->r;
s->brect.min.y = s->brect.max.y - labelh(def.font);
wa.override_redirect = 1;
wa.event_mask = ExposureMask
| ButtonPressMask
| ButtonReleaseMask
| FocusChangeMask;
if(s->barwin_rgba)
s->barwin = createwindow_rgba(&scr.root, s->brect,
&wa, CWOverrideRedirect
| CWEventMask);
else
s->barwin = createwindow(&scr.root, s->brect, scr.depth, InputOutput,
&wa, CWOverrideRedirect
| CWEventMask);
s->barwin->aux = s;
xdnd_initwindow(s->barwin);
sethandler(s->barwin, &handlers);
if(s == screens[0])
mapwin(s->barwin);
}
void
bar_resize(WMScreen *s) {
s->brect = s->r;
s->brect.min.y = s->r.max.y - labelh(def.font);
if(s == screens[0])
reshapewin(s->barwin, s->brect);
else
s->brect.min.y = s->r.max.y;
/* FIXME: view_arrange. */
}
void
bar_setbounds(WMScreen *s, int left, int right) {
Rectangle *r;
if(s != screens[0])
return;
r = &s->brect;
r->min.x = left;
r->max.x = right;
if(Dy(*r))
reshapewin(s->barwin, *r);
}
void
bar_sety(WMScreen *s, int y) {
Rectangle *r;
int dy;
r = &s->brect;
dy = Dy(*r);
r->min.y = y;
r->max.y = y + dy;
if(Dy(*r))
reshapewin(s->barwin, *r);
}
Bar*
bar_create(Bar **bp, const char *name) {
static uint id = 1;
WMScreen *s, **sp;
Bar *b;
uint i;
b = bar_find(*bp, name);;
if(b)
return b;
b = emallocz(sizeof *b);
b->id = id++;
utflcpy(b->name, name, sizeof b->name);
b->colors = def.normcolor;
strlcat(b->buf, b->colors.colstr, sizeof b->buf);
strlcat(b->buf, " ", sizeof b->buf);
strlcat(b->buf, b->text, sizeof b->buf);
SET(i);
for(sp=screens; (s = *sp); sp++) {
i = bp - s->bar;
if(i < nelem(s->bar))
break;
}
b->bar = i;
b->screen = s;
for(; *bp; bp = &bp[0]->next)
if(strcmp(bp[0]->name, name) >= 0)
break;
b->next = *bp;
*bp = b;
return b;
}
void
bar_destroy(Bar **bp, Bar *b) {
Bar **p;
for(p = bp; *p; p = &p[0]->next)
if(*p == b) break;
*p = b->next;
free(b);
}
void
bar_draw(WMScreen *s) {
Bar *b, *tb, *largest, **pb;
Image *ibuf;
Rectangle r;
Align align;
uint width, tw;
float shrink;
/* To do: Generalize this. */
largest = nil;
width = 0;
s->barwin_rgba = false;
foreach_bar(s, b) {
b->r.min = ZP;
b->r.max.y = Dy(s->brect);
b->r.max.x = (def.font->height & ~1) + def.font->pad.min.x + def.font->pad.max.x;
if(b->text && strlen(b->text))
b->r.max.x += textwidth(def.font, b->text);
width += Dx(b->r);
s->barwin_rgba += RGBA_P(b->colors);
}
if(width > Dx(s->brect)) { /* Not enough room. Shrink bars until they all fit. */
foreach_bar(s, b) {
for(pb=&largest; *pb; pb=&pb[0]->smaller)
if(Dx(pb[0]->r) < Dx(b->r))
break;
b->smaller = *pb;
*pb = b;
}
SET(shrink);
tw = 0;
for(tb=largest; tb; tb=tb->smaller) {
width -= Dx(tb->r);
tw += Dx(tb->r);
shrink = (Dx(s->brect) - width) / (float)tw;
if(tb->smaller && Dx(tb->r) * shrink < Dx(tb->smaller->r))
continue;
if(width + (int)(tw * shrink) <= Dx(s->brect))
break;
}
if(tb)
for(b=largest; b != tb->smaller; b=b->smaller)
b->r.max.x *= shrink;
width += tw * shrink;
}
if(s->bar[BRight])
s->bar[BRight]->r.max.x += Dx(s->brect) - width;
tb = nil;
foreach_bar(s, b) {
if(tb)
b->r = rectaddpt(b->r, Pt(tb->r.max.x, 0));
tb = b;
}
ibuf = s->barwin_rgba ? disp.ibuf32 : disp.ibuf;
r = rectsubpt(s->brect, s->brect.min);
fill(ibuf, r, &def.normcolor.bg);
border(ibuf, r, 1, &def.normcolor.border);
foreach_bar(s, b) {
align = Center;
if(b == s->bar[BRight])
align = East;
fillstring(ibuf, def.font, b->r, align, b->text, &b->colors, 1);
}
if(s->barwin_rgba != (s->barwin->depth == 32))
bar_init(s);
copyimage(s->barwin, r, ibuf, ZP);
}
Bar*
bar_find(Bar *bp, const char *name) {
Bar *b;
for(b=bp; b; b=b->next)
if(!strcmp(b->name, name))
break;
return b;
}
static char *barside[] = {
[BLeft] = "Left",
[BRight] = "Right",
};
static Bar*
findbar(WMScreen *s, Point p) {
Bar *b;
foreach_bar(s, b)
if(rect_haspoint_p(b->r, p))
return b;
return nil;
}
static bool
bdown_event(Window *w, void *aux, XButtonPressedEvent *e) {
WMScreen *s;
Bar *b;
/* Ungrab so a menu can receive events before the button is released */
XUngrabPointer(display, e->time);
sync();
s = aux;
b = findbar(s, Pt(e->x, e->y));
if(b)
event("%sBarMouseDown %d %s\n", barside[b->bar], e->button, b->name);
return false;
}
static bool
bup_event(Window *w, void *aux, XButtonPressedEvent *e) {
WMScreen *s;
Bar *b;
s = aux;
b = findbar(s, Pt(e->x, e->y));
if(b)
event("%sBarClick %d %s\n", barside[b->bar], e->button, b->name);
return false;
}
static Rectangle
dndmotion_event(Window *w, void *aux, Point p) {
WMScreen *s;
Bar *b;
s = aux;
b = findbar(s, p);
if(b) {
event("%sBarDND 1 %s\n", barside[b->bar], b->name);
return b->r;
}
return ZR;
}
static bool
expose_event(Window *w, void *aux, XExposeEvent *e) {
USED(w, e);
bar_draw(aux);
return false;
}
static Handlers handlers = {
.bdown = bdown_event,
.bup = bup_event,
.dndmotion = dndmotion_event,
.expose = expose_event,
};
|
Added cmd/wmii/client.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 |
/* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
* Copyright ©2006-2014 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <ctype.h>
#include <strings.h>
#include <signal.h>
#include <X11/Xatom.h>
#include "fns.h"
#define Mbsearch(k, l, cmp) bsearch(k, l, nelem(l), sizeof(*l), cmp)
static Handlers handlers;
enum {
ClientMask = StructureNotifyMask
| PropertyChangeMask
| EnterWindowMask
| FocusChangeMask,
ButtonMask = ButtonPressMask
| ButtonReleaseMask,
};
static Group* group;
void
group_init(Client *c) {
Group *g;
long *ret;
XWindow w;
long n;
w = c->w.hints->group;
if(w == 0) {
/* Not quite ICCCM compliant, but it seems to work. */
n = getprop_long(&c->w, "WM_CLIENT_LEADER", "WINDOW", 0L, &ret, 1L);
if(n == 0)
return;
w = *ret;
free(ret);
}
for(g=group; g; g=g->next)
if(g->leader == w)
break;
if(g == nil) {
g = emallocz(sizeof *g);
g->leader = w;
g->next = group;
group = g;
}
c->group = g;
g->ref++;
}
void
group_remove(Client *c) {
Group **gp;
Group *g;
g = c->group;
c->group = nil;
if(g == nil)
return;
if(g->client == c)
g->client = nil;
g->ref--;
if(g->ref == 0) {
for(gp=&group; *gp; gp=&gp[0]->next)
if(*gp == g) break;
assert(*gp == g);
gp[0] = gp[0]->next;
free(g);
}
}
Client*
group_leader(Group *g) {
Client *c;
c = win2client(g->leader);
if(c)
return c;
if(g->client)
return g->client;
/* Could do better. */
for(c=client; c; c=c->next)
if(c->frame && c->group == g)
break;
return c;
}
Client*
client_create(XWindow w, XWindowAttributes *wa) {
Client **t, *c;
char **host = nil;
ulong *pid = nil;
c = emallocz(sizeof *c);
c->fullscreen = -1;
c->border = wa->border_width;
c->r = rectsetorigin(Rect(0, 0, wa->width, wa->height),
Pt(wa->x, wa->y));
c->w.type = WWindow;
c->w.visual = wa->visual;
c->w.xid = w;
c->w.r = c->r;
c->w.aux = c;
setborder(&c->w, 0, &(Color){0});
client_prop(c, xatom("WM_PROTOCOLS"));
client_prop(c, xatom("WM_TRANSIENT_FOR"));
client_prop(c, xatom("WM_NORMAL_HINTS"));
client_prop(c, xatom("WM_HINTS"));
client_prop(c, xatom("WM_CLASS"));
client_prop(c, xatom("WM_NAME"));
client_prop(c, xatom("_MOTIF_WM_HINTS"));
gethostname(hostname, sizeof(hostname) - 1);
if(getprop_textlist(&c->w, "WM_CLIENT_MACHINE", &host) &&
getprop_ulong(&c->w, Net("WM_PID"), "CARDINAL", 0, &pid, 1) &&
!strcmp(hostname, *host))
c->pid = (int)*pid;
freestringlist(host);
free(pid);
c->rgba = render_argb_p(c->w.visual);
client_reparent(c);
sethandler(&c->w, &handlers);
selectinput(&c->w, ClientMask);
group_init(c);
grab_button(c->framewin->xid, AnyButton, AnyModifier);
for(t=&client ;; t=&t[0]->next)
if(!*t) {
c->next = *t;
*t = c;
break;
}
/*
* It's actually possible for a window to be destroyed
* before we get a chance to reparent it. Check for that
* now, because otherwise we'll wind up mapping a
* perceptibly empty frame before it's destroyed.
*/
traperrors(true);
XAddToSaveSet(display, w);
if(traperrors(false)) {
client_destroy(c);
return nil;
}
ewmh_initclient(c);
event("CreateClient %#C\n", c);
client_manage(c);
return c;
}
void
client_reparent(Client *c) {
Window *fw;
WinAttr wa;
bool rgba;
rgba = c->rgba | RGBA_P(def.normcolor) | RGBA_P(def.focuscolor);
fw = c->framewin;
if(fw && (fw->depth == 32) == rgba)
return;
wa.background_pixmap = None;
wa.bit_gravity = NorthWestGravity;
wa.event_mask = ButtonPressMask
| ButtonReleaseMask
| EnterWindowMask
| ExposureMask
| PointerMotionMask
| StructureNotifyMask
| SubstructureNotifyMask
| SubstructureRedirectMask;
wa.override_redirect = true;
if(rgba)
c->framewin = createwindow_rgba(&scr.root, c->r,
&wa, CWBackPixmap
| CWBitGravity
| CWEventMask
| CWOverrideRedirect);
else
c->framewin = createwindow(&scr.root, c->r, scr.depth, InputOutput,
&wa, CWBackPixmap
| CWBitGravity
| CWEventMask
| CWOverrideRedirect);
c->framewin->aux = c;
sethandler(c->framewin, &framehandler);
reparentwindow(&c->w, c->framewin, ZP);
if(fw)
destroywindow(fw);
}
static bool
apply_rules(Client *c) {
IxpMsg m;
Rule *r;
Ruleval *rv;
bool ret, more;
ret = true;
more = true;
for(r=def.rules.rule; r && more; r=r->next)
if(regexec(r->regex, c->props, nil, 0)) {
more = false;
for(rv=r->values; rv; rv=rv->next) {
if(!strcmp(rv->key, "continue"))
more = true;
else if(!strcmp(rv->key, "tags"))
utflcpy(c->tags, rv->value, sizeof c->tags);
else if(!strcmp(rv->key, "force-tags")) {
utflcpy(c->tags, rv->value, sizeof c->tags);
ret = false;
}else {
bufclear();
bufprint("%s %s", rv->key, rv->value);
m = ixp_message(buffer, _buf_end - buffer, MsgPack);
if(waserror())
warning("processing rule %q=%q: %r", rv->key, rv->value);
else {
message_client(c, &m);
poperror();
}
}
}
}
return ret;
}
void
client_manage(Client *c) {
Client *leader;
char *tags;
bool dotags;
if(Dx(c->r) == Dx(screen->r))
if(Dy(c->r) == Dy(screen->r))
if(c->w.ewmh.type == 0)
fullscreen(c, true, -1);
dotags = apply_rules(c);
if(!c->tags[0] || dotags) {
leader = win2client(c->trans);
if(leader == nil && c->group)
leader = group_leader(c->group);
tags = getprop_string(&c->w, "_WMII_TAGS");
if(tags)
utflcpy(c->tags, tags, sizeof c->tags);
else if(leader)
utflcpy(c->tags, leader->tags, sizeof c->tags);
free(tags);
}
if(c->tags[0])
client_applytags(c, c->tags);
else
client_applytags(c, "sel");
if(!starting)
view_update_all();
bool newgroup = !c->group
|| c->group->ref == 1
|| selclient() && (selclient()->group == c->group)
|| group_leader(c->group)
&& !client_viewframe(group_leader(c->group),
c->sel->view);
/* f = c->sel; */
if(!(c->w.ewmh.type & TypeSplash))
if(newgroup) {
/* XXX: Look over this.
if(f->area != f->view->sel)
f->view->oldsel = f->view->sel;
*/
}else {
frame_restack(c->sel, c->sel->area->sel);
view_restack(c->sel->view);
}
}
void
client_destroy(Client *c) {
Rectangle r;
char *none;
Client **tc;
bool hide;
unmapwin(c->framewin);
client_seturgent(c, false, UrgClient);
for(tc=&client; *tc; tc=&tc[0]->next)
if(*tc == c) {
*tc = c->next;
break;
}
r = client_grav(c, ZR);
hide = (!c->sel || c->sel->view != selview);
/* In case the client is already destroyed. */
traperrors(true);
sethandler(&c->w, nil);
if(hide)
reparentwindow(&c->w, &scr.root, screen->r.max);
else
reparentwindow(&c->w, &scr.root, r.min);
if(starting >= 0)
XRemoveFromSaveSet(display, c->w.xid);
none = nil;
client_setviews(c, &none);
if(starting >= 0) {
client_unmap(c, WithdrawnState);
delproperty(&c->w, "_WMII_TAGS");
}
refree(&c->tagre);
refree(&c->tagvre);
free(c->retags);
traperrors(false);
destroywindow(c->framewin);
ewmh_destroyclient(c);
group_remove(c);
if(starting >= 0)
event("DestroyClient %#C\n", c);
event_flush(FocusChangeMask, true);
cleanupwindow(&c->w);
free(c);
}
/* Convenience functions */
Frame*
client_viewframe(Client *c, View *v) {
Frame *f;
for(f=c->frame; f; f=f->cnext)
if(f->view == v)
break;
return f;
}
Client*
selclient(void) {
if(selview->sel->sel)
return selview->sel->sel->client;
return nil;
}
Client*
win2client(XWindow w) {
Client *c;
for(c=client; c; c=c->next)
if(c->w.xid == w) break;
return c;
}
int
Cfmt(Fmt *f) {
Client *c;
c = va_arg(f->args, Client*);
if(c)
if(f->flags & FmtSharp)
return fmtprint(f, "%W", &c->w);
else
return fmtprint(f, "%s", c->name);
return fmtprint(f, "<nil>");
}
Rectangle
client_grav(Client *c, Rectangle rd) {
Rectangle r, cr;
Point sp;
WinHints *h;
h = c->w.hints;
if(eqrect(rd, ZR)) {
if(c->sel) {
r = c->sel->floatr;
cr = frame_rect2client(c, r, true);
}else {
cr = c->r;
r = frame_client2rect(c, cr, true);
r = rectsetorigin(r, cr.min);
}
sp = subpt(cr.min, r.min);
r = gravitate(r, cr, h->grav);
if(!h->gravstatic)
r = rectsubpt(r, sp);
return frame_rect2client(c, r, true);
}else {
r = frame_client2rect(c, rd, true);
sp = subpt(rd.min, r.min);
r = gravitate(rd, r, h->grav);
if(!h->gravstatic)
r = rectaddpt(r, sp);
return frame_client2rect(c, r, true);
}
}
bool
client_floats_p(Client *c) {
if(c->floating == Never)
return false;
return c->trans
|| c->floating
|| c->fixedsize
|| c->titleless
|| c->borderless
|| c->fullscreen >= 0
|| (c->w.ewmh.type & (TypeDialog|TypeSplash|TypeDock|TypeMenu|TypeToolbar));
}
Frame*
client_groupframe(Client *c, View *v) {
if(c->group && c->group->client)
return client_viewframe(c->group->client, v);
return nil;
}
Rectangle
frame_hints(Frame *f, Rectangle r, Align sticky) {
Rectangle or;
WinHints h;
Point p;
Client *c;
c = f->client;
if(c->w.hints == nil)
return r;
or = r;
h = frame_gethints(f);
r = sizehint(&h, r);
if(!f->area->floating) {
/* Not allowed to grow */
if(Dx(r) > Dx(or))
r.max.x = r.min.x+Dx(or);
if(Dy(r) > Dy(or))
r.max.y = r.min.y+Dy(or);
}
p = ZP;
if((sticky&(East|West)) == East)
p.x = Dx(or) - Dx(r);
if((sticky&(North|South)) == South)
p.y = Dy(or) - Dy(r);
return rectaddpt(r, p);
}
static void
client_setstate(Client * c, int state) {
long data[] = { state, None };
changeprop_long(&c->w, "WM_STATE", "WM_STATE", data, nelem(data));
}
void
client_map(Client *c) {
if(!c->w.mapped) {
mapwin(&c->w);
client_setstate(c, NormalState);
}
}
void
client_unmap(Client *c, int state) {
if(c->w.mapped)
unmapwin(&c->w);
client_setstate(c, state);
}
int
client_mapframe(Client *c) {
return mapwin(c->framewin);
}
int
client_unmapframe(Client *c) {
return unmapwin(c->framewin);
}
void
focus(Client *c, bool user) {
View *v;
Frame *f;
Dprint(DFocus, "focus(%#C, %d)\n", c, user);
if(!c->nofocus || user)
if((f = c->sel)) {
v = f->view;
if(v != selview)
view_focus(screen, v);
frame_focus(c->sel);
view_restack(c->sel->view);
}
}
void
client_focus(Client *c) {
/* Round trip. */
if(c && c->group)
c->group->client = c;
sync();
event_flush(FocusChangeMask, true);
Dprint(DFocus, "client_focus([%#C]%C) collapsed=%s\n",
c, c, c && c->sel->collapsed ? "true" : "false");
Dprint(DFocus, "\t[%#C]%C\n\t=> [%#C]%C\n",
disp.focus, disp.focus, c, c);
if(disp.focus != c) {
if(c && !c->sel->collapsed) {
if(!c->noinput)
setfocus(&c->w, RevertToParent);
else if(c->proto & ProtoTakeFocus) {
event_updatextime();
client_message(c, "WM_TAKE_FOCUS", 0);
}
}else
setfocus(screen->barwin, RevertToParent);
sync();
event_flush(FocusChangeMask, true);
}
}
void
client_resize(Client *c, Rectangle r) {
Frame *f;
f = c->sel;
frame_resize(f, r);
if(f->view != selview) {
client_unmap(c, IconicState);
client_unmapframe(c);
return;
}
c->r = rectaddpt(f->crect, f->r.min);
if(f->collapsed) {
if(f->area->max && !resizing)
client_unmapframe(c);
else {
reshapewin(c->framewin, f->r);
movewin(&c->w, f->crect.min);
client_mapframe(c);
}
client_unmap(c, IconicState);
}else {
client_map(c);
reshapewin(c->framewin, f->r);
reshapewin(&c->w, f->crect);
client_mapframe(c);
if(!eqrect(c->r, c->configr))
client_configure(c);
ewmh_framesize(c);
}
}
void
client_setcursor(Client *c, Cursor cur) {
WinAttr wa;
if(c->cursor != cur) {
c->cursor = cur;
wa.cursor = cur;
setwinattr(c->framewin, &wa, CWCursor);
}
}
void
client_configure(Client *c) {
Rectangle r;
c->configr = c->r;
r = rectsubpt(c->r, Pt(c->border, c->border));
sendevent(&c->w, false, StructureNotifyMask,
&(XConfigureEvent) {
.type = ConfigureNotify,
.event = c->w.xid,
.window = c->w.xid,
.x = r.min.x,
.y = r.min.y,
.width = Dx(r),
.height = Dy(r),
.border_width = c->border,
});
}
void
client_message(Client *c, char *msg, long l2) {
sendmessage(&c->w, "WM_PROTOCOLS", xatom(msg), event_xtime, l2, 0, 0);
}
void
client_kill(Client *c, bool nice) {
if(!nice) {
if(c->pid)
kill(c->pid, SIGKILL);
XKillClient(display, c->w.xid);
}
else if(c->proto & ProtoDelete) {
c->dead = 1;
client_message(c, "WM_DELETE_WINDOW", 0);
ewmh_checkresponsive(c);
}
else
XKillClient(display, c->w.xid);
}
void
fullscreen(Client *c, int fullscreen, long screen) {
Client *leader;
Frame *f;
bool wassel;
if(fullscreen == Toggle)
fullscreen = (c->fullscreen >= 0) ^ On;
if(fullscreen == (c->fullscreen >= 0))
return;
event("Fullscreen %#C %s\n", c, (fullscreen ? "on" : "off"));
c->fullscreen = -1;
if(!fullscreen)
for(f=c->frame; f; f=f->cnext) {
if(f->oldarea == 0) {
frame_resize(f, f->floatr);
if(f->view == selview) /* FIXME */
client_resize(f->client, f->r);
}
else if(f->oldarea > 0) {
wassel = (f == f->area->sel);
area_moveto(view_findarea(f->view, f->oldscreen, f->oldarea, true),
f);
if(wassel)
frame_focus(f);
}
}
else {
c->fullscreen = 0;
if(screen >= 0)
c->fullscreen = screen;
else if(c->sel)
c->fullscreen = ownerscreen(c->r);
else if(c->group && (leader = group_leader(c->group)) && leader->sel)
c->fullscreen = ownerscreen(leader->r);
else if(selclient())
c->fullscreen = ownerscreen(selclient()->r);
for(f=c->frame; f; f=f->cnext)
f->oldarea = -1;
if((f = c->sel))
view_update(f->view);
}
ewmh_updatestate(c);
}
void
client_seturgent(Client *c, int urgent, int from) {
XWMHints *wmh;
char *cfrom, *cnot;
Frame *f;
if(urgent == Toggle)
urgent = c->urgent ^ On;
cfrom = (from == UrgManager ? "Manager" : "Client");
cnot = (urgent ? "" : "Not");
if(urgent != c->urgent) {
event("%sUrgent %#C %s\n", cnot, c, cfrom);
c->urgent = urgent;
ewmh_updatestate(c);
if(c->sel)
frame_draw(c->sel);
for(f=c->frame; f; f=f->cnext)
view_update_urgency(f->view, cfrom);
}
if(from == UrgManager) {
wmh = XGetWMHints(display, c->w.xid);
if(wmh == nil)
wmh = emallocz(sizeof *wmh);
wmh->flags &= ~XUrgencyHint;
if(urgent)
wmh->flags |= XUrgencyHint;
XSetWMHints(display, c->w.xid, wmh);
XFree(wmh);
}
}
/* X11 stuff */
void
update_class(Client *c) {
snprint(c->props, sizeof c->props, "%s:%s", c->class, c->name);
}
static void
client_updatename(Client *c) {
char *str;
c->name[0] = '\0';
if((str = windowname(&c->w))) {
utflcpy(c->name, str, sizeof c->name);
free(str);
}
update_class(c);
if(c->sel)
frame_draw(c->sel);
}
static void
updatemwm(Client *c) {
enum {
All = 0x1,
Border = 0x2,
Title = 0x8,
FlagDecor = 0x2,
Flags = 0,
Decor = 2,
};
Rectangle r;
ulong *ret;
int n;
/* To quote Metacity, or KWin quoting Metacity:
*
* We support MWM hints deemed non-stupid
*
* Our definition of non-stupid is a bit less lenient than
* theirs, though. In fact, we don't really even support the
* idea of supporting the hints that we support, but apps
* like xmms (which no one should use) break if we don't.
*/
n = getprop_ulong(&c->w, "_MOTIF_WM_HINTS", "_MOTIF_WM_HINTS",
0L, &ret, 3L);
/* FIXME: Should somehow handle all frames of a client. */
if(c->sel)
r = client_grav(c, ZR);
c->borderless = 0;
c->titleless = 0;
if(n >= 3 && (ret[Flags] & FlagDecor)) {
if(ret[Decor] & All)
ret[Decor] ^= ~0;
c->borderless = !(ret[Decor] & Border);
c->titleless = !(ret[Decor] & Title);
}
free(ret);
if(false && c->sel) {
c->sel->floatr = client_grav(c, r);
if(c->sel->area->floating) {
client_resize(c, c->sel->floatr);
frame_draw(c->sel);
}
}
}
bool
client_prop(Client *c, Atom a) {
WinHints h;
XWMHints *wmh;
char **class;
int n;
if(a == xatom("WM_PROTOCOLS"))
c->proto = ewmh_protocols(&c->w);
else
if(a == xatom("_NET_WM_NAME"))
goto wmname;
else
if(a == xatom("_MOTIF_WM_HINTS"))
updatemwm(c);
else
switch (a) {
default:
return true;
case XA_WM_TRANSIENT_FOR:
XGetTransientForHint(display, c->w.xid, &c->trans);
break;
case XA_WM_NORMAL_HINTS:
memset(&h, 0, sizeof h);
if(c->w.hints)
bcopy(c->w.hints, &h, sizeof h);
gethints(&c->w);
if(c->w.hints)
c->fixedsize = eqpt(c->w.hints->min, c->w.hints->max);
if(memcmp(&h, c->w.hints, sizeof h))
if(c->sel)
view_update(c->sel->view);
break;
case XA_WM_HINTS:
wmh = XGetWMHints(display, c->w.xid);
if(wmh) {
c->noinput = (wmh->flags&InputFocus) && !wmh->input;
client_seturgent(c, (wmh->flags & XUrgencyHint) != 0, UrgClient);
XFree(wmh);
}
break;
case XA_WM_CLASS:
n = getprop_textlist(&c->w, "WM_CLASS", &class);
snprint(c->class, sizeof c->class, "%s:%s",
(n > 0 ? class[0] : "<nil>"),
(n > 1 ? class[1] : "<nil>"));
freestringlist(class);
update_class(c);
break;
case XA_WM_NAME:
wmname:
client_updatename(c);
break;
}
return false;
}
/* Handlers */
static bool
configreq_event(Window *w, void *aux, XConfigureRequestEvent *e) {
Rectangle r;
Client *c;
c = aux;
r = client_grav(c, ZR);
r.max = subpt(r.max, r.min);
if(e->value_mask & CWX)
r.min.x = e->x;
if(e->value_mask & CWY)
r.min.y = e->y;
if(e->value_mask & CWWidth)
r.max.x = e->width;
if(e->value_mask & CWHeight)
r.max.y = e->height;
if(e->value_mask & CWBorderWidth)
c->border = e->border_width;
r.max = addpt(r.min, r.max);
r = client_grav(c, r);
if(c->sel->area->floating)
client_resize(c, r);
else {
c->sel->floatr = r;
client_configure(c);
}
return false;
}
static bool
destroy_event(Window *w, void *aux, XDestroyWindowEvent *e) {
USED(w, e);
client_destroy(aux);
return false;
}
static bool
enter_event(Window *w, void *aux, XCrossingEvent *e) {
Client *c;
c = aux;
if(e->detail != NotifyInferior) {
if(e->detail != NotifyVirtual)
if(e->serial > event_lastconfigure && disp.focus != c) {
Dprint(DFocus, "enter_notify([%#C]%s)\n", c, c->name);
focus(c, false);
}
client_setcursor(c, cursor[CurNormal]);
}else
Dprint(DFocus, "enter_notify(%#C[NotifyInferior]%s)\n", c, c->name);
return false;
}
static bool
focusin_event(Window *w, void *aux, XFocusChangeEvent *e) {
Client *c, *old;
c = aux;
print_focus("focusin_event", c, c->name);
if(e->mode == NotifyGrab)
disp.hasgrab = c;
old = disp.focus;
disp.focus = c;
if(c != old) {
event("ClientFocus %#C\n", c);
if(c->sel)
frame_draw(c->sel);
}
return false;
}
static bool
focusout_event(Window *w, void *aux, XFocusChangeEvent *e) {
Client *c;
c = aux;
if((e->mode == NotifyWhileGrabbed) && (disp.hasgrab != &c_root)) {
if(disp.focus)
disp.hasgrab = disp.focus;
}else if(disp.focus == c) {
print_focus("focusout_event", &c_magic, "<magic>");
disp.focus = &c_magic;
if(c->sel)
frame_draw(c->sel);
}
return false;
}
static bool
unmap_event(Window *w, void *aux, XUnmapEvent *e) {
Client *c;
c = aux;
if(!e->send_event && w->parent != c->framewin)
c->w.unmapped++;
if(e->send_event || c->w.unmapped < 0)
client_destroy(c);
return false;
}
static bool
map_event(Window *w, void *aux, XMapEvent *e) {
Client *c;
USED(e);
c = aux;
if(c == selclient())
client_focus(c);
return true;
}
static bool
property_event(Window *w, void *aux, XPropertyEvent *e) {
if(e->state == PropertyDelete) /* FIXME */
return true;
return client_prop(aux, e->atom);
}
static Handlers handlers = {
.configreq = configreq_event,
.destroy = destroy_event,
.enter = enter_event,
.focusin = focusin_event,
.focusout = focusout_event,
.map = map_event,
.unmap = unmap_event,
.property = property_event,
};
/* Other */
void
client_setviews(Client *c, char **tags) {
Frame **fp, *f;
int cmp;
fp = &c->frame;
while(*fp || *tags) {
SET(cmp);
while(*fp) {
if(*tags) {
cmp = strcmp(fp[0]->view->name, *tags);
if(cmp >= 0)
break;
}
f = *fp;
view_detach(f);
*fp = f->cnext;
if(c->sel == f)
c->sel = *fp;
free(f);
}
if(*tags) {
if(!*fp || cmp > 0) {
f = frame_create(c, view_create(*tags));
Dprint(DGeneric, "%#C %p %R %R %R %C\n", c, c->sel, c->r, f->floatr, c->sel ? c->sel->floatr : ZR, c);
if(f->view == selview || !c->sel)
c->sel = f;
kludge = c; /* FIXME */
view_attach(f->view, f);
kludge = nil;
f->cnext = *fp;
*fp = f;
}
if(fp[0]) fp=&fp[0]->cnext;
tags++;
}
}
if(c->sel == nil)
c->sel = c->frame;
if(c->sel)
frame_draw(c->sel);
}
static int
bsstrcmp(const void *a, const void *b) {
return strcmp((char*)a, *(char**)b);
}
static int
strpcmp(const void *ap, const void *bp) {
char **a, **b;
a = (char**)ap;
b = (char**)bp;
return strcmp(*a, *b);
}
static char *badtags[] = {
".",
"..",
"sel",
};
char*
client_extratags(Client *c) {
Fmt fmt;
Frame *f;
char *toks[32];
char **tags;
int i;
i = 0;
toks[i++] = "";
for(f=c->frame; f && i < nelem(toks)-1; f=f->cnext)
if(f != c->sel)
toks[i++] = f->view->name;
toks[i] = nil;
tags = comm(CLeft, toks, c->retags);
if(i == 1 && !c->tagre.regex && !c->tagvre.regex) {
free(tags);
return nil;
}
fmtstrinit(&fmt);
if(i > 1)
join(tags, "+", &fmt);
free(tags);
if(c->tagre.regex)
fmtprint(&fmt, "+/%s/", c->tagre.regex);
if(c->tagvre.regex)
fmtprint(&fmt, "-/%s/", c->tagvre.regex);
return fmtstrflush(&fmt);
}
bool
client_applytags(Client *c, const char *tags) {
Fmt fmt;
uint i, j, k;
char buf[512];
char *toks[32];
char **p;
char *cur, *s;
int add, old;
buf[0] = 0;
if(memchr("+-^", tags[0], 4))
utflcpy(buf, c->tags, sizeof c->tags);
else {
refree(&c->tagre);
refree(&c->tagvre);
}
strlcat(buf, tags, sizeof buf);
j = 0;
s = buf;
old = '+';
while((cur = mask(&s, &add, &old))) {
/* Check for regex. */
if(cur[0] == '/') {
cur++;
*strrchr(cur, '/') = '\0';
if(add == '+')
reinit(&c->tagre, cur);
else if(add == '-')
reinit(&c->tagvre, cur);
}
else if(!strcmp(cur, "~"))
c->floating = add ? On : Never;
else {
trim(cur, " \t\r\n");
if(!strcmp(cur, "sel"))
cur = selview->name;
else if(Mbsearch(cur, badtags, bsstrcmp))
continue;
if(j < nelem(toks)-1) {
if(add == '^')
add = bsearch(cur, toks, j, sizeof *toks, bsstrcmp) ? '-' : '+';
if(add == '+')
toks[j++] = cur;
else {
for(i = 0, k = 0; i < j; i++)
if(strcmp(toks[i], cur))
toks[k++] = toks[i];
j = k;
}
}
}
}
toks[j] = nil;
qsort(toks, j, sizeof *toks, strpcmp);
uniq(toks);
fmtstrinit(&fmt);
join(toks, "+", &fmt);
if(c->tagre.regex)
fmtprint(&fmt, "+/%s/", c->tagre.regex);
if(c->tagvre.regex)
fmtprint(&fmt, "-/%s/", c->tagvre.regex);
s = fmtstrflush(&fmt);
utflcpy(c->tags, s, sizeof c->tags);
changeprop_string(&c->w, "_WMII_TAGS", c->tags);
free(s);
free(c->retags);
p = view_names();
grep(p, c->tagre.regc, 0);
grep(p, c->tagvre.regc, GInvert);
c->retags = comm(CRight, toks, p);
free(p);
if(c->retags[0] == nil && toks[0] == nil) {
toks[0] = "orphans";
toks[1] = nil;
}
p = comm(~0, c->retags, toks);
client_setviews(c, p);
free(p);
return true;
}
|
Added cmd/wmii/column.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 |
/* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
* Copyright ©2006-2014 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <math.h>
#include <strings.h>
#include "fns.h"
static void column_resizeframe_h(Frame*, Rectangle);
char *modes[] = {
[Coldefault] = "default",
[Colstack] = "stack",
[Colmax] = "max",
};
bool
column_setmode(Area *a, const char *mode) {
char *str, *tok;
int add, old;
/*
* The mapping between the current internal
* representation and the external interface
* is currently a bit complex. That will probably
* change.
*/
str = freelater(estrdup(mode));
old = '+';
while((tok = mask(&str, &add, &old))) {
if(!strcmp(tok, "max")) {
if(add == '\0' || add == '+')
a->max = true;
else if(add == '-')
a->max = false;
else
a->max = !a->max;
}else
if(!strcmp(tok, "stack")) {
if(add == '\0' || add == '+')
a->mode = Colstack;
else if(add == '-')
a->mode = Coldefault;
else
a->mode = a->mode == Colstack ? Coldefault : Colstack;
}else
if(!strcmp(tok, "default")) {
if(add == '\0' || add == '+') {
a->mode = Coldefault;
column_arrange(a, true);
}else if(add == '-')
a->mode = Colstack;
else
a->mode = a->mode == Coldefault ? Colstack : Coldefault;
}else
return false;
}
return true;
}
char*
column_getmode(Area *a) {
return sxprint("%s%cmax", a->mode == Colstack ? "stack" : "default",
a->max ? '+' : '-');
}
int
column_minwidth(void)
{
return 4 * labelh(def.font);
}
static void
columns_update(View *v) {
Area *a;
Frame *f;
int s;
foreach_frame(v, s, a, f) {
f->screen = s;
f->column = area_idx(a);
}
}
Area*
column_new(View *v, Area *pos, int scrn, uint w) {
Area *a;
assert(!pos || !pos->floating && pos->screen == scrn);
a = area_create(v, pos, scrn, w);
return a;
#if 0
if(!a)
return nil;
view_arrange(v);
columns_update(v);
view_update(v);
#endif
}
void
column_insert(Area *a, Frame *f, Frame *pos) {
f->area = a;
if(f->client->floating == On)
f->client->floating = Off;
f->screen = a->screen;
f->column = area_idx(a);
frame_insert(f, pos);
if(a->sel == nil)
area_setsel(a, f);
}
void
column_destroy(Area *a) {
View *v;
v = a->view;
area_destroy(a);
columns_update(v);
}
void
column_attach(Area *a, Frame *f) {
Frame *first;
int nframe, dy, h;
f->colr = a->r;
if(a->sel) {
stack_info(a->sel, &first, nil, &dy, &nframe);
h = dy / (nframe+1);
f->colr.max.y = f->colr.min.y + h;
stack_scale(first, dy - h);
}
column_insert(a, f, a->sel);
column_arrange(a, false);
}
void
column_detach(Frame *f) {
Frame *first;
Area *a;
int dy;
a = f->area;
stack_info(f, &first, nil, &dy, nil);
if(first && first == f)
first = f->anext;
column_remove(f);
if(a->frame) {
if(first)
stack_scale(first, dy);
column_arrange(a, false);
}else if(a->view->areas[a->screen]->next && !a->permanent)
column_destroy(a);
}
static void column_scale(Area*);
void
column_attachrect(Area *a, Frame *f, Rectangle r) {
Frame *fp, *pos;
pos = nil;
for(fp=a->frame; fp; pos=fp, fp=fp->anext) {
if(r.max.y < fp->r.min.y || r.min.y > fp->r.max.y)
continue;
/*
before = fp->r.min.y - r.min.y;
after = -fp->r.max.y + r.max.y;
*/
}
column_insert(a, f, pos);
column_resizeframe_h(f, r);
column_scale(a);
}
void
column_remove(Frame *f) {
Frame *pr;
Area *a;
a = f->area;
pr = f->aprev;
frame_remove(f);
f->area = nil;
if(a->sel == f) {
if(pr == nil)
pr = a->frame;
if(pr && pr->collapsed)
if(pr->anext && !pr->anext->collapsed)
pr = pr->anext;
else
pr->collapsed = false;
a->sel = nil;
area_setsel(a, pr);
}
}
static int
column_surplus(Area *a) {
Frame *f;
int surplus;
surplus = Dy(a->r);
for(f=a->frame; f; f=f->anext)
surplus -= Dy(f->r);
return surplus;
}
static void
column_fit(Area *a, uint *n_colp, uint *n_uncolp) {
Frame *f, **fp;
uint minh, dy;
uint n_col, n_uncol;
uint col_h, uncol_h;
int surplus, i, j;
/* The minimum heights of collapsed and uncollpsed frames.
*/
minh = labelh(def.font);
col_h = labelh(def.font);
uncol_h = minh + col_h + 1;
if(a->max && !resizing)
col_h = 0;
/* Count collapsed and uncollapsed frames. */
n_col = 0;
n_uncol = 0;
for(f=a->frame; f; f=f->anext) {
frame_resize(f, f->colr);
if(f->collapsed)
n_col++;
else
n_uncol++;
}
if(n_uncol == 0) {
n_uncol++;
n_col--;
(a->sel ? a->sel : a->frame)->collapsed = false;
}
/* FIXME: Kludge. See frame_attachrect. */
dy = Dy(a->view->r[a->screen]) - Dy(a->r);
minh = col_h * (n_col + n_uncol - 1) + uncol_h;
if(dy && Dy(a->r) < minh)
a->r.max.y += min(dy, minh - Dy(a->r));
surplus = Dy(a->r)
- (n_col * col_h)
- (n_uncol * uncol_h);
/* Collapse until there is room */
if(surplus < 0) {
i = ceil(-1.F * surplus / (uncol_h - col_h));
if(i >= n_uncol)
i = n_uncol - 1;
n_uncol -= i;
n_col += i;
surplus += i * (uncol_h - col_h);
}
/* Push to the floating layer until there is room */
if(surplus < 0) {
i = ceil(-1.F * surplus / col_h);
if(i > n_col)
i = n_col;
n_col -= i;
surplus += i * col_h;
}
/* Decide which to collapse and which to float. */
j = n_uncol - 1;
i = n_col - 1;
for(fp=&a->frame; *fp;) {
f = *fp;
if(f != a->sel) {
if(!f->collapsed) {
if(j < 0)
f->collapsed = true;
j--;
}
if(f->collapsed) {
if(i < 0) {
f->collapsed = false;
area_moveto(f->view->floating, f);
continue;
}
i--;
}
}
/* Doesn't change if we 'continue' */
fp = &f->anext;
}
if(n_colp) *n_colp = n_col;
if(n_uncolp) *n_uncolp = n_uncol;
}
void
column_settle(Area *a) {
Frame *f;
uint yoff, yoffcr;
int surplus, n_uncol, n;
n_uncol = 0;
surplus = column_surplus(a);
for(f=a->frame; f; f=f->anext)
if(!f->collapsed) n_uncol++;
if(n_uncol == 0) {
fprint(2, "%s: Badness: No uncollapsed frames, column %d, view %q\n",
argv0, area_idx(a), a->view->name);
return;
}
if(surplus < 0)
fprint(2, "%s: Badness: surplus = %d in column_settle, column %d, view %q\n",
argv0, surplus, area_idx(a), a->view->name);
yoff = a->r.min.y;
yoffcr = yoff;
n = surplus % n_uncol;
surplus /= n_uncol;
for(f=a->frame; f; f=f->anext) {
f->r = rectsetorigin(f->r, Pt(a->r.min.x, yoff));
f->colr = rectsetorigin(f->colr, Pt(a->r.min.x, yoffcr));
f->r.min.x = a->r.min.x;
f->r.max.x = a->r.max.x;
if(def.incmode == ISqueeze && !resizing)
if(!f->collapsed) {
f->r.max.y += surplus;
if(n-- > 0)
f->r.max.y++;
}
yoff = f->r.max.y;
yoffcr = f->colr.max.y;
}
}
/*
* Returns how much a frame "wants" to grow.
*/
static int
foo(Frame *f) {
WinHints h;
int maxh;
h = frame_gethints(f);
maxh = 0;
if(h.aspect.max.x)
maxh = h.baspect.y +
(Dx(f->r) - h.baspect.x) *
h.aspect.max.y / h.aspect.max.x;
maxh = max(maxh, h.max.y);
if(Dy(f->r) >= maxh)
return 0;
return h.inc.y - (Dy(f->r) - h.base.y) % h.inc.y;
}
static int
comp_frame(const void *a, const void *b) {
int ia, ib;
ia = foo(*(Frame**)a);
ib = foo(*(Frame**)b);
/*
* I'd like to favor the selected client, but
* it causes windows to jump as focus changes.
*/
return ia < ib ? -1 :
ia > ib ? 1 :
0;
}
static void
column_squeeze(Area *a) {
static Vector_ptr fvec;
Frame *f;
int surplus, osurplus, dy, i;
fvec.n = 0;
for(f=a->frame; f; f=f->anext)
if(!f->collapsed) {
f->r = frame_hints(f, f->r, 0);
vector_ppush(&fvec, f);
}
surplus = column_surplus(a);
for(osurplus=0; surplus != osurplus;) {
osurplus = surplus;
qsort(fvec.ary, fvec.n, sizeof *fvec.ary, comp_frame);
for(i=0; i < fvec.n; i++) {
f=fvec.ary[i];
dy = foo(f);
if(dy > surplus)
break;
surplus -= dy;
f->r.max.y += dy;
}
}
}
/*
* Frobs a column. Which is to say, *temporary* kludge.
* Essentially seddles the column and resizes its clients.
*/
void
column_frob(Area *a) {
Frame *f;
for(f=a->frame; f; f=f->anext)
f->r = f->colr;
column_settle(a);
if(a->view == selview)
for(f=a->frame; f; f=f->anext)
client_resize(f->client, f->r);
}
static void
column_scale(Area *a) {
Frame *f;
uint dy;
uint ncol, nuncol;
uint colh;
int surplus;
if(!a->frame)
return;
column_fit(a, &ncol, &nuncol);
colh = labelh(def.font);
if(a->max && !resizing)
colh = 0;
dy = 0;
surplus = Dy(a->r);
for(f=a->frame; f; f=f->anext) {
if(f->collapsed)
f->colr.max.y = f->colr.min.y + colh;
else if(Dy(f->colr) == 0)
f->colr.max.y++;
surplus -= Dy(f->colr);
if(!f->collapsed)
dy += Dy(f->colr);
}
for(f=a->frame; f; f=f->anext) {
f->dy = Dy(f->colr);
f->colr.min.x = a->r.min.x;
f->colr.max.x = a->r.max.x;
if(!f->collapsed)
f->colr.max.y += ((float)f->dy / dy) * surplus;
if(btassert("6 full", !(f->collapsed ? Dy(f->r) >= 0 : dy > 0)))
warning("Something's fucked: %s:%d:%s()",
__FILE__, __LINE__, __func__);
frame_resize(f, f->colr);
}
if(def.incmode == ISqueeze && !resizing)
column_squeeze(a);
column_settle(a);
}
void
column_arrange(Area *a, bool dirty) {
Frame *f;
View *v;
if(a->floating)
float_arrange(a);
if(a->floating || !a->frame)
return;
v = a->view;
switch(a->mode) {
case Coldefault:
if(dirty)
for(f=a->frame; f; f=f->anext)
f->colr = Rect(0, 0, 100, 100);
break;
case Colstack:
/* XXX */
for(f=a->frame; f; f=f->anext)
f->collapsed = (f != a->sel);
break;
default:
fprint(2, "Dieing: %s: screen: %d a: %p mode: %x floating: %d\n",
v->name, a->screen, a, a->mode, a->floating);
die("not reached");
break;
}
column_scale(a);
/* XXX */
if(a->sel->collapsed)
area_setsel(a, a->sel);
if(v == selview) {
//view_restack(v);
client_resize(a->sel->client, a->sel->r);
for(f=a->frame; f; f=f->anext)
client_resize(f->client, f->r);
}
}
void
column_resize(Area *a, int w) {
Area *an;
int dw;
an = a->next;
assert(an != nil);
dw = w - Dx(a->r);
a->r.max.x += dw;
an->r.min.x += dw;
/* view_arrange(a->view); */
view_update(a->view);
}
static void
column_resizeframe_h(Frame *f, Rectangle r) {
Area *a;
Frame *fn, *fp;
uint minh;
minh = labelh(def.font);
a = f->area;
fn = f->anext;
fp = f->aprev;
if(fp)
r.min.y = max(r.min.y, fp->colr.min.y + minh);
else
r.min.y = max(r.min.y, a->r.min.y);
if(fn)
r.max.y = min(r.max.y, fn->colr.max.y - minh);
else
r.max.y = min(r.max.y, a->r.max.y);
if(fp) {
fp->colr.max.y = r.min.y;
frame_resize(fp, fp->colr);
}
else
r.min.y = min(r.min.y, r.max.y - minh);
if(fn) {
fn->colr.min.y = r.max.y;
frame_resize(fn, fn->colr);
}
else
r.max.y = max(r.max.y, r.min.y + minh);
f->colr = r;
frame_resize(f, r);
}
void
column_resizeframe(Frame *f, Rectangle r) {
Area *a, *al, *ar;
View *v;
uint minw;
a = f->area;
v = a->view;
minw = column_minwidth();
al = a->prev;
ar = a->next;
if(al)
r.min.x = max(r.min.x, al->r.min.x + minw);
else { /* Hm... */
r.min.x = max(r.min.x, v->r[a->screen].min.x);
r.max.x = max(r.max.x, r.min.x + minw);
}
if(ar)
r.max.x = min(r.max.x, ar->r.max.x - minw);
else {
r.max.x = min(r.max.x, v->r[a->screen].max.x);
r.min.x = min(r.min.x, r.max.x - minw);
}
a->r.min.x = r.min.x;
a->r.max.x = r.max.x;
if(al) {
al->r.max.x = a->r.min.x;
column_arrange(al, false);
}else {
v->pad[a->screen].min.x = r.min.x - v->r[a->screen].min.x;
}
if(ar) {
ar->r.min.x = a->r.max.x;
column_arrange(ar, false);
}else {
v->pad[a->screen].max.x = r.max.x - v->r[a->screen].max.x;
}
column_resizeframe_h(f, r);
view_update(v);
}
|
Added cmd/wmii/dat.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
/* Copyright ©2007-2014 Kris Maglione <jg@suckless.org>
* See LICENSE file for license details.
*/
#define _XOPEN_SOURCE 600
#define IXP_NO_P9_
#include <assert.h>
#include <regexp9.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <utf.h>
#include <ixp.h>
#include <stuff/x.h>
#include <stuff/util.h>
#include "debug.h"
#define FONT "fixed"
#define FOCUSCOLORS "#000000 #81654f #000000"
#define NORMCOLORS "#000000 #c1c48b #81654f"
/* From CGO */
#define assert_equal(x, y) typedef char _##x##_does_not_equal_##y[((x)-(y))*((x)-(y))*-2+1]
enum Barpos {
BBottom,
BTop,
};
enum {
Coldefault, Colstack, Colmax, Collast
};
enum {
CurNormal,
CurNECorner, CurNWCorner, CurSECorner, CurSWCorner,
CurDHArrow, CurDVArrow, CurMove, CurInput, CurSizing,
CurTCross, CurIcon,
CurNone,
CurLast,
};
Cursor cursor[CurLast];
enum IncMode {
IIgnore,
IShow,
ISqueeze,
};
enum {
PDesktop,
PExtents,
PMonitors = PExtents + 4,
PState = PMonitors + 4,
PLast = PState + 3
};
enum ClientPermission {
PermActivate = 1<<0,
};
enum {
PingTime = 10000,
PingPeriod = 4000,
PingPartition = 10,
};
enum Protocols {
ProtoDelete = 1<<0,
ProtoTakeFocus = 1<<1,
ProtoPing = 1<<2,
};
enum {
SourceUnknown,
SourceClient,
SourcePager
};
enum EWMHType {
TypeDesktop = 1<<0,
TypeDock = 1<<1,
TypeToolbar = 1<<2,
TypeMenu = 1<<3,
TypeUtility = 1<<4,
TypeSplash = 1<<5,
TypeDialog = 1<<6,
TypeNormal = 1<<7,
};
enum {
UrgManager,
UrgClient,
};
extern char* modes[];
#define toggle(val, x) \
((val) = ((x) == On ? true : \
(x) == Off ? false : \
(x) == Toggle ? !(val) : (val)))
#define TOGGLE(x) \
((x) == On ? "on" : \
(x) == Off ? "off" : \
(x) == Toggle ? "toggle" : "<toggle>")
enum {
Never = -1,
Off,
On,
/* Xlib defines this. :( */
// Always,
Toggle,
};
assert_equal(Always, 2);
enum {
NCOL = 16,
};
/* Data Structures */
typedef struct Area Area;
typedef struct Bar Bar;
typedef struct Client Client;
typedef struct Divide Divide;
typedef struct Frame Frame;
typedef struct Group Group;
typedef struct Key Key;
typedef struct Rule Rule;
typedef struct Ruleset Ruleset;
typedef struct Ruleval Ruleval;
typedef struct Strut Strut;
typedef struct View View;
typedef struct WMScreen WMScreen;
struct Area {
Area* next;
Area* prev;
Frame* frame;
Frame* frame_old;
Frame* stack;
Frame* sel;
View* view;
bool floating;
ushort id;
int mode;
int screen;
bool max;
bool permanent;
Rectangle r;
Rectangle r_old;
};
struct Bar {
Bar* next;
Bar* smaller;
char buf[280];
char text[256];
char name[256];
int bar;
ushort id;
CTuple colors;
Rectangle r;
WMScreen* screen;
};
struct Client {
Client* next;
Frame* frame;
Frame* sel;
Window w;
Window* framewin;
XWindow trans;
Regex tagre;
Regex tagvre;
Group* group;
Strut* strut;
Cursor cursor;
Rectangle configr;
Rectangle r;
char** retags;
char class[256];
char name[256];
char props[512];
char tags[256];
char proplen[PLast];
long propcache[PLast];
long permission;
long proto;
int border;
int dead;
int floating;
int fullscreen;
int pid;
bool borderless;
bool fixedsize;
bool nofocus;
bool noinput;
bool rgba;
bool titleless;
bool urgent;
};
struct Divide {
Divide* next;
Window* w;
Area* left;
Area* right;
bool mapped;
int x;
};
struct Frame {
Frame* cnext;
Frame* anext;
Frame* aprev;
Frame* anext_old;
Frame* snext;
Frame* sprev;
Client* client;
View* view;
Area* area;
int oldscreen;
int oldarea;
int screen;
int column;
ushort id;
bool collapsed;
int dy;
Rectangle r;
Rectangle colr;
Rectangle colr_old;
Rectangle floatr;
Rectangle crect;
Rectangle grabbox;
Rectangle titlebar;
};
struct Group {
Group* next;
XWindow leader;
Client* client;
int ref;
};
struct Key {
Key* next;
Key* lnext;
Key* tnext;
ushort id;
char name[128];
ulong mod;
KeyCode key;
};
struct Rule {
Rule* next;
Reprog* regex;
char* value;
Ruleval* values;
};
struct Ruleset {
Rule* rule;
char* string;
uint size;
};
struct Ruleval {
Ruleval* next;
char* key;
char* value;
};
struct Strut {
Rectangle left;
Rectangle right;
Rectangle top;
Rectangle bottom;
};
#define firstarea areas[screen->idx]
#define screenr r[screen->idx]
struct View {
View* next;
char name[256];
ushort id;
Area* floating;
Area** areas;
Area* sel;
Area* oldsel;
Area* revert;
int selcol;
int selscreen;
bool dead;
bool urgent;
Rectangle *r;
Rectangle *pad;
};
#ifndef EXTERN
# define EXTERN extern
#endif
/* global variables */
typedef struct Defs Defs;
EXTERN struct Defs {
CTuple focuscolor;
CTuple normcolor;
Font* font;
char* keys;
uint keyssz;
Ruleset colrules;
Ruleset rules;
long mod;
uint border;
uint snap;
int colmode;
int incmode;
} def;
enum {
BLeft, BRight
};
EXTERN struct WMScreen {
Bar* bar[2];
Window* barwin;
bool barwin_rgba;
bool showing;
int barpos;
int idx;
Rectangle r;
Rectangle brect;
} **screens, *screen;
EXTERN uint nscreens;
EXTERN struct {
Client* focus;
Client* hasgrab;
Image* ibuf;
Image* ibuf32;
bool sel;
} disp;
EXTERN Client c_magic;
EXTERN Client c_root;
EXTERN Client* client;
EXTERN Divide* divs;
EXTERN Key* key;
EXTERN View* selview;
EXTERN View* view;
EXTERN Handlers framehandler;
/* IXP */
EXTERN IxpServer srv;
EXTERN Ixp9Srv p9srv;
/* X11 */
EXTERN uint numlock_mask;
EXTERN uint valid_mask;
/* Misc */
EXTERN char* execstr;
EXTERN char hostname[HOST_NAME_MAX + 1];
EXTERN long ignoreenter;
EXTERN bool resizing;
EXTERN int starting;
EXTERN char* user;
EXTERN long nscreens_new;
EXTERN Client* kludge;
extern char* debugtab[];
|
Added cmd/wmii/debug.h.
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <stdbool.h>
enum DebugOpt {
D9p = 1<<0,
DDnd = 1<<1,
DEvent = 1<<2,
DEvents = 1<<3,
DEwmh = 1<<4,
DFocus = 1<<5,
DGeneric= 1<<6,
DStack = 1<<7,
NDebugOpt = 8,
};
#define Debug(x) if(((debugflag|debugfile)&(x)) && setdebug(x))
#define Dprint(x, ...) BLOCK( if((debugflag|debugfile)&(x)) debug(x, __VA_ARGS__) )
void debug(int, const char*, ...);
void dwrite(int, void*, int, bool);
bool setdebug(int);
void vdebug(int, const char*, va_list);
long debugflag;
long debugfile;
|
Added cmd/wmii/div.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
static Image* divimg;
static Image* divmask;
static CTuple divcolor;
static Handlers handlers;
static Divide*
getdiv(Divide ***dp) {
WinAttr wa;
Divide *d;
if(**dp)
d = **dp;
else {
d = emallocz(sizeof *d);
wa.override_redirect = true;
wa.cursor = cursor[CurDHArrow];
wa.event_mask =
ExposureMask
| EnterWindowMask
| ButtonPressMask
| ButtonReleaseMask;
d->w = createwindow(&scr.root, Rect(0, 0, 1, 1), scr.depth,
InputOutput, &wa,
CWOverrideRedirect
| CWEventMask
| CWCursor);
d->w->aux = d;
sethandler(d->w, &handlers);
**dp = d;
}
*dp = &d->next;
return d;
}
static void
mapdiv(Divide *d) {
mapwin(d->w);
}
static void
unmapdiv(Divide *d) {
unmapwin(d->w);
}
void
div_set(Divide *d, int x) {
Rectangle r;
int scrn;
scrn = d->left ? d->left->screen : d->right->screen;
d->x = x;
r = rectaddpt(divimg->r, Pt(x - Dx(divimg->r)/2, 0));
r.min.y = selview->r[scrn].min.y;
r.max.y = selview->r[scrn].max.y;
reshapewin(d->w, r);
mapdiv(d);
}
static void
drawimg(Image *img, Color cbg, Color cborder, Divide *d) {
Point pt[8];
int n, start, w;
w = Dx(img->r)/2;
n = 0;
pt[n++] = Pt(w, 0);
pt[n++] = Pt(0, 0);
pt[n++] = Pt(w - 1, w - 1);
pt[n++] = Pt(w - 1, Dy(img->r));
pt[n++] = Pt(w, pt[n-1].y);
pt[n++] = Pt(w, w - 1);
pt[n++] = Pt(2*w - 1, 0);
pt[n++] = Pt(w, 0);
start = d->left ? 0 : n/2;
n = d->right && d->left ? n : n/2;
fillpoly(img, pt + start, n, &cbg);
drawpoly(img, pt + start, n, CapNotLast, 1, &cborder);
}
static void
drawdiv(Divide *d) {
fill(divmask, divmask->r, &(Color){0});
drawimg(divmask, (Color){~0,~0,~0}, (Color){~0,~0,~0}, d);
drawimg(divimg, divcolor.bg, divcolor.border, d);
copyimage(d->w, divimg->r, divimg, ZP);
setshapemask(d->w, divmask, ZP);
}
static void
update_imgs(void) {
Divide *d;
int w, h;
w = 2 * (labelh(def.font) / 3);
w = max(w, 10);
/* XXX: Multihead. */
h = Dy(scr.rect);
if(divimg) {
if(w == Dx(divimg->r) && h == Dy(divimg->r)
&& !memcmp(&divcolor, &def.normcolor, sizeof divcolor))
return;
freeimage(divimg);
freeimage(divmask);
}
divimg = allocimage(w, h, scr.depth);
divmask = allocimage(w, h, 1);
divcolor = def.normcolor;
for(d = divs; d && d->w->mapped; d = d->next)
drawdiv(d);
}
void
div_update_all(void) {
Divide **dp, *d;
Area *a, *ap;
View *v;
int s;
update_imgs();
v = selview;
dp = &divs;
ap = nil;
foreach_column(v, s, a) {
if(ap && ap->screen != s)
ap = nil;
d = getdiv(&dp);
d->left = ap;
d->right = a;
div_set(d, a->r.min.x);
drawdiv(d);
ap = a;
if(!a->next) {
d = getdiv(&dp);
d->left = a;
d->right = nil;
div_set(d, a->r.max.x);
drawdiv(d);
}
}
for(d = *dp; d; d = d->next)
unmapdiv(d);
}
/* Div Handlers */
static bool
bdown_event(Window *w, void *aux, XButtonEvent *e) {
Divide *d;
USED(e);
d = aux;
mouse_resizecol(d);
return false;
}
static bool
expose_event(Window *w, void *aux, XExposeEvent *e) {
Divide *d;
USED(e);
d = aux;
drawdiv(d);
return false;
}
static Handlers handlers = {
.bdown = bdown_event,
.expose = expose_event,
};
|
Added cmd/wmii/error.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/* Copyright ©2007-2010 Kris Maglione <jg@suckless.org>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
static jmp_buf errjmp[16];
static long nerror;
void
error(char *fmt, ...) {
char errbuf[IXP_ERRMAX];
va_list ap;
va_start(ap, fmt);
vsnprint(errbuf, IXP_ERRMAX, fmt, ap);
va_end(ap);
ixp_errstr(errbuf, IXP_ERRMAX);
nexterror();
}
void
nexterror(void) {
assert(nerror > 0);
longjmp(errjmp[--nerror], 1);
}
void
poperror(void) {
assert(nerror > 0);
--nerror;
}
jmp_buf*
pusherror(void) {
assert(nerror < nelem(errjmp));
return &errjmp[nerror++];
}
|
Added cmd/wmii/event.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <X11/keysym.h>
#include "fns.h"
void
debug_event(XEvent *e) {
Dprint(DEvent, "%E\n", e);
}
void
print_focus(const char *fn, Client *c, const char *to) {
Dprint(DFocus, "%s() disp.focus:\n", fn);
Dprint(DFocus, "\t%#C => %#C\n", disp.focus, c);
Dprint(DFocus, "\t%C => %s\n", disp.focus, to);
}
void
event_focusin(XFocusChangeEvent *ev) {
Window *w;
Client *c;
/* Yes, we're focusing in on nothing, here. */
if(ev->detail == NotifyDetailNone) {
print_focus("focusin", &c_magic, "<magic[none]>");
disp.focus = &c_magic;
setfocus(screen->barwin, RevertToParent);
return;
}
if(!((ev->detail == NotifyNonlinear)
||(ev->detail == NotifyNonlinearVirtual)
||(ev->detail == NotifyVirtual)
||(ev->detail == NotifyInferior)
||(ev->detail == NotifyAncestor)))
return;
if((ev->mode == NotifyWhileGrabbed) && (disp.hasgrab != &c_root))
return;
if(ev->window == screen->barwin->xid) {
print_focus("focusin", nil, "<nil>");
disp.focus = nil;
}
else if((w = findwin(ev->window)))
event_handle(w, focusin, ev);
else if(ev->mode == NotifyGrab) {
/* Some unmanaged window has grabbed focus */
if((c = disp.focus)) {
print_focus("focusin", &c_magic, "<magic>");
disp.focus = &c_magic;
if(c->sel)
frame_draw(c->sel);
}
}
}
void
event_focusout(XFocusChangeEvent *ev) {
XEvent me;
Window *w;
if(!((ev->detail == NotifyNonlinear)
||(ev->detail == NotifyNonlinearVirtual)
||(ev->detail == NotifyVirtual)
||(ev->detail == NotifyInferior)
||(ev->detail == NotifyAncestor)))
return;
if(ev->mode == NotifyUngrab)
disp.hasgrab = nil;
if((ev->mode == NotifyGrab)
&& XCheckMaskEvent(display, KeyPressMask, &me))
event_dispatch(&me);
else if((w = findwin(ev->window)))
event_handle(w, focusout, ev);
}
|
Added cmd/wmii/ewmh.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <limits.h>
#include "fns.h"
Window *ewmhwin;
static void ewmh_getwinstate(Client*);
static void ewmh_setstate(Client*, Atom, int);
static void tick(long, void*);
static Handlers client_handlers;
static Handlers root_handlers;
static void
clientprop_long(Client *c, int cache, char *prop, char *type, long *data, int l) {
if(l != c->proplen[cache] || memcmp(&c->propcache[cache], data, l * sizeof *data)) {
c->proplen[cache] = l;
memcpy(&c->propcache[cache], data, l * sizeof *data);
changeprop_long(&c->w, prop, type, data, l);
}
}
static void
clientprop_del(Client *c, int cache, char *prop) {
c->proplen[cache] = 0;
delproperty(&c->w, prop);
}
void
ewmh_init(void) {
char myname[] = "wmii";
long win;
ewmhwin = createwindow(&scr.root,
Rect(0, 0, 1, 1), 0 /*depth*/,
InputOnly, nil, 0);
win = ewmhwin->xid;
changeprop_long(&scr.root, Net("SUPPORTING_WM_CHECK"), "WINDOW", &win, 1);
changeprop_long(ewmhwin, Net("SUPPORTING_WM_CHECK"), "WINDOW", &win, 1);
changeprop_string(ewmhwin, Net("WM_NAME"), myname);
changeprop_long(&scr.root, Net("DESKTOP_VIEWPORT"), "CARDINAL",
(long[2]){0, 0}, 2);
pushhandler(&scr.root, &root_handlers, nil);
tick(0L, nil);
long supported[] = {
/* Misc */
NET("SUPPORTED"),
/* Root Properties/Messages */
NET("ACTIVE_WINDOW"),
NET("CLOSE_WINDOW"),
NET("CURRENT_DESKTOP"),
/* Client Properties */
NET("FRAME_EXTENTS"),
NET("WM_DESKTOP"),
NET("WM_FULLSCREEN_MONITORS"),
NET("WM_NAME"),
NET("WM_PID"),
NET("WM_STRUT"),
NET("WM_STRUT_PARTIAL"),
/* Set this so clients don't update Net("USER_TIME") */
NET("USER_TIME_WINDOW"),
/* States */
NET("WM_STATE"),
STATE("DEMANDS_ATTENTION"),
STATE("FULLSCREEN"),
STATE("SHADED"),
/* Window Types */
NET("WM_WINDOW_TYPE"),
TYPE("DIALOG"),
TYPE("DOCK"),
TYPE("NORMAL"),
TYPE("MENU"),
TYPE("SPLASH"),
TYPE("TOOLBAR"),
/* Actions */
NET("WM_ALLOWED_ACTIONS"),
ACTION("FULLSCREEN"),
/* Desktops */
NET("DESKTOP_NAMES"),
NET("NUMBER_OF_DESKTOPS"),
/* Client List */
NET("CLIENT_LIST"),
NET("CLIENT_LIST_STACKING"),
};
changeprop_long(&scr.root, Net("SUPPORTED"), "ATOM", supported, nelem(supported));
}
inline bool
ewmh_responsive_p(Client *c) {
return c->w.ewmh.ping == 0 || (ulong)(nsec() / 1000000) - c->w.ewmh.ping < PingTime;
}
void
ewmh_checkresponsive(Client *c) {
if(!ewmh_responsive_p(c))
if(!c->dead)
frame_draw(c->sel);
else if(c->dead++ == 1)
event("Unresponsive %#C\n", c);
}
static void
tick(long id, void *v) {
static int count;
Client *c;
ulong time;
int mod, i;
time = nsec() / 1000000;
count++;
mod = count % PingPartition;
for(i=0, c=client; c; c=c->next, i++)
if(c->proto & ProtoPing) {
if(!ewmh_responsive_p(c))
ewmh_checkresponsive(c);
if(i % PingPartition == mod)
sendmessage(&c->w, "WM_PROTOCOLS", NET("WM_PING"), time, c->w.xid, 0, 0);
if(i % PingPartition == mod)
Dprint(DEwmh, "_NET_WM_PING %#C %,uld\n", c, time);
}
ixp_settimer(&srv, PingPeriod / PingPartition, tick, nil);
}
void
ewmh_updateclientlist(void) {
Vector_long vec;
Client *c;
vector_linit(&vec);
for(c=client; c; c=c->next)
vector_lpush(&vec, c->w.xid);
changeprop_long(&scr.root, Net("CLIENT_LIST"), "WINDOW", vec.ary, vec.n);
free(vec.ary);
}
void
ewmh_updatestacking(void) {
Vector_long vec;
Frame *f;
Area *a;
View *v;
int s;
vector_linit(&vec);
for(v=view; v; v=v->next) {
foreach_column(v, s, a)
for(f=a->frame; f; f=f->anext)
if(f->client->sel == f)
vector_lpush(&vec, f->client->w.xid);
}
for(v=view; v; v=v->next) {
for(f=v->floating->stack; f; f=f->snext)
if(!f->snext) break;
for(; f; f=f->sprev)
if(f->client->sel == f)
vector_lpush(&vec, f->client->w.xid);
}
changeprop_long(&scr.root, Net("CLIENT_LIST_STACKING"), "WINDOW", vec.ary, vec.n);
vector_lfree(&vec);
}
void
ewmh_initclient(Client *c) {
long allowed[] = {
ACTION("FULLSCREEN"),
};
changeprop_long(&c->w, Net("WM_ALLOWED_ACTIONS"), "ATOM",
allowed, nelem(allowed));
ewmh_getwintype(c);
ewmh_getwinstate(c);
ewmh_getstrut(c);
ewmh_framesize(c);
ewmh_updateclientlist();
pushhandler(&c->w, &client_handlers, c);
}
void
ewmh_destroyclient(Client *c) {
ewmh_updateclientlist();
free(c->strut);
}
#ifdef notdef
static ulong
usertime(Window *w) {
long *l;
long ret;
ret = 0;
if(getprop_long(w, Net("WM_USER_TIME_WINDOW"), "CARDINAL", 0, &l, 1)) {
w = window(*l);
free(l);
}
if(getprop_long(w, Net("WM_USER_TIME"), "CARDINAL", 0, &l, 1)) {
ret = *l;
free(l);
}
return ret;
}
#endif
static bool
event_client_clientmessage(Window *w, void *aux, XClientMessageEvent *e) {
Client *c;
ulong *l;
ulong msg;
int action;
c = aux;
l = (ulong*)e->data.l;
msg = e->message_type;
Dprint(DEwmh, "ClientMessage: %A\n", msg);
if(msg == NET("WM_STATE")) {
enum {
StateUnset,
StateSet,
StateToggle,
};
if(e->format != 32)
return false;
switch(l[0]) {
case StateUnset: action = Off; break;
case StateSet: action = On; break;
case StateToggle: action = Toggle; break;
default: return false;
}
Dprint(DEwmh, "\tAction: %s\n", TOGGLE(action));
ewmh_setstate(c, l[1], action);
ewmh_setstate(c, l[2], action);
return false;
}else
if(msg == NET("ACTIVE_WINDOW")) {
if(e->format != 32)
return false;
Dprint(DEwmh, "\tsource: %uld\n", l[0]);
Dprint(DEwmh, "\ttimestamp: %,uld\n", l[1]);
Dprint(DEwmh, "\tactive: %#ulx\n", l[2]);
Dprint(DEwmh, "\twindow: %#ulx\n", e->window);
Dprint(DEwmh, "\tclient: %C\n", c);
if(l[0] == SourceClient && !(c->permission & PermActivate))
return false;
if(l[0] == SourceClient || l[0] == SourcePager)
focus(c, true);
return false;
}else
if(msg == NET("CLOSE_WINDOW")) {
if(e->format != 32)
return false;
Dprint(DEwmh, "\tsource: %ld\n", l[0]);
Dprint(DEwmh, "\twindow: %#ulx\n", e->window);
client_kill(c, true);
return false;
}
return false;
}
static bool
event_client_property(Window *w, void *aux, XPropertyEvent *e) {
return ewmh_prop(aux, e->atom);
}
static Handlers client_handlers = {
.message = event_client_clientmessage,
.property = event_client_property,
};
bool
ewmh_prop(Client *c, Atom a) {
if(a == NET("WM_WINDOW_TYPE"))
ewmh_getwintype(c);
else
if(a == NET("WM_STRUT_PARTIAL"))
ewmh_getstrut(c);
else
return true;
return false;
}
typedef struct Prop Prop;
struct Prop {
char* name;
long mask;
Atom atom;
};
static long
getmask(Prop *props, ulong *vals, int n) {
Prop *p;
long ret;
if(props[0].atom == 0)
for(p=props; p->name; p++)
p->atom = xatom(p->name);
ret = 0;
while(n--) {
Dprint(DEwmh, "\tvals[%d] = \"%A\"\n", n, vals[n]);
for(p=props; p->name; p++)
if(p->atom == vals[n]) {
ret |= p->mask;
break;
}
}
return ret;
}
static long
getprop_mask(Window *w, char *prop, Prop *props) {
ulong *vals;
long n, mask;
n = getprop_ulong(w, prop, "ATOM",
0L, &vals, 16);
mask = getmask(props, vals, n);
free(vals);
return mask;
}
void
ewmh_getwintype(Client *c) {
static Prop props[] = {
{Type("DESKTOP"), TypeDesktop},
{Type("DOCK"), TypeDock},
{Type("TOOLBAR"), TypeToolbar},
{Type("MENU"), TypeMenu},
{Type("UTILITY"), TypeUtility},
{Type("SPLASH"), TypeSplash},
{Type("DIALOG"), TypeDialog},
{Type("NORMAL"), TypeNormal},
{0, }
};
long mask;
mask = getprop_mask(&c->w, Net("WM_WINDOW_TYPE"), props);
c->w.ewmh.type = mask;
if(mask & (TypeDock|TypeMenu|TypeToolbar)) {
c->borderless = true;
c->titleless = true;
}
if(mask & (TypeSplash|TypeDock))
c->nofocus = true;
}
static void
ewmh_getwinstate(Client *c) {
ulong *vals;
long n;
n = getprop_ulong(&c->w, Net("WM_STATE"), "ATOM",
0L, &vals, 16);
while(--n >= 0)
ewmh_setstate(c, vals[n], On);
free(vals);
}
long
ewmh_protocols(Window *w) {
static Prop props[] = {
{"WM_DELETE_WINDOW", ProtoDelete},
{"WM_TAKE_FOCUS", ProtoTakeFocus},
{Net("WM_PING"), ProtoPing},
{0, }
};
return getprop_mask(w, "WM_PROTOCOLS", props);
}
void
ewmh_getstrut(Client *c) {
enum {
Left, Right, Top, Bottom,
LeftMin, LeftMax,
RightMin, RightMax,
TopMin, TopMax,
BottomMin, BottomMax,
Last
};
long *strut;
ulong n;
if(c->strut != nil)
free(c->strut);
c->strut = nil;
n = getprop_long(&c->w, Net("WM_STRUT_PARTIAL"), "CARDINAL",
0L, &strut, Last);
if(n != Last) {
free(strut);
n = getprop_long(&c->w, Net("WM_STRUT"), "CARDINAL",
0L, &strut, 4L);
if(n != 4) {
free(strut);
return;
}
Dprint(DEwmh, "ewmh_getstrut(%#C[%C]) Using WM_STRUT\n", c, c);
strut = erealloc(strut, Last * sizeof *strut);
strut[LeftMin] = strut[RightMin] = 0;
strut[LeftMax] = strut[RightMax] = INT_MAX;
strut[TopMin] = strut[BottomMin] = 0;
strut[TopMax] = strut[BottomMax] = INT_MAX;
}
c->strut = emalloc(sizeof *c->strut);
c->strut->left = Rect(0, strut[LeftMin], strut[Left], strut[LeftMax]);
c->strut->right = Rect(-strut[Right], strut[RightMin], 0, strut[RightMax]);
c->strut->top = Rect(strut[TopMin], 0, strut[TopMax], strut[Top]);
c->strut->bottom = Rect(strut[BottomMin], -strut[Bottom], strut[BottomMax], 0);
Dprint(DEwmh, "ewmh_getstrut(%#C[%C])\n", c, c);
Dprint(DEwmh, "\ttop: %R\n", c->strut->top);
Dprint(DEwmh, "\tleft: %R\n", c->strut->left);
Dprint(DEwmh, "\tright: %R\n", c->strut->right);
Dprint(DEwmh, "\tbottom: %R\n", c->strut->bottom);
free(strut);
view_update(selview);
}
static void
ewmh_setstate(Client *c, Atom state, int action) {
Dprint(DEwmh, "\tSTATE = %A\n", state);
if(state == 0)
return;
if(state == STATE("FULLSCREEN"))
fullscreen(c, action, -1);
else
if(state == STATE("DEMANDS_ATTENTION"))
client_seturgent(c, action, UrgClient);
}
static bool
event_root_clientmessage(Window *w, void *aux, XClientMessageEvent *e) {
Client *c;
View *v;
ulong *l;
ulong msg;
int i;
l = (ulong*)e->data.l;
msg = e->message_type;
Debug(DEwmh)
if(msg != xatom("WM_PROTOCOLS") && l[0] != NET("WM_PING"))
Dprint(DEwmh, "ClientMessage: %A\n", msg);
if(msg == NET("CURRENT_DESKTOP")) {
if(e->format != 32)
return false;
for(v=view, i=l[0]; v; v=v->next, i--)
if(i == 0)
break;
Dprint(DEwmh, "\t%s\n", v->name);
if(i == 0)
view_select(v->name);
return 1;
}
if(msg == xatom("WM_PROTOCOLS")) {
if(e->format != 32)
return false;
if(l[0] == NET("WM_PING")) {
if(e->window != scr.root.xid)
return false;
if(!(c = win2client(l[2])))
return false;
i = ewmh_responsive_p(c);
c->w.ewmh.ping = nsec() / 1000000;
c->w.ewmh.lag = (c->w.ewmh.ping & 0xffffffff) - (l[1] & 0xffffffff);
if(i == false)
frame_draw(c->sel);
return false;
}
return false;
}
return false;
}
static Handlers root_handlers = {
.message = event_root_clientmessage,
};
void
ewmh_framesize(Client *c) {
Rectangle rc, rf;
Frame *f;
if((f = c->sel)) {
rc = f->crect;
rf = f->r;
}
else {
rf = frame_client2rect(c, ZR, c->floating);
rc = rectsubpt(ZR, rf.min);
}
long extents[] = {
rc.min.x, Dx(rf) - rc.max.x,
rc.min.y, Dy(rf) - rc.max.y,
};
clientprop_long(c, PExtents, Net("FRAME_EXTENTS"), "CARDINAL",
extents, nelem(extents));
}
void
ewmh_updatestate(Client *c) {
long state[16];
Frame *f;
int i;
f = c->sel;
if(f == nil || f->view != selview)
return;
i = 0;
if(f->collapsed)
state[i++] = STATE("SHADED");
if(c->fullscreen >= 0)
state[i++] = STATE("FULLSCREEN");
if(c->urgent)
state[i++] = STATE("DEMANDS_ATTENTION");
if(i > 0)
clientprop_long(c, PState, Net("WM_STATE"), "ATOM", state, i);
else
clientprop_del(c, PState, Net("WM_STATE"));
if(c->fullscreen >= 0)
clientprop_long(c, PMonitors, Net("WM_FULLSCREEN_MONITORS"), "CARDINAL",
(long[]) { c->fullscreen, c->fullscreen,
c->fullscreen, c->fullscreen },
4);
else
clientprop_del(c, PMonitors, Net("WM_FULLSCREEN_MONITORS"));
}
/* Views */
void
ewmh_updateviews(void) {
View *v;
Vector_ptr tags;
long i;
if(starting)
return;
vector_pinit(&tags);
for(v=view, i=0; v; v=v->next, i++)
vector_ppush(&tags, v->name);
vector_ppush(&tags, nil);
changeprop_textlist(&scr.root, Net("DESKTOP_NAMES"), "UTF8_STRING", (char**)tags.ary);
changeprop_long(&scr.root, Net("NUMBER_OF_DESKTOPS"), "CARDINAL", &i, 1);
vector_pfree(&tags);
ewmh_updateview();
ewmh_updateclients();
}
static int
viewidx(View *v) {
View *vp;
int i;
for(vp=view, i=0; vp; vp=vp->next, i++)
if(vp == v)
break;
assert(vp);
return i;
}
void
ewmh_updateview(void) {
long i;
if(starting)
return;
i = viewidx(selview);
changeprop_long(&scr.root, Net("CURRENT_DESKTOP"), "CARDINAL", &i, 1);
}
void
ewmh_updateclient(Client *c) {
long i;
i = -1;
if(c->sel)
i = viewidx(c->sel->view);
clientprop_long(c, PDesktop, Net("WM_DESKTOP"), "CARDINAL", &i, 1);
}
void
ewmh_updateclients(void) {
Client *c;
if(starting)
return;
for(c=client; c; c=c->next)
ewmh_updateclient(c);
}
|
Added cmd/wmii/float.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <limits.h>
#include "fns.h"
static void float_placeframe(Frame*);
void
float_attach(Area *a, Frame *f) {
if(f->client->floating == Off)
f->client->floating = On;
f->r = f->floatr;
float_placeframe(f);
assert(a->sel != f);
frame_insert(f, a->sel);
if(a->sel == nil)
area_setsel(a, f);
}
void
float_detach(Frame *f) {
Frame *pr;
Area *a, *sel, *oldsel;
View *v;
v = f->view;
a = f->area;
sel = view_findarea(v, v->selscreen, v->selcol, false);
oldsel = v->oldsel;
pr = f->aprev;
frame_remove(f);
if(a->sel == f) {
while(pr && pr->client->nofocus)
pr = pr->aprev;
if(!pr)
for(pr=a->frame; pr && pr->anext; pr=pr->anext)
if(!pr->client->nofocus) break;
a->sel = nil;
area_setsel(a, pr);
}
f->area = nil;
if(oldsel)
area_focus(oldsel);
else if(!a->frame || pr && pr->client->nofocus)
if(sel && sel->frame)
area_focus(sel);
}
void
float_resizeframe(Frame *f, Rectangle r) {
if(f->area->view == selview)
client_resize(f->client, r);
else
frame_resize(f, r);
}
void
float_arrange(Area *a) {
Frame *f;
assert(a->floating);
switch(a->mode) {
case Coldefault:
break;
case Colstack:
for(f=a->frame; f; f=f->anext)
f->collapsed = !(f->client->w.ewmh.type & (TypeDock|TypeMenu|TypeToolbar))
&& (f != a->sel);
break;
default:
die("not reached");
break;
}
for(f=a->frame; f; f=f->anext)
f->r = f->floatr;
view_update(a->view);
}
static void
rect_push(Vector_rect *vec, Rectangle r) {
Rectangle *rp;
int i;
for(i=0; i < vec->n; i++) {
rp = &vec->ary[i];
if(rect_contains_p(*rp, r))
return;
if(rect_contains_p(r, *rp)) {
*rp = r;
return;
}
}
vector_rpush(vec, r);
}
Vector_rect*
unique_rects(Vector_rect *vec, Rectangle orig) {
static Vector_rect vec1, vec2;
Vector_rect *v1, *v2, *v;
Rectangle r1, r2;
int i, j;
v1 = &vec1;
v2 = &vec2;
v1->n = 0;
vector_rpush(v1, orig);
for(i=0; i < vec->n; i++) {
v2->n = 0;
r1 = vec->ary[i];
for(j=0; j < v1->n; j++) {
r2 = v1->ary[j];
if(!rect_intersect_p(r1, r2)) {
rect_push(v2, r2);
continue;
}
if(r2.min.x < r1.min.x)
rect_push(v2, Rect(r2.min.x, r2.min.y, r1.min.x, r2.max.y));
if(r2.min.y < r1.min.y)
rect_push(v2, Rect(r2.min.x, r2.min.y, r2.max.x, r1.min.y));
if(r2.max.x > r1.max.x)
rect_push(v2, Rect(r1.max.x, r2.min.y, r2.max.x, r2.max.y));
if(r2.max.y > r1.max.y)
rect_push(v2, Rect(r2.min.x, r1.max.y, r2.max.x, r2.max.y));
}
v = v1;
v1 = v2;
v2 = v;
}
return v1;
}
Rectangle
max_rect(Vector_rect *vec) {
Rectangle *r, *rp;
int i, a, area;
area = 0;
r = 0;
for(i=0; i < vec->n; i++) {
rp = &vec->ary[i];
a = Dx(*rp) * Dy(*rp);
if(a > area) {
area = a;
r = rp;
}
}
return r ? *r : ZR;
}
static void
float_placeframe(Frame *f) {
static Vector_rect vec;
Vector_rect *vp;
Rectangle r;
Point dim, p;
Area *a, *sel;
Client *c;
Frame *ff;
View *v;
long area, l;
int i, s;
v = f->view;
a = f->area;
c = f->client;
/*
if(c->trans)
return;
*/
if(c->fullscreen >= 0 || c->w.hints->position || starting) {
f->r = f->floatr;
return;
}
/* Find all rectangles on the floating layer into which
* the new frame would fit.
*/
vec.n = 0;
for(ff=a->frame; ff; ff=ff->anext)
/* TODO: Find out why this check is needed.
* The frame hasn't been inserted yet, but somehow,
* its old rectangle winds up in the list.
*/
if(ff->client != f->client)
vector_rpush(&vec, ff->r);
/* Decide which screen we want to place this on.
* Ideally, it should probably Do the Right Thing
* when a screen fills, but what's the right thing?
* I think usage will show...
*/
s = -1;
ff = client_groupframe(c, f->view);
if(f->screen >= 0)
s = f->screen;
else if(ff)
s = ownerscreen(ff->r);
else if(selclient())
s = ownerscreen(selclient()->sel->r);
else {
sel = view_findarea(a->view, a->view->selscreen, a->view->selcol, false);
if(sel)
s = sel->screen;
}
if (s == -1)
r = a->r;
else
r = v->r[s];
vp = unique_rects(&vec, r);
area = LONG_MAX;
dim.x = Dx(f->r);
dim.y = Dy(f->r);
p = ZP;
for(i=0; i < vp->n; i++) {
r = vp->ary[i];
if(Dx(r) < dim.x || Dy(r) < dim.y)
continue;
l = Dx(r) * Dy(r);
if(l < area) {
area = l;
p = r.min;
}
}
if(area == LONG_MAX) {
/* Cascade. */
s = max(s, 0);
ff = a->sel;
if(ff)
p = addpt(ff->r.min, Pt(Dy(ff->titlebar), Dy(ff->titlebar)));
if(p.x + Dx(f->r) > screens[s]->r.max.x ||
p.y + Dy(f->r) > screens[s]->r.max.y)
p = screens[s]->r.min;
}
f->floatr = rectsetorigin(f->r, p);
}
|
Added cmd/wmii/fns.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | /* Copyright ©2007-2014 Kris Maglione <jg@suckless.org> * See LICENSE file for license details. */ #include <setjmp.h> #ifdef VARARGCK # pragma varargck argpos debug 2 # pragma varargck argpos dprint 1 # pragma varargck argpos event 1 # pragma varargck argpos warning 1 # # pragma varargck type "a" Area* # pragma varargck type "C" Client* # pragma varargck type "r" void #endif #define _cond(cond, n) (cond) && __alive++ == n #define _cont(cont) (void)(__alive--, cont) #define with(type, var) \ for(type var=(type)-1; (var == (type)-1) && ((var=0) || true);) /* Grotesque, but worth it. */ #define foreach_area(v, s, a) \ with(int, __alive) \ with(Area*, __anext) \ for(s=0; _cond(s <= nscreens, 0); _cont(s++)) \ for((a)=(s < nscreens ? (v)->areas[s] : v->floating), __anext=((a)?(a)->next:NULL); \ _cond(a, 1); \ _cont(((a)=__anext) && (__anext=(a)->next))) #define foreach_column(v, s, a) \ with(int, __alive) \ with(Area*, __anext) \ for(s=0; _cond(s < nscreens, 0); _cont(s++)) \ for((a)=(v)->areas[s], __anext=((a)?(a)->next:NULL); \ _cond(a, 1); \ _cont(((a)=__anext) && (__anext=(a)->next))) #define foreach_frame(v, s, a, f) \ with(Frame*, __fnext) \ foreach_area(v, s, a) \ for((void)(((f)=(a)->frame) && (__fnext=(f)?((f)->anext):NULL)); \ _cond(f, 2); \ _cont(((f)=__fnext) && (__fnext=(f)->anext))) #define btassert(arg, cond) \ (cond ? fprint(1, __FILE__":%d: failed assertion: " #cond "\n", __LINE__), backtrace(arg), true : false) /* area.c */ int afmt(Fmt*); void area_attach(Area*, Frame*); Area* area_create(View*, Area *pos, int scrn, uint w); void area_destroy(Area*); void area_detach(Frame*); Area* area_find(View*, Rectangle, int, bool); void area_focus(Area*); int area_idx(Area*); void area_moveto(Area*, Frame*); char* area_name(Area*); Client* area_selclient(Area*); void area_setsel(Area*, Frame*); /* bar.c */ Bar* bar_create(Bar**, const char*); void bar_destroy(Bar**, Bar*); void bar_draw(WMScreen*); Bar* bar_find(Bar*, const char*); void bar_init(WMScreen*); void bar_resize(WMScreen*); void bar_sety(WMScreen*, int); void bar_setbounds(WMScreen*, int, int); /* client.c */ int Cfmt(Fmt *f); bool client_applytags(Client*, const char*); void client_configure(Client*); Client* client_create(XWindow, XWindowAttributes*); void client_destroy(Client*); char* client_extratags(Client*); bool client_floats_p(Client*); void client_focus(Client*); Frame* client_groupframe(Client*, View*); void client_kill(Client*, bool); void client_manage(Client*); void client_map(Client*); void client_message(Client*, char*, long); bool client_prop(Client*, Atom); void client_reparent(Client*); void client_resize(Client*, Rectangle); void client_setcursor(Client*, Cursor); void client_seturgent(Client*, int, int); void client_setviews(Client*, char**); void client_unmap(Client*, int state); Frame* client_viewframe(Client *c, View *v); void focus(Client*, bool user); void fullscreen(Client*, int, long); void group_init(Client*); Client* group_leader(Group*); void group_remove(Client*); int client_mapframe(Client*); Client* selclient(void); int client_unmapframe(Client*); void update_class(Client*); Client* win2client(XWindow); Rectangle client_grav(Client*, Rectangle); /* column.c */ bool column_setmode(Area*, const char*); char* column_getmode(Area*); void column_arrange(Area*, bool dirty); void column_attach(Area*, Frame*); void column_attachrect(Area*, Frame*, Rectangle); void column_destroy(Area*); void column_detach(Frame*); void column_frob(Area*); void column_insert(Area*, Frame*, Frame*); int column_minwidth(void); Area* column_new(View*, Area*, int, uint); void column_remove(Frame*); void column_resize(Area*, int); void column_resizeframe(Frame*, Rectangle); void column_settle(Area*); void div_draw(Divide*); void div_set(Divide*, int x); void div_update_all(void); /* error.c */ #define waserror() setjmp(*pusherror()) void error(char*, ...); void nexterror(void); void poperror(void); jmp_buf* pusherror(void); /* event.c */ void debug_event(XEvent*); void print_focus(const char*, Client*, const char*); /* ewmh.c */ void ewmh_checkresponsive(Client*); void ewmh_destroyclient(Client*); void ewmh_framesize(Client*); void ewmh_getstrut(Client*); void ewmh_getwintype(Client*); void ewmh_init(void); void ewmh_initclient(Client*); bool ewmh_prop(Client*, Atom); long ewmh_protocols(Window*); bool ewmh_responsive_p(Client*); void ewmh_updateclient(Client*); void ewmh_updateclientlist(void); void ewmh_updateclients(void); void ewmh_updatestacking(void); void ewmh_updatestate(Client*); void ewmh_updateview(void); void ewmh_updateviews(void); /* float.c */ void float_arrange(Area*); void float_attach(Area*, Frame*); void float_detach(Frame*); void float_resizeframe(Frame*, Rectangle); Vector_rect* unique_rects(Vector_rect*, Rectangle); Rectangle max_rect(Vector_rect*); /* frame.c */ Frame* frame_create(Client*, View*); int frame_delta_h(void); void frame_draw(Frame*); void frame_draw_all(void); void frame_focus(Frame*); uint frame_idx(Frame*); void frame_insert(Frame*, Frame *pos); void frame_remove(Frame*); void frame_resize(Frame*, Rectangle); bool frame_restack(Frame*, Frame*); void frame_swap(Frame*, Frame*); int ingrabbox_p(Frame*, int x, int y); void move_focus(Frame*, Frame*); Rectangle constrain(Rectangle, int); Rectangle frame_client2rect(Client*, Rectangle, bool); WinHints frame_gethints(Frame*); Rectangle frame_hints(Frame*, Rectangle, Align); Rectangle frame_rect2client(Client*, Rectangle, bool); /* fs.c */ void fs_attach(Ixp9Req*); void fs_clunk(Ixp9Req*); void fs_create(Ixp9Req*); void fs_flush(Ixp9Req*); void fs_freefid(IxpFid*); void fs_open(Ixp9Req*); void fs_read(Ixp9Req*); void fs_remove(Ixp9Req*); void fs_stat(Ixp9Req*); void fs_walk(Ixp9Req*); void fs_write(Ixp9Req*); void event(const char*, ...); /* key.c */ void init_lock_keys(void); void kpress(XWindow, ulong mod, KeyCode); void update_keys(void); /* main.c */ void init_screens(void); void spawn_command(const char*); void wipe_screens(void); /* message.c */ char* mask(char**, int*, int*); char* message_bar(Bar*, IxpMsg*); char* message_client(Client*, IxpMsg*); char* message_root(void*, IxpMsg*); char* message_view(View*, IxpMsg*); void msg_debug(char*); void msg_eatrunes(IxpMsg*, int (*)(Rune), int); char* msg_getword(IxpMsg*, char*); void msg_parsecolors(IxpMsg*, CTuple*); char* msg_selectarea(Area*, IxpMsg*); char* msg_sendclient(View*, IxpMsg*, bool swap); char* readctl_bar(Bar*); char* readctl_client(Client*); char* readctl_root(void); char* readctl_view(View*); Area* strarea(View*, ulong, const char*); void warning(const char*, ...); /* mouse.c */ Window* constraintwin(Rectangle); void destroyconstraintwin(Window*); void grab_button(XWindow, uint button, ulong mod); void mouse_checkresize(Frame*, Point, bool); void mouse_movegrabbox(Client*, bool); void mouse_resize(Client*, Align, bool); void mouse_resizecol(Divide*); bool readmotion(Point*); int readmouse(Point*, uint*); Align snap_rect(const Rectangle *rects, int num, Rectangle *current, Align *mask, int snapw); /* print.c */ int Ffmt(Fmt*); /* root.c */ void root_init(void); /* screen.c */ void* findthing(Rectangle, int, Vector_ptr*, Rectangle(*)(void*), bool); int ownerscreen(Rectangle); /* rule.c */ void update_rules(Rule**, char*); /* stack.c */ bool find(Area* *, Frame**, int, bool, bool); int stack_count(Frame*, int*); Frame* stack_find(Area*, Frame*, int, bool); void stack_info(Frame*, Frame**, Frame**, int*, int*); void stack_scale(Frame*, int); /* view.c */ void view_arrange(View*); void view_attach(View*, Frame*); View* view_create(const char*); void view_destroy(View*); void view_detach(Frame*); Area* view_findarea(View*, int, int, bool); void view_focus(WMScreen*, View*); bool view_fullscreen_p(View*, int); char* view_index(View*); void view_init(View*, int iscreen); char** view_names(void); uint view_newcolwidth(View*, int, int); void view_restack(View*); void view_scale(View*, int, int); Client* view_selclient(View*); void view_select(const char*); void view_update(View*); void view_update_all(void); void view_update_rect(View*); void view_update_screens(View*); void view_update_urgency(View*, char*); Rectangle* view_rects(View*, uint *num, Frame *ignore); /* utf.c */ char* toutf8(const char*); char* toutf8n(const char*, size_t); /* xdnd.c */ void xdnd_initwindow(Window*); |
Added cmd/wmii/frame.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 |
/* Copyright ©2006-2014 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <math.h>
#include "fns.h"
uint
frame_idx(Frame *f) {
Frame *fp;
uint i;
fp = f->area->frame;
for(i = 1; fp != f; fp = fp->anext)
i++;
return i;
}
Frame*
frame_create(Client *c, View *v) {
static ushort id = 1;
Frame *f;
f = emallocz(sizeof *f);
f->id = id++;
f->client = c;
f->view = v;
if(c->sel) {
f->floatr = c->sel->floatr;
f->r = c->sel->r;
}else if(c->sel) {
f->floatr = c->frame->floatr;
f->r = c->frame->r;
}else {
f->r = client_grav(c, c->r);
f->floatr = f->r;
c->sel = f;
}
f->collapsed = false;
f->screen = -1;
f->oldarea = -1;
f->oldscreen = -1;
return f;
}
void
frame_remove(Frame *f) {
Area *a;
a = f->area;
if(f->aprev)
f->aprev->anext = f->anext;
if(f->anext)
f->anext->aprev = f->aprev;
if(f == a->frame)
a->frame = f->anext;
if(a->floating) {
if(f->sprev)
f->sprev->snext = f->snext;
if(f->snext)
f->snext->sprev = f->sprev;
if(f == a->stack)
a->stack = f->snext;
}
f->anext = f->aprev = f->snext = f->sprev = nil;
}
void
frame_insert(Frame *f, Frame *pos) {
Area *a;
a = f->area;
if(pos) {
assert(pos != f);
f->aprev = pos;
f->anext = pos->anext;
}else {
assert(f->area->frame != f);
f->anext = f->area->frame;
f->area->frame = f;
}
if(f->aprev)
f->aprev->anext = f;
if(f->anext)
f->anext->aprev = f;
if(a->floating) {
assert(f->sprev == nil);
frame_restack(f, nil);
}
}
bool
frame_restack(Frame *f, Frame *above) {
Area *a;
a = f->area;
if(!a->floating)
return false;
if(f == above)
return false;
if(f->sprev || f == a->stack)
if(f->sprev == above)
return false;
if(f->sprev)
f->sprev->snext = f->snext;
else if(f->snext)
a->stack = f->snext;
if(f->snext)
f->snext->sprev = f->sprev;
f->sprev = above;
if(above == nil) {
f->snext = a->stack;
a->stack = f;
}
else {
f->snext = above->snext;
above->snext = f;
}
if(f->snext)
f->snext->sprev = f;
assert(f->snext != f && f->sprev != f);
return true;
}
/* Handlers */
static bool
bup_event(Window *w, void *aux, XButtonEvent *e) {
if((e->state & def.mod) != def.mod)
XAllowEvents(display, ReplayPointer, e->time);
else
XUngrabPointer(display, e->time);
if(!e->subwindow)
event("ClientClick %#C %d\n", aux, e->button);
return false;
}
static bool
bdown_event(Window *w, void *aux, XButtonEvent *e) {
Frame *f;
Client *c;
c = aux;
f = c->sel;
if((e->state & def.mod) == def.mod) {
switch(e->button) {
case Button1:
focus(c, false);
mouse_resize(c, Center, true);
break;
case Button2:
frame_restack(f, nil);
view_restack(f->view);
focus(c, false);
grabpointer(c->framewin, nil, cursor[CurNone], ButtonReleaseMask);
break;
case Button3:
focus(c, false);
mouse_resize(c, quadrant(f->r, Pt(e->x_root, e->y_root)), true);
break;
default:
XAllowEvents(display, ReplayPointer, e->time);
break;
}
}else {
if(e->button == Button1) {
if(!e->subwindow) {
frame_restack(f, nil);
view_restack(f->view);
mouse_checkresize(f, Pt(e->x, e->y), true);
}
if(f->client != selclient())
focus(c, false);
}
if(e->subwindow)
XAllowEvents(display, ReplayPointer, e->time);
else {
/* Ungrab so a menu can receive events before the button is released */
XUngrabPointer(display, e->time);
sync();
event("ClientMouseDown %#C %d\n", f->client, e->button);
}
}
return false;
}
static bool
enter_event(Window *w, void *aux, XCrossingEvent *e) {
Client *c;
Frame *f;
c = aux;
f = c->sel;
if(disp.focus != c || selclient() != c) {
Dprint(DFocus, "%E\n", e);
Dprint(DFocus, "enter_notify(f) => [%#C]%s%s\n",
f->client, f->client->name,
e->serial <= event_lastconfigure ? " (ignored)" : "");
if(e->detail != NotifyInferior)
if(e->serial > event_lastconfigure && !f->collapsed)
focus(f->client, false);
}
mouse_checkresize(f, Pt(e->x, e->y), false);
return false;
}
static bool
expose_event(Window *w, void *aux, XExposeEvent *e) {
Client *c;
USED(e);
c = aux;
if(c->sel)
frame_draw(c->sel);
return false;
}
static bool
motion_event(Window *w, void *aux, XMotionEvent *e) {
Client *c;
c = aux;
mouse_checkresize(c->sel, Pt(e->x, e->y), false);
return false;
}
Handlers framehandler = {
.bup = bup_event,
.bdown = bdown_event,
.enter = enter_event,
.expose = expose_event,
.motion = motion_event,
};
WinHints
frame_gethints(Frame *f) {
WinHints h;
Client *c;
Rectangle r;
Point d;
int minh;
minh = labelh(def.font);
c = f->client;
h = *c->w.hints;
r = frame_client2rect(c, ZR, f->area->floating);
d = subpt(r.max, r.min);
if(!f->area->floating && def.incmode == IIgnore)
h.inc = Pt(1, 1);
if(h.min.x < 2*minh)
h.min.x = minh + (2*minh) % h.inc.x;
if(h.min.y < minh)
h.min.y = minh + minh % h.inc.y;
h.min.x += d.x;
h.min.y += d.y;
/* Guard against overflow. */
h.max.x = max(h.max.x + d.x, h.max.x);
h.max.y = max(h.max.y + d.y, h.max.y);
h.base.x += d.x;
h.base.y += d.y;
h.baspect.x += d.x;
h.baspect.y += d.y;
h.group = 0;
h.grav = ZP;
h.gravstatic = 0;
h.position = 0;
return h;
}
#define ADJ(PE, ME) \
if(c->fullscreen >= 0) \
return r; \
\
if(!floating) { \
r.min.x PE 1; \
r.min.y PE labelh(def.font); \
r.max.x ME 1; \
r.max.y ME 1; \
}else { \
if(!c->borderless) { \
r.min.x PE def.border; \
r.max.x ME def.border; \
r.max.y ME def.border; \
} \
if(!c->titleless) \
r.min.y PE labelh(def.font); \
} \
Rectangle
frame_rect2client(Client *c, Rectangle r, bool floating) {
ADJ(+=, -=)
/* Force clients to be at least 1x1 */
r.max.x = max(r.max.x, r.min.x+1);
r.max.y = max(r.max.y, r.min.y+1);
return r;
}
Rectangle
frame_client2rect(Client *c, Rectangle r, bool floating) {
ADJ(-=, +=)
return r;
}
#undef ADJ
void
frame_resize(Frame *f, Rectangle r) {
Client *c;
Rectangle fr, cr;
int collapsed, dx;
if(btassert("8 full", Dx(r) <= 0 || Dy(r) < 0
|| Dy(r) == 0 && (!f->area->max || resizing)
&& !f->collapsed)) {
fprint(2, "Frame rect: %R\n", r);
r.max.x = max(r.min.x+1, r.max.x);
r.max.y = max(r.min.y+1, r.max.y);
}
c = f->client;
if(c->fullscreen >= 0) {
f->r = screens[c->fullscreen]->r;
f->crect = rectsetorigin(f->r, ZP);
return;
}
/*
if(f->area->floating)
f->collapsed = false;
*/
fr = frame_hints(f, r, get_sticky(f->r, r));
if(f->area->floating && !c->strut)
fr = constrain(fr, -1);
/* Collapse managed frames which are too small */
/* XXX. */
collapsed = f->collapsed;
if(!f->area->floating && f->area->mode == Coldefault) {
f->collapsed = false;
if(Dy(r) < 2 * labelh(def.font))
f->collapsed = true;
}
if(collapsed != f->collapsed)
ewmh_updatestate(c);
fr.max.x = max(fr.max.x, fr.min.x + 2*labelh(def.font));
if(f->collapsed && f->area->floating)
fr.max.y = fr.min.y + labelh(def.font);
cr = frame_rect2client(c, fr, f->area->floating);
if(f->area->floating)
f->r = fr;
else {
f->r = r;
dx = Dx(r) - Dx(cr);
dx -= 2 * (cr.min.x - fr.min.x);
cr.min.x += dx / 2;
cr.max.x += dx / 2;
}
f->crect = rectsubpt(cr, f->r.min);
if(f->area->floating && !f->collapsed)
f->floatr = f->r;
}
static void
pushlabel(Image *img, Rectangle *rp, char *s, CTuple *col) {
Rectangle r;
int w;
w = textwidth(def.font, s) + def.font->height;
w = min(w, Dx(*rp) - 30); /* Magic number. */
if(w > 0) {
r = *rp;
r.min.x = r.max.x - w;
rp->max.x -= w;
if(0)
drawline(img, Pt(rp->max.x, r.min.y+2),
Pt(rp->max.x, r.max.y-2),
CapButt, 1, &col->border);
drawstring(img, def.font, r, East,
s, &col->fg);
}
free(s);
}
void
frame_draw(Frame *f) {
Rectangle r, fr;
Client *c;
CTuple *col;
Image *img;
char *s;
int n, m;
if(f == nil || f->view != selview || f->area == nil)
return;
c = f->client;
img = c->framewin->depth == 32 ? disp.ibuf32 : disp.ibuf;
fr = rectsetorigin(c->framewin->r, ZP);
/* Pick colors. */
if((c == selclient() || c == disp.focus) && disp.sel)
col = &def.focuscolor;
else
col = &def.normcolor;
/* Background/border */
r = fr;
fill(img, r, &col->bg);
border(img, r, 1, &col->border);
/* Title border */
r.max.y = r.min.y + labelh(def.font);
border(img, r, 1, &col->border);
f->titlebar = insetrect(r, 3);
f->titlebar.max.y += 3;
f->grabbox = insetrect(r, 2);
f->grabbox.max.x = f->grabbox.min.x + Dy(f->grabbox);
/* Odd focus. Unselected, with keyboard focus. */
/* Draw a border just inside the titlebar. */
if(c != selclient() && c == disp.focus) {
border(img, insetrect(r, 1), 1, &def.normcolor.bg);
border(img, insetrect(r, 2), 1, &def.focuscolor.border);
}
if(c->urgent)
fill(img, f->grabbox, &col->fg);
border(img, f->grabbox, 1, &col->border);
/* Odd focus. Selected, without keyboard focus. */
/* Draw a border around the grabbox. */
if(c != disp.focus && col == &def.focuscolor)
border(img, insetrect(r, -1), 1, &def.normcolor.bg);
/* Draw a border on borderless+titleless selected apps. */
if(c->borderless && c->titleless && f->area->floating && !c->fullscreen && c == selclient())
setborder(c->framewin, def.border, &def.focuscolor.border);
else
setborder(c->framewin, 0, &def.focuscolor.border);
/* Label */
r = Rect(f->grabbox.max.x, 0, fr.max.x, labelh(def.font));
/* Draw count on frames in 'max' columns. */
if(f->area->max && !resizing) {
n = stack_count(f, &m);
pushlabel(img, &r, smprint("%d/%d", m, n), col);
}
/* Label clients with extra tags. */
if((s = client_extratags(c)))
pushlabel(img, &r, s, col);
if(f->area->floating) /* Make sure floating clients have room for their indicators. */
r.max.x -= f->grabbox.max.x;
if(!ewmh_responsive_p(c))
r.min.x += drawstring(img, def.font, r, West, "(wedged) ", &col->fg);
r.min.x += drawstring(img, def.font, r, West, c->name, &col->fg);
/* Draw inner border on floating clients. */
if(f->area->floating) {
r.min.x += 10;
r.max.x += Dx(f->grabbox);
r.min.y = f->grabbox.min.y;
r.max.y = f->grabbox.max.y;
border(img, r, 1, &col->border);
}
/* Border increment gaps... */
r.min.y = f->crect.min.y;
r.min.x = max(1, f->crect.min.x - 1);
r.max.x = min(fr.max.x - 1, f->crect.max.x + 1);
r.max.y = min(fr.max.y - 1, f->crect.max.y + 1);
border(img, r, 1, &col->border);
/* Why? Because some non-ICCCM-compliant apps feel the need to
* change the background properties of all of their ancestor windows
* in order to implement pseudo-transparency.
* What's more, the designers of X11 felt that it would be unfair to
* implementers to make it possible to detect, or forbid, such changes.
*/
XSetWindowBackgroundPixmap(display, c->framewin->xid, None);
copyimage(c->framewin, fr, img, ZP);
}
void
frame_draw_all(void) {
Client *c;
for(c=client; c; c=c->next)
if(c->sel && c->sel->view == selview)
frame_draw(c->sel);
}
void
frame_swap(Frame *fa, Frame *fb) {
Frame **fp;
Client *c;
if(fa == fb) return;
for(fp = &fa->client->frame; *fp; fp = &fp[0]->cnext)
if(*fp == fa) break;
fp[0] = fp[0]->cnext;
for(fp = &fb->client->frame; *fp; fp = &fp[0]->cnext)
if(*fp == fb) break;
fp[0] = fp[0]->cnext;
c = fa->client;
fa->client = fb->client;
fb->client = c;
fb->cnext = c->frame;
c->frame = fb;
c = fa->client;
fa->cnext = c->frame;
c->frame = fa;
if(c->sel)
view_update(c->sel->view);
}
void
move_focus(Frame *old_f, Frame *f) {
int noinput;
noinput = (old_f && old_f->client->noinput) ||
(f && f->client->noinput) ||
disp.hasgrab != &c_root;
if(noinput || true) {
if(old_f)
frame_draw(old_f);
if(f)
frame_draw(f);
}
}
void
frame_focus(Frame *f) {
Frame *old_f, *ff;
View *v;
Area *a, *old_a;
v = f->view;
a = f->area;
old_a = v->sel;
if(0 && f->collapsed) {
for(ff=f; ff->collapsed && ff->anext; ff=ff->anext)
;
for(; ff->collapsed && ff->aprev; ff=ff->aprev)
;
/* XXX */
f->colr.max.y = f->colr.min.y + Dy(ff->colr);
ff->colr.max.y = ff->colr.min.y + labelh(def.font);
}
else if(f->area->mode == Coldefault) {
/* XXX */
for(; f->collapsed && f->anext; f=f->anext)
;
for(; f->collapsed && f->aprev; f=f->aprev)
;
}
old_f = old_a->sel;
a->sel = f;
if(a != old_a)
area_focus(f->area);
if(old_a != v->oldsel && f != old_f)
v->oldsel = nil;
if(f->area->floating)
f->collapsed = false;
if(v == selview && a == v->sel && !resizing) {
move_focus(old_f, f);
if(a->floating)
float_arrange(a);
// if(!a->floating && ((a->mode == Colstack) || (a->mode == Colmax)))
if(true)
column_arrange(a, false);
client_focus(f->client);
}
}
int
frame_delta_h(void) {
return def.border + labelh(def.font);
}
Rectangle
constrain(Rectangle r, int inset) {
WMScreen **sp;
WMScreen *s, *sbest;
Rectangle isect;
Point p;
int best, n;
if(inset < 0)
inset = Dy(screen->brect);
/*
* FIXME: This will cause problems for windows with
* D(r) < 2 * inset
*/
SET(best);
sbest = nil;
for(sp=screens; (s = *sp); sp++) {
if(!screen->showing)
continue;
isect = rect_intersection(r, insetrect(s->r, inset));
if(Dx(isect) >= 0 && Dy(isect) >= 0)
return r;
if(Dx(isect) <= 0 && Dy(isect) <= 0)
n = max(Dx(isect), Dy(isect));
else
n = min(Dx(isect), Dy(isect));
if(!sbest || n > best) {
sbest = s;
best = n;
}
}
isect = insetrect(sbest->r, inset);
p = ZP;
p.x -= min(r.max.x - isect.min.x, 0);
p.x -= max(r.min.x - isect.max.x, 0);
p.y -= min(r.max.y - isect.min.y, 0);
p.y -= max(r.min.y - isect.max.y, 0);
return rectaddpt(r, p);
}
|
Added cmd/wmii/fs.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <ctype.h>
#include <stdarg.h>
#include <time.h>
#include "fns.h"
typedef union IxpFileIdU IxpFileIdU;
union IxpFileIdU {
Bar* bar;
Bar** bar_p;
CTuple* col;
Client* client;
Ruleset* rule;
View* view;
char* buf;
void* ref;
};
#include <ixp_srvutil.h>
static IxpPending events;
static IxpPending pdebug[NDebugOpt];
/* Constants */
enum { /* Dirs */
FsDBars,
FsDClient,
FsDClients,
FsDDebug,
FsDTag,
FsDTags,
FsRoot,
/* Files */
FsFBar,
FsFCctl,
FsFClabel,
FsFColRules,
FsFCtags,
FsFDebug,
FsFEvent,
FsFKeys,
FsFRctl,
FsFRules,
FsFTctl,
FsFTindex,
FsFprops,
};
/* Error messages */
static char
Enoperm[] = "permission denied",
Enofile[] = "file not found",
Ebadvalue[] = "bad value",
Einterrupted[] = "interrupted";
/* Macros */
#define QID(t, i) (((vlong)((t)&0xFF)<<32)|((i)&0xFFFFFFFF))
/* Global Vars */
/***************/
Ixp9Srv p9srv = {
.open= fs_open,
.walk= fs_walk,
.read= fs_read,
.stat= fs_stat,
.write= fs_write,
.clunk= fs_clunk,
.flush= fs_flush,
.attach=fs_attach,
.create=fs_create,
.remove=fs_remove,
.freefid=fs_freefid
};
/* ad-hoc file tree. Empty names ("") indicate dynamic entries to be filled
* in by lookup_file
*/
static IxpDirtab
dirtab_root[]= {{".", QTDIR, FsRoot, 0500|DMDIR },
{"rbar", QTDIR, FsDBars, 0700|DMDIR },
{"lbar", QTDIR, FsDBars, 0700|DMDIR },
{"debug", QTDIR, FsDDebug, 0500|DMDIR, FLHide },
{"client", QTDIR, FsDClients, 0500|DMDIR },
{"tag", QTDIR, FsDTags, 0500|DMDIR },
{"ctl", QTAPPEND, FsFRctl, 0600|DMAPPEND },
{"colrules", QTFILE, FsFColRules, 0600 },
{"event", QTFILE, FsFEvent, 0600 },
{"keys", QTFILE, FsFKeys, 0600 },
{"rules", QTFILE, FsFRules, 0600 },
{nil}},
dirtab_clients[]={{".", QTDIR, FsDClients, 0500|DMDIR },
{"", QTDIR, FsDClient, 0500|DMDIR },
{nil}},
dirtab_client[]= {{".", QTDIR, FsDClient, 0500|DMDIR },
{"ctl", QTAPPEND, FsFCctl, 0600|DMAPPEND },
{"label", QTFILE, FsFClabel, 0600 },
{"tags", QTFILE, FsFCtags, 0600 },
{"props", QTFILE, FsFprops, 0400 },
{nil}},
dirtab_debug[]= {{".", QTDIR, FsDDebug, 0500|DMDIR, FLHide },
{"", QTFILE, FsFDebug, 0400 },
{nil}},
dirtab_bars[]= {{".", QTDIR, FsDBars, 0700|DMDIR },
{"", QTFILE, FsFBar, 0600 },
{nil}},
dirtab_tags[]= {{".", QTDIR, FsDTags, 0500|DMDIR },
{"", QTDIR, FsDTag, 0500|DMDIR },
{nil}},
dirtab_tag[]= {{".", QTDIR, FsDTag, 0500|DMDIR },
{"ctl", QTAPPEND, FsFTctl, 0600|DMAPPEND },
{"index", QTFILE, FsFTindex, 0400 },
{nil}};
static IxpDirtab* dirtab[] = {
[FsRoot] = dirtab_root,
[FsDBars] = dirtab_bars,
[FsDClients] = dirtab_clients,
[FsDClient] = dirtab_client,
[FsDDebug] = dirtab_debug,
[FsDTags] = dirtab_tags,
[FsDTag] = dirtab_tag,
};
typedef char* (*MsgFunc)(void*, IxpMsg*);
typedef char* (*BufFunc)(void*);
typedef struct ActionTab ActionTab;
static struct ActionTab {
MsgFunc msg;
BufFunc read;
size_t buffer;
size_t size;
int max;
} actiontab[] = {
[FsFBar] = { .msg = (MsgFunc)message_bar, .read = (BufFunc)readctl_bar },
[FsFCctl] = { .msg = (MsgFunc)message_client, .read = (BufFunc)readctl_client },
[FsFRctl] = { .msg = (MsgFunc)message_root, .read = (BufFunc)readctl_root },
[FsFTctl] = { .msg = (MsgFunc)message_view, .read = (BufFunc)readctl_view },
[FsFTindex] = { .msg = (MsgFunc)0, .read = (BufFunc)view_index },
[FsFColRules] = { .buffer = offsetof(Ruleset, string), .size = offsetof(Ruleset, size) },
[FsFKeys] = { .buffer = offsetof(Defs, keys), .size = offsetof(Defs, keyssz) },
[FsFRules] = { .buffer = offsetof(Ruleset, string), .size = offsetof(Ruleset, size) },
[FsFClabel] = { .buffer = offsetof(Client, name), .max = sizeof ((Client*)0)->name },
[FsFCtags] = { .buffer = offsetof(Client, tags), .max = sizeof ((Client*)0)->tags },
[FsFprops] = { .buffer = offsetof(Client, props), .max = sizeof ((Client*)0)->props },
};
void
event(const char *format, ...) {
va_list ap;
va_start(ap, format);
vsnprint(buffer, sizeof buffer, format, ap);
va_end(ap);
ixp_pending_write(&events, buffer, strlen(buffer));
Dprint(DEvents, "%s", buffer);
}
static int dflags;
bool
setdebug(int flag) {
dflags = flag;
return true;
}
void
vdebug(int flag, const char *fmt, va_list ap) {
char *s;
if(flag == 0)
flag = dflags;
if(!((debugflag|debugfile) & flag))
return;
s = vsmprint(fmt, ap);
dwrite(flag, s, strlen(s), false);
free(s);
}
void
debug(int flag, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vdebug(flag, fmt, ap);
va_end(ap);
}
void
dwrite(int flag, void *buf, int n, bool always) {
int i;
if(flag == 0)
flag = dflags;
if(always || debugflag&flag)
write(2, buf, n);
if(debugfile&flag)
for(i=0; i < nelem(pdebug); i++)
if(flag & (1<<i))
ixp_pending_write(pdebug+i, buf, n);
}
static uint fs_size(IxpFileId*);
static void
dostat(IxpStat *s, IxpFileId *f) {
s->type = 0;
s->dev = 0;
s->qid.path = QID(f->tab.type, f->id);
s->qid.version = 0;
s->qid.type = f->tab.qtype;
s->mode = f->tab.perm;
s->atime = time(nil);
s->mtime = s->atime;
s->length = fs_size(f);;
s->name = f->tab.name;
s->uid = user;
s->gid = user;
s->muid = user;
}
/*
* All lookups and directory organization should be performed through
* lookup_file, mostly through the dirtab[] tree.
*/
static IxpFileId*
lookup_file(IxpFileId *parent, char *name)
{
IxpFileId *ret, *file, **last;
IxpDirtab *dir;
Client *c;
View *v;
Bar *b;
uint id;
int i;
if(!(parent->tab.perm & DMDIR))
return nil;
dir = dirtab[parent->tab.type];
last = &ret;
ret = nil;
for(; dir->name; dir++) {
# define push_file(nam, id_, vol) \
file = ixp_srv_getfile(); \
file->id = id_; \
file->volatil = vol; \
*last = file; \
last = &file->next; \
file->tab = *dir; \
file->tab.name = estrdup(nam)
/* Dynamic dirs */
if(dir->name[0] == '\0') {
switch(parent->tab.type) {
case FsDClients:
if(!name || !strcmp(name, "sel")) {
if((c = selclient())) {
push_file("sel", c->w.xid, true);
file->p.client = c;
file->index = c->w.xid;
}
if(name)
goto LastItem;
}
SET(id);
if(name) {
id = (uint)strtol(name, &name, 16);
if(*name)
goto NextItem;
}
for(c=client; c; c=c->next) {
if(!name || c->w.xid == id) {
push_file(sxprint("%#C", c), c->w.xid, true);
file->p.client = c;
file->index = c->w.xid;
assert(file->tab.name);
if(name)
goto LastItem;
}
}
break;
case FsDDebug:
for(i=0; i < nelem(pdebug); i++)
if(!name || !strcmp(name, debugtab[i])) {
push_file(debugtab[i], i, false);
if(name)
goto LastItem;
}
break;
case FsDTags:
if(!name || !strcmp(name, "sel")) {
if(selview) {
push_file("sel", selview->id, true);
file->p.view = selview;
}
if(name)
goto LastItem;
}
for(v=view; v; v=v->next) {
if(!name || !strcmp(name, v->name)) {
push_file(v->name, v->id, true);
file->p.view = v;
if(name)
goto LastItem;
}
}
break;
case FsDBars:
for(b=*parent->p.bar_p; b; b=b->next) {
if(!name || !strcmp(name, b->name)) {
push_file(b->name, b->id, true);
file->p.bar = b;
if(name)
goto LastItem;
}
}
break;
}
}else /* Static dirs */
if(!name && !(dir->flags & FLHide) || name && !strcmp(name, dir->name)) {
push_file(file->tab.name, 0, false);
file->p.ref = parent->p.ref;
file->index = parent->index;
/* Special considerations: */
switch(file->tab.type) {
case FsDBars:
if(!strcmp(file->tab.name, "lbar"))
file->p.bar_p = &screen[0].bar[BLeft];
else
file->p.bar_p = &screen[0].bar[BRight];
file->id = (int)(uintptr_t)file->p.bar_p;
break;
case FsFColRules:
file->p.rule = &def.colrules;
break;
case FsFKeys:
file->p.ref = &def;
break;
case FsFRules:
file->p.rule = &def.rules;
break;
}
if(name)
goto LastItem;
}
NextItem:
continue;
# undef push_file
}
LastItem:
*last = nil;
return ret;
}
/* Service Functions */
void
fs_attach(Ixp9Req *r) {
IxpFileId *f;
f = ixp_srv_getfile();
f->tab = dirtab[FsRoot][0];
f->tab.name = estrdup("/");
r->fid->aux = f;
r->fid->qid.type = f->tab.qtype;
r->fid->qid.path = QID(f->tab.type, 0);
r->ofcall.rattach.qid = r->fid->qid;
ixp_respond(r, nil);
}
void
fs_walk(Ixp9Req *r) {
ixp_srv_walkandclone(r, lookup_file);
}
static uint
fs_size(IxpFileId *f) {
ActionTab *t;
t = &actiontab[f->tab.type];
if(f->tab.type < nelem(actiontab))
if(t->size)
return structmember(f->p.ref, int, t->size);
else if(t->buffer && t->max)
return strlen(structptr(f->p.ref, char, t->buffer));
else if(t->buffer)
return strlen(structmember(f->p.ref, char*, t->buffer));
else if(t->read)
return strlen(t->read(f->p.ref));
return 0;
}
void
fs_stat(Ixp9Req *r) {
IxpMsg m;
IxpStat s;
int size;
char *buf;
IxpFileId *f;
f = r->fid->aux;
if(!ixp_srv_verifyfile(f, lookup_file)) {
ixp_respond(r, Enofile);
return;
}
dostat(&s, f);
size = ixp_sizeof_stat(&s);
r->ofcall.rstat.nstat = size;
buf = emallocz(size);
m = ixp_message(buf, size, MsgPack);
ixp_pstat(&m, &s);
r->ofcall.rstat.stat = (uchar*)m.data;
ixp_respond(r, nil);
}
void
fs_read(Ixp9Req *r) {
char *buf;
IxpFileId *f;
ActionTab *t;
int n, found;
f = r->fid->aux;
found = 0;
if(!ixp_srv_verifyfile(f, lookup_file)) {
ixp_respond(r, Enofile);
return;
}
if(f->tab.perm & DMDIR && f->tab.perm & 0400) {
ixp_srv_readdir(r, lookup_file, dostat);
return;
}
else{
if(f->pending) {
ixp_pending_respond(r);
return;
}
t = &actiontab[f->tab.type];
if(f->tab.type < nelem(actiontab)) {
if(t->read)
buf = t->read(f->p.ref);
else if(t->buffer && t->max)
buf = structptr(f->p.ref, char, t->buffer);
else if(t->buffer)
buf = structmember(f->p.ref, char*, t->buffer);
else
goto done;
n = t->size ? structmember(f->p.ref, int, t->size) : strlen(buf);
ixp_srv_readbuf(r, buf, n);
ixp_respond(r, nil);
found++;
}
done:
switch(f->tab.type) {
default:
if(found)
return;
}
}
/* This should not be called if the file is not open for reading. */
die("Read called on an unreadable file");
}
void
fs_write(Ixp9Req *r) {
IxpFileId *f;
ActionTab *t;
char *errstr;
int found;
found = 0;
errstr = nil;
if(r->ifcall.io.count == 0) {
ixp_respond(r, nil);
return;
}
f = r->fid->aux;
if(!ixp_srv_verifyfile(f, lookup_file)) {
ixp_respond(r, Enofile);
return;
}
switch(f->tab.type) {
case FsFCtags:
r->ofcall.io.count = r->ifcall.io.count;
ixp_srv_data2cstring(r);
client_applytags(f->p.client, r->ifcall.io.data);
ixp_respond(r, nil);
return;
}
if(waserror()) {
ixp_respond(r, ixp_errbuf());
return;
}
t = &actiontab[f->tab.type];
if(f->tab.type < nelem(actiontab)) {
if(t->msg) {
errstr = ixp_srv_writectl(r, t->msg);
r->ofcall.io.count = r->ifcall.io.count;
}
else if(t->buffer && t->max)
ixp_srv_writebuf(r, (char*[]){ structptr(f->p.ref, char, t->buffer) },
t->size ? structptr(f->p.ref, uint, t->size)
: (uint[]){ strlen(structptr(f->p.ref, char, t->buffer)) },
t->max);
else if(t->buffer)
ixp_srv_writebuf(r, structptr(f->p.ref, char*, t->buffer),
t->size ? structptr(f->p.ref, uint, t->size) : nil,
t->max);
else
goto done;
ixp_respond(r, errstr);
found++;
}
done:
switch(f->tab.type) {
case FsFClabel:
frame_draw(f->p.client->sel);
update_class(f->p.client);
break;
case FsFCtags:
client_applytags(f->p.client, f->p.client->tags);
break;
case FsFEvent:
if(r->ifcall.io.data[r->ifcall.io.count-1] == '\n')
event("%.*s", (int)r->ifcall.io.count, r->ifcall.io.data);
else
event("%.*s\n", (int)r->ifcall.io.count, r->ifcall.io.data);
r->ofcall.io.count = r->ifcall.io.count;
ixp_respond(r, nil);
break;
default:
/* This should not be called if the file is not open for writing. */
if(!found)
die("Write called on an unwritable file");
}
poperror();
return;
}
void
fs_open(Ixp9Req *r) {
IxpFileId *f;
f = r->fid->aux;
if(!ixp_srv_verifyfile(f, lookup_file)) {
ixp_respond(r, Enofile);
return;
}
switch(f->tab.type) {
case FsFEvent:
ixp_pending_pushfid(&events, r->fid);
break;
case FsFDebug:
ixp_pending_pushfid(pdebug+f->id, r->fid);
debugfile |= 1<<f->id;
break;
}
if((r->ifcall.topen.mode&3) == OEXEC
|| (r->ifcall.topen.mode&3) != OREAD && !(f->tab.perm & 0200)
|| (r->ifcall.topen.mode&3) != OWRITE && !(f->tab.perm & 0400)
|| (r->ifcall.topen.mode & ~(3|OAPPEND|OTRUNC)))
ixp_respond(r, Enoperm);
else
ixp_respond(r, nil);
}
void
fs_create(Ixp9Req *r) {
IxpFileId *f;
f = r->fid->aux;
switch(f->tab.type) {
default:
ixp_respond(r, Enoperm);
return;
case FsDBars:
if(!strlen(r->ifcall.tcreate.name)) {
ixp_respond(r, Ebadvalue);
return;
}
bar_create(f->p.bar_p, r->ifcall.tcreate.name);
f = lookup_file(f, r->ifcall.tcreate.name);
if(!f) {
ixp_respond(r, Enofile);
return;
}
r->ofcall.ropen.qid.type = f->tab.qtype;
r->ofcall.ropen.qid.path = QID(f->tab.type, f->id);
f->next = r->fid->aux;
r->fid->aux = f;
ixp_respond(r, nil);
break;
}
}
void
fs_remove(Ixp9Req *r) {
IxpFileId *f;
WMScreen *s;
f = r->fid->aux;
if(!ixp_srv_verifyfile(f, lookup_file)) {
ixp_respond(r, Enofile);
return;
}
switch(f->tab.type) {
default:
ixp_respond(r, Enoperm);
return;
case FsFBar:
s = f->p.bar->screen;
bar_destroy(f->next->p.bar_p, f->p.bar);
bar_draw(s);
break;
case FsDClient:
client_kill(f->p.client, true);
break;
}
ixp_respond(r, nil);
}
void
fs_clunk(Ixp9Req *r) {
IxpFileId *f;
f = r->fid->aux;
if(!ixp_srv_verifyfile(f, lookup_file)) {
ixp_respond(r, nil);
return;
}
if(f->pending) {
/* Should probably be in freefid */
if(ixp_pending_clunk(r)) {
if(f->tab.type == FsFDebug)
debugfile &= ~(1<<f->id);
}
return;
}
switch(f->tab.type) {
case FsFColRules:
case FsFRules:
update_rules(&f->p.rule->rule, f->p.rule->string);
break;
case FsFKeys:
update_keys();
break;
}
ixp_respond(r, nil);
}
void
fs_flush(Ixp9Req *r) {
Ixp9Req *or;
IxpFileId *f;
or = r->oldreq;
f = or->fid->aux;
if(f->pending)
ixp_pending_flush(r);
/* else die() ? */
ixp_respond(r->oldreq, Einterrupted);
ixp_respond(r, nil);
}
void
fs_freefid(IxpFid *f) {
IxpFileId *id, *tid;
tid = f->aux;
while((id = tid)) {
tid = id->next;
ixp_srv_freefile(id);
}
}
|
Added cmd/wmii/key.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
/* Copyright ©2006-2010 Kris Maglione <fbsdaemon at Gmail>
* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <X11/keysym.h>
#include "fns.h"
static void
freekey(Key *k) {
Key *n;
while((n = k)) {
k = k->next;
free(n);
}
}
static void
_grab(XWindow w, int keycode, uint mod) {
XGrabKey(display, keycode, mod, w,
true, GrabModeAsync, GrabModeAsync);
}
static void
grabkey(Key *k) {
_grab(scr.root.xid, k->key, k->mod);
_grab(scr.root.xid, k->key, k->mod | LockMask);
if(numlock_mask) {
_grab(scr.root.xid, k->key, k->mod | numlock_mask);
_grab(scr.root.xid, k->key, k->mod | numlock_mask | LockMask);
}
}
static void
ungrabkey(Key *k) {
XUngrabKey(display, k->key, k->mod, scr.root.xid);
XUngrabKey(display, k->key, k->mod | LockMask, scr.root.xid);
if(numlock_mask) {
XUngrabKey(display, k->key, k->mod | numlock_mask, scr.root.xid);
XUngrabKey(display, k->key, k->mod | numlock_mask | LockMask, scr.root.xid);
}
}
static Key*
name2key(const char *name) {
Key *k;
for(k=key; k; k=k->lnext)
if(!strcmp(k->name, name))
return k;
return nil;
}
static Key*
getkey(const char *name) {
Key *k, *r;
char buf[128];
char *seq[8];
char *kstr;
int mask;
uint i, toks;
static ushort id = 1;
r = nil;
if((k = name2key(name))) {
ungrabkey(k);
return k;
}
utflcpy(buf, name, sizeof buf);
toks = tokenize(seq, 8, buf, ',');
for(i = 0; i < toks; i++) {
if(!k)
r = k = emallocz(sizeof *k);
else {
k->next = emallocz(sizeof *k);
k = k->next;
}
utflcpy(k->name, name, sizeof k->name);
if(parsekey(seq[i], &mask, &kstr)) {
k->key = keycode(kstr);
k->mod = mask;
}
if(k->key == 0) {
freekey(r);
return nil;
}
}
if(r) {
r->id = id++;
r->lnext = key;
key = r;
}
return r;
}
static void
next_keystroke(ulong *mod, KeyCode *code) {
XEvent e;
KeySym sym;
*mod = 0;
do {
XMaskEvent(display, KeyPressMask, &e);
*mod |= e.xkey.state & valid_mask;
*code = (KeyCode)e.xkey.keycode;
sym = XKeycodeToKeysym(display, e.xkey.keycode, 0);
} while(IsModifierKey(sym));
}
static void
fake_keypress(ulong mod, KeyCode key) {
XKeyEvent e;
Client *c;
c = disp.focus;
if(c == nil || c->w.xid == 0)
return;
e.time = event_xtime;
e.window = c->w.xid;
e.state = mod;
e.keycode = key;
e.type = KeyPress;
sendevent(&c->w, true, KeyPressMask, (XEvent*)&e);
e.type = KeyRelease;
sendevent(&c->w, true, KeyReleaseMask, (XEvent*)&e);
sync();
}
static Key *
match_keys(Key *k, ulong mod, KeyCode keycode, bool seq) {
Key *ret, *next;
int i; /* shut up ken */
ret = nil;
for(next = k->tnext; k; i = (k=next) && (next=k->tnext)) {
if(seq)
k = k->next;
if(k && (k->mod == mod) && (k->key == keycode)) {
k->tnext = ret;
ret = k;
}
}
USED(i);
return ret;
}
static void
kpress_seq(XWindow w, Key *done) {
ulong mod;
KeyCode key;
Key *found;
next_keystroke(&mod, &key);
found = match_keys(done, mod, key, true);
if((done->mod == mod) && (done->key == key))
fake_keypress(mod, key); /* double key */
else {
if(!found)
XBell(display, 0);
else if(!found->tnext && !found->next)
event("Key %s\n", found->name);
else
kpress_seq(w, found);
}
}
void
kpress(XWindow w, ulong mod, KeyCode keycode) {
Key *k, *found;
for(k=key; k; k=k->lnext)
k->tnext = k->lnext;
found = match_keys(key, mod, keycode, false);
if(!found) /* grabbed but not found */
XBell(display, 0);
else if(!found->tnext && !found->next)
event("Key %s\n", found->name);
else {
XGrabKeyboard(display, w, true, GrabModeAsync, GrabModeAsync, CurrentTime);
event_flush(FocusChangeMask, true);
kpress_seq(w, found);
XUngrabKeyboard(display, CurrentTime);
}
}
void
update_keys(void) {
Key *k;
char *l, *p;
numlock_mask = numlockmask();
valid_mask = 0xff & ~(numlock_mask | LockMask);
while((k = key)) {
key = key->lnext;
ungrabkey(k);
freekey(k);
}
for(l = p = def.keys; p && *p; p++) {
if(*p == '\n') {
*p = 0;
if((k = getkey(l)))
grabkey(k);
*p = '\n';
l = p + 1;
}
}
if(l < p && strlen(l)) {
if((k = getkey(l)))
grabkey(k);
}
}
|
Added cmd/wmii/layout.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
/* Here be dragons. */
/* Actually, I'm happy to say, the dragons have dissipated. */
enum {
ButtonMask =
ButtonPressMask | ButtonReleaseMask,
MouseMask =
ButtonMask | PointerMotionMask
};
static Handlers handlers;
enum { OHoriz, OVert };
typedef struct Framewin Framewin;
struct Framewin {
/* Todo... give these better names. */
Window* w;
Rectangle grabbox;
Frame* f;
Area* ra;
Point pt;
int orientation;
int xy;
int screen;
};
static Rectangle
framerect(Framewin *f) {
Rectangle r;
Point p;
int scrn;
r.min = ZP;
if(f->orientation == OHoriz) {
r.max.x = f->xy;
r.max.y = f->grabbox.max.y + f->grabbox.min.y;
}else {
r.max.x = f->grabbox.max.x + f->grabbox.min.x;
r.max.y = f->xy;
r = rectsubpt(r, Pt(Dx(r)/2, 0));
}
r = rectaddpt(r, f->pt);
scrn = f->screen;
if(scrn == -1)
scrn = max(ownerscreen(f->f->r), 0);
/* Keep onscreen */
p = ZP;
p.x -= min(0, r.min.x);
p.x -= max(0, r.max.x - screens[scrn]->r.max.x);
p.y -= max(0, r.max.y - screens[scrn]->brect.min.y - Dy(r)/2);
return rectaddpt(r, p);
}
static void
frameadjust(Framewin *f, Point pt, int orientation, int xy) {
f->orientation = orientation;
f->xy = xy;
f->pt = pt;
}
static Framewin*
framewin(Frame *f, Point pt, int orientation, int n) {
WinAttr wa;
Framewin *fw;
fw = emallocz(sizeof *fw);
wa.override_redirect = true;
wa.event_mask = ExposureMask;
fw->w = createwindow(&scr.root, Rect(0, 0, 1, 1),
scr.depth, InputOutput,
&wa, CWEventMask);
fw->w->aux = fw;
sethandler(fw->w, &handlers);
fw->f = f;
fw->screen = f->area->screen;
fw->grabbox = f->grabbox;
frameadjust(fw, pt, orientation, n);
reshapewin(fw->w, framerect(fw));
raisewin(fw->w);
return fw;
}
static void
framedestroy(Framewin *f) {
destroywindow(f->w);
free(f);
}
static bool
expose_event(Window *w, void *aux, XExposeEvent *e) {
Rectangle r;
Framewin *f;
Image *buf;
CTuple *c;
USED(e);
f = aux;
c = &def.focuscolor;
buf = disp.ibuf;
r = rectsubpt(w->r, w->r.min);
fill(buf, r, &c->bg);
border(buf, r, 1, &c->border);
border(buf, f->grabbox, 1, &c->border);
border(buf, insetrect(f->grabbox, -f->grabbox.min.x), 1, &c->border);
copyimage(w, r, buf, ZP);
return false;
}
static Handlers handlers = {
.expose = expose_event,
};
static Area*
find_area(Point pt) {
View *v;
Area *a;
int s;
v = selview;
for(s=0; s < nscreens; s++) {
if(!rect_haspoint_p(screens[s]->r, pt))
continue;
for(a=v->areas[s]; a; a=a->next)
if(pt.x < a->r.max.x)
return a;
}
return nil;
}
static void
vplace(Framewin *fw, Point pt) {
Vector_long vec = {0};
Rectangle r;
Frame *f;
Area *a;
long l;
int hr;
a = find_area(pt);
if(a == nil)
return;
fw->ra = a;
fw->screen = a->screen;
pt.x = a->r.min.x;
frameadjust(fw, pt, OHoriz, Dx(a->r));
r = fw->w->r;
hr = Dy(r)/2;
pt.y -= hr;
if(a->frame == nil)
goto done;
vector_lpush(&vec, a->frame->r.min.y);
for(f=a->frame; f; f=f->anext) {
if(f == fw->f)
vector_lpush(&vec, f->r.min.y + 0*hr);
else if(f->collapsed)
vector_lpush(&vec, f->r.min.y + 1*hr);
else
vector_lpush(&vec, f->r.min.y + 2*hr);
if(!f->collapsed && f->anext != fw->f)
vector_lpush(&vec, f->r.max.y - 2*hr);
}
for(int i=0; i < vec.n; i++) {
l = vec.ary[i];
if(abs(pt.y - l) < hr) {
pt.y = l;
break;
}
}
vector_lfree(&vec);
done:
pt.x = a->r.min.x;
frameadjust(fw, pt, OHoriz, Dx(a->r));
reshapewin(fw->w, framerect(fw));
}
static void
hplace(Framewin *fw, Point pt) {
Area *a;
int minw;
a = find_area(pt);
if(a == nil)
return; /* XXX: Multihead. */
fw->screen = a->screen;
fw->ra = nil;
minw = column_minwidth();
if(abs(pt.x - a->r.min.x) < minw/2) {
pt.x = a->r.min.x;
fw->ra = a->prev;
}
else if(abs(pt.x - a->r.max.x) < minw/2) {
pt.x = a->r.max.x;
fw->ra = a;
}
pt.y = a->r.min.y;
frameadjust(fw, pt, OVert, Dy(a->r));
reshapewin(fw->w, framerect(fw));
}
static Point
grabboxcenter(Frame *f) {
Point p;
p = addpt(f->r.min, f->grabbox.min);
p.x += Dx(f->grabbox)/2;
p.y += Dy(f->grabbox)/2;
return p;
}
static int tvcol(Frame*, bool);
static int thcol(Frame*, bool);
static int tfloat(Frame*, bool);
enum {
TDone,
TVCol,
THCol,
TFloat,
};
static int (*tramp[])(Frame*, bool) = {
0,
tvcol,
thcol,
tfloat,
};
/* Trampoline to allow properly tail recursive move/resize routines.
* We could probably get away with plain tail calls, but I don't
* like the idea.
*/
static void
trampoline(int fn, Frame *f, bool grabbox) {
int moved;
moved = 0;
while(fn > 0) {
if(grabbox)
warppointer(grabboxcenter(f));
//f->collapsed = false;
fn = tramp[fn](f, moved++);
}
ungrabpointer();
}
static void
resizemode(int mode) {
bool orig;
orig = resizing;
resizing = mode && mode != TFloat;
if(resizing != orig)
view_update(selview);
}
void
mouse_movegrabbox(Client *c, bool grabmod) {
Frame *f;
Point p;
float x, y;
f = c->sel;
SET(x);
SET(y);
if(grabmod) {
p = querypointer(f->client->framewin);
x = (float)p.x / Dx(f->r);
y = (float)p.y / Dy(f->r);
}
if(f->area->floating)
trampoline(TFloat, f, !grabmod);
else
trampoline(THCol, f, true);
if(grabmod)
warppointer(addpt(f->r.min, Pt(x * Dx(f->r),
y * Dy(f->r))));
else
warppointer(grabboxcenter(f));
}
static int
_openstack_down(Frame *f, int h) {
int ret;
int dy;
if(f == nil)
return 0;;
ret = 0;
if(!f->collapsed) {
dy = Dy(f->colr) - labelh(def.font);
if(dy >= h) {
f->colr.min.y += h;
return h;
}else {
f->collapsed = true;
f->colr.min.y += dy;
ret = dy;
h -= dy;
}
}
dy = _openstack_down(f->anext, h);
f->colr.min.y += dy;
f->colr.max.y += dy;
return ret + dy;
}
static int
_openstack_up(Frame *f, int h) {
int ret;
int dy;
if(f == nil)
return 0;
ret = 0;
if(!f->collapsed) {
dy = Dy(f->colr) - labelh(def.font);
if(dy >= h) {
f->colr.max.y -= h;
return h;
}else {
f->collapsed = true;
f->colr.max.y -= dy;
ret = dy;
h -= dy;
}
}
dy = _openstack_up(f->aprev, h);
f->colr.min.y -= dy;
f->colr.max.y -= dy;
return ret + dy;
}
static void
column_openstack(Area *a, Frame *f, int h) {
if(f == nil)
_openstack_down(a->frame, h);
else {
h -= _openstack_down(f->anext, h);
if(h)
_openstack_up(f->aprev, h);
}
}
static void
column_drop(Area *a, Frame *f, int y) {
Frame *ff;
int dy, extra_y;
extra_y = Dy(a->r);
for(ff=a->frame; ff; ff=ff->anext) {
assert(ff != f);
extra_y -= Dy(ff->colr);
}
if(a->frame == nil || y <= a->frame->r.min.y) {
f->collapsed = true;
f->colr.min.y = 0;
f->colr.max.y = labelh(def.font);
column_openstack(a, nil, labelh(def.font));
column_insert(a, f, nil);
return;
}
for(ff=a->frame; ff->anext; ff=ff->anext)
if(y <= ff->colr.max.y) break;
y = max(y, ff->colr.min.y + labelh(def.font));
y = min(y, ff->colr.max.y);
dy = ff->colr.max.y - y;
if(dy <= labelh(def.font)) {
f->collapsed = true;
f->colr.min.y = 0;
f->colr.max.y = labelh(def.font);
column_openstack(a, ff, labelh(def.font) - dy);
}else {
f->colr.min.y = y;
f->colr.max.y = ff->colr.max.y + extra_y;
ff->colr.max.y = y;
}
column_insert(a, f, ff);
}
static int
thcol(Frame *f, bool moved) {
Framewin *fw;
Frame *fp, *fn;
Area *a;
Point pt, pt2;
uint button;
int ret, collapsed;
focus(f->client, false);
ret = TDone;
if(!grabpointer(&scr.root, nil, None, MouseMask))
return TDone;
readmotion(&pt);
pt2.x = f->area->r.min.x;
pt2.y = pt.y;
fw = framewin(f, pt2, OHoriz, Dx(f->area->r));
if(moved)
goto casemotion;
vplace(fw, pt);
for(;;)
switch (readmouse(&pt, &button)) {
case MotionNotify:
casemotion:
moved = 1;
resizemode(THCol);
if(mapwin(fw->w))
grabpointer(&scr.root, nil, cursor[CurIcon], MouseMask);
vplace(fw, pt);
break;
case ButtonRelease:
if(!moved)
goto done;
if(button != 1)
continue;
SET(collapsed);
SET(fp);
SET(fn);
a = f->area;
if(a->floating)
area_detach(f);
else {
collapsed = f->collapsed;
fp = f->aprev;
fn = f->anext;
column_remove(f);
if(!f->collapsed)
if(fp)
fp->colr.max.y = f->colr.max.y;
else if(fn && fw->pt.y > fn->r.min.y)
fn->colr.min.y = f->colr.min.y;
}
column_drop(fw->ra, f, fw->pt.y);
if(!a->floating && collapsed) {
/* XXX */
for(; fn && fn->collapsed; fn=fn->anext)
;
if(fn == nil)
for(fn=fp; fn && fn->collapsed; fn=fn->aprev)
;
if(fp)
fp->colr.max.x += labelh(def.font);
}
if(!a->frame && !a->floating && a->view->areas[a->screen]->next)
area_destroy(a);
frame_focus(f);
goto done;
case ButtonPress:
if(button == 2)
ret = TVCol;
else if(button == 3)
ret = TFloat;
else
continue;
goto done;
}
done:
resizemode(0);
framedestroy(fw);
return ret;
}
static int
tvcol(Frame *f, bool moved) {
Framewin *fw;
Window *cwin;
Rectangle r;
Point pt, pt2;
uint button;
int ret, scrn;
focus(f->client, false);
pt = querypointer(&scr.root);
pt2.x = pt.x;
pt2.y = f->area->r.min.y;
scrn = f->area->screen > -1 ? f->area->screen : find_area(pt) ? find_area(pt)->screen : 0;
r = f->view->r[scrn];
fw = framewin(f, pt2, OVert, Dy(r));
mapwin(fw->w);
r.min.y += fw->grabbox.min.y + Dy(fw->grabbox)/2;
r.max.y = r.min.y + 1;
cwin = createwindow(&scr.root, r, 0, InputOnly, nil, 0);
mapwin(cwin);
ret = TDone;
if(!grabpointer(&scr.root, cwin, cursor[CurIcon], MouseMask))
goto done;
resizemode(TVCol);
hplace(fw, pt);
for(;;)
switch (readmouse(&pt, &button)) {
case MotionNotify:
moved = 1;
hplace(fw, pt);
continue;
case ButtonPress:
if(button == 2)
ret = THCol;
else if(button == 3)
ret = TFloat;
else
continue;
goto done;
case ButtonRelease:
if(button != 1)
continue;
if(fw->ra) {
fw->ra = column_new(f->view, fw->ra, screen->idx, 0);
area_moveto(fw->ra, f);
}
goto done;
}
done:
framedestroy(fw);
destroywindow(cwin);
resizemode(0);
return ret;
}
static int
tfloat(Frame *f, bool moved) {
Rectangle *rects;
Rectangle frect, origin;
Point pt, pt1;
Client *c;
Align align;
uint nrect, button;
int ret;
c = f->client;
if(!f->area->floating) {
if(f->anext)
f->anext->colr.min.y = f->colr.min.y;
else if(f->aprev)
f->aprev->colr.max.y = f->colr.max.y;
area_moveto(f->view->floating, f);
view_update(f->view);
warppointer(grabboxcenter(f));
}
client_mapframe(f->client);
if(!f->collapsed)
focus(f->client, false);
ret = TDone;
if(!grabpointer(c->framewin, nil, cursor[CurMove], MouseMask))
return TDone;
rects = view_rects(f->view, &nrect, f);
origin = f->r;
frect = f->r;
if(!readmotion(&pt)) {
focus(f->client, false);
goto done;
}
/* pt1 = grabboxcenter(f); */
pt1 = pt;
goto case_motion;
shut_up_ken:
for(;;pt1=pt)
switch (readmouse(&pt, &button)) {
default: goto shut_up_ken;
case MotionNotify:
moved = 1;
case_motion:
origin = rectaddpt(origin, subpt(pt, pt1));
origin = constrain(origin, -1);
frect = origin;
align = Center;
snap_rect(rects, nrect, &frect, &align, def.snap);
frect = frame_hints(f, frect, Center);
frect = constrain(frect, -1);
client_resize(c, frect);
continue;
case ButtonRelease:
if(button != 1)
continue;
if(!moved) {
f->collapsed = !f->collapsed;
client_resize(f->client, f->floatr);
}
goto done;
case ButtonPress:
if(button != 3)
continue;
client_unmapframe(f->client);
ret = THCol;
goto done;
}
done:
free(rects);
return ret;
}
|
Added cmd/wmii/main.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 |
/* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
* Copyright ©2006-2014 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#define EXTERN
#include "dat.h"
#include <X11/Xproto.h>
#include <X11/cursorfont.h>
#include <errno.h>
#include <fcntl.h>
#include <locale.h>
#include <pwd.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include "fns.h"
static const char
version[] = "wmii-"VERSION", "COPYRIGHT"\n";
static char* address;
static char* ns_path;
static int sleeperfd;
static int sock;
static int exitsignal;
static struct sigaction sa;
static struct passwd* passwd;
static void
usage(void) {
fatal("usage: wmii [-a <address>] [-r <wmiirc>] [-v]\n");
}
static int
errfmt(Fmt *f) {
return fmtstrcpy(f, ixp_errbuf());
}
static void
scan_wins(void) {
int i;
uint num;
XWindow *wins;
XWindowAttributes wa;
XWindow root, parent;
if(XQueryTree(display, scr.root.xid, &root, &parent, &wins, &num)) {
for(i = 0; i < num; i++) {
if(!XGetWindowAttributes(display, wins[i], &wa) || wa.override_redirect)
continue;
if(!XGetTransientForHint(display, wins[i], &parent))
if(wa.map_state == IsViewable)
client_create(wins[i], &wa);
}
/* Manage transients. */
for(i = 0; i < num; i++) {
if(!XGetWindowAttributes(display, wins[i], &wa) || wa.override_redirect)
continue;
if(XGetTransientForHint(display, wins[i], &parent))
if(wa.map_state == IsViewable)
client_create(wins[i], &wa);
}
}
if(wins)
XFree(wins);
}
static void
init_ns(void) {
char *s;
if(address && strncmp(address, "unix!", 5) == 0) {
ns_path = estrdup(&address[5]);
s = strrchr(ns_path, '/');
if(s != nil)
*s = '\0';
if(ns_path[0] != '/' || ns_path[0] == '\0')
fatal("address %q is not an absolute path", address);
setenv("NAMESPACE", ns_path, true);
}else
ns_path = ixp_namespace();
if(ns_path == nil)
fatal("Bad namespace path: %r\n");
}
static void
init_environment(void) {
init_ns();
if(address)
setenv("WMII_ADDRESS", address, true);
else
address = smprint("unix!%s/wmii", ns_path);
setenv("WMII_CONFPATH",
sxprint("%s/.%s:%s", getenv("HOME"), CONFDIR, GLOBALCONF),
true);
}
static void
create_cursor(int ident, uint shape) {
cursor[ident] = XCreateFontCursor(display, shape);
}
static void
init_cursors(void) {
static char zchar[1];
Pixmap pix;
XColor black, dummy;
create_cursor(CurNormal, XC_left_ptr);
create_cursor(CurNECorner, XC_top_right_corner);
create_cursor(CurNWCorner, XC_top_left_corner);
create_cursor(CurSECorner, XC_bottom_right_corner);
create_cursor(CurSWCorner, XC_bottom_left_corner);
create_cursor(CurMove, XC_fleur);
create_cursor(CurDHArrow, XC_sb_h_double_arrow);
create_cursor(CurDVArrow, XC_sb_v_double_arrow);
create_cursor(CurInput, XC_xterm);
create_cursor(CurSizing, XC_sizing);
create_cursor(CurIcon, XC_icon);
create_cursor(CurTCross, XC_tcross);
XAllocNamedColor(display, scr.colormap,
"black", &black, &dummy);
pix = XCreateBitmapFromData(
display, scr.root.xid,
zchar, 1, 1);
cursor[CurNone] = XCreatePixmapCursor(display,
pix, pix,
&black, &black,
0, 0);
XFreePixmap(display, pix);
}
/*
* There's no way to check accesses to destroyed windows, thus
* those cases are ignored (especially on UnmapNotifies).
* Other types of errors call Xlib's default error handler, which
* calls exit().
*/
ErrorCode ignored_xerrors[] = {
{ 0, BadWindow },
{ X_SetInputFocus, BadMatch },
{ X_PolyText8, BadDrawable },
{ X_PolyFillRectangle, BadDrawable },
{ X_PolySegment, BadDrawable },
{ X_ConfigureWindow, BadMatch },
{ X_GrabKey, BadAccess },
{ X_GetAtomName, BadAtom },
{ 0, }
};
void
regerror(char *err) {
fprint(2, "%s: %s\n", argv0, err);
}
static bool keep_screens = true;
void
init_screens(void) {
static int old_n, old_nscreens;
Rectangle *rects, *r;
View *v;
int i, j, n, m;
#ifdef notdef
d.x = Dx(scr.rect) - Dx(screen->r);
d.y = Dy(scr.rect) - Dy(screen->r);
for(v=view; v; v=v->next) {
v->r.max.x += d.x;
v->r.max.y += d.y;
}
#endif
/* Reallocate screens, zero any new ones. */
rects = xinerama_screens(&n);
r = malloc(n * sizeof *r);
/* Weed out subsumed/cloned screens */
for(m=-1; m < n; n=m) {
for(i=n-1, m=0; i >= 0; i--) {
for(j=0; j < n; j++)
if (i != j &&
eqrect(rects[i],
rect_intersection(rects[i], rects[j])))
break;
if (j == n)
r[m++] = rects[i];
}
for(i=m-1, j=0; i >= 0; i--)
rects[j++] = r[i];
}
free(r);
m = nscreens;
nscreens_new = keep_screens ? max(n, nscreens) : n;
for(v=view; v; v=v->next)
view_update_screens(v);
nscreens = nscreens_new;
screens = erealloc(screens, (nscreens + 1) * sizeof *screens);
screens[nscreens] = nil;
/* Reallocate buffers. */
freeimage(disp.ibuf);
freeimage(disp.ibuf32);
disp.ibuf = allocimage(Dx(scr.rect), Dy(scr.rect), scr.depth);
disp.ibuf32 = nil; /* Probably shouldn't do this until it's needed. */
if(render_visual)
disp.ibuf32 = allocimage(Dx(scr.rect), Dy(scr.rect), 32);
/* Resize and initialize screens. */
for(i=0; i < nscreens; i++) {
if(i >= m)
screens[i] = emallocz(sizeof *screens[i]);
screen = screens[i];
screen->idx = i;
screen->showing = i < n;
if(screen->showing)
screen->r = rects[i];
else
screen->r = rectsetorigin(screen->r, scr.rect.max);
if(i >= m)
for(v=view; v; v=v->next)
view_init(v, i);
def.snap = Dy(screen->r) / 63;
bar_init(screens[i]);
}
screen = screens[0];
if(selview)
view_update(selview);
if (old_n != n || old_nscreens != nscreens)
event("ScreenChange %d %d\n", n, nscreens);
old_n = n;
old_nscreens = nscreens;
}
void
wipe_screens(void) {
keep_screens = false;
init_screens();
keep_screens = true;
}
static void
cleanup(void) {
starting = -1;
while(client)
client_destroy(client);
ixp_server_close(&srv);
close(sleeperfd);
}
static void
cleanup_handler(int signal) {
sa.sa_handler = SIG_DFL;
sigaction(signal, &sa, nil);
srv.running = false;
switch(signal) {
case SIGTERM:
sa.sa_handler = cleanup_handler;
sigaction(SIGALRM, &sa, nil);
alarm(1);
default:
exitsignal = signal;
break;
case SIGALRM:
raise(SIGTERM);
case SIGINT:
break;
}
}
static void
init_traps(void) {
char buf[1];
int fd[2];
if(pipe(fd) != 0)
fatal("Can't pipe(): %r");
if(doublefork() == 0) {
close(fd[1]);
close(ConnectionNumber(display));
setsid();
display = XOpenDisplay(nil);
if(!display)
fatal("Can't open display");
/* Wait for parent to exit */
read(fd[0], buf, 1);
setfocus(pointerwin, RevertToPointerRoot);
XCloseDisplay(display);
exit(0);
}
close(fd[0]);
sleeperfd = fd[1];
sa.sa_flags = 0;
sa.sa_handler = cleanup_handler;
sigaction(SIGINT, &sa, nil);
sigaction(SIGTERM, &sa, nil);
sigaction(SIGQUIT, &sa, nil);
sigaction(SIGHUP, &sa, nil);
sigaction(SIGUSR1, &sa, nil);
sigaction(SIGUSR2, &sa, nil);
}
void
spawn_command(const char *cmd) {
char *shell, *p;
if(doublefork() == 0) {
if((p = pathsearch(getenv("WMII_CONFPATH"), cmd, true)))
cmd = p;
if(setsid() == -1)
fatal("Can't setsid: %r");
/* Run through the user's shell as a login shell */
shell = passwd->pw_shell;
if(shell[0] != '/')
fatal("Shell is not an absolute path: %s", shell);
p = smprint("-%s", strrchr(shell, '/') + 1);
close(0);
open("/dev/null", O_RDONLY);
execl(shell, p, "-c", cmd, nil);
fatal("Can't exec '%s': %r", cmd);
/* NOTREACHED */
}
}
static void
closedisplay(IxpConn *c) {
USED(c);
XCloseDisplay(display);
}
static void
printfcall(IxpFcall *f) {
Dprint(D9p, "%F\n", f);
}
int
main(int argc, char *argv[]) {
char **oargv;
char *wmiirc;
int i;
IXP_ASSERT_VERSION;
setlocale(LC_CTYPE, "");
fmtinstall('r', errfmt);
fmtinstall('a', afmt);
fmtinstall('C', Cfmt);
fmtinstall('E', fmtevent);
quotefmtinstall();
wmiirc = "wmiirc";
oargv = argv;
ARGBEGIN{
case 'a':
address = EARGF(usage());
break;
case 'r':
wmiirc = EARGF(usage());
break;
case 'v':
lprint(1, "%s", version);
exit(0);
case 'D':
if(waserror())
fatal("parsing debug flags: %r");
msg_debug(EARGF(usage()));
poperror();
break;
default:
usage();
break;
}ARGEND;
if(argc)
usage();
starting = true;
initdisplay();
traperrors(true);
selectinput(&scr.root, SubstructureRedirectMask);
if(traperrors(false))
fatal("another window manager is already running");
passwd = getpwuid(getuid());
user = estrdup(passwd->pw_name);
gethostname(hostname, sizeof(hostname) - 1);
init_environment();
fmtinstall('F', Ffmt);
ixp_printfcall = printfcall;
sock = ixp_announce(address);
if(sock < 0)
fatal("Can't create socket %q: %r", address);
closeexec(ConnectionNumber(display));
closeexec(sock);
if(wmiirc[0])
spawn_command(wmiirc);
init_traps();
init_cursors();
update_keys();
ewmh_init();
xext_init();
event_debug = debug_event;
srv.preselect = event_preselect;
ixp_listen(&srv, sock, &p9srv, ixp_serve9conn, nil);
ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, closedisplay);
def.border = 1;
def.colmode = Colstack;
def.font = loadfont(FONT);
def.incmode = ISqueeze;
def.mod = Mod1Mask;
loadcolor(&def.focuscolor, FOCUSCOLORS, nil);
loadcolor(&def.normcolor, NORMCOLORS, nil);
disp.sel = pointerscreen();
init_screens();
root_init();
disp.focus = nil;
setfocus(screen->barwin, RevertToParent);
view_select("1");
scan_wins();
starting = false;
view_update_all();
ewmh_updateviews();
event("FocusTag %s\n", selview->name);
i = ixp_serverloop(&srv);
if(i)
fprint(2, "%s: error: %r\n", argv0);
else
event("Quit");
cleanup();
if(exitsignal)
raise(exitsignal);
if(execstr) {
char *toks[32];
int n;
n = unquote(strdup(execstr), toks, nelem(toks)-1);
toks[n] = nil;
execvp(toks[0], toks);
fprint(2, "%s: failed to exec %q: %r\n", argv0, execstr);
execvp(argv0, oargv);
fatal("failed to exec myself");
}
return i;
}
|
Added cmd/wmii/message.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 |
/* Copyright ©2006-2014 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <ctype.h>
#include "fns.h"
static char* msg_grow(View*, IxpMsg*);
static char* msg_nudge(View*, IxpMsg*);
static char* msg_selectframe(Area*, IxpMsg*, int);
static char* msg_sendframe(Frame*, int, bool);
#define DIR(s) (\
s == LUP ? North : \
s == LDOWN ? South : \
s == LLEFT ? West : \
s == LRIGHT ? East : \
(error(Ebadvalue), 0))
static char
Ebadcmd[] = "bad command",
Ebadvalue[] = "bad value",
Ebadusage[] = "bad usage";
/* Edit |sort Edit |sed 's/"([^"]+)"/L\1/g' | tr 'a-z' 'A-Z' */
enum {
LALLOW,
LBAR,
LBORDER,
LCLIENT,
LCOLMODE,
LCOLORS,
LDEBUG,
LDOWN,
LEXEC,
LFLOATING,
LFOCUSCOLORS,
LFONT,
LFONTPAD,
LFULLSCREEN,
LGRABMOD,
LGROUP,
LGROW,
LINCMODE,
LKILL,
LLABEL,
LLEFT,
LNORMCOLORS,
LNUDGE,
LOFF,
LON,
LQUIT,
LRIGHT,
LSELCOLORS,
LSELECT,
LSEND,
LSLAY,
LSPAWN,
LSWAP,
LTAGS,
LTOGGLE,
LUP,
LURGENT,
LVIEW,
LWIPESCREENS,
LTILDE,
};
char *symtab[] = {
"allow",
"bar",
"border",
"client",
"colmode",
"colors",
"debug",
"down",
"exec",
"floating",
"focuscolors",
"font",
"fontpad",
"fullscreen",
"grabmod",
"group",
"grow",
"incmode",
"kill",
"label",
"left",
"normcolors",
"nudge",
"off",
"on",
"quit",
"right",
"selcolors",
"select",
"send",
"slay",
"spawn",
"swap",
"tags",
"toggle",
"up",
"urgent",
"view",
"wipescreens",
"~",
};
static char* barpostab[] = {
"bottom", "top",
};
char* debugtab[] = {
"9p",
"dnd",
"event",
"events",
"ewmh",
"focus",
"generic",
"stack",
nil
};
static char* permtab[] = {
"activate", nil
};
static char* incmodetab[] = {
"ignore", "show", "squeeze",
};
static char* floatingtab[] = {
"never", "off", "on", "always"
};
static char* toggletab[] = {
"off", "on", "toggle",
};
/* Edit ,y/^[a-zA-Z].*\n.* {\n/d
* Edit s/^([a-zA-Z].*)\n(.*) {\n/\1 \2;\n/
* Edit ,x/^static.*\n/d
*/
static int
_bsearch(char *from, char **tab, int ntab) {
int i, n, m, cmp;
char *to, *end;
Rune r;
if(from == nil)
return -1;
end = buffer + sizeof buffer - UTFmax - 1;
for(to=buffer; *from && to < end;) {
from += chartorune(&r, from);
if(r != 0x80) {
r = tolowerrune(r);
to += runetochar(to, &r);
}
}
*to = '\0';
to = buffer;
n = ntab;
i = 0;
while(n) {
m = n/2;
cmp = strcmp(to, tab[i+m]);
if(cmp == 0)
return i+m;
if(cmp < 0 || m == 0)
n = m;
else {
i += m;
n = n-m;
}
}
return -1;
}
static int
_lsearch(char *from, char **tab, int ntab) {
int i;
if(from != nil)
for(i=0; i < ntab; i++)
if(!strcmp(from, tab[i]))
return i;
error(Ebadvalue);
return 0;
}
static int
getsym(char *s) {
return _bsearch(s, symtab, nelem(symtab));
}
static void
setdef(int *ptr, char *s, char *tab[], int ntab) {
int i;
i = _bsearch(s, tab, ntab);
if(i < 0)
error(Ebadvalue);
*ptr = i;
}
static int
gettoggle(char *s) {
return _lsearch(s, toggletab, nelem(toggletab));
}
static int
getdirection(IxpMsg *m) {
int i;
switch(i = getsym(msg_getword(m, 0))) {
case LLEFT:
case LRIGHT:
case LUP:
case LDOWN:
return i;
}
error(Ebadusage);
return -1;
}
static ulong
msg_getulong(const char *s) {
ulong l;
if(!(s && getulong(s, &l)))
error(Ebadvalue);
return l;
}
static long
msg_getlong(const char *s) {
long l;
if(!(s && getlong(s, &l)))
error(Ebadvalue);
return l;
}
void
msg_eatrunes(IxpMsg *m, int (*p)(Rune), int val) {
Rune r;
int n;
while(m->pos < m->end) {
n = chartorune(&r, m->pos);
if(p(r) != val)
break;
m->pos += n;
}
if(m->pos > m->end)
m->pos = m->end;
}
char*
msg_getword(IxpMsg *m, char *errmsg) {
char *ret;
Rune r;
int n;
msg_eatrunes(m, isspacerune, true);
ret = m->pos;
msg_eatrunes(m, isspacerune, false);
n = chartorune(&r, m->pos);
*m->pos = '\0';
m->pos += n;
msg_eatrunes(m, isspacerune, true);
/* Filter out comments. */
if(*ret == '#') {
*ret = '\0';
m->pos = m->end;
}
if(*ret == '\\')
if(ret[1] == '\\' || ret[1] == '#')
ret++;
if(*ret == '\0')
ret = nil;
if(ret == nil && errmsg)
error(errmsg);
return ret;
}
typedef struct Mask Mask;
struct Mask {
long* mask;
char** table;
};
static int
Mfmt(Fmt *f) {
Mask m;
m = va_arg(f->args, Mask);
return unmask(f, *m.mask, m.table, '+');
}
char*
mask(char **s, int *add, int *old) {
static char seps[] = "+-^";
char *p, *q;
again:
p = *s;
if(*old == '\0')
return nil;
*add = *old;
if(*p == '/') {
/* Check for regex. */
if(!(q = strchr(p+1, '/')))
goto fail;
if(*q++ != '/' || !memchr(seps, (*old=*q), sizeof seps))
goto fail;
}
else {
for(q=p; (*old=*q) && !strchr(seps, *q);)
q++;
if(memchr(p, '/', q-p))
goto fail;
}
*q++ = '\0';
*s = q;
if(p + 1 == q)
goto again;
return p;
fail:
while((*old=*q) && !strchr(seps, *q))
q++;
goto again;
}
static void
setmask(Mask m, char *s) {
char *opt;
int add, old, i, n;
long newmask;
if(s == nil)
s = "";
for(n=0; m.table[n]; n++)
;
newmask = memchr("+-^", s[0], 3) ? *m.mask : 0L;
old = '+';
while((opt = mask(&s, &add, &old))) {
i = _bsearch(opt, m.table, n);
if(i == -1)
error(Ebadvalue);
else if(add = '^')
newmask ^= 1<<i;
else if(add == '+')
newmask |= 1<<i;
else if(add == '-')
newmask &= ~(1<<i);
}
*m.mask = newmask;
}
void
msg_debug(char *s) {
setmask((Mask){&debugflag, debugtab}, s);
}
static Client*
strclient(View *v, char *s) {
Client *c;
/*
* sel
* 0x<window xid>
*/
if(s && !strcmp(s, "sel"))
c = view_selclient(v);
else
c = win2client(msg_getulong(s));
if(c == nil)
error(Ebadvalue);
return c;
}
Area*
strarea(View *v, ulong scrn, const char *area) {
Area *a;
const char *screen;
char *p;
long i;
/*
* sel
* ~
* <column number>
*/
if(area == nil)
error(Ebadvalue);
if((p = strchr(area, ':'))) {
/* <screen>:<area> */
*p++ = '\0';
screen = area;
area = p;
if(!strcmp(screen, "sel"))
scrn = v->selscreen;
else
scrn = msg_getulong(screen);
}
else if(!strcmp(area, "sel"))
return v->sel;
if(!strcmp(area, "sel")) {
if(scrn != v->selscreen)
error(Ebadvalue);
return v->sel;
}
if(!strcmp(area, "~"))
return v->floating;
if(scrn < 0)
error(Ebadvalue);
i = msg_getlong(area);
if(i == 0)
error(Ebadvalue);
if(i > 0) {
for(a = v->areas[scrn]; a; a = a->next)
if(i-- == 1) break;
}
else {
/* FIXME: Switch to circularly linked list. */
for(a = v->areas[scrn]; a->next; a = a->next)
;
for(; a; a = a->prev)
if(++i == 0) break;
}
if(a == nil)
error(Ebadvalue);
return a;
}
static Frame*
getframe(View *v, int scrn, IxpMsg *m) {
Frame *f;
Area *a;
char *s;
ulong l;
s = msg_getword(m, Ebadvalue);
if(!strcmp(s, "client"))
f = client_viewframe(strclient(v, msg_getword(m, Ebadvalue)),
v);
else {
/* XXX: Multihead */
a = strarea(v, scrn, s);
s = msg_getword(m, Ebadvalue);
f = nil;
if(!strcmp(s, "sel"))
f = a->sel;
else {
l = msg_getulong(s);
for(f=a->frame; f; f=f->anext)
if(--l == 0) break;
}
}
if(f == nil)
error(Ebadvalue);
return f;
}
char*
readctl_bar(Bar *b) {
bufclear();
bufprint("colors %s\n", b->colors.colstr);
bufprint("label %s\n", b->text);
return buffer;
}
char*
message_bar(Bar *b, IxpMsg *m) {
switch(getsym(msg_getword(m, nil))) {
case LCOLORS:
msg_parsecolors(m, &b->colors);
break;
case LLABEL:
utflcpy(b->text, (char*)m->pos, sizeof b->text);
break;
default:
error(Ebadvalue);
}
bar_draw(b->screen);
return nil;
}
char*
readctl_client(Client *c) {
bufclear();
bufprint("%#C\n", c);
bufprint("allow %M\n", (Mask){&c->permission, permtab});
bufprint("floating %s\n", floatingtab[c->floating + 1]);
if(c->fullscreen >= 0)
bufprint("fullscreen %d\n", c->fullscreen);
else
bufprint("fullscreen off\n");
bufprint("group %#ulx\n", c->group ? c->group->leader : 0);
if(c->pid)
bufprint("pid %d\n", c->pid);
bufprint("tags %s\n", c->tags);
bufprint("urgent %s\n", TOGGLE(c->urgent));
return buffer;
}
char*
message_client(Client *c, IxpMsg *m) {
char *s;
long l;
s = msg_getword(m, Ebadcmd);
/*
* Toggle ::= on
* | off
* | toggle
* | <screen>
* floating <toggle>
* fullscreen <toggle>
* kill
* slay
* tags <tags>
* urgent <toggle>
*/
switch(getsym(s)) {
case LALLOW:
setmask((Mask){&c->permission, permtab}, msg_getword(m, 0));
break;
case LFLOATING:
c->floating = -1 + _lsearch(msg_getword(m, Ebadvalue), floatingtab, nelem(floatingtab));
break;
case LFULLSCREEN:
s = msg_getword(m, Ebadvalue);
if(getlong(s, &l))
fullscreen(c, On, l);
else
fullscreen(c, gettoggle(s), -1);
break;
case LGROUP:
group_remove(c);
c->w.hints->group = msg_getulong(msg_getword(m, Ebadvalue));
if(c->w.hints->group)
group_init(c);
break;
case LKILL:
client_kill(c, true);
break;
case LSLAY:
client_kill(c, false);
break;
case LTAGS:
client_applytags(c, m->pos);
break;
case LURGENT:
client_seturgent(c, gettoggle(msg_getword(m, Ebadvalue)), UrgManager);
break;
default:
error(Ebadcmd);
}
return nil;
}
char*
message_root(void *p, IxpMsg *m) {
Font *fn;
char *s, *ret;
ulong n;
int i;
USED(p);
ret = nil;
s = msg_getword(m, 0);
if(s == nil)
return nil;
if(!strcmp(s, "backtrace")) {
backtrace(m->pos);
return nil;
}
if(!strcmp(s, "xinerama")) {
setenv("XINERAMA_SCREENS", m->pos, 1);
init_screens();
return nil;
}
switch(getsym(s)) {
case LBAR: /* bar on? <"top" | "bottom"> */
s = msg_getword(m, Ebadvalue);
if(!strcmp(s, "on"))
s = msg_getword(m, Ebadvalue);
setdef(&screen->barpos, s, barpostab, nelem(barpostab));
view_update(selview);
break;
case LBORDER:
def.border = msg_getulong(msg_getword(m, 0));;
view_update(selview);
break;
case LCOLMODE:
setdef(&def.colmode, msg_getword(m, 0), modes, Collast);
break;
case LDEBUG:
msg_debug(msg_getword(m, 0));
break;
case LEXEC:
execstr = strdup(m->pos);
srv.running = 0;
break;
case LSPAWN:
spawn_command(m->pos);
break;
case LFOCUSCOLORS:
msg_parsecolors(m, &def.focuscolor);
goto updatecolors;
case LFONT:
fn = loadfont(m->pos);
if(fn) {
freefont(def.font);
def.font = fn;
for(n=0; n < nscreens; n++)
bar_resize(screens[n]);
}else
ret = "can't load font";
view_update(selview);
break;
case LFONTPAD:
if(!getint(msg_getword(m, 0), &def.font->pad.min.x) ||
!getint(msg_getword(m, 0), &def.font->pad.max.x) ||
!getint(msg_getword(m, 0), &def.font->pad.max.y) ||
!getint(msg_getword(m, 0), &def.font->pad.min.y))
ret = "invalid rectangle";
else {
for(n=0; n < nscreens; n++)
bar_resize(screens[n]);
view_update(selview);
}
break;
case LGRABMOD:
s = msg_getword(m, Ebadvalue);
if(!parsekey(s, &i, nil) || i == 0)
return Ebadvalue;
def.mod = i;
break;
case LINCMODE:
setdef(&def.incmode, msg_getword(m, 0), incmodetab, nelem(incmodetab));
view_update(selview);
break;
case LNORMCOLORS:
msg_parsecolors(m, &def.normcolor);
updatecolors:
for(Client *c=client; c; c=c->next)
client_reparent(c);
view_update(selview);
break;
case LSELCOLORS:
warning("selcolors have been removed");
return Ebadcmd;
case LVIEW:
view_select(m->pos);
break;
case LWIPESCREENS:
wipe_screens();
break;
case LQUIT:
srv.running = 0;
break;
default:
return Ebadcmd;
}
return ret;
}
char*
readctl_root(void) {
fmtinstall('M', Mfmt);
bufclear();
bufprint("bar on %s\n", barpostab[screen->barpos]);
bufprint("border %d\n", def.border);
bufprint("colmode %s\n", modes[def.colmode]);
if(debugflag)
bufprint("debug %M\n", (Mask){&debugflag, debugtab});
if(debugfile)
bufprint("debugfile %M", (Mask){&debugfile, debugtab});
bufprint("focuscolors %s\n", def.focuscolor.colstr);
bufprint("font %s\n", def.font->name);
bufprint("fontpad %d %d %d %d\n", def.font->pad.min.x, def.font->pad.max.x,
def.font->pad.max.y, def.font->pad.min.y);
bufprint("grabmod %s\n", (Mask){&def.mod, modkey_names});
bufprint("incmode %s\n", incmodetab[def.incmode]);
bufprint("normcolors %s\n", def.normcolor.colstr);
bufprint("view %s\n", selview->name);
return buffer;
}
char*
message_view(View *v, IxpMsg *m) {
Area *a;
char *s;
s = msg_getword(m, 0);
if(s == nil)
return nil;
/*
* area ::= ~
* | <column number>
* | sel
* direction ::= left
* | right
* | up
* | down
* # This *should* be identical to <frame>
* place ::= <column number>
* #| ~ # This should be, but isn't.
* | <direction>
* | toggle
* colmode ::= default
* | stack
* | normal
* column ::= sel
* | <column number>
* frame ::= up
* | down
* | left
* | right
* | toggle
* | client <window xid>
* | sel
* | ~
* | <column> <frame number>
* | <column>
* amount ::=
* | <number>
* | <number>px
*
* colmode <area> <colmode>
* select <area>
* send <frame> <place>
* swap <frame> <place>
* grow <thing> <direction> <amount>
* nudge <thing> <direction> <amount>
* select <ordframe>
*/
switch(getsym(s)) {
case LCOLMODE:
s = msg_getword(m, Ebadvalue);
a = strarea(v, screen->idx, s);
s = msg_getword(m, Ebadvalue);
if(!column_setmode(a, s))
return Ebadvalue;
column_arrange(a, false);
view_restack(v);
view_update(v);
return nil;
case LGROW:
return msg_grow(v, m);
case LNUDGE:
return msg_nudge(v, m);
case LSELECT:
return msg_selectarea(v->sel, m);
case LSEND:
return msg_sendclient(v, m, false);
case LSWAP:
return msg_sendclient(v, m, true);
default:
return Ebadcmd;
}
/* not reached */
}
char*
readctl_view(View *v) {
Area *a;
int s;
bufclear();
bufprint("%s\n", v->name);
bufprint("urgent %s\n", TOGGLE(v->urgent));
/* select <area>[ <frame>] */
bufprint("select %a", v->sel);
if(v->sel->sel)
bufprint(" %d", frame_idx(v->sel->sel));
bufprint("\n");
/* select client <client> */
if(v->sel->sel)
bufprint("select client %#C\n", v->sel->sel->client);
foreach_area(v, s, a)
bufprint("colmode %a %s\n", a, column_getmode(a));
return buffer;
}
static void
getamt(IxpMsg *m, Point *amt) {
char *s, *p;
long l;
s = msg_getword(m, 0);
if(s) {
p = strend(s, 2);
if(!strcmp(p, "px")) {
*p = '\0';
amt->x = 1;
amt->y = 1;
}
l = msg_getlong(s);
amt->x *= l;
amt->y *= l;
}
}
static char*
msg_grow(View *v, IxpMsg *m) {
Client *c;
Frame *f;
Rectangle h, r;
Point amount;
int dir;
f = getframe(v, screen->idx, m);
c = f->client;
h = c->w.hints->aspect;
dir = getdirection(m);
amount.x = Dy(f->titlebar);
amount.y = Dy(f->titlebar);
if(amount.x < c->w.hints->inc.x)
amount.x = c->w.hints->inc.x;
if(amount.y < c->w.hints->inc.y)
amount.y = c->w.hints->inc.y;
getamt(m, &amount);
if (dir == LLEFT || dir == LRIGHT)
amount.y = h.min.x ? amount.x * h.min.y / h.min.x : 0;
else
amount.x = h.min.y ? amount.y * h.min.x / h.min.y : 0;
if(f->area->floating)
r = f->r;
else
r = f->colr;
if (dir == LLEFT || dir == LUP)
r.min = subpt(r.min, amount);
else if (dir == LRIGHT || dir == LDOWN)
r.max = addpt(r.max, amount);
if(f->area->floating)
float_resizeframe(f, r);
else
column_resizeframe(f, r);
return nil;
}
static char*
msg_nudge(View *v, IxpMsg *m) {
Frame *f;
Rectangle r;
Point amount;
int dir;
f = getframe(v, screen->idx, m);
dir = getdirection(m);
amount.x = Dy(f->titlebar);
amount.y = Dy(f->titlebar);
getamt(m, &amount);
if(f->area->floating)
r = f->r;
else
r = f->colr;
switch(dir) {
case LLEFT: r = rectaddpt(r, Pt(-amount.x, 0)); break;
case LRIGHT: r = rectaddpt(r, Pt( amount.x, 0)); break;
case LUP: r = rectaddpt(r, Pt(0, -amount.y)); break;
case LDOWN: r = rectaddpt(r, Pt(0, amount.y)); break;
default: abort();
}
if(f->area->floating)
float_resizeframe(f, r);
else
column_resizeframe(f, r);
return nil;
}
void
msg_parsecolors(IxpMsg *m, CTuple *col) {
CTuple tpl;
char n;
n = loadcolor(&tpl, m->pos, m->end);
m->pos += n;
if(n == 0 || msg_getword(m, nil))
error("bad color string");
*col = tpl;
}
char*
msg_selectarea(Area *a, IxpMsg *m) {
Frame *f;
Area *ap;
View *v;
char *s;
ulong i;
int sym;
v = a->view;
s = msg_getword(m, Ebadvalue);
sym = getsym(s);
switch(sym) {
case LTOGGLE:
if(!a->floating)
ap = v->floating;
else if(v->revert && v->revert != a)
ap = v->revert;
else
ap = v->firstarea;
break;
case LLEFT:
case LRIGHT:
case LUP:
case LDOWN:
case LCLIENT:
return msg_selectframe(a, m, sym);
case LTILDE:
ap = v->floating;
break;
default:
/* XXX: Multihead */
ap = strarea(v, a->screen, s);
if(ap->floating)
return Ebadvalue;
if((s = msg_getword(m, 0))) {
i = msg_getulong(s);
for(f = ap->frame; f; f = f->anext)
if(--i == 0) break;
if(i != 0)
return Ebadvalue;
frame_focus(f);
return nil;
}
}
area_focus(ap);
return nil;
}
static char*
msg_selectframe(Area *a, IxpMsg *m, int sym) {
Client *c;
Frame *f, *fp;
char *s;
bool stack;
ulong i, dy;
f = a->sel;
fp = f;
stack = false;
if(sym == LUP || sym == LDOWN)
if((s = msg_getword(m, 0)))
if(!strcmp(s, "stack"))
stack = true;
else
return Ebadvalue;
if(sym == LCLIENT) {
s = msg_getword(m, Ebadvalue);
i = msg_getulong(s);
c = win2client(i);
if(c == nil)
return Ebadvalue;
f = client_viewframe(c, a->view);
if(!f)
return Ebadvalue;
}
else if(!find(&a, &f, DIR(sym), true, stack))
return Ebadvalue;
area_focus(a);
if(f != nil) {
/* XXX */
if(fp && fp->area == a)
if(f->collapsed && !f->area->floating && f->area->mode == Coldefault) {
dy = Dy(f->colr);
f->colr.max.y = f->colr.min.y + Dy(fp->colr);
fp->colr.max.y = fp->colr.min.y + dy;
column_arrange(a, false);
}
frame_focus(f);
frame_restack(f, nil);
if(f->view == selview)
view_restack(a->view);
}
return nil;
}
static char*
sendarea(Frame *f, Area *to, bool swap) {
Client *c;
c = f->client;
if(!to)
return Ebadvalue;
if(!swap)
area_moveto(to, f);
else if(to->sel)
frame_swap(f, to->sel);
else
return Ebadvalue;
frame_focus(client_viewframe(c, f->view));
/* view_arrange(v); */
view_update_all();
return nil;
}
char*
msg_sendclient(View *v, IxpMsg *m, bool swap) {
Area *to, *a;
Frame *f, *ff;
Client *c;
char *s;
int sym;
c = strclient(v, msg_getword(m, 0));
f = client_viewframe(c, v);
if(f == nil)
return Ebadvalue;
a = f->area;
to = nil;
s = msg_getword(m, Ebadvalue);
sym = getsym(s);
/* FIXME: Should use a helper function. */
switch(sym) {
case LUP:
case LDOWN:
return msg_sendframe(f, sym, swap);
case LLEFT:
if(a->floating)
return Ebadvalue;
to = a->prev;
break;
case LRIGHT:
if(a->floating)
return Ebadvalue;
to = a->next;
break;
case LTOGGLE:
if(!a->floating)
to = v->floating;
else if(f->column)
to = view_findarea(v, f->screen, f->column, true);
else
to = view_findarea(v, v->selscreen, v->selcol, true);
break;
case LTILDE:
if(a->floating)
return Ebadvalue;
to = v->floating;
break;
default:
to = strarea(v, v->selscreen, s);
// to = view_findarea(v, scrn, i, true);
break;
}
if(!to && !swap) {
/* XXX: Multihead - clean this up, move elsewhere. */
if(!f->anext && f == f->area->frame) {
ff = f;
to = a;
if(!find(&to, &ff, DIR(sym), false, false))
return Ebadvalue;
}
else {
to = (sym == LLEFT) ? nil : a;
to = column_new(v, to, a->screen, 0);
}
}
return sendarea(f, to, swap);
}
static char*
msg_sendframe(Frame *f, int sym, bool swap) {
Client *c;
Area *a;
Frame *fp;
SET(fp);
c = f->client;
a = f->area;
fp = f;
if(!find(&a, &fp, DIR(sym), false, false))
return Ebadvalue;
if(a != f->area)
return sendarea(f, a, swap);
switch(sym) {
case LUP:
fp = f->aprev;
if(!fp)
return Ebadvalue;
if(!swap)
fp = fp->aprev;
break;
case LDOWN:
fp = f->anext;
if(!fp)
return Ebadvalue;
break;
default:
die("can't get here");
}
if(swap)
frame_swap(f, fp);
else {
frame_remove(f);
frame_insert(f, fp);
}
/* view_arrange(f->view); */
frame_focus(client_viewframe(c, f->view));
view_update_all();
return nil;
}
void
warning(const char *fmt, ...) {
va_list ap;
char *s;
va_start(ap, fmt);
s = vsmprint(fmt, ap);
va_end(ap);
event("Warning %s\n", s);
fprint(2, "%s: warning: %s\n", argv0, s);
free(s);
}
|
Added cmd/wmii/mouse.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
/* Here be dragons. */
enum {
ButtonMask =
ButtonPressMask | ButtonReleaseMask,
MouseMask =
ButtonMask | PointerMotionMask
};
static Cursor
quad_cursor(Align align) {
switch(align) {
case NEast: return cursor[CurNECorner];
case NWest: return cursor[CurNWCorner];
case SEast: return cursor[CurSECorner];
case SWest: return cursor[CurSWCorner];
case South:
case North: return cursor[CurDVArrow];
case East:
case West: return cursor[CurDHArrow];
default: return cursor[CurMove];
}
}
static bool
cwin_expose(Window *w, void *aux, XExposeEvent *e) {
fill(w, rectsubpt(w->r, w->r.min), &def.focuscolor.bg);
fill(w, w->r, &def.focuscolor.bg);
return false;
}
static Handlers chandler = {
.expose = cwin_expose,
};
Window*
constraintwin(Rectangle r) {
Window *w;
w = createwindow(&scr.root, r, 0, InputOnly, nil, 0);
if(0) {
Window *w2;
w2 = createwindow(&scr.root, r, 0, InputOutput, nil, 0);
selectinput(w2, ExposureMask);
w->aux = w2;
setborder(w2, 1, &def.focuscolor.border);
sethandler(w2, &chandler);
mapwin(w2);
raisewin(w2);
}
mapwin(w);
return w;
}
void
destroyconstraintwin(Window *w) {
if(w->aux)
destroywindow(w->aux);
destroywindow(w);
}
static Window*
gethsep(Rectangle r) {
Window *w;
WinAttr wa;
wa.background_pixel = pixelvalue(&scr.root, &def.normcolor.border);
w = createwindow(&scr.root, r, scr.depth, InputOutput, &wa, CWBackPixel);
mapwin(w);
raisewin(w);
return w;
}
static void
rect_morph(Rectangle *r, Point d, Align *mask) {
int n;
if(*mask & North)
r->min.y += d.y;
if(*mask & West)
r->min.x += d.x;
if(*mask & South)
r->max.y += d.y;
if(*mask & East)
r->max.x += d.x;
if(r->min.x > r->max.x) {
n = r->min.x;
r->min.x = r->max.x;
r->max.x = n;
*mask ^= East|West;
}
if(r->min.y > r->max.y) {
n = r->min.y;
r->min.y = r->max.y;
r->max.y = n;
*mask ^= North|South;
}
}
/* Yes, yes, macros are evil. So are patterns. */
#define frob(x, y) \
const Rectangle *rp; \
int i, tx; \
\
for(i=0; i < nrect; i++) { \
rp = &rects[i]; \
if((rp->min.y <= r->max.y) && (rp->max.y >= r->min.y)) { \
tx = rp->min.x; \
if(abs(tx - x) <= abs(dx)) \
dx = tx - x; \
\
tx = rp->max.x; \
if(abs(tx - x) <= abs(dx)) \
dx = tx - x; \
} \
} \
return dx \
static int
snap_hline(const Rectangle *rects, int nrect, int dx, const Rectangle *r, int y) {
frob(y, x);
}
static int
snap_vline(const Rectangle *rects, int nrect, int dx, const Rectangle *r, int x) {
frob(x, y);
}
#undef frob
/* Returns a gravity for increment handling. It's normally the
* opposite of the mask (the directions that we're resizing in),
* unless a snap occurs, in which case, it's the direction of the
* snap.
*/
Align
snap_rect(const Rectangle *rects, int num, Rectangle *r, Align *mask, int snap) {
Align ret;
Point d;
d.x = snap+1;
d.y = snap+1;
if(*mask&North)
d.y = snap_hline(rects, num, d.y, r, r->min.y);
if(*mask&South)
d.y = snap_hline(rects, num, d.y, r, r->max.y);
if(*mask&East)
d.x = snap_vline(rects, num, d.x, r, r->max.x);
if(*mask&West)
d.x = snap_vline(rects, num, d.x, r, r->min.x);
ret = Center;
if(abs(d.x) <= snap)
ret ^= East|West;
else
d.x = 0;
if(abs(d.y) <= snap)
ret ^= North|South;
else
d.y = 0;
rect_morph(r, d, mask);
return ret ^ *mask;
}
int
readmouse(Point *p, uint *button) {
XEvent ev;
for(;;) {
XMaskEvent(display, MouseMask|ExposureMask|PropertyChangeMask, &ev);
debug_event(&ev);
switch(ev.type) {
case Expose:
case NoExpose:
case PropertyNotify:
event_dispatch(&ev);
default:
Dprint(DEvent, "readmouse(): ignored: %E\n", &ev);
continue;
case ButtonPress:
case ButtonRelease:
*button = ev.xbutton.button;
case MotionNotify:
p->x = ev.xmotion.x_root;
p->y = ev.xmotion.y_root;
if(p->x == scr.rect.max.x - 1)
p->x = scr.rect.max.x;
if(p->y == scr.rect.max.y - 1)
p->y = scr.rect.max.y;
break;
}
return ev.type;
}
}
bool
readmotion(Point *p) {
uint button;
for(;;)
switch(readmouse(p, &button)) {
case MotionNotify:
return true;
case ButtonRelease:
return false;
}
}
static void
mouse_resizecolframe(Frame *f, Align align) {
Window *cwin, *hwin = nil;
Divide *d;
View *v;
Area *a;
Rectangle r;
Point pt, min;
int s;
assert((align&(East|West)) != (East|West));
assert((align&(North|South)) != (North|South));
f->collapsed = false;
v = selview;
d = divs;
SET(a);
foreach_column(v, s, a) {
if(a == f->area)
break;
d = d->next;
}
if(align & East)
d = d->next;
min.x = column_minwidth();
min.y = /*frame_delta_h() +*/ labelh(def.font);
/* Set the limits of where this box may be dragged. */
#define frob(pred, f, aprev, rmin, rmax, plus, minus, xy, use_screen) BLOCK( \
if(pred) { \
r.rmin.xy = f->aprev->r.rmin.xy plus min.xy; \
r.rmax.xy = f->r.rmax.xy minus min.xy; \
}else if(use_screen) { \
r.rmin.xy = v->r[f->screen].rmin.xy plus 1; \
r.rmax.xy = a->r.rmax.xy minus min.xy; \
}else { \
r.rmin.xy = a->r.rmin.xy; \
r.rmax.xy = r.rmin.xy plus 1; \
})
r = f->r;
if(align & North)
frob(f->aprev, f, aprev, min, max, +, -, y, false);
else if(align & South)
frob(f->anext, f, anext, max, min, -, +, y, false);
if(align & West)
frob(a->prev, a, prev, min, max, +, -, x, true);
else if(align & East)
frob(a->next, a, next, max, min, -, +, x, true);
#undef frob
cwin = constraintwin(r);
r = f->r;
if(align & North)
r.min.y--;
else if(align & South)
r.min.y = r.max.y - 1;
r.max.y = r.min.y + 2;
if(align & (North|South))
hwin = gethsep(r);
if(!grabpointer(&scr.root, cwin, cursor[CurSizing], MouseMask))
goto done;
pt.x = (align & West ? f->r.min.x : f->r.max.x);
pt.y = (align & North ? f->r.min.y : f->r.max.y);
warppointer(pt);
while(readmotion(&pt)) {
if(align & West)
r.min.x = pt.x;
else if(align & East)
r.max.x = pt.x;
if(align & South)
r.min.y = pt.y;
else if(align & North)
r.min.y = pt.y - 1;
r.max.y = r.min.y+2;
if(align & (East|West))
div_set(d, pt.x);
if(hwin)
reshapewin(hwin, r);
}
r = f->r;
if(align & West)
r.min.x = pt.x;
else if(align & East)
r.max.x = pt.x;
if(align & North)
r.min.y = pt.y;
else if(align & South)
r.max.y = pt.y;
column_resizeframe(f, r);
/* XXX: Magic number... */
if(align & West)
pt.x = f->r.min.x + 4;
else if(align & East)
pt.x = f->r.max.x - 4;
if(align & North)
pt.y = f->r.min.y + 4;
else if(align & South)
pt.y = f->r.max.y - 4;
warppointer(pt);
done:
ungrabpointer();
destroyconstraintwin(cwin);
if (hwin)
destroywindow(hwin);
}
void
mouse_resizecol(Divide *d) {
Window *cwin;
View *v;
Rectangle r;
Point pt;
int minw, scrn;
v = selview;
scrn = (d->left ? d->left : d->right)->screen;
pt = querypointer(&scr.root);
minw = column_minwidth();
r.min.x = d->left ? d->left->r.min.x + minw : v->r[scrn].min.x;
r.max.x = d->right ? d->right->r.max.x - minw : v->r[scrn].max.x;
r.min.y = pt.y;
r.max.y = pt.y+1;
cwin = constraintwin(r);
if(!grabpointer(&scr.root, cwin, cursor[CurNone], MouseMask))
goto done;
while(readmotion(&pt))
div_set(d, pt.x);
if(d->left)
d->left->r.max.x = pt.x;
else
v->pad[scrn].min.x = pt.x - v->r[scrn].min.x;
if(d->right)
d->right->r.min.x = pt.x;
else
v->pad[scrn].max.x = pt.x - v->r[scrn].max.x;
view_arrange(v);
done:
ungrabpointer();
destroyconstraintwin(cwin);
}
void
mouse_resize(Client *c, Align align, bool grabmod) {
Rectangle *rects;
Rectangle frect, origin;
Align grav;
Cursor cur;
Point d, pt, hr;
float rx, ry, hrx, hry;
uint nrect;
Frame *f;
f = c->sel;
if(f->client->fullscreen >= 0) {
ungrabpointer();
return;
}
if(!f->area->floating) {
if(align==Center)
mouse_movegrabbox(c, grabmod);
else
mouse_resizecolframe(f, align);
return;
}
cur = quad_cursor(align);
if(align == Center)
cur = cursor[CurSizing];
if(!grabpointer(c->framewin, nil, cur, MouseMask))
return;
origin = f->r;
frect = f->r;
rects = view_rects(f->area->view, &nrect, c->frame);
pt = querypointer(c->framewin);
rx = (float)pt.x / Dx(frect);
ry = (float)pt.y / Dy(frect);
pt = querypointer(&scr.root);
SET(hrx);
SET(hry);
if(align != Center) {
hr = subpt(frect.max, frect.min);
hr = divpt(hr, Pt(2, 2));
d = hr;
if(align&North) d.y -= hr.y;
if(align&South) d.y += hr.y;
if(align&East) d.x += hr.x;
if(align&West) d.x -= hr.x;
pt = addpt(d, f->r.min);
warppointer(pt);
}else {
hrx = (double)(Dx(scr.rect)
+ Dx(frect)
- 2 * labelh(def.font))
/ Dx(scr.rect);
hry = (double)(Dy(scr.rect)
+ Dy(frect)
- 3 * labelh(def.font))
/ Dy(scr.rect);
pt.x = frect.max.x - labelh(def.font);
pt.y = frect.max.y - labelh(def.font);
d.x = pt.x / hrx;
d.y = pt.y / hry;
warppointer(d);
}
sync();
event_flush(PointerMotionMask, false);
while(readmotion(&d)) {
if(align == Center) {
d.x = (d.x * hrx) - pt.x;
d.y = (d.y * hry) - pt.y;
}else
d = subpt(d, pt);
pt = addpt(pt, d);
rect_morph(&origin, d, &align);
frect = constrain(origin, -1);
grav = snap_rect(rects, nrect, &frect, &align, def.snap);
frect = frame_hints(f, frect, grav);
frect = constrain(frect, -1);
client_resize(c, frect);
}
pt = addpt(c->framewin->r.min,
Pt(Dx(frect) * rx,
Dy(frect) * ry));
if(pt.y > scr.rect.max.y)
pt.y = scr.rect.max.y - 1;
warppointer(pt);
free(rects);
ungrabpointer();
}
static int
pushstack_down(Frame *f, int y) {
int ret;
int dh, dy;
if(f == nil)
return 0;;
ret = 0;
dy = y - f->colr.min.y;
if(dy < 0)
return 0;
if(!f->collapsed) {
dh = Dy(f->colr) - labelh(def.font);
if(dy <= dh) {
f->colr.min.y += dy;
return dy;
}else {
f->collapsed = true;
f->colr.min.y += dh;
ret = dh;
dy -= dh;
}
}
dy = pushstack_down(f->anext, f->colr.max.y + dy);
f->colr.min.y += dy;
f->colr.max.y += dy;
return ret + dy;
}
static int
pushstack_up(Frame *f, int y) {
int ret;
int dh, dy;
if(f == nil)
return 0;
ret = 0;
dy = f->colr.max.y - y;
if(dy < 0)
return 0;
if(!f->collapsed) {
dh = Dy(f->colr) - labelh(def.font);
if(dy <= dh) {
f->colr.max.y -= dy;
return dy;
}else {
f->collapsed = true;
f->colr.max.y -= dh;
ret = dh;
dy -= dh;
}
}
dy = pushstack_up(f->aprev, f->colr.min.y - dy);
f->colr.min.y -= dy;
f->colr.max.y -= dy;
return ret + dy;
}
static void
mouse_tempvertresize(Area *a, Point p) {
Frame *fa, *fb, *f;
Window *cwin;
Rectangle r;
Point pt;
int incmode, nabove, nbelow;
if(a->mode != Coldefault)
return;
for(fa=a->frame; fa; fa=fa->anext)
if(p.y < fa->r.max.y + labelh(def.font)/2)
break;
if(!(fa && fa->anext))
return;
fb = fa->anext;
nabove=0;
nbelow=0;
for(f=fa; f; f=f->aprev)
nabove++;
for(f=fa->anext; f; f=f->anext)
nbelow++;
incmode = def.incmode;
def.incmode = IIgnore;
resizing = true;
column_arrange(a, false);
r.min.x = p.x;
r.max.x = p.x + 1;
r.min.y = a->r.min.y + labelh(def.font) * nabove;
r.max.y = a->r.max.y - labelh(def.font) * nbelow;
cwin = constraintwin(r);
if(!grabpointer(&scr.root, cwin, cursor[CurDVArrow], MouseMask))
goto done;
for(f=a->frame; f; f=f->anext)
f->colr_old = f->colr;
while(readmotion(&pt)) {
for(f=a->frame; f; f=f->anext) {
f->collapsed = false;
f->colr = f->colr_old;
}
if(pt.y > p.y)
pushstack_down(fb, pt.y);
else
pushstack_up(fa, pt.y);
fa->colr.max.y = pt.y;
fb->colr.min.y = pt.y;
column_frob(a);
}
done:
ungrabpointer();
destroyconstraintwin(cwin);
def.incmode = incmode;
resizing = false;
column_arrange(a, false);
}
void
mouse_checkresize(Frame *f, Point p, bool exec) {
Rectangle r;
Cursor cur;
int q;
cur = cursor[CurNormal];
if(rect_haspoint_p(f->crect, p)) {
client_setcursor(f->client, cur);
return;
}
r = rectsubpt(f->r, f->r.min);
q = quadrant(r, p);
if(rect_haspoint_p(f->grabbox, p)) {
cur = cursor[CurTCross];
if(exec)
mouse_movegrabbox(f->client, false);
}
else if(f->area->floating) {
if(p.x <= 2
|| p.y <= 2
|| r.max.x - p.x <= 2
|| r.max.y - p.y <= 2) {
cur = quad_cursor(q);
if(exec)
mouse_resize(f->client, q, false);
}
else if(exec && rect_haspoint_p(f->titlebar, p))
mouse_movegrabbox(f->client, true);
}else {
if(f->aprev && p.y <= 2
|| f->anext && r.max.y - p.y <= 2) {
cur = cursor[CurDVArrow];
if(exec)
mouse_tempvertresize(f->area, addpt(p, f->r.min));
}
}
if(!exec)
client_setcursor(f->client, cur);
}
static void
_grab(XWindow w, uint button, ulong mod) {
XGrabButton(display, button, mod, w, false, ButtonMask,
GrabModeSync, GrabModeSync, None, None);
}
/* Doesn't belong here */
void
grab_button(XWindow w, uint button, ulong mod) {
_grab(w, button, mod);
if((mod != AnyModifier) && numlock_mask) {
_grab(w, button, mod | numlock_mask);
_grab(w, button, mod | numlock_mask | LockMask);
}
}
|
Added cmd/wmii/print.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
#include "dat.h"
#include <fmt.h>
#include "fns.h"
static char* fcnames[] = {
"TVersion",
"RVersion",
"TAuth",
"RAuth",
"TAttach",
"RAttach",
"TError",
"RError",
"TFlush",
"RFlush",
"TWalk",
"RWalk",
"TOpen",
"ROpen",
"TCreate",
"RCreate",
"TRead",
"RRead",
"TWrite",
"RWrite",
"TClunk",
"RClunk",
"TRemove",
"RRemove",
"TStat",
"RStat",
"TWStat",
"RWStat",
};
static int
qid(Fmt *f, IxpQid *q) {
return fmtprint(f, "(%uhd,%uld,%ullx)", q->type, q->version, q->path);
}
int
Ffmt(Fmt *f) {
IxpFcall *fcall;
fcall = va_arg(f->args, IxpFcall*);
fmtprint(f, "% 2d %s\t", fcall->hdr.tag, fcnames[fcall->hdr.type - TVersion]);
switch(fcall->hdr.type) {
case TVersion:
case RVersion:
fmtprint(f, " msize: %uld version: \"%s\"", (ulong)fcall->version.msize, fcall->version.version);
break;
case TAuth:
fmtprint(f, " afid: %uld uname: \"%s\" aname: \"%s\"", (ulong)fcall->tauth.afid, fcall->tauth.uname, fcall->tauth.aname);
break;
case RAuth:
fmtprint(f, " aqid: ");
qid(f, &fcall->rauth.aqid);
break;
case RAttach:
fmtprint(f, " qid: ");
qid(f, &fcall->rattach.qid);
break;
case TAttach:
fmtprint(f, " fid: %uld afid: %uld uname: \"%s\" aname: \"%s\"", (ulong)fcall->hdr.fid, (ulong)fcall->tattach.afid, fcall->tattach.uname, fcall->tattach.aname);
break;
case RError:
fmtprint(f, " \"%s\"", fcall->error.ename);
break;
case TFlush:
fmtprint(f, " oldtag: %uld", (ulong)fcall->tflush.oldtag);
break;
case TWalk:
fmtprint(f, " newfid: %uld wname: {", (ulong)fcall->twalk.newfid);
for(int i=0; i<fcall->twalk.nwname; i++) {
if(i > 0) fmtprint(f, ", ");
fmtprint(f, "\"%s\"", fcall->twalk.wname[i]);
}
fmtprint(f, "}");
break;
case RWalk:
fmtprint(f, " wqid: {");
for(int i=0; i<fcall->rwalk.nwqid; i++) {
if(i > 0) fmtprint(f, ", ");
qid(f, &fcall->rwalk.wqid[i]);
}
fmtprint(f, "}");
break;
case TOpen:
fmtprint(f, " fid: %uld mode: %ulo", (ulong)fcall->hdr.fid, (ulong)fcall->topen.mode);
break;
case ROpen:
case RCreate:
fmtprint(f, " qid: ");
qid(f, &fcall->ropen.qid);
fmtprint(f, " %uld", (ulong)fcall->ropen.iounit);
break;
case TCreate:
fmtprint(f, " fid: %uld name: \"%s\" perm: %ulo mode: %ulo", (ulong)fcall->hdr.fid, fcall->tcreate.name, (ulong)fcall->tcreate.perm, (ulong)fcall->tcreate.mode);
break;
case TRead:
fmtprint(f, " fid: %uld offset: %ulld count: %uld", (ulong)fcall->hdr.fid, fcall->tread.offset, (ulong)fcall->tread.count);
break;
case RRead:
fmtprint(f, " data: {data: %uld}", fcall->rread.count);
break;
case TWrite:
fmtprint(f, " fid: %uld offset: %ulld data: {data: %uld}", (ulong)fcall->hdr.fid, fcall->twrite.offset, fcall->twrite.count);
break;
case RWrite:
fmtprint(f, " count: %uld", (ulong)fcall->rwrite.count);
break;
case TClunk:
case TRemove:
case TStat:
fmtprint(f, " fid: %uld", (ulong)fcall->hdr.fid);
break;
case RStat:
fmtprint(f, " stat: {data: %uld}", fcall->rstat.nstat);
break;
}
return 0;
}
|
Added cmd/wmii/root.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
static Handlers handlers;
void
root_init(void) {
WinAttr wa;
wa.cursor = cursor[CurNormal];
wa.event_mask = EnterWindowMask
| FocusChangeMask
| LeaveWindowMask
| PointerMotionMask
| SubstructureNotifyMask
| SubstructureRedirectMask;
setwinattr(&scr.root, &wa, CWCursor
| CWEventMask);
sethandler(&scr.root, &handlers);
}
static bool
enter_event(Window *w, void *aux, XCrossingEvent *e) {
disp.sel = true;
frame_draw_all();
return false;
}
static bool
leave_event(Window *w, void *aux, XCrossingEvent *e) {
if(!e->same_screen) {
disp.sel = false;
frame_draw_all();
}
return false;
}
static bool
focusin_event(Window *w, void *aux, XFocusChangeEvent *e) {
if(e->mode == NotifyGrab)
disp.hasgrab = &c_root;
return false;
}
static bool
mapreq_event(Window *w, void *aux, XMapRequestEvent *e) {
XWindowAttributes wa;
if(!XGetWindowAttributes(display, e->window, &wa) || wa.override_redirect)
return false;
if(!win2client(e->window))
client_create(e->window, &wa);
return false;
}
static bool
motion_event(Window *w, void *aux, XMotionEvent *e) {
Rectangle r, r2;
r = rectsetorigin(Rect(0, 0, 1, 1), Pt(e->x_root, e->y_root));
r2 = constrain(r, 0);
if(!eqrect(r, r2))
warppointer(r2.min);
return false;
}
static bool
kdown_event(Window *w, void *aux, XKeyEvent *e) {
e->state &= valid_mask;
kpress(w->xid, e->state, (KeyCode)e->keycode);
return false;
}
static Handlers handlers = {
.enter = enter_event,
.focusin = focusin_event,
.kdown = kdown_event,
.leave = leave_event,
.mapreq = mapreq_event,
.motion = motion_event,
};
|
Added cmd/wmii/rule.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
void
update_rules(Rule **rule, char *data) {
#define putc(m, c) BLOCK(if((m)->pos < (m)->end) *(m)->pos++ = c;)
#define getc(m) ((m)->pos < (m)->end ? *(m)->pos++ : 0)
#define ungetc(m) BLOCK(if((m)->pos > (m)->data) --(m)->pos)
IxpMsg buf, valuebuf, rebuf;
Reprog *re;
Rule *r;
Ruleval **rvp;
Ruleval *rv;
char *w;
char regexp[256];
char c;
int len;
while((r = *rule)) {
*rule = r->next;
while((rv = r->values)) {
r->values = rv->next;
free(rv);
}
free(r->regex);
free(r->value);
free(r);
}
if(!data || !data[0])
return;
buf = ixp_message(data, strlen(data), MsgUnpack);
begin:
msg_eatrunes(&buf, isspacerune, true);
if(getc(&buf) == '/')
goto regexp;
/* Regexp not at begining of the line. Rest of the line is junk. */
while((c = getc(&buf)))
if(c == '\n')
goto begin;
goto done;
regexp:
rebuf = ixp_message(regexp, sizeof regexp - 1, MsgPack);
while((c = getc(&buf)))
if(c == '/')
goto value;
else if(c != '\\')
putc(&rebuf, c);
else if(buf.pos[1] == '/' || buf.pos[1] == '\\' && buf.pos[2] == '/')
putc(&rebuf, getc(&buf));
else {
putc(&rebuf, c);
putc(&rebuf, getc(&buf));
}
goto done;
value:
valuebuf = ixp_message(buffer, sizeof buffer - 1, MsgPack);
while((c = getc(&buf))) {
if(c == '\n') {
putc(&valuebuf, ' ');
msg_eatrunes(&buf, isspacerune, true);
if((c = getc(&buf)) == '/') {
ungetc(&buf);
break;
}
}
putc(&valuebuf, c);
}
putc(&rebuf, '\0');
re = regcomp(regexp);
if(!re)
goto begin;
r = emallocz(sizeof *r);
*rule = r;
rule = &r->next;
r->regex = re;
valuebuf.end = valuebuf.pos;
valuebuf.pos = valuebuf.data;
rvp = &r->values;
while((w = msg_getword(&valuebuf, 0))) {
free(r->value);
r->value = estrdup(w);
if(strchr(w, '=')) {
len = strlen(w) + 1;
*rvp = rv = emallocz(sizeof *rv + len);
rvp = &rv->next;
memcpy(&rv[1], w, len);
tokenize(&rv->key, 2, (char*)&rv[1], '=');
}
}
goto begin;
done:
return;
}
|
Added cmd/wmii/screen.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include <math.h>
#include "fns.h"
#ifdef notdef
void
mapscreens(void) {
WMScreen *s, *ss;
Rectangle r;
int i, j;
#define frob(left, min, max, x, y) \
if(Dy(r) > 0) /* If they intersect at some point on this axis */ \
if(ss->r.min.x < s->r.min.x) { \
if((!s->left) \
|| (abs(Dy(r)) < abs(s->left.max.x - s->min.x))) \
s->left = ss; \
}
/* Variable hell? Certainly. */
for(i=0; i < nscreens; i++) {
s = screens[i];
for(j=0; j < nscreens; j++) {
if(i == j)
continue;
ss = screens[j];
r = rect_intersection(ss->r, s->r);
frob(left, min, max, x, y);
frob(right, max, min, x, y);
frob(atop, min, max, y, x);
frob(below, max, min, y, x);
}
}
#undef frob
}
int findscreen(Rectangle, int);
int
findscreen(Rectangle rect, int direction) {
Rectangle r;
WMScreen *ss, *s;
int best, i, j;
best = -1;
#define frob(min, max, x, y)
if(Dy(r) > 0) /* If they intersect at some point on this axis */
if(ss->r.min.x < rect.min.x) {
if(best == -1
|| (abs(ss->r.max.x - rect.min.x) < abs(screens[best]->r.max.x - rect.min.x)))
best = s->idx;
}
/* Variable hell? Certainly. */
for(i=0; i < nscreens; i++) {
ss = screens[j];
r = rect_intersection(ss->r, rect);
switch(direction) {
default:
return -1;
case West:
frob(min, max, x, y);
break;
case East:
frob(max, min, x, y);
break;
case North:
frob(min, max, y, x);
break;
case South:
frob(max, min, y, x);
break;
}
}
#undef frob
}
#endif
static Rectangle
leastthing(Rectangle rect, int direction, Vector_ptr *vec, Rectangle (*key)(void*)) {
Rectangle r;
int i, best, d;
SET(d);
SET(best);
for(i=0; i < vec->n; i++) {
r = key(vec->ary[i]);
switch(direction) {
case South: d = r.min.y; break;
case North: d = -r.max.y; break;
case East: d = r.min.x; break;
case West: d = -r.max.x; break;
}
if(i == 0 || d < best)
best = d;
}
switch(direction) {
case South: rect.min.y = rect.max.y = best; break;
case North: rect.min.y = rect.max.y = -best; break;
case East: rect.min.x = rect.max.x = best; break;
case West: rect.min.x = rect.max.x = -best; break;
}
return rect;
}
void*
findthing(Rectangle rect, int direction, Vector_ptr *vec, Rectangle (*key)(void*), bool wrap) {
Rectangle isect;
Rectangle r, bestisect = {0,}, bestr = {0,};
void *best, *p;
int i, n;
best = nil;
/* For the record, I really hate these macros. */
#define frob(min, max, LT, x, y) \
if(D##y(isect) > 0) /* If they intersect at some point on this axis */ \
if(r.min.x LT rect.min.x) { \
n = abs(r.max.x - rect.min.x) - abs(bestr.max.x - rect.min.x); \
if(best == nil \
|| n == 0 && D##y(isect) > D##y(bestisect) \
|| n < 0 \
) { \
best = p; \
bestr = r; \
bestisect = isect; \
} \
}
/* Variable hell? Certainly. */
for(i=0; i < vec->n; i++) {
p = vec->ary[i];
r = key(p);
isect = rect_intersection(rect, r);
switch(direction) {
default:
die("not reached");
/* Not reached */
case West:
frob(min, max, <, x, y);
break;
case East:
frob(max, min, >, x, y);
break;
case North:
frob(min, max, <, y, x);
break;
case South:
frob(max, min, >, y, x);
break;
}
}
#undef frob
if(!best && wrap) {
r = leastthing(rect, direction, vec, key);
return findthing(r, direction, vec, key, false);
}
return best;
}
static int
area(Rectangle r) {
return Dx(r) * Dy(r) *
(Dx(r) < 0 && Dy(r) < 0 ? -1 : 1);
}
int
ownerscreen(Rectangle r) {
Rectangle isect;
int s, a, best, besta;
SET(besta);
best = -1;
for(s=0; s < nscreens; s++) {
if(!screens[s]->showing)
continue;
isect = rect_intersection(r, screens[s]->r);
a = area(isect);
if(best < 0 || a > besta) {
besta = a;
best = s;
}
}
return best;
}
|
Added cmd/wmii/stack.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
/* Copyright ©2009-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
void
stack_scale(Frame *first, int height) {
Frame *f;
uint dy;
int surplus;
/*
* Will need something like this.
a = first->area;
column_fit(a, &ncol, &nuncol);
*/
dy = 0;
for(f=first; f && !f->collapsed; f=f->anext)
dy += Dy(f->colr);
/* Distribute the surplus.
*/
surplus = height - dy;
for(f=first; f && !f->collapsed; f=f->anext)
f->colr.max.y += ((float)Dy(f->r) / dy) * surplus;
}
void
stack_info(Frame *f, Frame **firstp, Frame **lastp, int *dyp, int *nframep) {
Frame *ft, *first, *last;
int dy, nframe;
nframe = 0;
dy = 0;
first = f;
last = f;
for(ft=f; ft && ft->collapsed; ft=ft->anext)
;
if(ft && ft != f) {
f = ft;
dy += Dy(f->colr);
}
for(ft=f; ft && !ft->collapsed; ft=ft->aprev) {
first = ft;
nframe++;
dy += Dy(ft->colr);
}
for(ft=f->anext; ft && !ft->collapsed; ft=ft->anext) {
if(first == nil)
first = ft;
last = ft;
nframe++;
dy += Dy(ft->colr);
}
if(nframep) *nframep = nframe;
if(firstp) *firstp = first;
if(lastp) *lastp = last;
if(dyp) *dyp = dy;
}
int
stack_count(Frame *f, int *mp) {
Frame *fp;
int n, m;
n = 0;
for(fp=f->aprev; fp && fp->collapsed; fp=fp->aprev)
n++;
m = ++n;
for(fp=f->anext; fp && fp->collapsed; fp=fp->anext)
n++;
if(mp) *mp = m;
return n;
}
Frame*
stack_find(Area *a, Frame *f, int dir, bool stack) {
Frame *fp;
#define predicate(f) !((f)->collapsed && stack || (f)->client->nofocus)
switch (dir) {
default:
die("not reached");
case North:
if(f)
for(f=f->aprev; f && !predicate(f); f=f->aprev)
;
else {
f = nil;
for(fp=a->frame; fp; fp=fp->anext)
if(predicate(fp))
f = fp;
}
break;
case South:
if(f)
for(f=f->anext; f && !predicate(f); f=f->anext)
;
else
for(f=a->frame; f && !predicate(f); f=f->anext)
;
break;
}
#undef predicate
return f;
}
bool
find(Area **ap, Frame **fp, int dir, bool wrap, bool stack) {
Rectangle r;
Frame *f;
Area *a;
f = *fp;
a = *ap;
r = f ? f->r : a->r;
if(dir == North || dir == South) {
*fp = stack_find(a, f, dir, stack);
if(*fp)
return true;
if(!a->floating)
*ap = area_find(a->view, r, dir, wrap);
if(!*ap)
return false;
*fp = stack_find(*ap, *fp, dir, stack);
return true;
}
if(dir != East && dir != West)
die("not reached");
*ap = area_find(a->view, r, dir, wrap);
if(!*ap)
return false;
*fp = ap[0]->sel;
return true;
}
|
Added cmd/wmii/utf.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
/* Public Domain --Kris Maglione */
#include "dat.h"
#include <errno.h>
#include <iconv.h>
#include <langinfo.h>
#include <string.h>
#include "fns.h"
char*
toutf8n(const char *str, size_t nstr) {
static iconv_t cd;
static bool haveiconv;
char *buf, *pos;
size_t nbuf, bsize;
if(cd == nil) {
cd = iconv_open("UTF-8", nl_langinfo(CODESET));
if((long)cd == -1)
warning("Can't convert from local character encoding to UTF-8");
else
haveiconv = true;
}
if(!haveiconv) {
buf = emalloc(nstr+1);
memcpy(buf, str, nstr);
buf[nstr+1] = '\0';
return buf;
}
iconv(cd, nil, nil, nil, nil);
bsize = (nstr+1) << 1;
buf = emalloc(bsize);
pos = buf;
nbuf = bsize-1;
/* The (void*) cast is because, while the BSDs declare:
* size_t iconv(iconv_t, const char**, size_t*, char**, size_t*),
* GNU/Linux and POSIX declare:
* size_t iconv(iconv_t, char**, size_t*, char**, size_t*).
* This just happens to be safer than declaring our own
* prototype.
*/
while(iconv(cd, (void*)&str, &nstr, &pos, &nbuf) == -1)
if(errno == E2BIG) {
bsize <<= 1;
nbuf = pos - buf;
buf = erealloc(buf, bsize);
pos = buf + nbuf;
nbuf = bsize - nbuf - 1;
}else
break;
*pos++ = '\0';
return erealloc(buf, pos-buf);
}
char*
toutf8(const char *str) {
return toutf8n(str, strlen(str));
}
|
Added cmd/wmii/view.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 |
/* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
* Copyright ©2006-2014 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
static bool
empty_p(View *v) {
Frame *f;
Area *a;
char **p;
int cmp;
int s;
foreach_frame(v, s, a, f) {
cmp = 1;
for(p=f->client->retags; *p; p++) {
cmp = strcmp(*p, v->name);
if(cmp >= 0)
break;
}
if(cmp)
return false;
}
return true;
}
static void
_view_select(View *v) {
if(selview != v) {
if(selview)
event("UnfocusTag %s\n",selview->name);
selview = v;
event("FocusTag %s\n", v->name);
event("AreaFocus %a\n", v->sel);
ewmh_updateview();
}
}
Client*
view_selclient(View *v) {
if(v->sel && v->sel->sel)
return v->sel->sel->client;
return nil;
}
bool
view_fullscreen_p(View *v, int scrn) {
Frame *f;
for(f=v->floating->frame; f; f=f->anext)
if(f->client->fullscreen == scrn)
return true;
return false;
}
View*
view_create(const char *name) {
static ushort id = 1;
View **vp;
Client *c;
View *v;
int i;
for(vp=&view; *vp; vp=&(*vp)->next) {
i = strcmp((*vp)->name, name);
if(i == 0)
return *vp;
if(i > 0)
break;
}
v = emallocz(sizeof *v);
v->id = id++;
v->r = emallocz(nscreens * sizeof *v->r);
v->pad = emallocz(nscreens * sizeof *v->pad);
utflcpy(v->name, name, sizeof v->name);
event("CreateTag %s\n", v->name);
area_create(v, nil, screen->idx, 0);
v->areas = emallocz(nscreens * sizeof *v->areas);
for(i=0; i < nscreens; i++)
view_init(v, i);
area_focus(v->firstarea);
v->next = *vp;
*vp = v;
/* FIXME: Belongs elsewhere */
/* FIXME: Can do better. */
for(c=client; c; c=c->next)
if(c != kludge)
client_applytags(c, c->tags);
view_arrange(v);
if(!selview)
_view_select(v);
ewmh_updateviews();
return v;
}
void
view_init(View *v, int iscreen) {
v->r[iscreen] = screens[iscreen]->r;
v->pad[iscreen] = ZR;
v->areas[iscreen] = nil;
column_new(v, nil, iscreen, 0);
}
void
view_update_screens(View *v) {
Area *a;
Frame *f;
int s;
if (v->sel->screen > (long)nscreens)
v->sel = v->floating->next;
v->selscreen = min(v->selscreen, nscreens);
if (nscreens_new < nscreens) {
foreach_frame(v, s, a, f) {
f->oldscreen = min(f->oldscreen, nscreens_new);
if (a->screen >= nscreens_new) {
a->permanent = true;
area_detach(f);
view_attach(v, f);
}
}
foreach_area(v, s, a) {
if (a->screen >= nscreens_new)
area_destroy(a);
}
}
v->areas = erealloc(v->areas, nscreens_new * sizeof *v->areas);
v->r = erealloc(v->r, nscreens_new * sizeof *v->r);
v->pad = erealloc(v->pad, nscreens_new * sizeof *v->pad);
}
void
view_destroy(View *v) {
View **vp;
Frame *f;
View *tv;
Area *a;
int s;
if(v->dead)
return;
v->dead = true;
for(vp=&view; *vp; vp=&(*vp)->next)
if(*vp == v) break;
*vp = v->next;
assert(v != v->next);
/* Detach frames held here by regex tags. */
/* FIXME: Can do better. */
foreach_frame(v, s, a, f)
client_applytags(f->client, f->client->tags);
foreach_area(v, s, a)
area_destroy(a);
event("DestroyTag %s\n", v->name);
if(v == selview) {
for(tv=view; tv; tv=tv->next)
if(tv->next == *vp) break;
if(tv == nil)
tv = view;
if(tv)
view_focus(screen, tv);
}
free(v->areas);
free(v->r);
free(v->pad);
free(v);
ewmh_updateviews();
}
Area*
view_findarea(View *v, int screen, int idx, bool create) {
Area *a;
assert(screen >= 0 && screen < nscreens);
for(a=v->areas[screen]; a && --idx > 0; a=a->next)
if(create && a->next == nil)
return area_create(v, a, screen, 0);
return a;
}
static void
frames_update_sel(View *v) {
Frame *f;
Area *a;
int s;
foreach_frame(v, s, a, f)
f->client->sel = f;
}
/* Don't let increment hints take up more than half
* of the screen, in either direction.
*/
static Rectangle
fix_rect(Rectangle old, Rectangle new) {
double r;
new = rect_intersection(new, old);
r = (Dy(old) - Dy(new)) / Dy(old);
if(r > .5) {
r -= .5;
new.min.y -= r * (new.min.y - old.min.y);
new.max.y += r * (old.max.y - new.max.y);
}
r = (Dx(old) - Dx(new)) / Dx(old);
if(r > .5) {
r -= .5;
new.min.x -= r * (new.min.x - old.min.x);
new.max.x += r * (old.max.x - new.max.x);
}
return new;
}
void
view_update_rect(View *v) {
static Vector_rect vec;
static Vector_rect *vp;
Rectangle r, sr, rr, brect, scrnr;
WMScreen *scrn;
Strut *strut;
Frame *f;
int left, right, top, bottom;
int s, i;
/* XXX:
if(v != selview)
return false;
*/
top = 0;
left = 0;
right = 0;
bottom = 0;
vec.n = 0;
for(f=v->floating->frame; f; f=f->anext) {
strut = f->client->strut;
if(!strut)
continue;
/* Can do better in the future. */
top = max(top, strut->top.max.y);
left = max(left, strut->left.max.x);
right = min(right, strut->right.min.x);
bottom = min(bottom, strut->bottom.min.y);
vector_rpush(&vec, strut->top);
vector_rpush(&vec, strut->left);
vector_rpush(&vec, rectaddpt(strut->right, Pt(scr.rect.max.x, 0)));
vector_rpush(&vec, rectaddpt(strut->bottom, Pt(0, scr.rect.max.y)));
}
vp = unique_rects(&vec, scr.rect);
scrnr = scr.rect;
scrnr.min.y += top;
scrnr.min.x += left;
scrnr.max.x += right;
scrnr.max.y += bottom;
/* FIXME: Multihead. */
v->floating->r = scr.rect;
for(s=0; s < nscreens; s++) {
scrn = screens[s];
r = fix_rect(scrn->r, scrnr);
/* Ugly. Very, very ugly. */
/*
* Try to find some rectangle near the edge of the
* screen where the bar will fit. This way, for
* instance, a system tray can be placed there
* without taking up too much extra screen real
* estate.
*/
rr = r;
brect = scrn->brect;
for(i=0; i < vp->n; i++) {
sr = rect_intersection(vp->ary[i], scrn->r);
if(Dx(sr) < Dx(r)/2 || Dy(sr) < Dy(brect))
continue;
if(scrn->barpos == BTop && sr.min.y < rr.min.y
|| scrn->barpos != BTop && sr.max.y > rr.max.y)
rr = sr;
}
if(scrn->barpos == BTop) {
bar_sety(scrn, rr.min.y);
r.min.y = max(r.min.y, scrn->brect.max.y);
}else {
bar_sety(scrn, rr.max.y - Dy(brect));
r.max.y = min(r.max.y, scrn->brect.min.y);
}
bar_setbounds(scrn, rr.min.x, rr.max.x);
v->r[s] = r;
}
}
void
view_update(View *v) {
Client *c;
Frame *f;
Area *a;
int s;
if(v == selview && !starting) {
frames_update_sel(v);
foreach_frame(v, s, a, f)
if(f->client->fullscreen >= 0) {
f->collapsed = false;
if(!f->area->floating) {
f->oldarea = area_idx(f->area);
f->oldscreen = f->area->screen;
area_moveto(v->floating, f);
area_setsel(v->floating, f);
}else if(f->oldarea == -1)
f->oldarea = 0;
}
view_arrange(v);
for(c=client; c; c=c->next) {
f = c->sel;
if((f && f->view == v)
&& (f->area == v->sel || !(f->area && f->area->max && f->area->floating))) {
if(f->area)
client_resize(c, f->r);
}else {
client_unmapframe(c);
client_unmap(c, IconicState);
}
ewmh_updatestate(c);
ewmh_updateclient(c);
}
view_restack(v);
if(!v->sel->floating && view_fullscreen_p(v, v->sel->screen))
area_focus(v->floating);
else
area_focus(v->sel);
frame_draw_all();
}
view_update_urgency(v, nil);
}
void
view_update_urgency(View *v, char *from) {
Area *a;
Frame *f;
int s, urgent;
urgent = 0;
foreach_frame(v, s, a, f)
if (f->client->urgent) {
urgent++;
break;
}
if (urgent != v->urgent)
event("%sUrgentTag %s %s\n",
urgent ? "" : "Not",
from ? from : "Unknown",
v->name);
v->urgent = urgent;
}
void
view_focus(WMScreen *s, View *v) {
USED(s);
_view_select(v);
view_update(v);
}
void
view_select(const char *arg) {
char buf[256];
utflcpy(buf, arg, sizeof buf);
trim(buf, " \t+/");
if(buf[0] == '\0')
return;
if(!strcmp(buf, ".") || !strcmp(buf, ".."))
return;
_view_select(view_create(buf));
view_update_all(); /* performs view_focus */
}
void
view_attach(View *v, Frame *f) {
Client *c;
Frame *ff;
Area *a, *oldsel;
c = f->client;
oldsel = v->oldsel;
a = v->sel;
if(c->floating == Never)
a = view_findarea(v, v->selscreen, v->selcol, false);
else if(client_floats_p(c)) {
if(v->sel != v->floating && c->fullscreen < 0)
oldsel = v->sel;
a = v->floating;
}
else if(c->sel && c->sel->screen >= 0 && c->sel->screen < nscreens_new &&
c->sel->screen != v->sel->screen)
a = view_findarea(v, c->sel->screen, 0, false);
else if((ff = client_groupframe(c, v))) {
if (ff->client != c && ff->area->screen < nscreens_new)
a = ff->area;
if(v->oldsel && ff->client == view_selclient(v))
a = v->oldsel;
}
else if(v->sel->floating) {
if(v->oldsel)
a = v->oldsel;
/* Don't float a frame when starting or when its
* last focused frame didn't float. Important when
* tagging with +foo.
*/
else if(starting
|| c->sel && c->sel->area && !c->sel->area->floating)
a = v->firstarea;
}
if(!a->floating && c->floating != Never && view_fullscreen_p(v, a->screen))
a = v->floating;
event("ViewAttach %s %#C\n", v->name, c);
area_attach(a, f);
/* TODO: Decide whether to focus this frame */
bool newgroup = !c->group
|| c->group->ref == 1
|| view_selclient(v)
&& view_selclient(v)->group == c->group
|| group_leader(c->group)
&& !client_viewframe(group_leader(c->group),
c->sel->view);
USED(newgroup);
if(!(c->w.ewmh.type & (TypeSplash|TypeDock))) {
if(!(c->tagre.regex && regexec(c->tagre.regc, v->name, nil, 0)))
frame_focus(f);
else if(c->group && f->area->sel->client->group == c->group)
/* XXX: Stack. */
area_setsel(f->area, f);
}
if(oldsel)
v->oldsel = oldsel;
if(c->sel == nil)
c->sel = f;
view_update(v);
}
void
view_detach(Frame *f) {
Client *c;
View *v;
v = f->view;
c = f->client;
area_detach(f);
if(c->sel == f)
c->sel = f->cnext;
event("ViewDetach %s %#C\n", v->name, c);
view_update(v);
if(v != selview && empty_p(v))
view_destroy(v);
}
char**
view_names(void) {
Vector_ptr vec;
View *v;
vector_pinit(&vec);
for(v=view; v; v=v->next)
vector_ppush(&vec, v->name);
vector_ppush(&vec, nil);
return erealloc(vec.ary, vec.n * sizeof *vec.ary);
}
void
view_restack(View *v) {
static Vector_long wins;
Divide *d;
Frame *f;
Area *a;
int s;
if(v != selview)
return;
wins.n = 0;
for(f=v->floating->stack; f; f=f->snext)
vector_lpush(&wins, f->client->framewin->xid);
for(int s=0; s < nscreens; s++)
vector_lpush(&wins, screens[s]->barwin->xid);
for(d = divs; d && d->w->mapped; d = d->next)
vector_lpush(&wins, d->w->xid);
foreach_column(v, s, a)
if(a->frame) {
vector_lpush(&wins, a->sel->client->framewin->xid);
for(f=a->frame; f; f=f->anext)
if(f != a->sel)
vector_lpush(&wins, f->client->framewin->xid);
}
ewmh_updatestacking();
if(wins.n)
XRestackWindows(display, (ulong*)wins.ary, wins.n);
}
void
view_scale(View *v, int scrn, int width) {
uint xoff, numcol;
uint minwidth;
Area *a;
float scale;
int dx, minx;
minwidth = column_minwidth();
minx = v->r[scrn].min.x + v->pad[scrn].min.x;
if(!v->areas[scrn])
return;
numcol = 0;
dx = 0;
for(a=v->areas[scrn]; a; a=a->next) {
numcol++;
dx += Dx(a->r);
}
scale = (float)width / dx;
xoff = minx;
for(a=v->areas[scrn]; a; a=a->next) {
a->r.max.x = xoff + Dx(a->r) * scale;
a->r.min.x = xoff;
if(!a->next)
a->r.max.x = v->r[scrn].min.x + width;
xoff = a->r.max.x;
}
if(numcol * minwidth > width)
return;
xoff = minx;
for(a=v->areas[scrn]; a; a=a->next) {
a->r.min.x = xoff;
if(Dx(a->r) < minwidth)
a->r.max.x = xoff + minwidth;
if(!a->next)
a->r.max.x = minx + width;
xoff = a->r.max.x;
}
}
/* XXX: Multihead. */
void
view_arrange(View *v) {
Area *a;
int s;
if(!v->firstarea)
return;
view_update_rect(v);
for(s=0; s < nscreens; s++)
view_scale(v, s, Dx(v->r[s]) + Dx(v->pad[s]));
foreach_area(v, s, a) {
if(a->floating)
continue;
/* This is wrong... */
a->r.min.y = v->r[s].min.y;
a->r.max.y = v->r[s].max.y;
column_arrange(a, false);
}
if(v == selview)
div_update_all();
}
Rectangle*
view_rects(View *v, uint *num, Frame *ignore) {
Vector_rect result;
Frame *f;
int i;
vector_rinit(&result);
for(f=v->floating->frame; f; f=f->anext)
if(f != ignore)
vector_rpush(&result, f->r);
for(i=0; i < nscreens; i++) {
vector_rpush(&result, v->r[i]);
vector_rpush(&result, screens[i]->r);
}
*num = result.n;
return result.ary;
}
void
view_update_all(void) {
View *n, *v, *old;
old = selview;
for(v=view; v; v=v->next)
frames_update_sel(v);
for(v=view; v; v=n) {
n=v->next;
if(v != old && empty_p(v))
view_destroy(v);
}
view_update(selview);
}
uint
view_newcolwidth(View *v, int scrn, int num) {
Rule *r;
char *toks[16];
char buf[sizeof r->value];
ulong n;
/* XXX: Multihead. */
for(r=def.colrules.rule; r; r=r->next)
if(regexec(r->regex, v->name, nil, 0)) {
utflcpy(buf, r->value, sizeof buf);
n = tokenize(toks, 16, buf, '+');
if(num < n)
if(getulong(toks[num], &n))
return Dx(v->r[scrn]) * (n / 100.0);
else if(!strcmp("px", strend(toks[num], 2))) {
toks[num][strlen(toks[num]) - 2] = '\0';
if(getulong(toks[num], &n))
return n;
}
break;
}
return 0;
}
char*
view_index(View *v) {
Rectangle *r;
Frame *f;
Area *a;
int s;
bufclear();
foreach_area(v, s, a) {
if(a->floating)
bufprint("# %a %d %d\n", a, Dx(a->r), Dy(a->r));
else
bufprint("# %a %d %d\n", a, a->r.min.x, Dx(a->r));
for(f=a->frame; f; f=f->anext) {
r = &f->r;
if(a->floating)
bufprint("%a %#C %d %d %d %d %s\n",
a, f->client,
r->min.x, r->min.y,
Dx(*r), Dy(*r),
f->client->props);
else
bufprint("%a %#C %d %d %s\n",
a, f->client,
r->min.y, Dy(*r),
f->client->props);
}
}
return buffer;
}
|
Added cmd/wmii/xdnd.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "dat.h"
#include "fns.h"
static Handlers handlers;
void
xdnd_initwindow(Window *w) {
long l;
l = 3; /* They are insane. Why is this an ATOM?! */
changeprop_long(w, "XdndAware", "ATOM", &l, 1);
pushhandler(w, &handlers, nil);
}
typedef struct Dnd Dnd;
struct Dnd {
XWindow source;
Rectangle r;
};
static bool
clientmessage_event(Window *w, void *aux, XClientMessageEvent *e) {
Dnd *dnd;
long *l;
Rectangle r;
Point p;
long pos, siz;
ulong msg;
dnd = nil;
msg = e->message_type;
l = e->data.l;
Dprint(DDnd, "ClientMessage: %A\n", msg);
if(msg == xatom("XdndEnter")) {
if(e->format != 32)
return false;
if(w->dnd == nil)
w->dnd = emallocz(sizeof *dnd);
dnd = w->dnd;
dnd->source = l[0];
dnd->r = ZR;
return false;
}else
if(msg == xatom("XdndLeave")) {
if(e->format != 32)
return false;
if(w->dnd) {
free(w->dnd);
w->dnd = nil;
}
return false;
}else
if(msg == xatom("XdndPosition")) {
if(e->format != 32)
return false;
r = ZR;
dnd = w->dnd;
if(dnd) {
p.x = (ulong)l[2] >> 16;
p.y = (ulong)l[2] & 0xffff;
p = subpt(p, w->r.min);
Dprint(DDnd, "\tw: %W\n", w);
Dprint(DDnd, "\tp: %P\n", p);
if(eqrect(dnd->r, ZR) || !rect_haspoint_p(dnd->r, p))
if(w->handler->dndmotion)
dnd->r = w->handler->dndmotion(w, w->aux, p);
r = dnd->r;
if(!eqrect(r, ZR))
r = rectaddpt(r, w->r.min);
Dprint(DDnd, "\tr: %R\n", r);
}
pos = (r.min.x<<16) | r.min.y;
siz = (Dx(r)<<16) | Dy(r);
sendmessage(window(l[0]), "XdndStatus", e->window, 0, pos, siz, 0);
return false;
}
return true;
}
static Handlers handlers = {
.message = clientmessage_event
};
|
Added cmd/wmiir.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 |
/* Copyight ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#define IXP_NO_P9_
#define IXP_P9_STRUCTS
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <time.h>
#include <unistd.h>
#include <wchar.h>
#include <ixp.h>
#include <stuff/util.h>
#include <bio.h>
#include <fmt.h>
static IxpClient* client;
static Biobuf* outbuf;
static bool binary;
static void
usage(void) {
lprint(1,
"usage: %s [-a <address>] [-b] {create | ls [-dlp] | read | remove | write} <file>\n"
" %s [-a <address>] xwrite <file> <data>\n"
" %s -v\n", argv0, argv0, argv0);
exit(1);
}
static int
errfmt(Fmt *f) {
return fmtstrcpy(f, ixp_errbuf());
}
static bool
flush(IxpCFid *fid, char *in, int len, bool binary) {
static mbstate_t state;
static char buf[IXP_MAX_MSG];
static char *out = buf, *outend = buf + sizeof buf;
char *inend;
wchar_t w;
Rune r;
int res;
if(binary)
return ixp_write(fid, in, len) == len;
inend = in + len;
do {
if(in == nil || out + UTFmax > outend) {
if(ixp_write(fid, buf, out - buf) != out - buf)
return false;
out = buf;
}
if(in == nil) {
state = (mbstate_t){0};
return true;
}
switch((res = mbrtowc(&w, in, inend - in, &state))) {
case -1:
return false;
case 0:
case -2:
return true;
default:
in += res;
r = w < Runemax ? w : Runesync;
out += runetochar(out, &r);
}
} while(in < inend);
return true;
}
static bool
unflush(int fd, char *in, int len, bool binary) {
static mbstate_t state;
static char buf[IXP_MAX_MSG], extra[UTFmax];
static char *out = buf, *outend = buf + sizeof buf;
static int nextra;
char *start;
Rune r;
int res, n;
if(binary)
return write(fd, in, len) == len;
if(in) {
if((n = nextra)) {
nextra = 0;
while(len > 0 && n < UTFmax && !fullrune(extra, n)) {
extra[n++] = *in++;
len--;
}
unflush(fd, extra, n, binary);
}
n = utfnlen(in, len);
}
start = in;
do {
if(in == nil || out + MB_LEN_MAX > outend) {
if(write(fd, buf, out - buf) != out - buf)
return false;
out = buf;
}
if(in == nil || n == 0) {
state = (mbstate_t){0};
return true;
}
in += chartorune(&r, in);
n--;
res = wcrtomb(out, r, &state);
if(res == -1)
*out++ = '?';
else
out += res;
} while(n > 0);
if(in < start + len) {
nextra = min(sizeof extra, len - (in - start));
memcpy(extra, in, nextra);
}
return true;
}
/* Utility Functions */
static void
write_data(IxpCFid *fid, char *name, bool binary) {
char buf[IXP_MAX_MSG];
int len;
while((len = read(0, buf, fid->iounit)) > 0)
if(!flush(fid, buf, len, binary))
fatal("cannot write file %q\n", name);
if(!binary)
flush(fid, nil, 0, binary);
}
static int
comp_stat(const void *s1, const void *s2) {
Stat *st1, *st2;
st1 = (Stat*)s1;
st2 = (Stat*)s2;
return strcmp(st1->name, st2->name);
}
static void
setrwx(long m, char *s) {
static char *modes[] = {
"---", "--x", "-w-",
"-wx", "r--", "r-x",
"rw-", "rwx",
};
strncpy(s, modes[m], 3);
}
static char *
modestr(uint mode) {
static char buf[16];
buf[0]='-';
if(mode & P9_DMDIR)
buf[0]='d';
buf[1]='-';
setrwx((mode >> 6) & 7, &buf[2]);
setrwx((mode >> 3) & 7, &buf[5]);
setrwx((mode >> 0) & 7, &buf[8]);
buf[11] = 0;
return buf;
}
static char*
timestr(time_t val) {
static char buf[32];
strftime(buf, sizeof buf, "%Y-%m-%d %H:%M", localtime(&val));
return buf;
}
static void
print_stat(Stat *s, int lflag, char *file, int pflag) {
char *slash;
slash = "";
if(pflag)
slash = "/";
else
file = "";
if(lflag)
Blprint(outbuf, "%s %s %s %5llud %s %s%s%s\n",
modestr(s->mode), s->uid, s->gid, s->length,
timestr(s->mtime), file, slash, s->name);
else {
if((s->mode&P9_DMDIR) && strcmp(s->name, "/"))
Blprint(outbuf, "%s%s%s/\n", file, slash, s->name);
else
Blprint(outbuf, "%s%s%s\n", file, slash, s->name);
}
}
/* Service Functions */
static int
xwrite(int argc, char *argv[]) {
IxpCFid *fid;
char *file;
ARGBEGIN{
default:
usage();
}ARGEND;
file = EARGF(usage());
fid = ixp_open(client, file, P9_OWRITE);
if(fid == nil)
fatal("Can't open file '%s': %r\n", file);
write_data(fid, file, binary);
ixp_close(fid);
return 0;
}
static int
xawrite(int argc, char *argv[]) {
IxpCFid *fid;
char *file, *buf;
int nbuf, i;
ARGBEGIN{
default:
usage();
}ARGEND;
file = EARGF(usage());
fid = ixp_open(client, file, P9_OWRITE);
if(fid == nil)
fatal("Can't open file '%s': %r\n", file);
nbuf = 1;
for(i=0; i < argc; i++)
nbuf += strlen(argv[i]) + (i > 0);
buf = emalloc(nbuf);
buf[0] = '\0';
while(argc) {
strcat(buf, ARGF());
if(argc)
strcat(buf, " ");
}
if(!(flush(fid, buf, nbuf, binary) && (binary || flush(fid, 0, 0, binary))))
fatal("cannot write file '%s': %r\n", file);
ixp_close(fid);
free(buf);
return 0;
}
static int
xcreate(int argc, char *argv[]) {
IxpCFid *fid;
char *file;
ARGBEGIN{
default:
usage();
}ARGEND;
file = EARGF(usage());
fid = ixp_create(client, file, 0777, P9_OWRITE);
if(fid == nil)
fatal("Can't create file '%s': %r\n", file);
if((fid->qid.type&P9_DMDIR) == 0)
write_data(fid, file, binary);
ixp_close(fid);
return 0;
}
static int
xremove(int argc, char *argv[]) {
char *file;
ARGBEGIN{
default:
usage();
}ARGEND;
file = EARGF(usage());
do {
if(!ixp_remove(client, file))
lprint(2, "%s: Can't remove file '%s': %r\n", argv0, file);
}while((file = ARGF()));
return 0;
}
static int
xread(int argc, char *argv[]) {
IxpCFid *fid;
char *file, *buf;
int count;
ARGBEGIN{
default:
usage();
}ARGEND;
if(argc == 0)
usage();
file = EARGF(usage());
do {
fid = ixp_open(client, file, P9_OREAD);
if(fid == nil)
fatal("Can't open file '%s': %r\n", file);
buf = emalloc(fid->iounit);
while((count = ixp_read(fid, buf, fid->iounit)) > 0) {
unflush(1, buf, count, binary);
if (!binary && count < fid->iounit)
unflush(1, 0, 0, binary);
}
if(!binary)
unflush(1, 0, 0, binary);
ixp_close(fid);
if(count == -1)
lprint(2, "%s: cannot read file '%s': %r\n", argv0, file);
} while((file = ARGF()));
return 0;
}
static int
xls(int argc, char *argv[]) {
IxpMsg m;
Stat *stat;
IxpCFid *fid;
char *file;
char *buf;
int lflag, dflag, pflag;
int count, nstat, mstat, i;
lflag = dflag = pflag = 0;
ARGBEGIN{
case 'l':
lflag++;
break;
case 'd':
dflag++;
break;
case 'p':
pflag++;
break;
default:
usage();
}ARGEND;
count = 0;
file = EARGF(usage());
do {
stat = ixp_stat(client, file);
if(stat == nil)
fatal("cannot stat file '%s': %r\n", file);
i = strlen(file);
if(file[i-1] == '/') {
file[i-1] = '\0';
if(!(stat->mode&P9_DMDIR))
fatal("%s: not a directory", file);
}
if(dflag || (stat->mode&P9_DMDIR) == 0) {
print_stat(stat, lflag, file, pflag);
ixp_freestat(stat);
continue;
}
ixp_freestat(stat);
fid = ixp_open(client, file, P9_OREAD);
if(fid == nil)
fatal("Can't open file '%s': %r\n", file);
nstat = 0;
mstat = 16;
stat = emalloc(mstat * sizeof *stat);
buf = emalloc(fid->iounit);
while((count = ixp_read(fid, buf, fid->iounit)) > 0) {
m = ixp_message(buf, count, MsgUnpack);
while(m.pos < m.end) {
if(nstat == mstat) {
mstat <<= 1;
stat = erealloc(stat, mstat * sizeof *stat);
}
ixp_pstat(&m, &stat[nstat++]);
}
}
ixp_close(fid);
qsort(stat, nstat, sizeof *stat, comp_stat);
for(i = 0; i < nstat; i++) {
print_stat(&stat[i], lflag, file, pflag);
ixp_freestat(&stat[i]);
}
free(stat);
} while((file = ARGF()));
if(count == -1)
fatal("cannot read directory '%s': %r\n", file);
return 0;
}
static int
xnamespace(int argc, char *argv[]) {
char *path;
ARGBEGIN{
default:
usage();
}ARGEND;
path = ixp_namespace();
if(path == nil)
fatal("can't find namespace: %r\n");
Blprint(outbuf, "%s", path);
return 0;
}
static int
xproglist(int argc, char *argv[]) {
DIR *d;
struct dirent *de;
struct stat st;
char *dir, *cwd;
int i;
quotefmtinstall();
ARGBEGIN{
default:
usage();
}ARGEND;
i = 7, cwd = nil;
do
cwd = erealloc(cwd, 1<<i);
while(!getcwd(cwd, 1<<i) && errno == ERANGE);
while((dir = ARGF()))
/* Don't use Blprint. wimenu expects UTF-8. */
if(!chdir(cwd) && !chdir(dir) && (d = opendir(dir))) {
while((de = readdir(d))) {
stat(de->d_name, &st);
if(S_ISREG(st.st_mode) && !access(de->d_name, X_OK))
Bprint(outbuf, "%q\n", de->d_name);
}
closedir(d);
}
return 0; /* NOTREACHED */
}
static int
xsetsid(int argc, char *argv[]) {
char *av0;
bool dofork;
av0 = nil;
dofork = false;
ARGBEGIN{
case '0':
av0 = EARGF(usage());
break;
case 'f':
dofork = true;
break;
default:
usage();
}ARGEND;
if(av0 == nil)
av0 = argv[0];
if(av0 == nil)
return 1;
setsid();
if(dofork)
switch(fork()) {
case 0: break;
case -1: fatal("can't fork: %r\n");
default: return 0;
}
execvp(av0, argv);
fatal("setsid: can't exec: %r");
return 1; /* NOTREACHED */
}
typedef struct exectab exectab;
struct exectab {
char *cmd;
int (*fn)(int, char**);
} fstab[] = {
{"cat", xread},
{"create", xcreate},
{"ls", xls},
{"read", xread},
{"remove", xremove},
{"rm", xremove},
{"write", xwrite},
{"xwrite", xawrite},
{0, }
}, utiltab[] = {
{"namespace", xnamespace},
{"ns", xnamespace},
{"proglist", xproglist},
{"setsid", xsetsid},
{0, }
};
int
main(int argc, char *argv[]) {
char *address;
exectab *tab;
int ret;
IXP_ASSERT_VERSION;
setlocale(LC_ALL, "");
binary = utf8locale();
quotefmtinstall();
fmtinstall('r', errfmt);
address = getenv("WMII_ADDRESS");
ARGBEGIN{
case 'b':
binary = true;
break;
case 'v':
lprint(1, "%s-" VERSION ", " COPYRIGHT "\n", argv0);
exit(0);
case 'a':
address = EARGF(usage());
break;
default:
usage();
}ARGEND;
if(argc < 1)
usage();
outbuf = Bfdopen(1, OWRITE);
for(tab=utiltab; tab->cmd; tab++)
if(!strcmp(*argv, tab->cmd)) {
ret = tab->fn(argc, argv);
goto done;
}
if(address && *address)
client = ixp_mount(address);
else
client = ixp_nsmount("wmii");
if(client == nil)
fatal("can't mount: %r\n");
signal(SIGPIPE, SIG_DFL);
for(tab=fstab; tab->cmd; tab++)
if(strcmp(*argv, tab->cmd) == 0) break;
if(tab->cmd == 0)
usage();
ret = tab->fn(argc, argv);
ixp_unmount(client);
done:
Bterm(outbuf);
return ret;
}
|
Added cmd/x11/Makefile.
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ROOT= ../.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk TARG = wikeyname \ wmii9menu PACKAGES += $(X11PACKAGES) LIB = $(LIBS9) $(LIBIXP) LIBS += $(LIB) CFLAGS += $(INCX11) wiclick.out: wiclick.o $(LINK) $@ $< -lXtst include $(ROOT)/mk/many.mk |
Added cmd/x11/setfocus.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* Copyight 2008 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <stuff/x.h>
#include <stuff/util.h>
#include <fmt.h>
int
main(int argc, char *argv[]) {
XWindow w;
ARGBEGIN{
}ARGEND;
initdisplay();
if(!getulong(EARGF(exit(1)), &w))
exit(1);
XSetInputFocus(display, w, RevertToParent, CurrentTime);
XCloseDisplay(display);
}
|
Added cmd/x11/wikeyname.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <stuff/util.h>
#include <stuff/x.h>
#include <fmt.h>
#include <locale.h>
#include <unistd.h>
static const char version[] = "wikeyname-"VERSION", "COPYRIGHT"\n";
static Handlers handlers;
static char* keyname;
static int nkeys;
static void
usage(void) {
lprint(2, "usage: wikeyname\n");
exit(1);
}
int
main(int argc, char *argv[]) {
setlocale(LC_CTYPE, "");
ARGBEGIN{
case 'v':
lprint(2, version);
return 0;
default: usage();
}ARGEND;
if(argc)
usage();
fmtinstall('K', fmtkey);
initdisplay();
selectinput(&scr.root, KeyPressMask|KeyReleaseMask);
sethandler(&scr.root, &handlers);
if(!grabkeyboard(&scr.root))
fatal("can't grab keyboard\n");
if(isatty(1))
lprint(2, "Please press a key...\n");
event_loop();
lprint(1, "%s\n", keyname);
XCloseDisplay(display);
return 0;
}
static bool
kdown_event(Window *w, void *aux, XKeyEvent *ev) {
USED(w, aux);
nkeys++;
free(keyname);
keyname = smprint("%K", ev);
return false;
}
static bool
kup_event(Window *w, void *aux, XKeyEvent *ev) {
USED(w, aux, ev);
if(keyname != nil && --nkeys <= 0)
event_looprunning = false;
return false;
}
static Handlers handlers = {
.kup = kup_event,
.kdown = kdown_event,
};
|
Added cmd/x11/wiwarp.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/* Copyight 2008 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <stuff/x.h>
#include <stuff/util.h>
#include <fmt.h>
int
main(int argc, char *argv[]) {
Point pt;
ARGBEGIN{
}ARGEND;
initdisplay();
if(argc) {
if(!getint(EARGF(exit(1)), &pt.x))
exit(1);
if(!getint(EARGF(exit(1)), &pt.y))
exit(1);
}else {
pt = querypointer(&scr.root);
lprint(1, "%d %d\n", pt.x, pt.y);
}
warppointer(pt);
XCloseDisplay(display);
}
|
Added cmd/x11/wmii9menu.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
/* Licence
* =======
*
* 9menu is free software, and is Copyright (c) 1994 by David Hogan and
* Arnold Robbins. Permission is granted to all sentient beings to use
* this software, to make copies of it, and to distribute those copies,
* provided that:
*
* (1) the copyright and licence notices are left intact
* (2) the recipients are aware that it is free software
* (3) any unapproved changes in functionality are either
* (i) only distributed as patches
* or (ii) distributed as a new program which is not called 9menu
* and whose documentation gives credit where it is due
* (4) the authors are not held responsible for any defects
* or shortcomings in the software, or damages caused by it.
*
* There is no warranty for this software. Have a nice day.
*
* --
* Arnold Robbins
* arnold@skeeve.com
*
* 9menu.c
*
* This program puts up a window that is just a menu, and executes
* commands that correspond to the items selected.
*
* Initial idea: Arnold Robbins
* Version using libXg: Matty Farrow (some ideas borrowed)
* This code by: David Hogan and Arnold Robbins
*/
/*
* Heavily modified by Kris Maglione for use with wmii.
*/
#define IXP_NO_P9_
#define IXP_P9_STRUCTS
#include <fmt.h>
#include <ixp.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stuff/clientutil.h>
#include <stuff/util.h>
#include <stuff/x.h>
char version[] = "wmii9menu-"VERSION" "COPYRIGHT", ©1994 David Hogan, Arnold Robbins";
static Window* menuwin;
static CTuple cnorm;
static CTuple csel;
static Font* font;
static int wborder;
static char* initial = "";
static int cur;
static char** labels; /* list of labels and commands */
static char** commands;
static int numitems;
void usage(void);
void run_menu(void);
void create_window(void);
void size_window(int, int);
void redraw(int, int);
void warpmouse(int, int);
void
init_screens(void) {
Rectangle *rects;
Point p;
int i, n;
rects = xinerama_screens(&n);
p = querypointer(&scr.root);
for(i=0; i < n; i++) {
if(rect_haspoint_p(rects[i], p))
break;
}
if(i == n)
i = 0;
scr.rect = rects[i];
}
/* main --- crack arguments, set up X stuff, run the main menu loop */
int
main(int argc, char **argv)
{
static char *address;
char *cp;
int i;
ARGBEGIN{
case 'v':
lprint(1, "%s\n", version);
return 0;
case 'a':
address = EARGF(usage());
break;
case 'i':
initial = EARGF(usage());
break;
default:
usage();
}ARGEND;
if(argc == 0)
usage();
initdisplay();
xext_init();
init_screens();
create_window();
numitems = argc;
labels = emalloc(numitems * sizeof *labels);
commands = emalloc(numitems * sizeof *labels);
for(i = 0; i < numitems; i++) {
labels[i] = argv[i];
commands[i] = argv[i];
if((cp = strchr(labels[i], ':')) != nil) {
*cp++ = '\0';
commands[i] = cp;
}
if(strcmp(labels[i], initial) == 0)
cur = i;
}
client_init(address);
wborder = strtol(readctl("/ctl", "border "), nil, 10);
client_readconfig(&cnorm, &csel, &font);
run_menu();
XCloseDisplay(display);
return 0;
}
void
usage(void)
{
lprint(2, "usage: %s [-a <address>] [-i <arg>] <menitem>[:<command>] ...\n", argv0);
lprint(2, " %s -v\n", argv0);
exit(0);
}
enum {
MouseMask = ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
| PointerMotionMask,
MenuMask = MouseMask
| StructureNotifyMask
| ExposureMask
};
void
run_menu(void)
{
XEvent ev;
int i, old, wide, high;
high = labelh(font);
wide = 0;
for(i = 0; i < numitems; i++)
wide = max(wide, textwidth(font, labels[i]));
wide += font->height & ~1;
size_window(wide, high);
warpmouse(wide, high);
for(;;) {
XNextEvent(display, &ev);
switch (ev.type) {
default:
lprint(2, "%s: unknown ev.type %d\n", argv0, ev.type);
break;
case ButtonRelease:
i = ev.xbutton.y / high;
if(ev.xbutton.x < 0 || ev.xbutton.x > wide)
return;
else if(i < 0 || i >= numitems)
return;
lprint(1, "%s\n", commands[i]);
return;
case ButtonPress:
case MotionNotify:
old = cur;
cur = ev.xbutton.y / high;
if(ev.xbutton.x < 0 || ev.xbutton.x > wide)
cur = ~0;
if(cur == old)
break;
redraw(high, wide);
break;
case Expose:
redraw(high, wide);
break;
case MapNotify:
case ConfigureNotify:
case MappingNotify:
break;
}
}
}
void
create_window(void)
{
WinAttr wa = { 0 };
wa.override_redirect = true;
menuwin = createwindow(&scr.root, Rect(-1, -1, 0, 0),
scr.depth, InputOutput,
&wa, CWOverrideRedirect);
selectinput(menuwin, MenuMask);
mapwin(menuwin);
if(!grabpointer(menuwin, nil, 0, MouseMask))
fatal("Failed to grab the mouse\n");
}
void
size_window(int wide, int high)
{
Rectangle r;
Point p;
int h;
h = high * numitems;
r = Rect(0, 0, wide, h);
p = querypointer(&scr.root);
p.x -= wide / 2;
p.x = max(p.x, scr.rect.min.x);
p.x = min(p.x, scr.rect.max.x - wide);
p.y -= cur * high + high / 2;
p.y = max(p.y, scr.rect.min.y);
p.y = min(p.y, scr.rect.max.y - h);
reshapewin(menuwin, rectaddpt(r, p));
setborder(menuwin, 1, &cnorm.border);
}
void
redraw(int high, int wide)
{
Rectangle r;
int i;
r = Rect(0, 0, wide, high);
for(i = 0; i < numitems; i++) {
r = rectsetorigin(r, Pt(0, i * high));
fillstring(menuwin, font, r, Center, labels[i], (cur == i ? &csel : &cnorm), 0);
}
}
void
warpmouse(int wide, int high)
{
Point p;
int offset;
/* move tip of pointer into middle of menu item */
offset = labelh(font) / 2;
offset += 6; /* fudge factor */
p = Pt(wide / 2, cur*high - high/2 + offset);
p = addpt(p, menuwin->r.min);
warppointer(p);
}
|
Added config.mk.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | # Customize below to fit your system # Paths PREFIX = /usr/local BIN = $(PREFIX)/bin MAN = $(PREFIX)/share/man DOC = $(PREFIX)/share/doc/wmii ETC = $(PREFIX)/etc LIBDIR = $(PREFIX)/lib INCLUDE = $(PREFIX)/include PYPREFIX = --prefix=$(PREFIX) # Includes and libs INCLUDES = -I. -I$(ROOT)/include -I$(INCLUDE) -I/usr/include LIBS = -L$(ROOT)/lib -L/usr/lib TERMINAL = xterm # Flags include $(ROOT)/mk/gcc.mk CFLAGS += -Os $(DEBUGCFLAGS) LDFLAGS += -g # Compiler, Linker. Linker should usually *not* be ld. CC = cc -c LD = cc # Archiver AR = ar crs PYTHON = python X11PACKAGES = x11 xinerama xrender xrandr INCX11 = $$(pkg-config --cflags $(X11PACKAGES)) LIBIXP = $(LIBDIR)/libixp.a # Enable RTLD. Only necessary for Xft support. CFLAGS += -DHAVE_RTLD LDFLAGS += -ldl # Comment this out on BSD systems. SOLDFLAGS += $(LDFLAGS) SHARED = -shared -Wl,-soname=$(SONAME) STATIC = -static # Your make shell. By default, the first found of /bin/dash, /bin/ksh, # /bin/sh. Except with bsdmake, which assumes /bin/sh is sane. bash and zsh # are painfully slow, and should be avoided. #BINSH = /bin/ash ## Operating System Configurations # KenCC # Note: wmii *must* always compile under KenCC. It's vital for # argument checking in formatted IO, and similar diagnostics. #CFLAGS = -wF #STATIC = # Implied #CC=pcc -c #LD=pcc # Darwin #STATIC = # Darwin doesn't like static linking #SHARED = -dynamiclib #SOEXT = dylib # Solaris #SHELL = /bin/bash #CFLAGS = -fast $(INCS) #LDFLAGS = $(LIBS) -R$(PREFIX)/lib -lsocket -lnsl #CFLAGS += -xtarget=ultra |
Added debian/changelog.
> > > > > | 1 2 3 4 5 | wmii-hg (2728) unstable; urgency=low * Remove long deprecated special treatment of the '!' tag. -- Kris Maglione <kris@suckless.org> Tue, 15 Jun 2010 15:13:12 -0400 |
Added debian/compat.
> | 1 | 7 |
Added debian/control.
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Source: wmii-hg
Section: x11
Priority: optional
Maintainer: Kris Maglione <jg@suckless.org>
Build-Depends: libixp-hg, dash, python, libx11-dev, libxft-dev, libxext-dev, libxinerama-dev, libxrandr-dev, x11proto-xext-dev, quilt, debhelper (>= 4.0)
Standards-Version: 3.8.4
Homepage: http://wmii.suckless.org/
Package: wmii-hg
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, dash (>= 0.1)
Conflicts: wmii, wmii2
Replaces: wmii, wmii2
Provides: x-window-manager
Description: lightweight tabbed and tiled X11 window manager
wmii is a dynamic window manager for X11, which is highly customizable and
usable with keyboard and mouse. It supports conventional, tabbed and tiled
window management with low memory usage. It is highly modularized and uses an
inter-process communication interface which is oriented on the 9p protocol of
plan9.
|
Added debian/copyright.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | Debian packaging based on that of Daniel Baumann <daniel.baumann@panthera-systems.net>, now maintained by the upstream author. It was downloaded from <http://wmii.suckless.org/>. Upstream Author: Kris Maglione <jg@suckless.org> © 2006-2010 Kris Maglione <maglione.k at Gmail> © 2003-2006 Anselm R. Garbe <garbeam at suckless dot org> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Original debian packaging is (C) 2005-2007, Daniel Baumann <daniel@debian.org> and is licensed under the GPL, see `/usr/share/common-licenses/GPL'. Portions by Kris Maglione are in the Public Domain. |
Added debian/docs.
> > | 1 2 | FAQ README |
Added debian/file/wmii.desktop.
> > > > > > > | 1 2 3 4 5 6 7 | [Desktop Entry] Encoding=UTF-8 Name=wmii Comment=wmii pre-3.6 Development Snapshot Exec=wmii Icon=wmii.png Type=XSession |
Added debian/rules.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#!/usr/bin/make -f
PACKAGE=$(shell awk 'NR == 1 { print $$2 }' debian/control)
FLAGS = DESTDIR=$(CURDIR)/debian/$(PACKAGE)/ \
PREFIX=/usr \
ETC=/etc/X11 \
STATIC= \
TERMINAL=x-terminal-emulator
%:
dh $@
override_dh_installwm:
dh_installwm --priority=60
override_dh_compress:
dh_compress -X.pdf
override_dh_auto_build:
$(MAKE) $(FLAGS) all
override_dh_auto_install:
$(MAKE) $(FLAGS) install
rm debian/$(PACKAGE)/usr/share/doc/wmii/LICENSE
install -D -m0644 img/icon.png debian/$(PACKAGE)/usr/share/icons/wmii.png
install -D -m0644 debian/file/wmii.desktop debian/$(PACKAGE)/usr/share/xsessions/wmii.desktop
.depend:
true
|
Added debian/wmii.menu.
> > > | 1 2 3 | ?package(wmii):needs="wm" section="WindowManagers"\ title="wmii" longtitle="wmii pre-3.6 Development Snapshot"\ command="/usr/bin/wmii" |
Added debian/wmii.wm.
> | 1 | /usr/bin/wmii |
Added doc/Makefile.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | ROOT=.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk TARG = wmii.pdf all: $(TARG) install: $(TARG:.pdf=.install) uninstall: $(TARG:.pdf=.uninstall) clean:; true |
Added doc/customizing.tex.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 |
\chapter{Customizing \wmii}
There are several configuration schemes available for \wmii. If
you're only looking to add basic key bindings, status monitors,
\emph{et cetera}, you should have no trouble modifying the stock
configuration for your language of choice. If you're looking for
deeper knowledge of \wmii's control interface though, this
section is for you. We'll proceed by building a configuration
script in \POSIX\ |sh| syntax and then move on to a discussion
of the higher level constructs in the stock configuration
scripts.
For the purposes of pedagogy, we'll construct the script in the
literate programming style of Knuth, whereby we construct the
code in fragments and explain each one in detail. For your
convenience, each fragment name is linked to its definition.
\section{Events}
The \wmii\ control interface is largely event driven. Each event
is represented by a single, plain-text line written to the
|/event| file. You can think of this file as a named pipe. When
reading it, you won't receive an EOF\footnote{End of File} until
\wmii\ exits. Moreover, any lines written to the file will be
transmitted to everyone currently reading from it. Notable
events include key presses, the creation and destruction of
windows, and changes of focus and views.
We'll start building our configuration with an event processing
framework:
\begin{Fragment}{Event Loop}
# Broadcast a custom event
wmiir xwrite /event Start wmiirc
# Turn off globbing
set -f
# Open /event for reading
wmiir read /event |
# Read the events line by line
while read line; do
# Split the line into words, store in $@
set -- $line
event=$1; shift
line = "$(echo $line | sed ‘s/^[^ ]* //’ | tr -d ‘\n’)"
# Process the event
case $event in
Start) # Quit when a new instance starts
[ $1 = wmiirc ] && exit;;
«Event Handlers»
esac
done
\end{Fragment}
Now, we need to consider which types of events we'll need to
handle:
\begin{Fragment}{Event Handlers}
«View Button Events»
«Urgency Events»
«Unresponsive Clients»
«Notice Events»
«Key Events»
«Client Menu Events»
«Tag Menu Events»
\end{Fragment}
\section{Bar Items}
The bar is described by the files in the two directories |/lbar/| and
|/rbar/| for buttons on the left and right side of the bar,
respectively. The files act as control files (section
\ref{sec:controlfiles}) with the contents:
\begin{code}
color ‹Color Tuple›
label ‹Label›
\end{code}
A ‹Color Tuple› is defined as:
\begin{code}
‹Color Tuple› ≔ ‹foreground color› ‹background color› ‹border color›
‹* Color› ≔ ‹RGB color› | ‹RGBA color›
‹RGB color› ≔ #‹6 character RGB hex color code›
‹RGBA color› ≔ rgba:‹red›/‹green›/‹blue›/‹alpha›
\end{code}
\noindent
where all of the colors are represented as lowercase,
hexidecimal values. In the case of RGBA colors, they may be 1--4
characters long, though they will be standardized internally to
2 characters.
\medskip
Let's define our basic theme information now:
\begin{Fragment}{Theme Definitions}
normcolors=‘#000000 #c1c48b #81654f’
focuscolors=‘#000000 #81654f #000000’
background=‘#333333’
font=‘drift,-*-fixed-*-*-*-*-9-*-*-*-*-*-*-*’
\end{Fragment}
\subsection{View Buttons}
With a basic understanding of bar items in mind, we can write
our view event handlers:
\index{events!CreateTag}
\index{events!DestroyTag}
\index{events!FocusTag}
\index{events!UnfocusTag}
\begin{Fragment}{View Button Events}
CreateTag) # CreateTag ‹Tag Name›
echo $normcolors $1 | wmiir create /lbar/$1;;
DestroyTag) # DestroyTag ‹Tag Name›
wmiir rm /lbar/$1;;
FocusTag) # FocusTag ‹Tag Name›
wmiir xwrite /lbar/$1 $focuscolors $1;;
UnfocusTag) # UnfocusTag ‹Tag Name›
wmiir xwrite /lbar/$1 $normcolors $1;;
\end{Fragment}
\subsection{Urgency}
\index{events!UrgentTag|(}
\index{events!NotUrgentTag|(}
Windows can specify that they require attention, and in X11
parlance, this is called urgency\footnote{\ICCCM{4.1.2.4}}. When
a window requests attention as such, or declares that it's been
satisfied, \wmii\ broadcasts an event for the client and an
event for each view that it belongs to. It also fills in the
layout box of any client deemed urgent. It's the job of a script
to decide how to handle urgency events above and beyond that
basic measure. The standard scripts simply mark urgent views
with an asterisk:
\begin{Fragment}{Urgency Events}
# The urgency events are ‘Client’ events when the program
# owning the window sets its urgency state. They're ‘Manager’
# events when wmii or the wmii user sets the state.
UrgentTag) # UrgentTag ‹‘Client’ or ‘Manager’› ‹Tag Name›
wmiir xwrite /lbar/$2 $2;;
NotUrgentTag) # NotUrgentTag ‹‘Client’ or ‘Manager’› ‹Tag Name›
wmiir xwrite /lbar/$2 $2;;
\end{Fragment}
\index{events!UrgentTag|)}
\index{events!NotUrgentTag|)}
\subsection{Notices}
The standard scripts provide a custom Notice event for
displaying status information. The events appear in the long bar
between the left and right sides for five seconds.
\begin{Fragment}{Notice Events}
Notice)
wmiir xwrite /rbar/!notice $line
kill $xpid 2>/dev/null # Let's hope this isn't reused...
{ sleep 5; wmiir xwrite /rbar/!notice ‘ ’; } &
xpid = $!;;
\end{Fragment}
\section{Keys}
\label{sec:keybindings}
\index{key bindings}
\index{filesystem!/!keys}
\index{filesystem!/!event}
Now to the part you've no doubt been waiting for: binding keys.
When binding keys, you need to be aware of two files, |/keys|
and |/event|. The former defines which keys \wmii\ needs to
grab, and the latter broadcasts the events when they're pressed.
Key names are specified as a series of modifiers followed by a
key name, all separated by hyphens. Valid modifier names are
|Control|, |Shift|, |Mod1| (usually Alt), |Mod2|, |Mod3|, |Mod4|
(usually the Windows® key), and |Mod5|. Modifier keys can be
changed via |xmodmap(1)|, the details of which are beyond the
scope of this document.
Key names can be detected by running |xev| from a
terminal, pressing the desired key, and looking at the output
(it's in the parentheses, after the keysym). Or, more simply,
you can run the \man 1 {wikeyname} utility bundled with \wmii\
and press the key you wish to bind.
Examples of key bindings:
\begin{description}
\item[Windows® key + Capital A] |Mod4-Shift-A|
\item[Control + Alt + Space] |Mod1-Control-Space|
\end{description}
Now, let's bind the keys we plan on using:
\begin{Fragment}{Bind Keys}
{
cat <<!
Mod4-space
Mod4-d
Mod4-s
Mod4-m
Mod4-a
Mod4-p
Mod4-t
Mod4-Return
Mod4-Shift-space
Mod4-f
Mod4-Shift-c
Mod4-Shift-t
Mod4-h
Mod4-j
Mod4-k
Mod4-l
Mod4-Shift-h
Mod4-Shift-j
Mod4-Shift-k
Mod4-Shift-l
!
for i in 1 2 3 4 5 6 7 8 9 0; do
echo Mod4-$i
echo Mod4-Shift-$i
done
} | wmiir write /keys
\end{Fragment}
and lay a framework for processing their events:
\begin{Fragment}{Key Events}
Key) # Key ‹Key Name›
case $1 in
«Motion Keys»
«Client Movement Keys»
«Column Mode Keys»
«Client Command Keys»
«Command Execution Keys»
«Tag Selection Keys»
«Tagging Keys»
esac;;
\end{Fragment}
\section{Click Menus}
Sometimes, you have your hand on the mouse and don't want to
reach for the keyboard. To help cope, \wmii\ provides a
mouse-driven, single-click menu. The default configuration uses
it for client and tag menus.
\begin{Fragment}{Click Menu Initialization}
clickmenu() {
if res=$(wmii9menu -- “$@”); then eval “$res”; fi
}
\end{Fragment}
\section{Control Files}
\label{sec:controlfiles}
Several directories including the root, have control files,
named |ctl|. These files are used to control the object (e.g., a
client or tag) represented by the directory. Each line of the
file, with the possible section of the first, represents a
control variable and its value. In the case of all but the root
|/ctl| file, the first line represents the id of the directory.
In the case of |/tag/foo/ctl|, for instance, the first line
should read |foo|. This is useful when dealing with the special
|sel/| directories. For instance, when |foo| is the selected
tag, the special |/tag/sel| directory is a link to |/tag/foo|,
and the first line of |/tag/sel/ctl| will read |foo|, just as
if you'd accessed |/tag/foo/ctl| directly.
The rest of the lines, the control variables, can be modified by
writing new values to the control file. For instance, if a
client is fullscreen, its control file will contain the line:
\begin{code}
fullscreen on
\end{code}
\noindent To restore the client from fullscreen, either of the
following lines may be written to its control file:
\begin{code}
fullscreen off
fullscreen toggle
\end{code}
When next read, the |fullscreen on| line will have been replaced
with |fullscreen off|. No care need be taken to preserve the
other contents of the file. They're generated anew each time
it's read.
\section{Clients}
\def\clientlabel{/client/$\langle\mathit{client}\rangle$/}
\index{filesystem!/client/*/@\clientlabel|(}
Clients are represented by directories under the |/client/|
tree. Subdirectory names represent the client's X11 window ID.
The special |sel/| directory represents the currently selected
client. The files in these directories are:
\begin{description}
\item[ctl] The client's control file, containing the following
properties:
\index{filesystem!/client/*/@\clientlabel!ctl}
\begin{description}
\item[allow] The set of unusual actions the client is
allowed to perform, in the same format as the tag set.
\begin{description}
\item[activate] The client is allowed to activate
itself—that is, focus its window and, as the case may
require, uncollapse it and select a tag it resides on.
This flag must be set on a client if you wish it able to
activate itself from the system tray.
\end{description}
\item[floating] Defines whether this client is likely to
float when attached to a new view. May be |on|, |off|,
|always|, or |never|. Ordinarilly, the value changes
automatically whenever the window is moved between the
floating and managed layers. However, setting a value of
|always| or |never| overrides this behavior.
\item[fullscreen] The client's fullscreen state. When
|on|, the client is displayed fullscreen on all of its
views. Possible values are |on|, |off|, and |toggle|.
\item[group] The client's group ID, or |0| if not part of
a group. Clients tend to open with the same tags and in
the same columns as the last active member of their
group. Setting this property is only useful when done
via the rules file.
\item[kill] When written, the window is closed politely,
if possible.
\item[pid] Read-only value of the PID of the program that
owns the window, if the value is available and the
process is on the same machine as wmii.
\item[slay] When written, the client is disconnected
peremptorily. If the client's PID is available and the
process is the same machine as wmii, its parent process
is killed
\item[tags] The client's tags. The same as the tags file.
\item[urgent] The client's urgency state. When |on|, the
client's layout box will be highlighted. Possible values
are |on|, |off|, and |toggle|.
\end{description}
\item[props] The client's window class (the X11
|WM_CLASS|\footnote{\ICCCM{4.1.2.5}}
property) and title string, separated by colons. This file
is not writable.
\index{filesystem!/client/*/@\clientlabel!props}
\item[label] The client's window title. May be written to
change the client's title.
\index{filesystem!/client/*/@\clientlabel!label}
\item[tags]
\index{filesystem!/client/*/@\clientlabel!tags}
The client's tags. Tag names are separated by |+|, |-|, or
|^| signs. Tag names which directly follow a |+| sign are
added, while whose following a |-| sign are removed and
those following a |^| are toggled. If the value written
begins with one of these characters, the value is appended
to the clients tags rather than replacing them.
Tags formatted as |/‹regex›/| are treated as regular
expressions, which place the client on any extant matching
tag\footnote{While a client with a regex tag will always
appear in all matching views, it will not keep those views
in existence. When the last client explicitly tagged with a
view is removed, the view is deleted as soon as it becomes
inactive.}. Regular expression tags which directly follow a
minus sign are treated as exclusion expressions. For
example, the tag string |+/foo/-/food/| will match the tag
|foobar|, but not the tag |foodstand|.
\end{description}
\index{filesystem!/client/*/@\clientlabel|)}
\subsection{Key Bindings}
To control clients, we'll add the following key bindings:
\begin{Fragment}{Client Command Keys}
Mod4-Shift-c) wmiir xwrite /client/sel/ctl kill;;
Mod4-f) wmiir xwrite /client/sel/ctl Fullscreen toggle;;
\end{Fragment}
And to manage their tags, we'll need:
\begin{Fragment}{Tagging Keys}
Mod4-Shift-t)
# Get the selected client's id
c=$(wmiir read /client/sel/ctl | sed 1q)
# Prompt the user for new tags
tags=$(wmiir ls /tag | sed ‘s,/,,; /^sel$/d’ | wimenu)
# Write them to the client
wmiir xwrite /client/$c/tags $tag;;
Mod4-Shift-[0-9])
wmiir xwrite /client/sel/tags ${1##*-};;
\end{Fragment}
\subsection{Click Menus}
\index{events!ClientMouseDown}
\begin{Fragment}{Client Menu Events}
ClientMouseDown) # ClientMouseDown ‹Client ID› ‹Button›
[ $2 = 3 ] && clickmenu \
“Delete:wmiir xwrite /client/$1/ctl kill” \
“Kill: wmiirxwrite /client/$1/ctl slay” \
“Fullscreen:wmiir xwrite /client/$1/ctl fullscreen on”
\end{Fragment}
\subsection{Unresponsive Clients}
\index{events!UnresponsiveClient|(}
When \wmii\ tries to close a window, it waits 8 seconds for the
client to respond, and then lets its scripts decide what to do
with it. The stock scripts prompt the user for input:
\begin{Fragment}{Unresponsive Clients}
UnresponsiveClient) # UnresponsiveClient ‹Client ID›
{
# Use wihack to make the xmessage a transient window of
# the problem client. This will force it to open in the
# floaing layer of whatever views the client is attached to
resp=$(wihack -transient $1 \
xmessage -nearmouse -buttons Kill,Wait -print \
“The following client is not responding.” \
“What would you like to do?$(echo)” \
$(wmiir read /client/$1/label))
[ $resp = Kill ] && wmiir xwrite /client/$1/ctl slay
} &;;
\end{Fragment}
\index{events!UnresponsiveClient|)}
\section{Views}
\def\taglabel{/tag/$\langle\mathit{tag}\rangle$/}
\index{filesystem!/tag/*/@\taglabel|(}
Views are represented by directories under the |/tag/| tree. The
special |sel/| directory represents the currently selected
client. The |sel| tag is treated similarly elsewhere. The files
in these directories are:
\begin{description}
\item[ctl]
The view's control file. The properties are:
\index{filesystem!/tag/*/@\taglabel!ctl|(}
\begin{description}
\item[select ‹Area›] Select the column ‹Area›, where
‹Area› is a 1-based column index, or |~| for the floating
area. It may be optionally preceded by ‹Screen›|:|, where
‹Screen› is a 0-based Xinerama screen index, or “sel”. When
omitted, ‹Screen› defaults to 0, the primary screen.
\item[select ‹Area› ‹Client Index›] Select the column ‹Area›, and
the ‹Client Index›th client.
\item[select client ‹Client ID›] Select the client with the
X11 window ID ‹Client ID›.
\item[select ‹Direction›]
Select the client in ‹Direction› where ‹Direction› may be
one of ‹up $\wedge$ down $\wedge$ left $\wedge$ right›.
\item[send client ‹Client ID› ‹Area›] Send ‹Client ID› to
‹Area›. ‹Area› may be |sel| for the selected area, and
|client ‹Client ID›| may be |sel| for the currently selected
client.
\item[send client ‹Client ID› ‹Direction›]
Send ‹Client ID› to a column or position in its column in
the given direction.
\item[send client ‹Client ID› toggle] If ‹Client ID› is
floating, send it to the managed layer. If it's managed,
send it to the floating layer.
\item[swap client ‹Client ID› \ldots] The same as the |send|
commands, but swap ‹Client ID› with the client at the given
location.
\item[colmode ‹Area› ‹Mode›] Set ‹Area›'s mode to ‹Mode›,
where ‹Mode› is a string of values similar to tag
specifications. Values which may be added and removed are as
follows for managed areas:
\begin{description}
\item[stack] One and only one client in the area is
uncollapsed at any given time. When a new client is
selected, it is uncollapsed and the previously selected
client is collapsed.
\item[max] Collapsed clients are hidden from view
entirely. Uncollapsed clients display an indicator
{\it‹n›/‹m›}, where ‹m› is the number of collapsed
clients directly above and below the client, plus one,
and ‹n› is the client's index in the stack.
\item[default] Like subtracting the stack mode, but all
clients in the column are given equal height.
\end{description}
For the floating area, the values are the same, except that
in |max| mode, floating clients are hidden when the managed
layer is selected.
\item[grow ‹Frame› ‹Direction› {[‹Amount›]}] Grow ‹Frame› in
the given direction, by ‹Amount›. ‹Amount› may be any
integer, positive or negative. If suffixed with |px|,
it specifies an exact pixel amount, otherwise it specifies a
“reasonable increment”. Defaults to 1.
‹Frame› may be one of:
\begin{itemize}
\item client ‹Client ID›
\item ‹Area› ‹Client Index›
\end{itemize}
\item[nudge ‹Frame› ‹Direction› {[‹Amount›]}] Like
|grow|, but move the client in ‹Direction› instead of
resizing it.
\end{description}
\index{filesystem!/tag/*/@\taglabel!ctl|)}
\end{description}
\index{filesystem!/tag/*/@\taglabel|)}
\subsection{Key Bindings}
We'll use the following key bindings to interact with views:
\begin{Fragment}{Motion Keys}
Mod4-h) wmiir xwrite /tag/sel/ctl select left;;
Mod4-l) wmiir xwrite /tag/sel/ctl select right;;
Mod4-k) wmiir xwrite /tag/sel/ctl select up;;
Mod4-j) wmiir xwrite /tag/sel/ctl select down;;
Mod4-space) wmiir xwrite /tag/sel/ctl select toggle;;
\end{Fragment}
\begin{Fragment}{Client Movement Keys}
Mod4-Shift-h) wmiir xwrite /tag/sel/ctl send sel left;;
Mod4-Shift-l) wmiir xwrite /tag/sel/ctl send sel right;;
Mod4-Shift-k) wmiir xwrite /tag/sel/ctl send sel up;;
Mod4-Shift-j) wmiir xwrite /tag/sel/ctl send sel down;;
Mod4-Shift-space) wmiir xwrite /tag/sel/ctl send sel toggle;;
\end{Fragment}
\begin{Fragment}{Column Mode Keys}
Mod4-d) wmiir xwrite /tag/sel/ctl colmode sel -stack-max;;
Mod4-s) wmiir xwrite /tag/sel/ctl colmode sel stack-max;;
Mod4-m) wmiir xwrite /tag/sel/ctl colmode sel stack+max;;
\end{Fragment}
\subsection{Click Menus}
\index{events!LeftBarMouseDown}
\begin{Fragment}{Tag Menu Events}
LeftBarMouseDown) # LeftBarMouseDown ‹Button› ‹Bar Name›
[ $1 = 3 ] && clickmenu \
“Delete:delete_view $2”
\end{Fragment}
\section{Command and Program Execution}
Perhaps the most important function we need to provide for is
the execution of programs. Since \wmii\ users tend to use
terminals often, we'll add a direct shortcut to launch one.
Aside from that, we'll add a menu to launch arbitrary programs
(with completions) and a separate menu to launch wmii specific
commands.
We use |wmiir setsid| to launch programs with their own session
IDs to prevent untoward effects when this script dies.
\begin{Fragment}{Command Execution Initialization}
terminal() { wmiir setsid xterm “$@” }
proglist() {
IFS=:
wmiir proglist $1 | sort | uniq
unset IFS
}
\end{Fragment}
\subsection{Key Bindings}
\begin{Fragment}{Command Execution Keys}
Mod4-Return) terminal & ;;
Mod4-p) eval exec wmiir setsid “$(proglist $PATH | wimenu)” &;;
Mod4-a) {
set -- $(proglist $WMII_CONFPATH | wimenu)
which=$(which which)
prog=$(PATH=$WMII_CONFPATH $which $1); shift
eval exec $prog “$@”
} &;;
\end{Fragment}
\section{The Root}
The root filesystem contains the following:
\index{!filesystem!/|(}
\begin{description}
\item[ctl] The control file. The properties are:
\index{filesystem!/!ctl}
\begin{description}
\item[bar on ‹top $\wedge$ bottom›] Controls where the bar
is shown.
\item[border] The border width, in pixels, of floating
clients.
\item[colmode ‹Mode›] The default column mode for newly
created columns.
\item[focuscolors ‹Color Tuple›] The colors of focused
clients.
\item[normcolors ‹Color Tuple›] The colors of unfocused
clients and the default color of bar buttons.
\item[font ‹Font›] The font used throughout \wmii. If
prefixed with |xft:|, the Xft font renderer is used, and
fonts may be antialiased. Xft font names follow the
fontconfig formula. For instance, 10pt, italic Lucida
Sans would be specified as
\begin{code}
xft:Lucida Sans-10:italic
\end{code}
See \man 1 {fc-match}.
\item[grabmod ‹Modifier Keys›] The key which must be
pressed to move and resize windows with the mouse
without clicking hot spots.
\item[incmode ‹Mode›] Controls how X11 increment hints are
handled in managed mode. Possible values are:
\begin{description}
\item[ignore] Increment hints are ignored entirely.
Clients are stretched to fill their full allocated
space.
\item[show] Gaps are shown around managed client
windows when their increment hints prevent them from
filling their entire allocated space.
\item[squeeze] When increment hints cause gaps to show
around clients, \wmii\ will try to adjust the sizes
of the clients in the column to minimize lost space.
\end{description}
\item[view ‹Tag›] Change the currently visible view.
\item[exec ‹Command›] Replaces this \wmii\ instance with
‹Command›. ‹Command› is split according to rc quoting
rules, and no expansion occurs. If the command fails to
execute, \wmii\ will respawn.
\item[spawn ‹Command›] Spawns ‹Command› as it would spawn
|wmiirc| at startup. If ‹Command› is a single argument
and doesn't begin with |/| or |./|,%
\hskip 1ex|$WMII_CONF|\-|PATH| is
searched for the executable. Otherwise, the whole
argument is passed to the shell for evaluation.
\end{description}
\item[keys] The global keybindings. See section \ref{sec:keybindings}.
\index{filesystem!/!keys|primary}
\item[event] The global event feed. See section \ref{sec:keybindings}.
\index{filesystem!/!event|primary}
\item[colrules]
\index{filesystem!/!colrules}
The |/colrules| file contains a list of
rules which affect the width of newly created columns.
Rules have the form:
\begin{quote}\texttt{
/‹regex›/ -> ‹width›{\color{gray}[}+‹width›{\color{gray}]*}}
\end{quote}
Where,
\begin{code}
‹width› ≔ ‹percent of screen› | ‹pixels›px
\end{code}
When a new column, ‹n›, is created on a view whose name
matches ‹regex›, it is given the ‹n›th supplied ‹width›.
If there is no ‹n›th width, it is given
$1/\mbox{‹ncol›th}$ of the screen.
\item[rules]
\index{filesystem!/!rules}
The |/rules| file contains a list of
rules similar to the colrules. These rules set
properties for a client when it is created.
Rules are specified:
\begin{quote}\texttt{
/‹regex›/ -> ‹key›{\color{gray}=}‹value› {\color{gray}\ldots}}
\end{quote}
When a client's ‹name›:‹class›:‹title› matches
‹regex›, the matching rules are applied. For each
‹key›=‹value› pair, the |ctl| file property matching
‹key› is set to ‹value›. Additionally, the following
keys are accepted and have special meaning:
\begin{description}
\item[continue]
Normally, when a matching rule is encountered,
rule matching stops. When the continue key is
provided (with any value), matching continues at
the next rule.
\item[force-tags]
Like tags, but overrides any settings obtained
obtained from the client's group or from the
|_WMII_TAGS| window property.
\end{description}
\end{description}
\index{!filesystem!/|)}
\subsection{Configuration}
We'll need to let \wmii\ know about our previously defined theme
information:
\begin{Fragment}{Configuration}
«Theme Definitions»
xsetroot -solid $background
wmiir write /ctl <<!
border 2
focuscolors $focuscolors
normcolors $normcolors
font $font
grabmod Mod4
!
\end{Fragment}
\subsection{Key Bindings}
And we need a few more key bindings to select our views:
\begin{Fragment}{Tag Selection Keys}
Mod4-t)
# Prompt the user for a tag
tags=$(wmiir ls /tag | sed ‘s,/,,; /^sel$/d’ | wimenu)
# Write it to the filesystem.
wmiir xwrite /ctl view $tags;;
Mod4-[0-9])
wmiir xwrite /ctl view ${1##*-};;
\end{Fragment}
\section{Tieing it All Together}
\begin{code}
#!/bin/sh
«Click Menu Initialization»
«Command Execution Initialization»
«Configuration»
«Bind Keys»
«Event Loop»
\end{code}
\section{The End Result}
For clarity, here is the end result:
\begin{code}
#!/bin/sh
# «Click Menu Initialization»
clickmenu() {
if res=$(wmii9menu -- “$@”); then eval “$res”; fi
}
# «Command Execution Initialization»
terminal() { wmiir setsid xterm “$@” }
proglist() {
IFS=:
wmiir proglist $1 | sort | uniq
unset IFS
}
# «Configuration»
# «Theme Definitions»
normcolors=‘#000000 #c1c48b #81654f’
focuscolors=‘#000000 #81654f #000000’
background=‘#333333’
font=‘drift,-*-fixed-*-*-*-*-9-*-*-*-*-*-*-*’
xsetroot -solid $background
wmiir write /ctl <<!
border 2
focuscolors $focuscolors
normcolors $normcolors
font $font
grabmod Mod4
!
# «Bind Keys»
{
cat <<!
Mod4-space
Mod4-d
Mod4-s
Mod4-m
Mod4-a
Mod4-p
Mod4-t
Mod4-Return
Mod4-Shift-space
Mod4-f
Mod4-Shift-c
Mod4-Shift-t
Mod4-h
Mod4-j
Mod4-k
Mod4-l
Mod4-Shift-h
Mod4-Shift-j
Mod4-Shift-k
Mod4-Shift-l
!
for i in 1 2 3 4 5 6 7 8 9 0; do
echo Mod4-$i
echo Mod4-Shift-$i
done
} | wmiir write /keys
# «Event Loop»
# Broadcast a custom event
wmiir xwrite /event Start wmiirc
# Turn off globbing
set -f
# Open /event for reading
wmiir read /event |
# Read the events line by line
while read line; do
# Split the line into words, store in $@
set -- $line
event=$1; shift
line = "$(echo $line | sed ‘s/^[^ ]* //’ | tr -d ‘\n’)"
# Process the event
case $event in
Start) # Quit when a new instance starts
[ $1 = wmiirc ] && exit;;
# «Event Handlers»
# «View Button Events»
CreateTag) # CreateTag ‹Tag Name›
echo $normcolors $1 | wmiir create /lbar/$1;;
DestroyTag) # DestroyTag ‹Tag Name›
wmiir rm /lbar/$1;;
FocusTag) # FocusTag ‹Tag Name›
wmiir xwrite /lbar/$1 $focuscolors $1;;
UnfocusTag) # UnfocusTag ‹Tag Name›
wmiir xwrite /lbar/$1 $normcolors $1;;
# «Urgency Events»
# The urgency events are ‘Client’ events when the program
# owning the window sets its urgency state. They're ‘Manager’
# events when wmii or the wmii user sets the state.
UrgentTag) # UrgentTag ‹‘Client’ or ‘Manager’› ‹Tag Name›
wmiir xwrite /lbar/$2 $2;;
NotUrgentTag) # NotUrgentTag ‹‘Client’ or ‘Manager’› ‹Tag Name›
wmiir xwrite /lbar/$2 $2;;
# «Unresponsive Clients»
UnresponsiveClient) # UnresponsiveClient ‹Client ID›
{
# Use wihack to make the xmessage a transient window of
# the problem client. This will force it to open in the
# floaing layer of whatever views the client is attached to
resp=$(wihack -transient $1 \
xmessage -nearmouse -buttons Kill,Wait -print \
“The following client is not responding.” \
“What would you like to do?$(echo)” \
$(wmiir read /client/$1/label))
[ $resp = Kill ] && wmiir xwrite /client/$1/ctl slay
} &;;
# «Notice Events»
Notice)
wmiir xwrite /rbar/!notice $line
kill $xpid 2>/dev/null # Let's hope this isn't reused...
{ sleep 5; wmiir xwrite /rbar/!notice ‘ ’; } &
xpid = $!;;
# «Key Events»
Key) # Key ‹Key Name›
case $1 in
# «Motion Keys»
Mod4-h) wmiir xwrite /tag/sel/ctl select left;;
Mod4-l) wmiir xwrite /tag/sel/ctl select right;;
Mod4-k) wmiir xwrite /tag/sel/ctl select up;;
Mod4-j) wmiir xwrite /tag/sel/ctl select down;;
Mod4-space) wmiir xwrite /tag/sel/ctl select toggle;;
# «Client Movement Keys»
Mod4-Shift-h) wmiir xwrite /tag/sel/ctl send sel left;;
Mod4-Shift-l) wmiir xwrite /tag/sel/ctl send sel right;;
Mod4-Shift-k) wmiir xwrite /tag/sel/ctl send sel up;;
Mod4-Shift-j) wmiir xwrite /tag/sel/ctl send sel down;;
Mod4-Shift-space) wmiir xwrite /tag/sel/ctl send sel toggle;;
# «Column Mode Keys»
Mod4-d) wmiir xwrite /tag/sel/ctl colmode sel -stack-max;;
Mod4-s) wmiir xwrite /tag/sel/ctl colmode sel stack-max;;
Mod4-m) wmiir xwrite /tag/sel/ctl colmode sel stack+max;;
# «Client Command Keys»
Mod4-Shift-c) wmiir xwrite /client/sel/ctl kill;;
Mod4-f) wmiir xwrite /client/sel/ctl fullscreen toggle;;
# «Command Execution Keys»
Mod4-Return) terminal & ;;
Mod4-p) eval exec wmiir setsid “$(proglist $PATH | wimenu)” &;;
Mod4-a) {
set -- $(proglist $WMII_CONFPATH | wimenu)
prog=$(PATH=$WMII_CONFPATH which $1); shift
eval exec $prog “$@”
} &;;
# «Tag Selection Keys»
Mod4-t)
# Prompt the user for a tag
tags=$(wmiir ls /tag | sed ‘s,/,,; /^sel$/d’ | wimenu)
# Write it to the filesystem.
wmiir xwrite /ctl view $tag;;
Mod4-[0-9])
wmiir xwrite /ctl view ${1##*-};;
# «Tagging Keys»
Mod4-Shift-t)
# Get the selected client's id
c=$(wmiir read /client/sel/ctl | sed 1q)
# Prompt the user for new tags
tags=$(wmiir ls /tag | sed ‘s,/,,; /^sel$/d’ | wimenu)
# Write them to the client
wmiir xwrite /client/$c/tags $tag;;
Mod4-Shift-[0-9])
wmiir xwrite /client/sel/tags ${1##*-};;
esac;;
# «Client Menu Events»
ClientMouseDown) # ClientMouseDown ‹Client ID› ‹Button›
[ $2 = 3 ] && clickmenu \
“Delete:wmiir xwrite /client/$1/ctl kill” \
“Kill:wmiir xwrite /client/$1/ctl slay” \
“Fullscreen:wmiir xwrite /client/$1/ctl fullscreen on”
# «Tag Menu Events»
LeftBarMouseDown) # LeftBarMouseDown ‹Button› ‹Bar Name›
[ $1 = 3 ] && clickmenu \
“Delete:delete_view $2”
esac
done
\end{code}
|
Added doc/floating.png.
cannot compute difference between binary files
Added doc/focused.png.
cannot compute difference between binary files
Added doc/gettingstarted.tex.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
\chapter{Getting Started}
This section will walk you through your first \wmii\ startup.
For your first experience, we recommend running \wmii\ in its
own X session, so you can easily switch back to a more
comfortable environment if you get lost. Though you may start
\wmii\ from a session manager in your day to day use, these
instructions will use |xinit|. To begin with, copy this file
to your home directory, so we can open it in your new X session.
Then setup your |~/.xinitrc| as follows:
\begin{code}
cd
# Start a PDF viewer with this guide. Use any viewer
# you're comfortable with.
xpdf wmii.pdf &
# Launch wmii
exec wmii
# That was easy.
\end{code}
Before you run |xinit|, make sure you know how to switch
between terminals. Depending on your system, your current X
session is probably on terminal 5 or 7. You should be able to
switch between your terminals by pressing
Ctrl-Alt-F$\langle n\rangle$. Assuming that your current X
session is on terminal 7, you should be able to switch between
it and your new session by pressing Ctrl-Alt-F7 and Ctrl-Alt-F8.
Now you should be ready to start \wmii. When you run the
following command, you should be presented with a new X session
running wmii and a PDF viewer showing this document.
\begin{code}
xinit
\end{code}
When you're there, find this page in the new PDF viewer and
continue.
\section{Your First Steps}
If everything went according to plan, you should be viewing this
from a nearly empty \wmii\ session. We're going to be using the
keyboard a lot, so let's start with a convention for key
notation. We'll be using the key modifiers Control, Alt, Shift,
and Meta\footnote{The Windows$^{\mbox{\tiny®}}$ key on most
keyboards. The Penguin key on the more tongue in cheek
varieties.}, which we'll specify as C-, A-, S-, and M-,
respectively. So, <C-S-a> means pressing ‘|a|’ while holding
|Control| and |Shift|. We'll also express mouse clicks this
way, with <M-Mouse1> signifying a press of the right mouse
button, with the Meta key depressed. Buttons 4 and 5 are the up
and down scroll wheel directions, respectively.
\subsection{Floating Mode}
Beginning with what's familiar to most users, we'll first explore
floating mode. First, we need to select the floating layer.
Press <M-Space>. You should see the titlebar of this window
change color. Now, press <M-Return> to launch a terminal.
The easiest way to drag the terminal around is to press and hold
<M-Mouse1> over the window and simply drag the window
around. You should be able to drag the window anywhere onscreen
without ever releasing the mouse button. As you drag near the
screen edges, you should notice a snap. If you try to drag the
window fully off-screen, you'll find it constrained so that a
portion always remains visible. Now, release the window and move
the mouse toward one of its corners. Press and hold
<M-Mouse3>\footnote{The right button.}. As you drag the
mouse around, you should see the window resized accordingly.
To move the window without the modifier key, move the pointer
over the layout box to the left of its titlebar. You should see
the cursor change. Now, simply click and drag. To resize it,
move the pointer toward the window's edge until you see the
cursor change, and again, click and drag. Now, to close the
window, move the mouse over the windows titlebar, press and hold
<Mouse3>, select |Delete|, and release it. You should
see this window's titlebar return to its original color,
indicating that it's regained focus.
\subsection{Managed Mode}
Now, for the fun part. We'll start exploring managed mode by
looking at the basics of columns. In the default configuration,
columns have three modes:
\begin{description}
\item[Stack] <M-s> The default mode for new columns. Only one window
is fully visible per column at once. The others only display
their title bars. When new windows are added to the column,
the active window collapses, and the new one takes its
place. Whenever a collapsed client is selected, the active
window is collapsed to take its place.
\item[Max] <M-m> Like stack mode, but the titlebars of collapsed
clients are hidden.
\item[Default] <M-d> Multiple uncollapsed windows may be visible at
once. New windows split the space with the other uncollapsed
windows in their vicinity. Windows may still be collapsed by
shrinking them to the size of their titlebars. At this
point, the behavior of a stack of collapsed and uncollapsed
clients is similar to that of stack mode.
\end{description}
Before we open any new windows in managed mode, we need to
explore the column modes a bit. Column modes are activated with
the key bindings listed above. This column should be in stack
mode now. Watch the right side of the titlebar as you press
<M-m> to enter max mode. You should see an indicator appear.
This tells you the number of hidden windows directly above and
below the current window, and its position in that stack. Press
<M-d> to enter default mode. Now we're ready to open another
client. Press <M-Return> to launch another terminal. Now,
press <M-S-l> to move the terminal to a new column to the
right of this one. Once it's there, press <M-Return> two
more times to launch two more terminals. Now that you have more
than one window in a column, cycle through the three column
modes again until they seem familiar.
\subsection{Keyboard Navigation}
To begin, switch back to default mode. The basic keyboard
navigation keys, <M-h>, <M-j>, <M-k>, and <M-l>,
derive from vi, and represent moving left, down, up, and right
respectively. Try selecting each of the four windows currently
visible on screen. Notice that navigation wraps from one side of
the screen to the other, and from the top to the bottom. Now,
return to the write column, switch to stack mode, and select
each of the three terminals again. Do the same in max mode,
paying careful attention to the indicator to the right of the
titlebar.
Now that you can select windows, you'll want to move them
around. To move a window, just add the Shift key to the
direction keys. So, to move a window left, instead of <M-h>,
type <M-S-h>. Now, experiment with moving windows, just as
you did with navigating them, in each of the three column modes.
Once you're comfortable with that, move a window to the floating
layer. Since we toggled between the floating and managed layers
with <M-Space>, we'll move windows between them with
<M-S-Space>. Try moving some windows back and forth until it
becomes familiar. Now, move several windows to the floating
layer and try switching between them with the keyboard. You'll
notice that <M-h> and <M-l> don't function in the
floating layer. This is for both historical and logistical
reasons. <M-j> and <M-k> cycle through floating windows
in order of their most recent use.
\subsection{Mouse Navigation}
\wmii\ uses the “sloppy focus” model, which is to say, it focuses
windows when the mouse enters them and when you click them. It
focuses windows only when you select them with the keyboard,
click their titlebars, or press click them with <M-Mouse2>.
Collapsed windows may be opened with the mouse by clicking their
titlebars. Moving and resizing floating windows should be
largely familiar, and has already been covered. The same can't
be said for managed windows.
Let's begin working with the mouse in the managed layer. Return
to a layout with this document in a column on the left, and
three terminals in a column to the right. Switch the right
column to default mode. Now, bring the mouse to the top of the
third terminal's titlebar until you see a resize cursor. Click
and drag the titlebar to the very top of the screen. Now, move
the cursor to the top of the second terminal's titlebar and drag
it to the very bottom of the screen. Press <M-d> to restore the
terminals to their original sizes. Now, click and hold the
layout box of the second terminal. Drag it to the middle of the
terminal's window and release. Click and hold the layout box of
the third terminal and drag it to the middle of the first
terminal's window. Finally, drag the first terminal's layout box
to halfway down this window. <M-Mouse1> works to the same
effect as dragging the layout box, but allows you to click
anywhere in the window.
Now that you've seen the basics of moving and dragging windows,
let's move on to columns. Click and drag the border between the
two columns. If that's a difficult target to click, there's a
triangle at the top of the division between the two columns that
you can click and drag as well. If that's still too hard a
target, try using <M-Mouse3>, which works anywhere and provides
much richer functionality.
\subsection{Window Focus and Selection}
For the purposes of keyboard navigation, \wmii\ keeps track of
which window is currently selected, and confers its titlebar a
different color scheme from the other windows. This window is
the basis of relative motion commands, such as “select the
window to the left”, and the target of commands such as “close
this window”. Normally, the selected window is the same as the
focused window, i.e., the window that receives keyboard events.
Some applications, however, present strange corner cases.
\begin{description}
\item[Focused, selected window] This is the normal case of a
window which is both selected and has the keyboard focus.
\titlebar{selected}
\item[Unfocused, unselected window] This is the normal case for an
unselected window which does not have the keyboard focus.
\titlebar{unselected}
\item[Unfocused, selected window] This is the first unusual
case. This is the selected window, for the purposes of
keyboard navigation, but it does not receive keyboard events.
A good example is an onscreen keyboard, which will receive
mouse clicks and translate them to keyboard events, but
won't absorb those keyboard events itself. Other examples
include any window whilst another (such as \wimenu) has
grabbed the keyboard.
\titlebar{unfocused}
\item[Focused, unselected window] This is the second unusual
focus case. The window has the keyboard focus, but for the
purposes of keyboard navigation, it is not considered
selected. In the case of an onscreen keyboard, this is the
window which will receive the generated events. In the case
of a keyboard grab, the will likely be the window holding
the grab.
\titlebar{focused}
\end{description}
\section{Running Programs}
You've already seen the convenient key binding to launch a
terminal, but what about other programs? To get a menu of all of
the executables in your path, type <M-p>. This should replace
the bar at the bottom of the screen with a prompt, followed by a
string of completions. Start typing the name of a program that
you want to open. You can press <Tab> and <S-Tab> to cycle
through the completions, or you can just press <Return> to
select the first one. If you want to execute a more complex
command, just type it out and press <Return>. If you want to
recall that command later, use \wimenu's history. Start typing
the command you want and then press <C-p> until you come to it.
When you're done with a program, you'll probably want an easy
way to close it. The first way is to ask the program to close
itself. Since that can be tedious (and sometimes impossible),
\wmii\ provides other ways. As mentioned, you can right click
the titlebar and select |Delete|. If you're at the keyboard,
you can type <M-S-c>. These two actions cause \wmii\ to ask
nicely that the program exit. In those sticky cases where the
program doesn't respond, \wmii\ will wait 10 seconds before
prompting you to kill the program. If you don't feel like
waiting, you can select |Kill| from the window's titlebar
menu, in which case \wmii\ will forcefully and immediately kill
it. Beware, killing clients is a last resort. In cases where the
same program opens multiple windows, killing one will kill them
all—without warning.
\section{Using Views}
As already noticed, \wmii's concept of virtual workspaces is
somewhat unique, so let's begin exploring it. Open up a terminal
and press <M-S-2>. You should see a new button on the bar at the
bottom of the screen. When you click it, you should see your
original terminal. Press <M-1> to come back here. Now, press
<M-3>, and <M-1> again to return here once more. Notice that the
views were created when needed, and destroyed when no longer
necessary. If you want to select a view with a proper name, use
<M-t> and enter the name. Other than the dynamic creation of
views, this is still similar to the familiar X11 workspace
model. But that's just the beginning of \wmii's model. Open a new
terminal, and type:
\begin{code}
echo ‘Hello world!’
\end{code}
\noindent Now, type <M-S-t>. In the menu that appears, enter
|1+2+3|. Now, visit the views |1|, |2|, and |3|, and you'll see
the client on each. To remove a tag, type <M-S-t> again, and
this time enter |-2|. You'll notice that the client is no longer
on the |2| view. Finally, tag names needn't be discrete,
ordinary strings. They can also be regular expressions. Select
the terminal again, and enter |+/^5/|. Now, switch to the |5|
view. Now try the |6| view. Finally, type <M-t> and enter |50|
to check the |50| view. Clients tagged with regular expressions
are attached to any matching views when they're created. So,
when you switch to an empty view, or tag a client with a new
tag, any clients with matching regular expressions are
automatically added to it. When all explicitly tagged clients
disappear from the view, and it's no longer visible, clients
held there by regular expressions are automatically removed.
\section{Learning More}
For full tables of the standard key bindings, and descriptions
of the precise semantics of the topics discussed above, you
should refer to \wmii's |man| pages.
|
Added doc/introduction.tex.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
\chapter{Introduction}
\wmii\ is a simple but powerful window manager for the X Window
System. It provides both the classic (“floating”) and tiling
(“managed”) window management paradigms, which is to say, it does
the job of managing your windows, so you don't have to. It also
provides programability by means of a simple file-like
interface, which allows the user to program in virtually any
language he chooses. These basic features have become
indispensable to the many users of \wmii\ and other similar
window managers, but they come at a cost. Though our penchant
for simplicity makes \wmii's learning curve significantly
shorter than most of its competitors, there's still a lot to
learn. The rest of this guide will be devoted to familiarizing
new users with \wmii's novel features and eccentricities, as
well as provide advanced users with an in-depth look at our
customization facilities.
\section{Concepts}
As noted, \wmii\ provides two management styles:
\begin{description}
\item[Managed] This is the primary style of window management
in \wmii. Windows managed in this style are automatically
arranged by \wmii\ into columns. Columns are created and
destroyed on demand. Individual windows in the column may be
moved or resized, and are often collapsed or hidden
entirely. Ad-hoc stacks of collapsed and uncollapsed windows
allow the user to efficiently manage their tasks. When
switching from an active to a collapsed window, the active
window collapses and the collapsed one effectively takes
its place.
Managed windows have an unadorned titlebar:
\titlebar{managed}
\item[Floating] Since some programs aren't designed in ways
conducive to the managed work flow, \wmii\ also provides the
classic “floating” window management model. Windows managed
in this model float above the managed windows and may be moved
freely about. Other than automatic placement of new windows
and snapping of edges, \wmii\ doesn't manage floating
windows at all.
Floating windows are indicated by a decorated titlebar:
\titlebar{floating}
\item[Fullscreen] Fullscreen mode is actually a subset of the
floating style. Windows may be toggled to and from
fullscreen mode at will. When fullscreen, windows reside in
the floating layer, above the managed windows. They have no
borders or titlebars, and occupy the full area of the
screen. Other than that, however, they're not special in any
way. Other floating windows may appear above them and the
user can still select, open, and close other windows at
will.
\end{description}
\subsection{The Filesystem}
All of \wmii's customization is done via a virtual filesystem.
Since the filesystem is implemented in the standardized \ninep\
protocol, it can be accessed in many ways. \wmii\ provides a
simple command-line client, \wmiir, but many alternatives exist,
including libraries for Python, Perl, Ruby, PHP, and C. It can
even be mounted, either by Linux's 9p.ko kernel module or
indirectly via FUSE.
The filesystem that \wmii\ provides is “virtual”, which is to
say that it doesn't reside on disk anywhere. In a sense, it's a
figment of \wmii's imagination. Files, when read, represent
\wmii's current configuration or state. When written, they
perform actions, update the UI, etc. For instance, the directory
|/client/| contains a directory for each window that \wmii\
is currently managing. Each of those directories, in turn,
contains files describing the client's properties (its title,
its views\footnote{Views in \wmii\ are akin to workspaces or
virtual desktops in other window managers, but with some subtle
differences.}, its state). Most files can be written to update
the state they describe. For instance,
|/client/sel/ctl| describes the state of the selected
client. If a client is fullscreen, it contains the line:
\begin{code}
fullscreen on
\end{code}
\noindent To change this, you'd update the file with the line
% XXX: Line broken at /ctl cmd.
|fullscreen off| or even |fullscreen| |toggle| to toggle
the client's fullscreen state.
The concept of controlling a program via a filesystem derives
from \plannine, where such interfaces are extensive and well
proven\footnote{The concept has also taken hold on most Unixes
in the form of \texttt{/proc} and \texttt{/sys} virtual
filesystems, but tends to be very kernel-centric. On \plannine,
where the model is more pervasive, there are more virtual
filesystems for user-level applications than for the kernel.}.
The metaphor has shown itself to be quite intuitive to Unix
users, once the shock of a “virtual” filesystem wears off. The
flexibility of being able to control \wmii\ from myriad
programming languages, including the standard Unix shell and
even from the command line, is well worth the shock.
\subsection{Views and Tags}
Like most X11 window managers, \wmii\ provides virtual
workspaces. Unlike other window managers though, \wmii's
workspaces are created and destroyed on demand. Instead of being
sent to a workspace, windows in \wmii\ are tagged with any
number of names. Views are created dynamically from these tags,
and automatically if the user tries to access them. For
instance, if a window is given the tags ‘foo’ and ‘bar’, the two
views ‘foo’ and ‘bar’ are created, if they don't already exist.
The window is now visible on both of them. Moreover, tags can be
specified as regular expressions. So, a client tagged with {\tt
\verb+/^foo/+} will appear on any view named ‘foo’, ‘foo:bar’,
and so forth. Any time a client is tagged with a matching tag,
or the user opens a matching view, the window is automatically
added to it.
\subsection{The Bar}
\wmii\ provides a general purpose information bar at the top or
bottom of the screen. The bar is divided into a left and a right
section. Each section is made up of buttons, with a single
button spanning the gap between the two sides. Buttons can be
individually styled and can hold any text content the user
wishes. By convention, the buttons to the left show view names,
and those to the right display status information.
\subsection{The Menus}
\wmii\ includes two simple, external menu programs. The first,
\wimenu, is keyboard-based, and is used to launch programs and
generally prompt the user for input. It provides a list of
completions which are automatically filtered as you type. The
second, \wiIXmenu, is mouse-based, and is generally used to
provide context menus for titlebars and view buttons. Both menus
can be easily launched from shell scripts or the command line,
as well as from more complex scripting languages.
\subsection{The Keyboard}
\wmii\ is a very keyboard friendly window manager. Most actions
can be performed without touching the mouse, including
launching, closing, moving, resizing, and selecting programs.
New keybindings of any complexity can easily be added to handle
any missing functionality, or to simplify any repetitive tasks.
\subsection{The Mouse}
Despite being highly keyboard-accessible, \wmii\ strives to be
highly mouse accessible as well. Windows can be moved or resized
by dragging their window borders. When combined with a key
press, they can be moved, resized, or raised by dragging any
visible portion of the window. Mouse menus are accessed with a
single click and drag. View buttons in the bar and client
titlebars respond to the mouse wheel; view buttons can be
activated by dragging any draggable object (e.g., a file from a
file manager) over them.
|
Added doc/license.tex.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
\chapter*{License}
This file is distributed under the same terms as wmii:
\begingroup
\ttfamily
\parindent=0pt
\parskip=1em
Copyright © 2009-2010 Kris Maglione <\href{mailto:maglione.k@gmail.com}{maglione.k@gmail.com}>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
\endgroup
|
Added doc/managed.png.
cannot compute difference between binary files
Added doc/mkfile.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
MKSHELL=rc
TARG = wmii.pdf
SRC = ${TARG:%.pdf=%.tex}
TEX = xelatex
default:V: all
all:V: $TARG
# mk doesn't recognize nested `{}
deps = `{ ash -c 'dep() { echo $1; for f in $(9 sed -n "s/.*\\include{([^}]+)}.*/\1.tex/p; s/.*\\input (.*)/\1.tex/p" $1); do dep $f; done; }; dep $SRC' }
# `
$TARG: $deps
junk = aux idx ilg ind log toc out
CLEAN = ${TARG:%.pdf=%}
CLEAN = ${junk:%=$CLEAN.%} ${deps:%.tex=%.aux}
clean:V:
rm -f $CLEAN
%.pdf: %.tex mkfile
flag x +
if (~ $MAINFONT '')
fn tex { builtin $TEX $stem.tex }
if not
fn tex { builtin $TEX '\def\mainfont{'$"MAINFONT'}\input{'$stem.tex'}' }
tex
makeindex $stem
tex
rm -f $stem.out 2>/dev/null
# vim:se ft=make:
|
Added doc/selected.png.
cannot compute difference between binary files
Added doc/unfocused.png.
cannot compute difference between binary files
Added doc/unselected.png.
cannot compute difference between binary files
Added doc/wmii.pdf.
cannot compute difference between binary files
Added doc/wmii.tex.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
\documentclass[letterpaper,oneside]{scrbook}
\usepackage{txfonts}
\usepackage{fontspec}
\usepackage{xunicode}
\usepackage{xltxtra}
\usepackage{fancyvrb}
\usepackage[top=1in,bottom=1in]{geometry}
\usepackage{graphicx}
\usepackage{makeidx}
\usepackage{xcolor}
\usepackage[xetex,breaklinks,colorlinks,linkcolor=black]{hyperref}
\let\EA=\expandafter
\newif\ifexpandfragments
\newif\ifdefinefragments
%% Indexes
\makeindex
\let\primary=\textbf
\ifx\mainfont\undefined
\def\mainfont{Palatino LT Std}
\fi
\setmainfont[Mapping=tex-text, Numbers=OldStyle]\mainfont
\def\lining{\addfontfeature{Numbers=Lining}}
\let\primary=\textbf
\def\titlebar#1{%
\begin{center}\includegraphics[width=5.5in]{#1.png}\end{center}}
\def\man#1#2{#2\textbf{(#1)}}
\makeatletter
%% Key specs
\def\key#1{{\small$\langle$\lining#1\/$\rangle$}}
\let\<=<
\catcode`\<=\active
\def<#1>{\key{#1}}
%% Display ‹...› and «...» as text in left and right pointing
%% angle brackets. I use «» and ‹› because my terminal doesn't
%% display left and right pointing angle brackets properly, and
%% Xorg's compose maps don't provide them, anyway.
\def\«{«}\def\‹{‹}
\catcode`\«=\active
\catcode`\‹=\active
\def‹#1›{$\langle${\itshape#1}$\rangle$}
\def«#1»{$\langle\langle${\itshape#1}$\rangle\rangle$}
\catcode`\∅=\active
\def∅{\box0}
\def«{%
\let\dofragment@target=\hyperlink%
\@ifnextchar*\dofragment@@\dofragment@}
\def\dofragment@@*{%
\let\dofragment@target=\hypertarget%
\dofragment@}
\def\dofragment@#1»{%
\setbox0=\hbox{$\langle\langle${\itshape#1}$\rangle\rangle$}%
\ifexpandfragments%
\def\a{\sp\sp\comment \boxzero^^J}%
\begingroup%
\def\ { }\xdef\@frag@name{#1}%
\endgroup%
\UseFragment{∅}\@frag@name%
\else%
\dofragment@target{frag:#1}{\box0}%
\fi}
% Display |...| as verbatim, teletype text.
\DefineShortVerb{\|}
\def\macroname#1{%
\expandafter\@macroname\string#1}
\def\@macroname#1{}
\def\defverb#1{%
\EA\def\EA#1\EA{\EA\protect\EA\UseVerb\EA{\macroname#1}}%
\EA\SaveVerb\EA{\macroname#1}}
\let\idx@@heading\chapter
%% Create a verbatim {code} environment which highlights strings
%% and comments. Several unicode characters are hacked to replace
%% the grabbed characters, since we can't escape them in the
%% verbatim environment.
\colorlet{comment}{gray}
\colorlet{string}{red!100!black!90}
\let\‘=‘
\let\“=“
\def\≔{≔}
\catcode`#=\active
\catcode`\≔=\active
\def\docodes{%
\catcode`\#=\active%
\catcode`“=\active%
\catcode`‘=\active}
\def≔{\ensuremath{\Coloneqq}}
\let#=\#
\begingroup
\docodes
\catcode`\#=\active%
\catcode`¶=6
\gdef\comment{\itshape\color{comment}\let“=\“\let‘=\‘\#}
\gdef\dodefineactive{%
\let#=\comment%
\gdef“¶¶1”{{\color{string}\“¶¶1”}}%
\gdef‘¶¶1’{{\color{string}\‘¶¶1’}}}
\endgroup
\DefineVerbatimEnvironment{code}{Verbatim}{xleftmargin=2em,gobble=2,%
codes={\docodes\catcode`\☺=0},%
defineactive={\dodefineactive}}
%% Save code fragments for piecing together later
\begingroup
\catcode`\@=0
@catcode`\\=12
@gdef@bcode{@detokenize{\begin{code}^^J}}
@gdef@ecode{@detokenize{\end{code}^^J}}
@catcode`@ =12@gdef@sp{ }
@endgroup
% Ripped from fancyverb
% I'm currently rather unfond of it.
\def\Fragment{\FV@Environment{}{Fragment}}
\def\FVB@Fragment#1{%
\@bsphack
\begingroup
\FV@UseKeyValues
\gdef\Fragment@Name{#1}%
\xdef\Fragment@Prefix{\«*#1» \≔^^J}
\xdef\TheFragment{}
\def\FV@ProcessLine##1{%
\edef\frag{\detokenize{##1^^J}}%
\xdef\TheFragment{\TheFragment\frag}}%
\FV@Scan}
\def\FVE@Fragment{%
\EA\global\EA\let
\csname SV@\Fragment@Name\endcsname\TheFragment%
\endgroup%
\EA\UseFragment\EA{\Fragment@Prefix}\Fragment@Name}
\DefineVerbatimEnvironment{Fragment}{Fragment}{}
\def\UseFragment#1#2{
\begingroup
\EA\let\EA\a\csname SV@#2\endcsname
\ifx\a\undefined\def\a{\ldots}\fi
\ifx\FV@EnvironName\relax%
\edef\a{\bcode\detokenize{++#1}\a\ecode}\else%
\edef\a{\detokenize{#1}\a}\fi%
\newtoks\tokens
\EA\tokens\EA{\a}
\everyeof{\noexpand}%
\scantokens\EA{\the\tokens}
\endgroup
}
%% Convenience defs for the various wmii commands, and a few
%% others.
\defverb\wmii|wmii|
\defverb\wiIXmenu|wimii9menu|
\defverb\wimenu|wimenu|
\defverb\wmiir|wmiir|
\def\ninep{{\lining 9P}}
\def\POSIX{\textsc{POSIX}}
\def\plannine{{\lining Plan 9}}
\def\ICCCM#1{%
\@ICCCM#1@
\href{http://www.tronche.com/gui/x/icccm/sec-\@ICCCM@chap.html\#s-#1}{%
ICCCM \lining§#1}}
\def\@ICCCM#1.#2@{\def\@ICCCM@chap{#1}}
\makeatother
\begin{document}
\thispagestyle{empty}
\leavevmode
\vfill
\begin{center}
\centerline{\includegraphics[width=2in]{../img/wmii.pdf}}
\vskip 1in
\LARGE
The \wmii\ User Guide
\vskip .5in
\Large
Kris Maglione \\[1em]
\lining
13 October 2009
\end{center}
\vfill
\newpage
\frontmatter
\tableofcontents
\newpage
\include{license}
\mainmatter
\include{introduction}
\include{gettingstarted}
\include{customizing}
\backmatter
\printindex
\end{document}
|
Added examples/Makefile.
> > > > > > > | 1 2 3 4 5 6 7 | ROOT=.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk DOCS = wimenu-file-completion.sh DOCDIR = $(DOC)/examples |
Added examples/wimenu-file-completion.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
#!/bin/sh
# This script will launch wimenu and provide command
# completion for the first argument and filename completion
# for each following argument, and execute the result.
# Program name completion requires that a program list already
# exist in $(wmiir namespace)/.proglist
fifo="$HOME/.wmii/menu_fifo"
mkfifo $fifo 2>/dev/null
script=$(cat <<'!'
BEGIN {
progs = "cat $(wmiir namespace)/.proglist"
# Print the first set of completions to wimenu’s fifo
print read(progs) >fifo
fflush(fifo)
}
# Process the input and provide the completions
{
# Skip the trailing part of the command.
# If there is none, this is the result.
if (!getline rest) {
print
exit
}
if (!match($0, /.*[ \t]/))
# First argument, provide the program list
update(0, progs)
else {
# Set the offset to the location of the last
# space, and save that part of the completion
offset = RLENGTH
str = substr($0, offset + 1)
# If we're completing a sub-directory, adjust
# the offset to the position of the last /
if (match(str, ".*/"))
offset += RLENGTH
# If the last component of the path begins with
# a ., include hidden files
arg = ""
if(match(str, "(^|/)\\.[^/]*$"))
arg = "-A"
# Substitute ~/ for $HOME/
sub("^~/", ENVIRON["HOME"] "/", str)
# Strip the trailing filename
sub("[^/]+$", "", str)
update(offset, "ls " arg quote(str))
}
}
# Push out a new set of completions
function update(offset, cmd) {
# Only push out the completion if the offset or the
# option of ls has changed. The behavior will be the
# same regardless, but this is a minor optimization
if (offset != loffset || cmd != lcmd) {
loffset = offset
lcmd = cmd
cmpl = read(cmd)
print offset >fifo
print cmpl >fifo
fflush(fifo)
}
}
# Quote a string. This should work in any Bourne
# or POSIX compatible shell.
function quote(str) {
if (!match(str, /[\[\](){}$'"^#~!&;*?|<>]/))
return str
gsub(/\\/, "'\\\\'", str)
gsub(/'/, "'\\''", str)
return "'" str "'"
}
# Read the output of a command and return it
function read(cmd) {
if (cmd in cache)
return cache[cmd]
res = ""
while (cmd | getline)
res = res quote($0) "\n"
close(cmd)
return cache[cmd] = res
}
!
)
res="$(wimenu -c "$@" <$fifo | awk -v "fifo=$fifo" "$script")"
exec ${SHELL:-sh} -c "exec $res"
|
Added img/icon.png.
cannot compute difference between binary files
Added img/mkfile.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
MKSHELL=rc
path=$PLAN9/bin $path
eps = wmii.eps
calc = rc -c 'echo 4k $* p | dc}
iconwidth = 16
imagewidth = 154
%.pdf: %.eps
sh epstopdf $stem.eps
%-small.png: %.eps
epsbox = `{sed -n '/^%%BoundingBox:/{s/.*://p; q;}' $stem.eps}
iconscale = `{*=$epsbox; $calc $iconwidth $3 $1 -/}
iconheight = `{*=$epsbox; $calc $4 $2 - $iconscale '*'}
* = `{hoc -e'-('$epsbox')'}
x = $1
y = $2
gs -q -dBATCH -dNOPAUSE -s'DEVICE=pngalpha' -s'OutputFile='$target -g$iconwidth^x^$iconheight - <<!
$iconscale $iconscale scale
$x $y translate
($eps) run
showpage
quit
!
optipng -fix $target
%.png: %.eps
epsbox = `{sed -n '/^%%BoundingBox:/{s/.*://p; q;}' $stem.eps}
imagescale = `{*=$epsbox; $calc $imagewidth $3 $1 -/}
imageheight = `{*=$epsbox; $calc $4 $2 - $imagescale '*'}
* = `{hoc -e'-('$epsbox')'}
x = $1
y = $2
gs -q -dBATCH -dNOPAUSE -s'DEVICE=pngalpha' -s'OutputFile='$target -g$imagewidth^x^$imageheight - <<!
$imagescale $imagescale scale
$x $y translate
($eps) run
showpage
quit
!
optipng -fix $target
|
Added img/wmii.eps.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | %!PS-Adobe-2.0 EPSF-1.2 %%BoundingBox: -1 0 51 27 %%Creator: MetaPost %%CreationDate: 2007.02.27:1944 %%Pages: 1 %%EndProlog %%Page: 1 1 0 6.23616 dtransform truncate idtransform setlinewidth pop [] 0 setdash 0 setlinecap 2 setlinejoin 10 setmiterlimit newpath 2.83461 17.00761 moveto 2.83461 2.83461 lineto 14.17302 2.83461 lineto 14.17302 17.00761 lineto 14.17302 2.83461 lineto 25.51143 2.83461 lineto 25.51143 14.173 lineto 36.84984 14.173 lineto stroke 0 setlinejoin newpath 36.84984 14.173 moveto 36.84984 0 lineto 36.84984 14.173 lineto 48.18825 14.173 lineto 48.18825 0 lineto stroke newpath 36.84984 20.40916 moveto 36.84984 26.07837 lineto stroke newpath 48.18825 20.40916 moveto 48.18825 26.07837 lineto stroke showpage %%EOF |
Added img/wmii.mp.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | beginfig(1) %u=0.6cm; u=0.2cm; h=3u; space=u; linecap:=butt; linejoin:=beveled; pickup pencircle scaled 1.1u; draw (.5u,h)--(.5u,.5u)--(1.5u+space,.5u)--(1.5u+space,h)--(1.5u+space,.5u)--(2.5u+2space,.5u)\ --(2.5u+2space,h-.5u)--(3.5u+3space,h-.5u); linejoin:=mitered; draw (3.5u+3space,h-.5u)--(3.5u+3space,0)--(3.5u+3space,h-.5u)--(4.5u+4space,h-.5u)--(4.5u+4space,0);; gap=.6u; draw (3.5u+3space,h+gap)--(3.5u+3space,h+u+gap); draw (4.5u+4space,h+gap)--(4.5u+4space,h+u+gap); endfig end |
Added img/wmii.pdf.
cannot compute difference between binary files
Added img/wmii.png.
cannot compute difference between binary files
Added include/Makefile.
> > > > > > | 1 2 3 4 5 6 | ROOT= .. include $(ROOT)/mk/hdr.mk HFILES = ixp.h ixp_fcall.h include $(ROOT)/mk/common.mk |
Added include/bio.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
#ifndef _BIO_H_
#define _BIO_H_ 1
#ifdef AUTOLIB
AUTOLIB(bio)
#endif
#include <sys/types.h> /* for off_t */
#include <fcntl.h> /* for O_RDONLY, O_WRONLY */
#include <stdarg.h> /* for va_list */
typedef struct Biobuf Biobuf;
enum
{
Bsize = 8*1024,
Bungetsize = 4, /* space for ungetc */
Bmagic = 0x314159,
Beof = -1,
Bbad = -2,
Binactive = 0, /* states */
Bractive,
Bwactive,
Bracteof,
Bend
};
struct Biobuf
{
int icount; /* neg num of bytes at eob */
int ocount; /* num of bytes at bob */
int rdline; /* num of bytes after rdline */
int runesize; /* num of bytes of last getrune */
int state; /* r/w/inactive */
int fid; /* open file */
int flag; /* magic if malloc'ed */
off_t offset; /* offset of buffer in file */
int bsize; /* size of buffer */
unsigned char* bbuf; /* pointer to beginning of buffer */
unsigned char* ebuf; /* pointer to end of buffer */
unsigned char* gbuf; /* pointer to good data in buf */
unsigned char b[Bungetsize+Bsize];
};
#define BGETC(bp)\
((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
#define BPUTC(bp,c)\
((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
#define BOFFSET(bp)\
(((bp)->state==Bractive)?\
(bp)->offset + (bp)->icount:\
(((bp)->state==Bwactive)?\
(bp)->offset + ((bp)->bsize + (bp)->ocount):\
-1))
#define BLINELEN(bp)\
(bp)->rdline
#define BFILDES(bp)\
(bp)->fid
int Bbuffered(Biobuf*);
Biobuf* Bfdopen(int, int);
int Bfildes(Biobuf*);
int Bflush(Biobuf*);
int Bgetc(Biobuf*);
int Bgetd(Biobuf*, double*);
long Bgetrune(Biobuf*);
int Binit(Biobuf*, int, int);
int Binits(Biobuf*, int, int, unsigned char*, int);
int Blinelen(Biobuf*);
off_t Boffset(Biobuf*);
Biobuf* Bopen(const char*, int);
int Bprint(Biobuf*, const char*, ...);
int Bputc(Biobuf*, int);
int Bputrune(Biobuf*, long);
void* Brdline(Biobuf*, int);
char* Brdstr(Biobuf*, int, int);
long Bread(Biobuf*, void*, long);
off_t Bseek(Biobuf*, off_t, int);
int Bterm(Biobuf*);
int Bungetc(Biobuf*);
int Bungetrune(Biobuf*);
long Bwrite(Biobuf*, void*, long);
int Bvprint(Biobuf*, const char*, va_list);
#endif
|
Added include/fmt.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
#ifndef _FMT_H_
#define _FMT_H_ 1
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <utf.h>
typedef struct Fmt Fmt;
struct Fmt{
unsigned char runes; /* output buffer is runes or chars? */
void *start; /* of buffer */
void *to; /* current place in the buffer */
void *stop; /* end of the buffer; overwritten if flush fails */
int (*flush)(Fmt *); /* called when to == stop */
void *farg; /* to make flush a closure */
int nfmt; /* num chars formatted so far */
va_list args; /* args passed to dofmt */
Rune r; /* % format Rune */
int width;
int prec;
unsigned long flags;
char *decimal; /* decimal point; cannot be "" */
/* For %'d */
char *thousands; /* separator for thousands */
/*
* Each char is an integer indicating #digits before next separator. Values:
* \xFF: no more grouping (or \x7F; defined to be CHAR_MAX in POSIX)
* \x00: repeat previous indefinitely
* \x**: count that many
*/
char *grouping; /* descriptor of separator placement */
};
enum{
FmtWidth = 1,
FmtLeft = FmtWidth << 1,
FmtPrec = FmtLeft << 1,
FmtSharp = FmtPrec << 1,
FmtSpace = FmtSharp << 1,
FmtSign = FmtSpace << 1,
FmtApost = FmtSign << 1,
FmtZero = FmtApost << 1,
FmtUnsigned = FmtZero << 1,
FmtShort = FmtUnsigned << 1,
FmtLong = FmtShort << 1,
FmtVLong = FmtLong << 1,
FmtComma = FmtVLong << 1,
FmtByte = FmtComma << 1,
FmtLDouble = FmtByte << 1,
FmtFlag = FmtLDouble << 1
};
extern int (*fmtdoquote)(int);
#ifdef VARARGCK
/* *sigh* */
typedef unsigned char _fmt_uchar;
typedef unsigned short _fmt_ushort;
typedef unsigned int _fmt_uint;
typedef unsigned long _fmt_ulong;
typedef unsigned long long _fmt_uvlong;
typedef long long _fmt_vlong;
# pragma varargck argpos fmtprint 2
# pragma varargck argpos fprint 2
# pragma varargck argpos print 1
# pragma varargck argpos runeseprint 3
# pragma varargck argpos runesmprint 1
# pragma varargck argpos runesnprint 3
# pragma varargck argpos runesprint 2
# pragma varargck argpos seprint 3
# pragma varargck argpos smprint 1
# pragma varargck argpos snprint 3
# pragma varargck argpos sprint 2
# pragma varargck type "lld" _fmt_vlong
# pragma varargck type "llx" _fmt_vlong
# pragma varargck type "lld" _fmt_uvlong
# pragma varargck type "llx" _fmt_uvlong
# pragma varargck type "ld" long
# pragma varargck type "lx" long
# pragma varargck type "lb" long
# pragma varargck type "ld" _fmt_ulong
# pragma varargck type "lx" _fmt_ulong
# pragma varargck type "lb" _fmt_ulong
# pragma varargck type "d" int
# pragma varargck type "x" int
# pragma varargck type "c" int
# pragma varargck type "C" int
# pragma varargck type "b" int
# pragma varargck type "d" _fmt_uint
# pragma varargck type "x" _fmt_uint
# pragma varargck type "c" _fmt_uint
# pragma varargck type "C" _fmt_uint
# pragma varargck type "b" _fmt_uint
# pragma varargck type "f" double
# pragma varargck type "e" double
# pragma varargck type "g" double
# pragma varargck type "s" char*
# pragma varargck type "q" char*
# pragma varargck type "S" Rune*
# pragma varargck type "Q" Rune*
# pragma varargck type "r" void
# pragma varargck type "%" void
# pragma varargck type "n" int*
# pragma varargck type "p" uintptr_t
# pragma varargck type "p" void*
# pragma varargck flag ','
# pragma varargck flag 'h'
# pragma varargck type "<" void*
# pragma varargck type "[" void*
# pragma varargck type "H" void*
# pragma varargck type "lH" void*
#endif
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */
int dofmt(Fmt*, const char *fmt);
int dorfmt(Fmt*, const Rune *fmt);
double fmtcharstod(int(*f)(void*), void*);
int fmtfdflush(Fmt*);
int fmtfdinit(Fmt*, int fd, char *buf, int size);
int fmtinstall(int, int (*f)(Fmt*));
void fmtlocaleinit(Fmt*, char *decimal, char *thousands, char *grouping);
int fmtprint(Fmt*, const char*, ...);
int fmtrune(Fmt*, int);
int fmtrunestrcpy(Fmt*, Rune*);
int fmtstrcpy(Fmt*, const char*);
char* fmtstrflush(Fmt*);
int fmtstrinit(Fmt*);
double fmtstrtod(const char*, char**);
int fmtvprint(Fmt*, const char*, va_list);
int fprint(int, const char*, ...);
int print(const char*, ...);
void quotefmtinstall(void);
int quoterunestrfmt(Fmt*);
int quotestrfmt(Fmt*);
Rune* runefmtstrflush(Fmt*);
int runefmtstrinit(Fmt*);
Rune* runeseprint(Rune*,Rune*, const char*, ...);
Rune* runesmprint(const char*, ...);
int runesnprint(Rune*, int, const char*, ...);
int runesprint(Rune*, const char*, ...);
Rune* runevseprint(Rune*, Rune *, const char*, va_list);
Rune* runevsmprint(const char*, va_list);
int runevsnprint(Rune*, int, const char*, va_list);
char* seprint(char*, char*, const char*, ...);
char* smprint(const char*, ...);
int snprint(char*, int, const char *, ...);
int sprint(char*, const char*, ...);
int vfprint(int, const char*, va_list);
char* vseprint(char*, char*, const char*, va_list);
char* vsmprint(const char*, va_list);
int vsnprint(char*, int, const char*, va_list);
#endif
|
Added include/plan9.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | /* * compiler directive on Plan 9 */ /* * easiest way to make sure these are defined */ #ifndef KENC # ifndef USED # define USED(x) if(x);else # endif #endif #define uchar _p9uchar #define ushort _p9ushort #define uint _p9uint #define ulong _p9ulong typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; typedef long long vlong; typedef unsigned long long uvlong; #include <utf.h> #include <stdint.h> #include <fmt.h> #include <string.h> #include <unistd.h> #define OREAD O_RDONLY #define OWRITE O_WRONLY #define OCEXEC 0 #define ORCLOSE 0 #define OTRUNC 0 #define exits(x) exit(x && *x ? 1 : 0) #undef nil #define nil ((void*)0) #undef nelem #define nelem(x) (sizeof (x)/sizeof (x)[0]) |
Added include/regcomp.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
/*
* substitution list
*/
#define NSUBEXP 32
typedef struct Resublist Resublist;
struct Resublist
{
Resub m[NSUBEXP];
};
/* max character classes per program */
extern Reprog RePrOg;
#define NCLASS (sizeof(RePrOg.class)/sizeof(Reclass))
/* max rune ranges per character class */
#define NCCRUNE (sizeof(Reclass)/sizeof(Rune))
/*
* Actions and Tokens (Reinst types)
*
* 02xx are operators, value == precedence
* 03xx are tokens, i.e. operands for operators
*/
#define RUNE 0177
#define OPERATOR 0200 /* Bitmask of all operators */
#define START 0200 /* Start, used for marker on stack */
#define RBRA 0201 /* Right bracket, ) */
#define LBRA 0202 /* Left bracket, ( */
#define OR 0203 /* Alternation, | */
#define CAT 0204 /* Concatentation, implicit operator */
#define STAR 0205 /* Closure, * */
#define PLUS 0206 /* a+ == aa* */
#define QUEST 0207 /* a? == a|nothing, i.e. 0 or 1 a's */
#define ANY 0300 /* Any character except newline, . */
#define ANYNL 0301 /* Any character including newline, . */
#define NOP 0302 /* No operation, internal use only */
#define BOL 0303 /* Beginning of line, ^ */
#define EOL 0304 /* End of line, $ */
#define CCLASS 0305 /* Character class, [] */
#define NCCLASS 0306 /* Negated character class, [] */
#define END 0377 /* Terminate: match found */
/*
* regexec execution lists
*/
#define LISTSIZE 10
#define BIGLISTSIZE (10*LISTSIZE)
typedef struct Relist Relist;
struct Relist
{
Reinst* inst; /* Reinstruction of the thread */
Resublist se; /* matched subexpressions in this thread */
};
typedef struct Reljunk Reljunk;
struct Reljunk
{
Relist* relist[2];
Relist* reliste[2];
int starttype;
Rune startchar;
char* starts;
char* eol;
Rune* rstarts;
Rune* reol;
};
extern Relist* _renewthread(Relist*, Reinst*, int, Resublist*);
extern void _renewmatch(Resub*, int, Resublist*);
extern Relist* _renewemptythread(Relist*, Reinst*, int, char*);
extern Relist* _rrenewemptythread(Relist*, Reinst*, int, Rune*);
|
Added include/regexp9.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
#ifndef _REGEXP9_H_
#define _REGEXP9_H_ 1
#ifdef AUTOLIB
AUTOLIB(regexp9)
#endif
#include <utf.h>
typedef struct Resub Resub;
typedef struct Reclass Reclass;
typedef struct Reinst Reinst;
typedef struct Reprog Reprog;
/*
* Sub expression matches
*/
struct Resub{
union {
char *sp;
Rune *rsp;
}s;
union {
char *ep;
Rune *rep;
}e;
};
/*
* character class, each pair of rune's defines a range
*/
struct Reclass{
Rune *end;
Rune spans[64];
};
/*
* Machine instructions
*/
struct Reinst{
int type;
union {
Reclass *cp; /* class pointer */
Rune r; /* character */
int subid; /* sub-expression id for RBRA and LBRA */
Reinst *right; /* right child of OR */
}u1;
union { /* regexp relies on these two being in the same union */
Reinst *left; /* left child of OR */
Reinst *next; /* next instruction for CAT & LBRA */
}u2;
};
/*
* Reprogram definition
*/
struct Reprog{
Reinst *startinst; /* start pc */
Reclass class[32]; /* .data */
Reinst firstinst[5]; /* .text */
};
extern Reprog *regcomp9(char*);
extern Reprog *regcomplit9(char*);
extern Reprog *regcompnl9(char*);
extern void regerror9(char*);
extern int regexec9(Reprog*, char*, Resub*, int);
extern void regsub9(char*, char*, int, Resub*, int);
extern int rregexec9(Reprog*, Rune*, Resub*, int);
extern void rregsub9(Rune*, Rune*, int, Resub*, int);
/*
* Darwin simply cannot handle having routines that
* override other library routines.
*/
#ifndef NOPLAN9DEFINES
#define regcomp regcomp9
#define regcomplit regcomplit9
#define regcompnl regcompnl9
#define regerror regerror9
#define regexec regexec9
#define regsub regsub9
#define rregexec rregexec9
#define rregsub rregsub9
#endif
#endif
|
Added include/stuff/base.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
#pragma once
#define _XOPEN_SOURCE 600
#include <sys/types.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#ifndef nil
# define nil ((void*)0)
#endif
#ifndef nelem
# define nelem(ary) (sizeof(ary) / sizeof(*ary))
#endif
#ifndef offsetof
# define offsetof(type, member) ((size_t)&((type*)0)->member)
#endif
#define structptr(ptr, type, offset) \
((type*)((char*)(ptr) + (offset)))
#define structmember(ptr, type, offset) \
(*structptr(ptr, type, offset))
#undef uchar
#undef ushort
#undef uint
#undef ulong
#undef uvlong
#undef vlong
#define uchar _x_uchar
#define ushort _x_ushort
#define uint _x_uint
#define ulong _x_ulong
#define uvlong _x_uvlong
#define vlong _x_vlong
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long uvlong;
typedef long long vlong;
#define BLOCK(x) do { x; }while(0)
static inline void
_used(long a, ...) {
if(a){}
}
#ifndef KENC
# undef USED
# undef SET
# define USED(...) _used((long)__VA_ARGS__)
# define SET(x) (x = 0)
/* # define SET(x) USED(&x) GCC 4 is 'too smart' for this. */
#endif
|
Added include/stuff/clientutil.h.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | /* Copyright ©2009-2010 Kris Maglione <maglione.k at Gmail> * See LICENSE file for license details. */ #ifndef CLIENTEXTERN # define CLIENTEXTERN extern #endif char* readctl(char*, char*); void client_init(char*); CLIENTEXTERN IxpClient* client; |
Added include/stuff/geom.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
#pragma once
#include <stuff/base.h>
typedef struct Point Point;
typedef struct Rectangle Rectangle;
struct Point {
int x, y;
};
struct Rectangle {
Point min, max;
};
enum Align {
North = 0x01,
East = 0x02,
South = 0x04,
West = 0x08,
NEast = North | East,
NWest = North | West,
SEast = South | East,
SWest = South | West,
Center = NEast | SWest,
};
typedef enum Align Align;
#define Dx(r) ((r).max.x - (r).min.x)
#define Dy(r) ((r).max.y - (r).min.y)
#define Pt(x, y) ((Point){(x), (y)})
#define Rpt(p, q) ((Rectangle){(p), (q)})
#define Rect(x0, y0, x1, y1) Rpt(Pt(x0, y0), Pt(x1, y1))
Point addpt(Point, Point);
Point divpt(Point, Point);
int eqpt(Point, Point);
int eqrect(Rectangle, Rectangle);
Rectangle gravitate(Rectangle dst, Rectangle src, Point grav);
Rectangle insetrect(Rectangle, int);
Point mulpt(Point p, Point q);
Rectangle rectaddpt(Rectangle, Point);
Rectangle rectsetorigin(Rectangle, Point);
Rectangle rectsubpt(Rectangle, Point);
Point subpt(Point, Point);
Align get_sticky(Rectangle src, Rectangle dst);
Align quadrant(Rectangle, Point);
bool rect_contains_p(Rectangle, Rectangle);
bool rect_haspoint_p(Rectangle, Point);
bool rect_intersect_p(Rectangle, Rectangle);
Rectangle rect_intersection(Rectangle, Rectangle);
|
Added include/stuff/util.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <stuff/geom.h>
#include <langinfo.h>
#include <stdarg.h>
#include <bio.h>
#include <fmt.h>
#include <regexp9.h>
/* Types */
typedef struct Regex Regex;
struct Regex {
char* regex;
Reprog* regc;
};
enum {
CLeft = 1<<0,
CCenter = 1<<1,
CRight = 1<<2,
};
enum {
GInvert = 1<<0,
};
#define utf8locale() (!strcmp(nl_langinfo(CODESET), "UTF-8"))
#ifdef VARARGCK
# pragma varargck argpos _die 3
# pragma varargck argpos fatal 1
# pragma varargck argpos sxprint 1
#endif
#define strlcat stuff_strlcat
#define strcasestr stuff_strcasestr
int Blprint(Biobuf*, const char*, ...);
int Bvlprint(Biobuf*, const char*, va_list);
void _die(char*, int, char*, ...);
void backtrace(char*);
void closeexec(int);
char** comm(int, char**, char**);
int doublefork(void);
void* emalloc(uint);
void* emallocz(uint);
void* erealloc(void*, uint);
char* estrdup(const char*);
char* estrndup(const char*, uint);
void fatal(const char*, ...);
Fmt fmtbuf(char*, int);
void* freelater(void*);
int getbase(const char**, long*);
bool getint(const char*, int*);
bool getlong(const char*, long*);
bool getulong(const char*, ulong*);
void grep(char**, Reprog*, int);
char* join(char**, char*, Fmt*);
int localefmt(Fmt*);
void localefmtinstall(void);
int localelen(char*, char*);
int lprint(int, const char*, ...);
int max(int, int);
int min(int, int);
uvlong nsec(void);
char* pathsearch(const char*, const char*, bool);
void refree(Regex*);
void reinit(Regex*, char*);
int spawn3(int[3], const char*, char*[]);
int spawn3l(int[3], const char*, ...);
uint stokenize(char**, uint, char*, char*);
char* strcasestr(const char*, const char*);
char* strend(char*, int);
uint strlcat(char*, const char*, uint);
int strlcatprint(char*, int, const char*, ...);
char* sxprint(const char*, ...);
uint tokenize(char**, uint, char*, char);
void trim(char *str, const char *chars);
void uniq(char**);
int unmask(Fmt*, long, char**, long);
int unquote(char*, char*[], int);
int utflcpy(char*, const char*, int);
int vlprint(int, const char*, va_list);
char* vsxprint(const char*, va_list);
extern char* _buffer;
extern char buffer[8092];
extern char* const _buf_end;
#define bufclear() \
BLOCK( _buffer = buffer; _buffer[0] = '\0' )
#define bufprint(...) \
_buffer = seprint(_buffer, _buf_end, __VA_ARGS__)
#define die(...) \
_die(__FILE__, __LINE__, __VA_ARGS__)
char *argv0;
#undef ARGBEGIN
#undef ARGEND
#undef ARGF
#undef EARGF
#define ARGBEGIN \
int _argtmp=0, _inargv; char *_argv=nil; \
if(!argv0) argv0=*argv; argv++, argc--; \
_inargv=1; USED(_inargv); \
while(argc && argv[0][0] == '-') { \
_argv=&argv[0][1]; argv++; argc--; \
if(_argv[0] == '-' && _argv[1] == '\0') \
break; \
while(*_argv) switch(*_argv++)
#define ARGEND }_inargv=0;USED(_argtmp, _argv, _inargv)
#define EARGF(f) ((_inargv && *_argv) ? \
(_argtmp=strlen(_argv), _argv+=_argtmp, _argv-_argtmp) \
: ((argc > 0) ? \
(--argc, ++argv, _used(argc), *(argv-1)) \
: ((f), (char*)0)))
#define ARGF() EARGF(_used(0))
/* map.c */
typedef struct Map Map;
typedef struct MapEnt MapEnt;
struct Map {
MapEnt**bucket;
uint nhash;
uint nmemb;
};
void** hash_get(Map*, const char*, bool create);
void* hash_rm(Map*, const char*);
void** map_get(Map*, ulong, bool create);
void* map_rm(Map*, ulong);
/* Yuck. */
#define VECTOR(type, nam, c) \
typedef struct Vector_##nam Vector_##nam; \
struct Vector_##nam { \
type* ary; \
long n; \
long size; \
}; \
void vector_##c##free(Vector_##nam*); \
void vector_##c##init(Vector_##nam*); \
void vector_##c##push(Vector_##nam*, type); \
VECTOR(long, long, l)
VECTOR(Rectangle, rect, r)
VECTOR(void*, ptr, p)
#undef VECTOR
|
Added include/stuff/x.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
#include <stuff/base.h>
#include <stuff/x11.h>
#include <fmt.h>
extern void init_screens(void);
#define Net(x) ("_NET_" x)
#define Action(x) ("_NET_WM_ACTION_" x)
#define State(x) ("_NET_WM_STATE_" x)
#define Type(x) ("_NET_WM_WINDOW_TYPE_" x)
#define NET(x) xatom(Net(x))
#define ACTION(x) xatom(Action(x))
#define STATE(x) xatom(State(x))
#define TYPE(x) xatom(Type(x))
/* printevent.c */
int fmtevent(Fmt*);
int fmtkey(Fmt*);
/* xext.c */
void randr_event(XEvent*);
bool render_argb_p(Visual*);
void xext_event(XEvent*);
void xext_init(void);
Rectangle* xinerama_screens(int*);
void client_readconfig(CTuple*, CTuple*, Font**);
#define event_handle(w, fn, ev) \
_event_handle(w, offsetof(Handlers, fn), (XEvent*)ev)
void _event_handle(Window*, ulong, XEvent*);
void event_check(void);
void event_dispatch(XEvent*);
uint event_flush(long, bool dispatch);
uint event_flushenter(void);
void event_loop(void);
#ifdef IXP_API /* Evil. */
void event_fdclosed(IxpConn*);
void event_fdready(IxpConn*);
void event_preselect(IxpServer*);
#endif
long event_updatextime(void);
void event_buttonpress(XButtonPressedEvent*);
void event_buttonrelease(XButtonPressedEvent*);
void event_clientmessage(XClientMessageEvent*);
void event_configurenotify(XConfigureEvent*);
void event_configurerequest(XConfigureRequestEvent*);
void event_destroynotify(XDestroyWindowEvent*);
void event_enternotify(XCrossingEvent*);
void event_expose(XExposeEvent*);
void event_focusin(XFocusChangeEvent*);
void event_focusout(XFocusChangeEvent*);
void event_keypress(XKeyEvent*);
void event_keyrelease(XKeyEvent*);
void event_leavenotify(XCrossingEvent*);
void event_mapnotify(XMapEvent*);
void event_mappingnotify(XMappingEvent*);
void event_maprequest(XMapRequestEvent*);
void event_motionnotify(XMotionEvent*);
void event_propertynotify(XPropertyEvent*);
void event_reparentnotify(XReparentEvent *ev);
void event_selection(XSelectionEvent*);
void event_selectionclear(XSelectionClearEvent*);
void event_selectionrequest(XSelectionRequestEvent*);
void event_unmapnotify(XUnmapEvent*);
extern long event_lastconfigure;
extern long event_xtime;
extern bool event_looprunning;
extern void (*event_debug)(XEvent*);
extern Visual* render_visual;
extern Colormap render_colormap;
extern bool have_RandR;
extern bool have_render;
extern bool have_xinerama;
|
Added include/stuff/x11.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#define Window XWindow
#define Font XFont
#define Screen XScreen
#define Mask XMask
#include <stuff/geom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xrender.h>
#ifdef _X11_VISIBLE
# include <X11/Xatom.h>
# include <X11/extensions/shape.h>
# include <X11/extensions/Xrandr.h>
#endif
#undef Window
#undef Font
#undef Screen
#undef Mask
enum FontType {
FX11 = 1,
FFontSet,
FXft,
};
enum WindowType {
WWindow,
WImage,
};
typedef enum FontType FontType;
typedef enum WindowType WindowType;
typedef XSetWindowAttributes WinAttr;
typedef union ClientMessageData ClientMessageData;
typedef struct Color Color;
typedef struct CTuple CTuple;
typedef struct ErrorCode ErrorCode;
typedef struct Ewmh Ewmh;
typedef struct Font Font;
typedef struct Handlers Handlers;
typedef struct HandlersLink HandlersLink;
typedef struct Screen Screen;
typedef struct WinHints WinHints;
typedef struct Window Image;
typedef struct Window Window;
typedef struct Xft Xft;
typedef struct XftColor XftColor;
typedef void XftDraw;
typedef struct XftFont XftFont;
union ClientMessageData {
char b[20];
short s[10];
long l[5];
};
struct Color {
ushort red;
ushort green;
ushort blue;
ushort alpha;
ulong pixel;
};
struct CTuple {
Color bg;
Color fg;
Color border;
char colstr[64];
};
struct ErrorCode {
uchar rcode;
uchar ecode;
};
struct Ewmh {
long type;
ulong ping;
ulong lag;
};
struct Font {
int type;
union {
XFontStruct* x11;
XFontSet set;
XftFont* xft;
} font;
Rectangle pad;
int ascent;
int descent;
uint height;
char* name;
};
struct Handlers {
Rectangle (*dndmotion)(Window*, void*, Point);
bool (*bdown)(Window*, void*, XButtonEvent*);
bool (*bup)(Window*, void*, XButtonEvent*);
bool (*config)(Window*, void*, XConfigureEvent*);
bool (*configreq)(Window*, void*, XConfigureRequestEvent*);
bool (*destroy)(Window*, void*, XDestroyWindowEvent*);
bool (*enter)(Window*, void*, XCrossingEvent*);
bool (*expose)(Window*, void*, XExposeEvent*);
bool (*focusin)(Window*, void*, XFocusChangeEvent*);
bool (*focusout)(Window*, void*, XFocusChangeEvent*);
bool (*kdown)(Window*, void*, XKeyEvent*);
bool (*kup)(Window*, void*, XKeyEvent*);
bool (*leave)(Window*, void*, XCrossingEvent*);
bool (*map)(Window*, void*, XMapEvent*);
bool (*mapreq)(Window*, void*, XMapRequestEvent*);
bool (*message)(Window*, void*, XClientMessageEvent*);
bool (*motion)(Window*, void*, XMotionEvent*);
bool (*property)(Window*, void*, XPropertyEvent*);
bool (*reparent)(Window*, void*, XReparentEvent*);
bool (*selection)(Window*, void*, XSelectionEvent*);
bool (*selectionclear)(Window*, void*, XSelectionClearEvent*);
bool (*selectionrequest)(Window*, void*, XSelectionRequestEvent*);
bool (*unmap)(Window*, void*, XUnmapEvent*);
};
struct HandlersLink {
HandlersLink* next;
void* aux;
Handlers* handler;
};
struct WinHints {
Point min;
Point max;
Point base;
Point baspect;
Point inc;
Point grav;
Rectangle aspect;
XWindow group;
bool gravstatic;
bool position;
};
struct Window {
int type;
XID xid;
XIC xic;
GC gc;
Visual* visual;
Colormap colormap;
XftDraw* xft;
Rectangle r;
int border;
Window* parent;
Window* next;
Window* prev;
Handlers* handler;
HandlersLink* handler_link;
WinHints* hints;
Ewmh ewmh;
long eventmask;
void* dnd;
void* aux;
bool mapped;
int unmapped;
int depth;
};
struct Xft {
XftDraw* (*drawcreate)(Display*, Drawable, Visual*, Colormap);
void (*drawdestroy)(XftDraw*);
XftFont* (*fontopen)(Display*, int, const char*);
XftFont* (*fontopenname)(Display*, int, const char*);
XftFont* (*fontclose)(Display*, XftFont*);
void (*textextents)(Display*, XftFont*, const char*, int len, XGlyphInfo*);
void (*drawstring)(Display*, XftColor*, XftFont*, int x, int y, const char*, int len);
};
struct XftColor {
ulong pixel;
XRenderColor color;
};
struct XftFont {
int ascent;
int descent;
int height;
int max_advance_width;
void* charset;
void* pattern;
};
struct Screen {
int screen;
Window root;
GC gc;
Colormap colormap;
Colormap colormap32;
Visual* visual;
Visual* visual32;
Rectangle rect;
int depth;
int fd;
XIM xim;
};
#ifdef VARARGCK
# pragma varargck type "A" Atom
# pragma varargck type "P" Point
# pragma varargck type "R" Rectangle
# pragma varargck type "W" Window*
#endif
Display *display;
Screen scr;
extern char* modkey_names[];
extern struct Map windowmap;
extern struct Map atommap;
extern struct Map atomnamemap;
extern const Point ZP;
extern const Rectangle ZR;
extern const WinHints ZWinHints;
extern Window* pointerwin;
extern Xft* xft;
XRectangle XRect(Rectangle r);
#define RGBA_P(tuple) (\
((long)(tuple).fg.alpha + (long)(tuple).bg.alpha + (long)(tuple).border.alpha) < 3 * 0xff00)
#define changeprop(w, prop, type, data, n) \
changeproperty(w, prop, type, \
((sizeof(*(data)) == 8 ? 4 : sizeof(*(data))) * 8), \
(uchar*)(data), n)
/* x11.c */
XRectangle XRect(Rectangle);
Image* allocimage(int w, int h, int depth);
char* atomname(ulong);
void border(Image *dst, Rectangle, int w, Color*);
void changeprop_char(Window*, const char*, const char*, const char*, int);
void changeprop_long(Window*, const char*, const char*, long[], int);
void changeprop_short(Window*, const char*, const char*, short[], int);
void changeprop_string(Window*, const char*, const char*);
void changeprop_textlist(Window*, const char*, const char*, char*[]);
void changeprop_ulong(Window*, const char*, const char*, ulong[], int);
void changeproperty(Window*, const char*, const char*, int width, const uchar*, int);
void cleanupwindow(Window*);
void clientmessage(Window*, const char*, long, int, ClientMessageData);
void copyimage(Image*, Rectangle, Image*, Point);
Window* createwindow(Window*, Rectangle, int depth, uint class, WinAttr*, int valuemask);
Window* createwindow_rgba(Window*, Rectangle, WinAttr*, int valuemask);
Window* createwindow_visual(Window*, Rectangle, int depth, Visual*, uint class, WinAttr*, int);
void delproperty(Window*, const char*);
void destroywindow(Window*);
void drawline(Image*, Point, Point, int cap, int w, Color*);
void drawpoly(Image*, Point*, int, int cap, int w, Color*);
uint drawstring(Image*, Font*, Rectangle, Align, const char*, Color*);
void fill(Image*, Rectangle, Color*);
void fillpoly(Image*, Point*, int, Color*);
uint fillstring(Image*, Font*, Rectangle, Align, const char*, CTuple*, int border);
Window* findwin(XWindow);
void freefont(Font*);
void freeimage(Image *);
void freestringlist(char**);
XWindow getfocus(void);
void gethints(Window*);
ulong getprop(Window*, const char*, const char*, Atom*, int*, ulong, uchar**, ulong);
ulong getprop_long(Window*, const char*, const char*, ulong, long**, ulong);
char* getprop_string(Window*, const char*);
int getprop_textlist(Window *w, const char *name, char **ret[]);
ulong getprop_ulong(Window*, const char*, const char*, ulong, ulong**, ulong);
ulong getproperty(Window*, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length);
Rectangle getwinrect(Window*);
int grabkeyboard(Window*);
int grabpointer(Window*, Window *confine, Cursor, int mask);
void getselection(char*, void (*)(void*, char*), void*);
bool havexft(void);
void initdisplay(void);
KeyCode keycode(const char*);
uint labelh(Font*);
int loadcolor(CTuple*, const char*, const char*);
Font* loadfont(const char*);
void lowerwin(Window*);
int mapwin(Window*);
void movewin(Window*, Point);
int numlockmask(void);
bool parsecolor(const char *name, Color*);
bool parsekey(char*, int*, char**);
ulong pixelvalue(Image*, Color*);
int pointerscreen(void);
bool pophandler(Window*, Handlers*);
void pushhandler(Window*, Handlers*, void*);
Point querypointer(Window*);
void raisewin(Window*);
void reparentwindow(Window*, Window*, Point);
void reshapewin(Window*, Rectangle);
void selectinput(Window*, long);
void sendevent(Window*, bool propagate, long mask, void*);
void sendmessage(Window*, const char*, long, long, long, long, long);
void setborder(Window*, int, Color*);
void setfocus(Window*, int mode);
Handlers* sethandler(Window*, Handlers*);
void sethints(Window*, WinHints*);
void setshapemask(Window *dst, Image *src, Point);
void setwinattr(Window*, WinAttr*, int valmask);
Rectangle sizehint(WinHints*, Rectangle);
char** strlistdup(char**);
void sync(void);
Rectangle textextents_l(Font*, const char*, uint, int*);
uint textwidth(Font*, const char*);
uint textwidth_l(Font*, const char*, uint len);
Point translate(Window*, Window*, Point);
int traperrors(bool);
void ungrabkeyboard(void);
void ungrabpointer(void);
int unmapwin(Window*);
void warppointer(Point);
Window* window(XWindow);
char* windowname(Window*);
long winprotocols(Window*);
Atom xatom(const char*);
|
Added include/utf.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
#ifndef _UTF_H_
#define _UTF_H_ 1
typedef unsigned int Rune; /* 32 bits */
enum
{
UTFmax = 4, /* maximum bytes per rune */
Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
Runeself = 0x80, /* rune and UTF sequences are the same (<) */
Runeerror = 0xFFFD, /* decoding error in UTF */
Runemax = 0x10FFFF /* maximum rune value */
};
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/utf/?*.c | grep -v static |grep -v __ */
int chartorune(Rune *rune, const char *str);
int fullrune(const char *str, int n);
int isalpharune(Rune);
int islowerrune(Rune);
int isspacerune(Rune);
int istitlerune(Rune);
int isupperrune(Rune);
int runelen(long);
int runenlen(const Rune*, int);
Rune* runestrcat(Rune*, const Rune*);
Rune* runestrchr(const Rune*, Rune);
int runestrcmp(const Rune*, const Rune*);
Rune* runestrcpy(Rune*, const Rune*);
Rune* runestrdup(const Rune*) ;
Rune* runestrecpy(Rune*, Rune *e, const Rune*);
long runestrlen(const Rune*);
Rune* runestrncat(Rune*, const Rune*, long);
int runestrncmp(const Rune*, const Rune*, long);
Rune* runestrncpy(Rune*, const Rune*, long);
Rune* runestrrchr(const Rune*, Rune);
Rune* runestrstr(const Rune*, const Rune*);
int runetochar(char*, const Rune*);
Rune tolowerrune(Rune);
Rune totitlerune(Rune);
Rune toupperrune(Rune);
char* utfecpy(char*, char*, const char*);
int utflen(const char*);
int utfnlen(const char*, long);
char* utfrrune(const char*, long);
char* utfrune(const char*, long);
char* utfutf(const char*, const char*);
#endif
|
Added lib/Makefile.
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ROOT=.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk PDIRS = \ libwmii_hack DIRS = \ libstuff \ libbio \ libfmt \ libregexp \ libutf \ $(PDIRS) include $(ROOT)/mk/dir.mk INSTDIRS = $(PDIRS) |
Added lib/libbio/Makefile.
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ROOT= ../.. include $(ROOT)/mk/hdr.mk VERSION=2.0 TARG=libbio OBJ=\ bbuffered\ bfildes\ bflush\ bgetc\ bgetd\ bgetrune\ binit\ boffset\ bprint\ bvprint\ bputc\ bputrune\ brdline\ brdstr\ bread\ bseek\ bwrite include $(ROOT)/mk/lib.mk |
Added lib/libbio/NOTICE.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | This copyright NOTICE applies to all files in this directory and subdirectories, unless another copyright notice appears in a given file or subdirectory. If you take substantial code from this software to use in other programs, you must somehow include with it an appropriate copyright notice that includes the copyright notice and the other notices below. It is fine (and often tidier) to do that in a separate file such as NOTICE, LICENCE or COPYING. Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. Revisions Copyright © 2000-2005 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---- This software is also made available under the Lucent Public License version 1.02; see http://plan9.bell-labs.com/plan9dist/license.html |
Added lib/libbio/README.
> > > > > | 1 2 3 4 5 | This software was packaged for Unix by Russ Cox. Please send comments to rsc@swtch.com. http://swtch.com/plan9port/unix |
Added lib/libbio/bbuffered.c.
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include "plan9.h"
#include <bio.h>
int
Bbuffered(Biobuf *bp)
{
switch(bp->state) {
case Bracteof:
case Bractive:
return -bp->icount;
case Bwactive:
return bp->bsize + bp->ocount;
case Binactive:
return 0;
}
fprint(2, "Bbuffered: unknown state %d\n", bp->state);
return 0;
}
|
Added lib/libbio/bcat.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include <fmt.h>
#include "bio.h"
Biobuf bout;
void
bcat(Biobuf *b, char *name)
{
char buf[1000];
int n;
while((n = Bread(b, buf, sizeof buf)) > 0){
if(Bwrite(&bout, buf, n) < 0)
fprint(2, "writing during %s: %r\n", name);
}
if(n < 0)
fprint(2, "reading %s: %r\n", name);
}
int
main(int argc, char **argv)
{
int i;
Biobuf b, *bp;
Fmt fmt;
Binit(&bout, 1, O_WRONLY);
Bfmtinit(&fmt, &bout);
fmtprint(&fmt, "hello, world\n");
Bfmtflush(&fmt);
if(argc == 1){
Binit(&b, 0, O_RDONLY);
bcat(&b, "<stdin>");
}else{
for(i=1; i<argc; i++){
if((bp = Bopen(argv[i], O_RDONLY)) == 0){
fprint(2, "Bopen %s: %r\n", argv[i]);
continue;
}
bcat(bp, argv[i]);
Bterm(bp);
}
}
exit(0);
}
|
Added lib/libbio/bfildes.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
#include "plan9.h"
#include <bio.h>
int
Bfildes(Biobuf *bp)
{
return bp->fid;
}
|
Added lib/libbio/bflush.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include "plan9.h"
#include <bio.h>
int
Bflush(Biobuf *bp)
{
int n, c;
switch(bp->state) {
case Bwactive:
n = bp->bsize+bp->ocount;
if(n == 0)
return 0;
c = write(bp->fid, bp->bbuf, n);
if(n == c) {
bp->offset += n;
bp->ocount = -bp->bsize;
return 0;
}
bp->state = Binactive;
bp->ocount = 0;
break;
case Bracteof:
bp->state = Bractive;
case Bractive:
bp->icount = 0;
bp->gbuf = bp->ebuf;
return 0;
}
return Beof;
}
|
Added lib/libbio/bgetc.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#include "plan9.h"
#include <bio.h>
int
Bgetc(Biobuf *bp)
{
int i;
loop:
i = bp->icount;
if(i != 0) {
bp->icount = i+1;
return bp->ebuf[i];
}
if(bp->state != Bractive) {
if(bp->state == Bracteof)
bp->state = Bractive;
return Beof;
}
/*
* get next buffer, try to keep Bungetsize
* characters pre-catenated from the previous
* buffer to allow that many ungets.
*/
memmove(bp->bbuf-Bungetsize, bp->ebuf-Bungetsize, Bungetsize);
i = read(bp->fid, bp->bbuf, bp->bsize);
bp->gbuf = bp->bbuf;
if(i <= 0) {
bp->state = Bracteof;
if(i < 0)
bp->state = Binactive;
return Beof;
}
if(i < bp->bsize) {
memmove(bp->ebuf-i-Bungetsize, bp->bbuf-Bungetsize, i+Bungetsize);
bp->gbuf = bp->ebuf-i;
}
bp->icount = -i;
bp->offset += i;
goto loop;
}
int
Bungetc(Biobuf *bp)
{
if(bp->state == Bracteof)
bp->state = Bractive;
if(bp->state != Bractive)
return Beof;
bp->icount--;
return 1;
}
|
Added lib/libbio/bgetd.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include "plan9.h"
#include <bio.h>
struct bgetd
{
Biobuf* b;
int eof;
};
static int
Bgetdf(void *vp)
{
int c;
struct bgetd *bg = vp;
c = Bgetc(bg->b);
if(c == Beof)
bg->eof = 1;
return c;
}
int
Bgetd(Biobuf *bp, double *dp)
{
double d;
struct bgetd b;
b.b = bp;
b.eof = 0;
d = fmtcharstod(Bgetdf, &b);
if(b.eof)
return -1;
Bungetc(bp);
*dp = d;
return 1;
}
|
Added lib/libbio/bgetrune.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include "plan9.h"
#include <bio.h>
#include <utf.h>
long
Bgetrune(Biobuf *bp)
{
int c, i;
Rune rune;
char str[UTFmax];
c = Bgetc(bp);
if(c < Runeself) { /* one char */
bp->runesize = 1;
return c;
}
str[0] = c;
for(i=1;;) {
c = Bgetc(bp);
if(c < 0)
return c;
str[i++] = c;
if(fullrune(str, i)) {
bp->runesize = chartorune(&rune, str);
while(i > bp->runesize) {
Bungetc(bp);
i--;
}
return rune;
}
}
}
int
Bungetrune(Biobuf *bp)
{
if(bp->state == Bracteof)
bp->state = Bractive;
if(bp->state != Bractive)
return Beof;
bp->icount -= bp->runesize;
bp->runesize = 0;
return 1;
}
|
Added lib/libbio/binit.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
#include <stdlib.h>
#include <plan9.h>
#include <bio.h>
enum
{
MAXBUFS = 20
};
static Biobuf* wbufs[MAXBUFS];
static int atexitflag;
static
void
batexit(void)
{
Biobuf *bp;
int i;
for(i=0; i<MAXBUFS; i++) {
bp = wbufs[i];
if(bp != 0) {
wbufs[i] = 0;
Bflush(bp);
}
}
}
static
void
deinstall(Biobuf *bp)
{
int i;
for(i=0; i<MAXBUFS; i++)
if(wbufs[i] == bp)
wbufs[i] = 0;
}
static
void
install(Biobuf *bp)
{
int i;
deinstall(bp);
for(i=0; i<MAXBUFS; i++)
if(wbufs[i] == 0) {
wbufs[i] = bp;
break;
}
if(atexitflag == 0) {
atexitflag = 1;
atexit(batexit);
}
}
int
Binits(Biobuf *bp, int f, int mode, unsigned char *p, int size)
{
p += Bungetsize; /* make room for Bungets */
size -= Bungetsize;
switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
default:
fprint(2, "Bopen: unknown mode %d\n", mode);
return Beof;
case OREAD:
bp->state = Bractive;
bp->ocount = 0;
break;
case OWRITE:
install(bp);
bp->state = Bwactive;
bp->ocount = -size;
break;
}
bp->bbuf = p;
bp->ebuf = p+size;
bp->bsize = size;
bp->icount = 0;
bp->gbuf = bp->ebuf;
bp->fid = f;
bp->flag = 0;
bp->rdline = 0;
bp->offset = 0;
bp->runesize = 0;
return 0;
}
int
Binit(Biobuf *bp, int f, int mode)
{
return Binits(bp, f, mode, bp->b, sizeof(bp->b));
}
Biobuf*
Bfdopen(int f, int mode)
{
Biobuf *bp;
bp = malloc(sizeof(Biobuf));
if(bp == 0)
return 0;
Binits(bp, f, mode, bp->b, sizeof(bp->b));
bp->flag = Bmagic;
return bp;
}
Biobuf*
Bopen(const char *name, int mode)
{
Biobuf *bp;
int f;
switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
default:
fprint(2, "Bopen: unknown mode %d\n", mode);
return 0;
case OREAD:
f = open(name, mode);
if(f < 0)
return 0;
break;
case OWRITE:
f = creat(name, mode);
if(f < 0)
return 0;
}
bp = Bfdopen(f, mode);
if(bp == 0)
close(f);
return bp;
}
int
Bterm(Biobuf *bp)
{
deinstall(bp);
Bflush(bp);
if(bp->flag == Bmagic) {
bp->flag = 0;
close(bp->fid);
free(bp);
}
return 0;
}
|
Added lib/libbio/bio.3.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
.deEX
.ift .ft5
.nf
..
.deEE
.ft1
.fi
..
.TH BIO 3
.SH NAME
Bopen, Bfdopen, Binit, Binits, Brdline, Brdstr, Bgetc, Bgetrune, Bgetd, Bungetc, Bungetrune, Bread, Bseek, Boffset, Bfildes, Blinelen, Bputc, Bputrune, Bprint, Bvprint, Bwrite, Bflush, Bterm, Bbuffered \- buffered input/output
.SH SYNOPSIS
.ta \w'\fLBiobuf* 'u
.B #include <utf.h>
.br
.B #include <fmt.h>
.br
.B #include <bio.h>
.PP
.B
Biobuf* Bopen(char *file, int mode)
.PP
.B
Biobuf* Bfdopen(int fd, int mode)
.PP
.B
int Binit(Biobuf *bp, int fd, int mode)
.PP
.B
int Binits(Biobufhdr *bp, int fd, int mode, uchar *buf, int size)
.PP
.B
int Bterm(Biobufhdr *bp)
.PP
.B
int Bprint(Biobufhdr *bp, char *format, ...)
.PP
.B
int Bvprint(Biobufhdr *bp, char *format, va_list arglist);
.PP
.B
void* Brdline(Biobufhdr *bp, int delim)
.PP
.B
char* Brdstr(Biobufhdr *bp, int delim, int nulldelim)
.PP
.B
int Blinelen(Biobufhdr *bp)
.PP
.B
vlong Boffset(Biobufhdr *bp)
.PP
.B
int Bfildes(Biobufhdr *bp)
.PP
.B
int Bgetc(Biobufhdr *bp)
.PP
.B
long Bgetrune(Biobufhdr *bp)
.PP
.B
int Bgetd(Biobufhdr *bp, double *d)
.PP
.B
int Bungetc(Biobufhdr *bp)
.PP
.B
int Bungetrune(Biobufhdr *bp)
.PP
.B
vlong Bseek(Biobufhdr *bp, vlong n, int type)
.PP
.B
int Bputc(Biobufhdr *bp, int c)
.PP
.B
int Bputrune(Biobufhdr *bp, long c)
.PP
.B
long Bread(Biobufhdr *bp, void *addr, long nbytes)
.PP
.B
long Bwrite(Biobufhdr *bp, void *addr, long nbytes)
.PP
.B
int Bflush(Biobufhdr *bp)
.PP
.B
int Bbuffered(Biobufhdr *bp)
.PP
.SH DESCRIPTION
These routines implement fast buffered I/O.
I/O on different file descriptors is independent.
.PP
.I Bopen
opens
.I file
for mode
.B O_RDONLY
or creates for mode
.BR O_WRONLY .
It calls
.IR malloc (3)
to allocate a buffer.
.PP
.I Bfdopen
allocates a buffer for the already-open file descriptor
.I fd
for mode
.B O_RDONLY
or
.BR O_WRONLY .
It calls
.IR malloc (3)
to allocate a buffer.
.PP
.I Binit
initializes a standard size buffer, type
.IR Biobuf ,
with the open file descriptor passed in
by the user.
.I Binits
initializes a non-standard size buffer, type
.IR Biobufhdr ,
with the open file descriptor,
buffer area, and buffer size passed in
by the user.
.I Biobuf
and
.I Biobufhdr
are related by the declaration:
.IP
.EX
typedef struct Biobuf Biobuf;
struct Biobuf
{
Biobufhdr;
uchar b[Bungetsize+Bsize];
};
.EE
.PP
Arguments
of types pointer to Biobuf and pointer to Biobufhdr
can be used interchangeably in the following routines.
.PP
.IR Bopen ,
.IR Binit ,
or
.I Binits
should be called before any of the
other routines on that buffer.
.I Bfildes
returns the integer file descriptor of the associated open file.
.PP
.I Bterm
flushes the buffer for
.IR bp .
If the buffer was allocated by
.IR Bopen ,
the buffer is
.I freed
and the file is closed.
.PP
.I Brdline
reads a string from the file associated with
.I bp
up to and including the first
.I delim
character.
The delimiter character at the end of the line is
not altered.
.I Brdline
returns a pointer to the start of the line or
.L 0
on end-of-file or read error.
.I Blinelen
returns the length (including the delimiter)
of the most recent string returned by
.IR Brdline .
.PP
.I Brdstr
returns a
.IR malloc (3)-allocated
buffer containing the next line of input delimited by
.IR delim ,
terminated by a NUL (0) byte.
Unlike
.IR Brdline ,
which returns when its buffer is full even if no delimiter has been found,
.I Brdstr
will return an arbitrarily long line in a single call.
If
.I nulldelim
is set, the terminal delimiter will be overwritten with a NUL.
After a successful call to
.IR Brdstr ,
the return value of
.I Blinelen
will be the length of the returned buffer, excluding the NUL.
.PP
.I Bgetc
returns the next character from
.IR bp ,
or a negative value
at end of file.
.I Bungetc
may be called immediately after
.I Bgetc
to allow the same character to be reread.
.PP
.I Bgetrune
calls
.I Bgetc
to read the bytes of the next
.SM UTF
sequence in the input stream and returns the value of the rune
represented by the sequence.
It returns a negative value
at end of file.
.I Bungetrune
may be called immediately after
.I Bgetrune
to allow the same
.SM UTF
sequence to be reread as either bytes or a rune.
.I Bungetc
and
.I Bungetrune
may back up a maximum of five bytes.
.PP
.I Bgetd
uses
.I fmtcharstod
(see
.IR fmtstrtod (3))
and
.I Bgetc
to read the formatted
floating-point number in the input stream,
skipping initial blanks and tabs.
The value is stored in
.BR *d.
.PP
.I Bread
reads
.I nbytes
of data from
.I bp
into memory starting at
.IR addr .
The number of bytes read is returned on success
and a negative value is returned if a read error occurred.
.PP
.I Bseek
applies
.IR lseek (2)
to
.IR bp .
It returns the new file offset.
.I Boffset
returns the file offset of the next character to be processed.
.PP
.I Bputc
outputs the low order 8 bits of
.I c
on
.IR bp .
If this causes a
.IR write
to occur and there is an error,
a negative value is returned.
Otherwise, a zero is returned.
.PP
.I Bputrune
calls
.I Bputc
to output the low order
16 bits of
.I c
as a rune
in
.SM UTF
format
on the output stream.
.PP
.I Bprint
is a buffered interface to
.IR print (3).
If this causes a
.IR write
to occur and there is an error,
a negative value
.RB ( Beof )
is returned.
Otherwise, the number of bytes output is returned.
.I Bvprint
does the same except it takes as argument a
.B va_list
parameter, so it can be called within a variadic function.
.PP
.I Bwrite
outputs
.I nbytes
of data starting at
.I addr
to
.IR bp .
If this causes a
.IR write
to occur and there is an error,
a negative value is returned.
Otherwise, the number of bytes written is returned.
.PP
.I Bflush
causes any buffered output associated with
.I bp
to be written.
The return is as for
.IR Bputc .
.I Bflush
is called on
exit for every buffer still open
for writing.
.PP
.I Bbuffered
returns the number of bytes in the buffer.
When reading, this is the number of bytes still available from the last
read on the file; when writing, it is the number of bytes ready to be
written.
.SH SOURCE
.B http://swtch.com/plan9port/unix
.SH SEE ALSO
.IR open (2),
.IR print (3),
.IR atexit (3),
.IR utf (7),
.SH DIAGNOSTICS
.I Bio
routines that return integers yield
.B Beof
if
.I bp
is not the descriptor of an open file.
.I Bopen
returns zero if the file cannot be opened in the given mode.
All routines set
.I errstr
on error.
.SH BUGS
.I Brdline
returns an error on strings longer than the buffer associated
with the file
and also if the end-of-file is encountered
before a delimiter.
.I Blinelen
will tell how many characters are available
in these cases.
In the case of a true end-of-file,
.I Blinelen
will return zero.
At the cost of allocating a buffer,
.I Brdstr
sidesteps these issues.
.PP
The data returned by
.I Brdline
may be overwritten by calls to any other
.I bio
routine on the same
.IR bp.
|
Added lib/libbio/boffset.c.
> > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include "plan9.h"
#include <bio.h>
off_t
Boffset(Biobuf *bp)
{
off_t n;
switch(bp->state) {
default:
fprint(2, "Boffset: unknown state %d\n", bp->state);
n = Beof;
break;
case Bracteof:
case Bractive:
n = bp->offset + bp->icount;
break;
case Bwactive:
n = bp->offset + (bp->bsize + bp->ocount);
break;
}
return n;
}
|
Added lib/libbio/bprint.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include "plan9.h"
#include <bio.h>
int
Bprint(Biobuf *bp, const char *fmt, ...)
{
int n;
va_list arg;
va_start(arg, fmt);
n = Bvprint(bp, fmt, arg);
va_end(arg);
return n;
}
|
Added lib/libbio/bputc.c.
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include "plan9.h"
#include <bio.h>
int
Bputc(Biobuf *bp, int c)
{
int i;
for(;;) {
i = bp->ocount;
if(i) {
bp->ebuf[i++] = c;
bp->ocount = i;
return 0;
}
if(Bflush(bp) == Beof)
break;
}
return Beof;
}
|
Added lib/libbio/bputrune.c.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include "plan9.h"
#include <bio.h>
#include <utf.h>
int
Bputrune(Biobuf *bp, long c)
{
Rune rune;
char str[UTFmax];
int n;
rune = c;
if(rune < Runeself) {
Bputc(bp, rune);
return 1;
}
n = runetochar(str, &rune);
if(n == 0)
return Bbad;
if(Bwrite(bp, str, n) != n)
return Beof;
return n;
}
|
Added lib/libbio/brdline.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
#include "plan9.h"
#include <bio.h>
void*
Brdline(Biobuf *bp, int delim)
{
char *ip, *ep;
int i, j;
i = -bp->icount;
if(i == 0) {
/*
* eof or other error
*/
if(bp->state != Bractive) {
if(bp->state == Bracteof)
bp->state = Bractive;
bp->rdline = 0;
bp->gbuf = bp->ebuf;
return 0;
}
}
/*
* first try in remainder of buffer (gbuf doesn't change)
*/
ip = (char*)bp->ebuf - i;
ep = memchr(ip, delim, i);
if(ep) {
j = (ep - ip) + 1;
bp->rdline = j;
bp->icount += j;
return ip;
}
/*
* copy data to beginning of buffer
*/
if(i < bp->bsize)
memmove(bp->bbuf, ip, i);
bp->gbuf = bp->bbuf;
/*
* append to buffer looking for the delim
*/
ip = (char*)bp->bbuf + i;
while(i < bp->bsize) {
j = read(bp->fid, ip, bp->bsize-i);
if(j <= 0) {
/*
* end of file with no delim
*/
memmove(bp->ebuf-i, bp->bbuf, i);
bp->rdline = i;
bp->icount = -i;
bp->gbuf = bp->ebuf-i;
return 0;
}
bp->offset += j;
i += j;
ep = memchr(ip, delim, j);
if(ep) {
/*
* found in new piece
* copy back up and reset everything
*/
ip = (char*)bp->ebuf - i;
if(i < bp->bsize){
memmove(ip, bp->bbuf, i);
bp->gbuf = (unsigned char*)ip;
}
j = (ep - (char*)bp->bbuf) + 1;
bp->rdline = j;
bp->icount = j - i;
return ip;
}
ip += j;
}
/*
* full buffer without finding
*/
bp->rdline = bp->bsize;
bp->icount = -bp->bsize;
bp->gbuf = bp->bbuf;
return 0;
}
int
Blinelen(Biobuf *bp)
{
return bp->rdline;
}
|
Added lib/libbio/brdstr.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
#include <stdlib.h>
#include <plan9.h>
#include <bio.h>
static char*
badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
{
int n;
n = *np;
p = realloc(p, n+ndata+1);
if(p){
memmove(p+n, data, ndata);
n += ndata;
if(n>0 && nulldelim && p[n-1]==delim)
p[--n] = '\0';
else
p[n] = '\0';
*np = n;
}
return p;
}
char*
Brdstr(Biobuf *bp, int delim, int nulldelim)
{
char *ip, *ep, *p;
int i, j;
i = -bp->icount;
bp->rdline = 0;
if(i == 0) {
/*
* eof or other error
*/
if(bp->state != Bractive) {
if(bp->state == Bracteof)
bp->state = Bractive;
bp->gbuf = bp->ebuf;
return nil;
}
}
/*
* first try in remainder of buffer (gbuf doesn't change)
*/
ip = (char*)bp->ebuf - i;
ep = memchr(ip, delim, i);
if(ep) {
j = (ep - ip) + 1;
bp->icount += j;
return badd(nil, &bp->rdline, ip, j, delim, nulldelim);
}
/*
* copy data to beginning of buffer
*/
if(i < bp->bsize)
memmove(bp->bbuf, ip, i);
bp->gbuf = bp->bbuf;
/*
* append to buffer looking for the delim
*/
p = nil;
for(;;){
ip = (char*)bp->bbuf + i;
while(i < bp->bsize) {
j = read(bp->fid, ip, bp->bsize-i);
if(j <= 0 && i == 0)
return p;
if(j <= 0 && i > 0){
/*
* end of file but no delim. pretend we got a delim
* by making the delim \0 and smashing it with nulldelim.
*/
j = 1;
ep = ip;
delim = '\0';
nulldelim = 1;
*ep = delim; /* there will be room for this */
}else{
bp->offset += j;
ep = memchr(ip, delim, j);
}
i += j;
if(ep) {
/*
* found in new piece
* copy back up and reset everything
*/
ip = (char*)bp->ebuf - i;
if(i < bp->bsize){
memmove(ip, bp->bbuf, i);
bp->gbuf = (unsigned char*)ip;
}
j = (ep - (char*)bp->bbuf) + 1;
bp->icount = j - i;
return badd(p, &bp->rdline, ip, j, delim, nulldelim);
}
ip += j;
}
/*
* full buffer without finding; add to user string and continue
*/
p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0);
i = 0;
bp->icount = 0;
bp->gbuf = bp->ebuf;
}
}
|
Added lib/libbio/bread.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#include "plan9.h"
#include <bio.h>
long
Bread(Biobuf *bp, void *ap, long count)
{
long c;
unsigned char *p;
int i, n, ic;
p = ap;
c = count;
ic = bp->icount;
while(c > 0) {
n = -ic;
if(n > c)
n = c;
if(n == 0) {
if(bp->state != Bractive)
break;
i = read(bp->fid, bp->bbuf, bp->bsize);
if(i <= 0) {
bp->state = Bracteof;
if(i < 0)
bp->state = Binactive;
break;
}
bp->gbuf = bp->bbuf;
bp->offset += i;
if(i < bp->bsize) {
memmove(bp->ebuf-i, bp->bbuf, i);
bp->gbuf = bp->ebuf-i;
}
ic = -i;
continue;
}
memmove(p, bp->ebuf+ic, n);
c -= n;
ic += n;
p += n;
}
bp->icount = ic;
return count-c;
}
|
Added lib/libbio/bseek.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
#include "plan9.h"
#include <bio.h>
off_t
Bseek(Biobuf *bp, off_t offset, int base)
{
vlong n, d;
int bufsz;
switch(bp->state) {
default:
fprint(2, "Bseek: unknown state %d\n", bp->state);
return Beof;
case Bracteof:
bp->state = Bractive;
bp->icount = 0;
bp->gbuf = bp->ebuf;
case Bractive:
n = offset;
if(base == 1) {
n += Boffset(bp);
base = 0;
}
/*
* try to seek within buffer
*/
if(base == 0) {
d = n - Boffset(bp);
bufsz = bp->ebuf - bp->gbuf;
if(-bufsz <= d && d <= bufsz){
bp->icount += d;
if(d >= 0) {
if(bp->icount <= 0)
return n;
} else {
if(bp->ebuf - bp->gbuf >= -bp->icount)
return n;
}
}
}
/*
* reset the buffer
*/
n = lseek(bp->fid, n, base);
bp->icount = 0;
bp->gbuf = bp->ebuf;
break;
case Bwactive:
Bflush(bp);
n = lseek(bp->fid, offset, base);
break;
}
bp->offset = n;
return n;
}
|
Added lib/libbio/bvprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include "plan9.h"
#include <bio.h>
static int
fmtBflush(Fmt *f)
{
Biobuf *bp;
bp = f->farg;
bp->ocount = (char*)f->to - (char*)f->stop;
if(Bflush(bp) < 0)
return 0;
f->stop = bp->ebuf;
f->to = (char*)f->stop + bp->ocount;
f->start = f->to;
return 1;
}
int
Bvprint(Biobuf *bp, const char *fmt, va_list arg)
{
int n;
Fmt f;
f.runes = 0;
f.stop = bp->ebuf;
f.start = (char*)f.stop + bp->ocount;
f.to = f.start;
f.flush = fmtBflush;
f.farg = bp;
f.nfmt = 0;
fmtlocaleinit(&f, nil, nil, nil);
n = fmtvprint(&f, fmt, arg);
bp->ocount = (char*)f.to - (char*)f.stop;
if(n == 0)
n = f.nfmt;
return n;
}
|
Added lib/libbio/bwrite.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#include "plan9.h"
#include <bio.h>
long
Bwrite(Biobuf *bp, void *ap, long count)
{
long c;
unsigned char *p;
int i, n, oc;
p = ap;
c = count;
oc = bp->ocount;
while(c > 0) {
n = -oc;
if(n > c)
n = c;
if(n == 0) {
if(bp->state != Bwactive)
return Beof;
i = write(bp->fid, bp->bbuf, bp->bsize);
if(i != bp->bsize) {
bp->state = Binactive;
return Beof;
}
bp->offset += i;
oc = -bp->bsize;
continue;
}
memmove(bp->ebuf+oc, p, n);
oc += n;
c -= n;
p += n;
}
bp->ocount = oc;
return count-c;
}
|
Added lib/libfmt/Makefile.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | ROOT= ../.. include $(ROOT)/mk/hdr.mk VERSION=2.0 TARG=libfmt NUM=\ charstod\ pow10\ nan64 OBJ=\ dofmt\ dorfmt\ errfmt\ fltfmt\ fmt\ fmtfd\ fmtfdflush\ fmtlocale\ fmtlock\ fmtprint\ fmtquote\ fmtrune\ fmtstr\ fmtvprint\ fprint\ print\ runefmtstr\ runeseprint\ runesmprint\ runesnprint\ runesprint\ runevseprint\ runevsmprint\ runevsnprint\ seprint\ smprint\ snprint\ sprint\ strtod\ vfprint\ vseprint\ vsmprint\ vsnprint\ $(NUM) include $(ROOT)/mk/lib.mk |
Added lib/libfmt/NOTICE.
> > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /* * The authors of this software are Rob Pike and Ken Thompson. * Copyright (c) 2002 by Lucent Technologies. * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ This is a Unix port of the Plan 9 formatted I/O package. Please send comments about the packaging to Russ Cox <rsc@swtch.com>. ---- This software is also made available under the Lucent Public License version 1.02; see http://plan9.bell-labs.com/plan9dist/license.html |
Added lib/libfmt/README.
> > > > > | 1 2 3 4 5 | This software was packaged for Unix by Russ Cox. Please send comments to rsc@swtch.com. http://swtch.com/plan9port/unix |
Added lib/libfmt/charstod.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
/*
* Reads a floating-point number by interpreting successive characters
* returned by (*f)(vp). The last call it makes to f terminates the
* scan, so is not a character in the number. It may therefore be
* necessary to back up the input stream up one byte after calling charstod.
*/
double
fmtcharstod(int(*f)(void*), void *vp)
{
double num, dem;
int neg, eneg, dig, exp, c;
num = 0;
neg = 0;
dig = 0;
exp = 0;
eneg = 0;
c = (*f)(vp);
while(c == ' ' || c == '\t')
c = (*f)(vp);
if(c == '-' || c == '+'){
if(c == '-')
neg = 1;
c = (*f)(vp);
}
while(c >= '0' && c <= '9'){
num = num*10 + c-'0';
c = (*f)(vp);
}
if(c == '.')
c = (*f)(vp);
while(c >= '0' && c <= '9'){
num = num*10 + c-'0';
dig++;
c = (*f)(vp);
}
if(c == 'e' || c == 'E'){
c = (*f)(vp);
if(c == '-' || c == '+'){
if(c == '-'){
dig = -dig;
eneg = 1;
}
c = (*f)(vp);
}
while(c >= '0' && c <= '9'){
exp = exp*10 + c-'0';
c = (*f)(vp);
}
}
exp -= dig;
if(exp < 0){
exp = -exp;
eneg = !eneg;
}
dem = __fmtpow10(exp);
if(eneg)
num /= dem;
else
num *= dem;
if(neg)
return -num;
return num;
}
|
Added lib/libfmt/dofmt.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
/* format the output into f->to and return the number of characters fmted */
int
dofmt(Fmt *f, const char *fmt)
{
Rune rune, *rt, *rs;
int r;
char *t, *s;
int n, nfmt;
nfmt = f->nfmt;
for(;;){
if(f->runes){
rt = (Rune*)f->to;
rs = (Rune*)f->stop;
while((r = *(uchar*)fmt) && r != '%'){
if(r < Runeself)
fmt++;
else{
fmt += chartorune(&rune, fmt);
r = rune;
}
FMTRCHAR(f, rt, rs, r);
}
fmt++;
f->nfmt += rt - (Rune *)f->to;
f->to = rt;
if(!r)
return f->nfmt - nfmt;
f->stop = rs;
}else{
t = (char*)f->to;
s = (char*)f->stop;
while((r = *(uchar*)fmt) && r != '%'){
if(r < Runeself){
FMTCHAR(f, t, s, r);
fmt++;
}else{
n = chartorune(&rune, fmt);
if(t + n > s){
t = (char*)__fmtflush(f, t, n);
if(t != nil)
s = (char*)f->stop;
else
return -1;
}
while(n--)
*t++ = *fmt++;
}
}
fmt++;
f->nfmt += t - (char *)f->to;
f->to = t;
if(!r)
return f->nfmt - nfmt;
f->stop = s;
}
fmt = (char*)__fmtdispatch(f, fmt, 0);
if(fmt == nil)
return -1;
}
}
void *
__fmtflush(Fmt *f, void *t, int len)
{
if(f->runes)
f->nfmt += (Rune*)t - (Rune*)f->to;
else
f->nfmt += (char*)t - (char *)f->to;
f->to = t;
if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
f->stop = f->to;
return nil;
}
return f->to;
}
/*
* put a formatted block of memory sz bytes long of n runes into the output buffer,
* left/right justified in a field of at least f->width charactes
*/
int
__fmtpad(Fmt *f, int n)
{
char *t, *s;
int i;
t = (char*)f->to;
s = (char*)f->stop;
for(i = 0; i < n; i++)
FMTCHAR(f, t, s, ' ');
f->nfmt += t - (char *)f->to;
f->to = t;
return 0;
}
int
__rfmtpad(Fmt *f, int n)
{
Rune *t, *s;
int i;
t = (Rune*)f->to;
s = (Rune*)f->stop;
for(i = 0; i < n; i++)
FMTRCHAR(f, t, s, ' ');
f->nfmt += t - (Rune *)f->to;
f->to = t;
return 0;
}
int
__fmtcpy(Fmt *f, const void *vm, int n, int sz)
{
Rune *rt, *rs, r;
char *t, *s, *m, *me;
ulong fl;
int nc, w;
m = (char*)vm;
me = m + sz;
fl = f->flags;
w = 0;
if(fl & FmtWidth)
w = f->width;
if((fl & FmtPrec) && n > f->prec)
n = f->prec;
if(f->runes){
if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
return -1;
rt = (Rune*)f->to;
rs = (Rune*)f->stop;
for(nc = n; nc > 0; nc--){
r = *(uchar*)m;
if(r < Runeself)
m++;
else if((me - m) >= UTFmax || fullrune(m, me-m))
m += chartorune(&r, m);
else
break;
FMTRCHAR(f, rt, rs, r);
}
f->nfmt += rt - (Rune *)f->to;
f->to = rt;
if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
return -1;
}else{
if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
return -1;
t = (char*)f->to;
s = (char*)f->stop;
for(nc = n; nc > 0; nc--){
r = *(uchar*)m;
if(r < Runeself)
m++;
else if((me - m) >= UTFmax || fullrune(m, me-m))
m += chartorune(&r, m);
else
break;
FMTRUNE(f, t, s, r);
}
f->nfmt += t - (char *)f->to;
f->to = t;
if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
return -1;
}
return 0;
}
int
__fmtrcpy(Fmt *f, const void *vm, int n)
{
Rune r, *m, *me, *rt, *rs;
char *t, *s;
ulong fl;
int w;
m = (Rune*)vm;
fl = f->flags;
w = 0;
if(fl & FmtWidth)
w = f->width;
if((fl & FmtPrec) && n > f->prec)
n = f->prec;
if(f->runes){
if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
return -1;
rt = (Rune*)f->to;
rs = (Rune*)f->stop;
for(me = m + n; m < me; m++)
FMTRCHAR(f, rt, rs, *m);
f->nfmt += rt - (Rune *)f->to;
f->to = rt;
if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
return -1;
}else{
if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
return -1;
t = (char*)f->to;
s = (char*)f->stop;
for(me = m + n; m < me; m++){
r = *m;
FMTRUNE(f, t, s, r);
}
f->nfmt += t - (char *)f->to;
f->to = t;
if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
return -1;
}
return 0;
}
/* fmt out one character */
int
__charfmt(Fmt *f)
{
char x[1];
x[0] = va_arg(f->args, int);
f->prec = 1;
return __fmtcpy(f, (const char*)x, 1, 1);
}
/* fmt out one rune */
int
__runefmt(Fmt *f)
{
Rune x[1];
x[0] = va_arg(f->args, int);
return __fmtrcpy(f, (const void*)x, 1);
}
/* public helper routine: fmt out a null terminated string already in hand */
int
fmtstrcpy(Fmt *f, const char *s)
{
int i, j;
Rune r;
if(!s)
return __fmtcpy(f, "<nil>", 5, 5);
/* if precision is specified, make sure we don't wander off the end */
if(f->flags & FmtPrec){
i = 0;
for(j=0; j<f->prec && s[i]; j++)
i += chartorune(&r, s+i);
return __fmtcpy(f, s, j, i);
}
return __fmtcpy(f, s, utflen(s), strlen(s));
}
/* fmt out a null terminated utf string */
int
__strfmt(Fmt *f)
{
char *s;
s = va_arg(f->args, char *);
return fmtstrcpy(f, s);
}
/* public helper routine: fmt out a null terminated rune string already in hand */
int
fmtrunestrcpy(Fmt *f, Rune *s)
{
Rune *e;
int n, p;
if(!s)
return __fmtcpy(f, "<nil>", 5, 5);
/* if precision is specified, make sure we don't wander off the end */
if(f->flags & FmtPrec){
p = f->prec;
for(n = 0; n < p; n++)
if(s[n] == 0)
break;
}else{
for(e = s; *e; e++)
;
n = e - s;
}
return __fmtrcpy(f, s, n);
}
/* fmt out a null terminated rune string */
int
__runesfmt(Fmt *f)
{
Rune *s;
s = va_arg(f->args, Rune *);
return fmtrunestrcpy(f, s);
}
/* fmt a % */
int
__percentfmt(Fmt *f)
{
Rune x[1];
x[0] = f->r;
f->prec = 1;
return __fmtrcpy(f, (const void*)x, 1);
}
/* fmt an integer */
int
__ifmt(Fmt *f)
{
char buf[140], *p, *conv;
/* 140: for 64 bits of binary + 3-byte sep every 4 digits */
uvlong vu;
ulong u;
int neg, base, i, n, fl, w, isv;
int ndig, len, excess, bytelen;
char *grouping;
char *thousands;
neg = 0;
fl = f->flags;
isv = 0;
vu = 0;
u = 0;
if(f->r == 'p'){
u = (ulong)va_arg(f->args, void*);
f->r = 'x';
fl |= FmtUnsigned;
}else if(fl & FmtVLong){
isv = 1;
if(fl & FmtUnsigned)
vu = va_arg(f->args, uvlong);
else
vu = va_arg(f->args, vlong);
}else if(fl & FmtLong){
if(fl & FmtUnsigned)
u = va_arg(f->args, ulong);
else
u = va_arg(f->args, long);
}else if(fl & FmtByte){
if(fl & FmtUnsigned)
u = (uchar)va_arg(f->args, int);
else
u = (char)va_arg(f->args, int);
}else if(fl & FmtShort){
if(fl & FmtUnsigned)
u = (ushort)va_arg(f->args, int);
else
u = (short)va_arg(f->args, int);
}else{
if(fl & FmtUnsigned)
u = va_arg(f->args, uint);
else
u = va_arg(f->args, int);
}
conv = "0123456789abcdef";
grouping = "\4"; /* for hex, octal etc. (undefined by spec but nice) */
thousands = f->thousands;
switch(f->r){
case 'd':
case 'i':
case 'u':
base = 10;
grouping = f->grouping;
break;
case 'X':
conv = "0123456789ABCDEF";
/* fall through */
case 'x':
base = 16;
thousands = ":";
break;
case 'b':
base = 2;
thousands = ":";
break;
case 'o':
base = 8;
break;
default:
return -1;
}
if(!(fl & FmtUnsigned)){
if(isv && (vlong)vu < 0){
vu = -(vlong)vu;
neg = 1;
}else if(!isv && (long)u < 0){
u = -(long)u;
neg = 1;
}
}
p = buf + sizeof buf - 1;
n = 0; /* in runes */
excess = 0; /* number of bytes > number runes */
ndig = 0;
len = utflen(thousands);
bytelen = strlen(thousands);
if(isv){
while(vu){
i = vu % base;
vu /= base;
if((fl & FmtComma) && n % 4 == 3){
*p-- = ',';
n++;
}
if((fl & FmtApost) && __needsep(&ndig, &grouping)){
n += len;
excess += bytelen - len;
p -= bytelen;
memmove(p+1, thousands, bytelen);
}
*p-- = conv[i];
n++;
}
}else{
while(u){
i = u % base;
u /= base;
if((fl & FmtComma) && n % 4 == 3){
*p-- = ',';
n++;
}
if((fl & FmtApost) && __needsep(&ndig, &grouping)){
n += len;
excess += bytelen - len;
p -= bytelen;
memmove(p+1, thousands, bytelen);
}
*p-- = conv[i];
n++;
}
}
if(n == 0){
/*
* "The result of converting a zero value with
* a precision of zero is no characters." - ANSI
*
* "For o conversion, # increases the precision, if and only if
* necessary, to force the first digit of the result to be a zero
* (if the value and precision are both 0, a single 0 is printed)." - ANSI
*/
if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){
*p-- = '0';
n = 1;
if(fl & FmtApost)
__needsep(&ndig, &grouping);
}
/*
* Zero values don't get 0x.
*/
if(f->r == 'x' || f->r == 'X')
fl &= ~FmtSharp;
}
for(w = f->prec; n < w && p > buf+3; n++){
if((fl & FmtApost) && __needsep(&ndig, &grouping)){
n += len;
excess += bytelen - len;
p -= bytelen;
memmove(p+1, thousands, bytelen);
}
*p-- = '0';
}
if(neg || (fl & (FmtSign|FmtSpace)))
n++;
if(fl & FmtSharp){
if(base == 16)
n += 2;
else if(base == 8){
if(p[1] == '0')
fl &= ~FmtSharp;
else
n++;
}
}
if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
w = 0;
if(fl & FmtWidth)
w = f->width;
for(; n < w && p > buf+3; n++){
if((fl & FmtApost) && __needsep(&ndig, &grouping)){
n += len;
excess += bytelen - len;
p -= bytelen;
memmove(p+1, thousands, bytelen);
}
*p-- = '0';
}
f->flags &= ~FmtWidth;
}
if(fl & FmtSharp){
if(base == 16)
*p-- = f->r;
if(base == 16 || base == 8)
*p-- = '0';
}
if(neg)
*p-- = '-';
else if(fl & FmtSign)
*p-- = '+';
else if(fl & FmtSpace)
*p-- = ' ';
f->flags &= ~FmtPrec;
return __fmtcpy(f, p + 1, n, n + excess);
}
int
__countfmt(Fmt *f)
{
void *p;
ulong fl;
fl = f->flags;
p = va_arg(f->args, void*);
if(fl & FmtVLong){
*(vlong*)p = f->nfmt;
}else if(fl & FmtLong){
*(long*)p = f->nfmt;
}else if(fl & FmtByte){
*(char*)p = f->nfmt;
}else if(fl & FmtShort){
*(short*)p = f->nfmt;
}else{
*(int*)p = f->nfmt;
}
return 0;
}
int
__flagfmt(Fmt *f)
{
switch(f->r){
case ',':
f->flags |= FmtComma;
break;
case '-':
f->flags |= FmtLeft;
break;
case '+':
f->flags |= FmtSign;
break;
case '#':
f->flags |= FmtSharp;
break;
case '\'':
f->flags |= FmtApost;
break;
case ' ':
f->flags |= FmtSpace;
break;
case 'u':
f->flags |= FmtUnsigned;
break;
case 'h':
if(f->flags & FmtShort)
f->flags |= FmtByte;
f->flags |= FmtShort;
break;
case 'L':
f->flags |= FmtLDouble;
break;
case 'l':
if(f->flags & FmtLong)
f->flags |= FmtVLong;
f->flags |= FmtLong;
break;
}
return 1;
}
/* default error format */
int
__badfmt(Fmt *f)
{
char x[2+UTFmax];
int n;
x[0] = '%';
n = 1 + runetochar(x+1, &f->r);
x[n++] = '%';
f->prec = n;
__fmtcpy(f, (const void*)x, n, n);
return 0;
}
|
Added lib/libfmt/dorfmt.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
/* format the output into f->to and return the number of characters fmted */
/* BUG: THIS FILE IS NOT UPDATED TO THE NEW SPEC */
int
dorfmt(Fmt *f, const Rune *fmt)
{
Rune *rt, *rs;
int r;
char *t, *s;
int nfmt;
nfmt = f->nfmt;
for(;;){
if(f->runes){
rt = (Rune*)f->to;
rs = (Rune*)f->stop;
while((r = *fmt++) && r != '%'){
FMTRCHAR(f, rt, rs, r);
}
f->nfmt += rt - (Rune *)f->to;
f->to = rt;
if(!r)
return f->nfmt - nfmt;
f->stop = rs;
}else{
t = (char*)f->to;
s = (char*)f->stop;
while((r = *fmt++) && r != '%'){
FMTRUNE(f, t, f->stop, r);
}
f->nfmt += t - (char *)f->to;
f->to = t;
if(!r)
return f->nfmt - nfmt;
f->stop = s;
}
fmt = (Rune*)__fmtdispatch(f, (Rune*)fmt, 1);
if(fmt == nil)
return -1;
}
return 0; /* not reached */
}
|
Added lib/libfmt/errfmt.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
__errfmt(Fmt *f)
{
char *s;
s = strerror(errno);
return fmtstrcpy(f, s);
}
|
Added lib/libfmt/fltfmt.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <fmt.h>
#include <assert.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
enum
{
FDIGIT = 30,
FDEFLT = 6,
NSIGNIF = 17
};
/*
* first few powers of 10, enough for about 1/2 of the
* total space for doubles.
*/
static double pows10[] =
{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49,
1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69,
1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89,
1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, 1e98, 1e99,
1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
};
#define npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
#define pow10(x) fmtpow10(x)
static double
pow10(int n)
{
double d;
int neg;
neg = 0;
if(n < 0){
neg = 1;
n = -n;
}
if(n < npows10)
d = pows10[n];
else{
d = pows10[npows10-1];
for(;;){
n -= npows10 - 1;
if(n < npows10){
d *= pows10[n];
break;
}
d *= pows10[npows10 - 1];
}
}
if(neg)
return 1./d;
return d;
}
/*
* add 1 to the decimal integer string a of length n.
* if 99999 overflows into 10000, return 1 to tell caller
* to move the virtual decimal point.
*/
static int
xadd1(char *a, int n)
{
char *b;
int c;
if(n < 0 || n > NSIGNIF)
return 0;
for(b = a+n-1; b >= a; b--) {
c = *b + 1;
if(c <= '9') {
*b = c;
return 0;
}
*b = '0';
}
/*
* need to overflow adding digit.
* shift number down and insert 1 at beginning.
* decimal is known to be 0s or we wouldn't
* have gotten this far. (e.g., 99999+1 => 00000)
*/
a[0] = '1';
return 1;
}
/*
* subtract 1 from the decimal integer string a.
* if 10000 underflows into 09999, make it 99999
* and return 1 to tell caller to move the virtual
* decimal point. this way, xsub1 is inverse of xadd1.
*/
static int
xsub1(char *a, int n)
{
char *b;
int c;
if(n < 0 || n > NSIGNIF)
return 0;
for(b = a+n-1; b >= a; b--) {
c = *b - 1;
if(c >= '0') {
if(c == '0' && b == a) {
/*
* just zeroed the top digit; shift everyone up.
* decimal is known to be 9s or we wouldn't
* have gotten this far. (e.g., 10000-1 => 09999)
*/
*b = '9';
return 1;
}
*b = c;
return 0;
}
*b = '9';
}
/*
* can't get here. the number a is always normalized
* so that it has a nonzero first digit.
*/
abort();
}
/*
* format exponent like sprintf(p, "e%+02d", e)
*/
static void
xfmtexp(char *p, int e, int ucase)
{
char se[9];
int i;
*p++ = ucase ? 'E' : 'e';
if(e < 0) {
*p++ = '-';
e = -e;
} else
*p++ = '+';
i = 0;
while(e) {
se[i++] = e % 10 + '0';
e /= 10;
}
while(i < 2)
se[i++] = '0';
while(i > 0)
*p++ = se[--i];
*p++ = '\0';
}
/*
* compute decimal integer m, exp such that:
* f = m*10^exp
* m is as short as possible with losing exactness
* assumes special cases (NaN, +Inf, -Inf) have been handled.
*/
static void
xdtoa(double f, char *s, int *exp, int *neg, int *ns)
{
int c, d, e2, e, ee, i, ndigit, oerrno;
char tmp[NSIGNIF+10];
double g;
oerrno = errno; /* in case strtod smashes errno */
/*
* make f non-negative.
*/
*neg = 0;
if(f < 0) {
f = -f;
*neg = 1;
}
/*
* must handle zero specially.
*/
if(f == 0){
*exp = 0;
s[0] = '0';
s[1] = '\0';
*ns = 1;
return;
}
/*
* find g,e such that f = g*10^e.
* guess 10-exponent using 2-exponent, then fine tune.
*/
frexp(f, &e2);
e = (int)(e2 * .301029995664);
g = f * pow10(-e);
while(g < 1) {
e--;
g = f * pow10(-e);
}
while(g >= 10) {
e++;
g = f * pow10(-e);
}
/*
* convert NSIGNIF digits as a first approximation.
*/
for(i=0; i<NSIGNIF; i++) {
d = (int)g;
s[i] = d+'0';
g = (g-d) * 10;
}
s[i] = 0;
/*
* adjust e because s is 314159... not 3.14159...
*/
e -= NSIGNIF-1;
xfmtexp(s+NSIGNIF, e, 0);
/*
* adjust conversion until strtod(s) == f exactly.
*/
for(i=0; i<10; i++) {
g = fmtstrtod(s, nil);
if(f > g) {
if(xadd1(s, NSIGNIF)) {
/* gained a digit */
e--;
xfmtexp(s+NSIGNIF, e, 0);
}
continue;
}
if(f < g) {
if(xsub1(s, NSIGNIF)) {
/* lost a digit */
e++;
xfmtexp(s+NSIGNIF, e, 0);
}
continue;
}
break;
}
/*
* play with the decimal to try to simplify.
*/
/*
* bump last few digits up to 9 if we can
*/
for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
c = s[i];
if(c != '9') {
s[i] = '9';
g = fmtstrtod(s, nil);
if(g != f) {
s[i] = c;
break;
}
}
}
/*
* add 1 in hopes of turning 9s to 0s
*/
if(s[NSIGNIF-1] == '9') {
strcpy(tmp, s);
ee = e;
if(xadd1(tmp, NSIGNIF)) {
ee--;
xfmtexp(tmp+NSIGNIF, ee, 0);
}
g = fmtstrtod(tmp, nil);
if(g == f) {
strcpy(s, tmp);
e = ee;
}
}
/*
* bump last few digits down to 0 as we can.
*/
for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
c = s[i];
if(c != '0') {
s[i] = '0';
g = fmtstrtod(s, nil);
if(g != f) {
s[i] = c;
break;
}
}
}
/*
* remove trailing zeros.
*/
ndigit = NSIGNIF;
while(ndigit > 1 && s[ndigit-1] == '0'){
e++;
--ndigit;
}
s[ndigit] = 0;
*exp = e;
*ns = ndigit;
errno = oerrno;
}
#ifdef PLAN9PORT
static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
#else
static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
#endif
int
__efgfmt(Fmt *fmt)
{
char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
double f;
int c, chr, dotwid, e, exp, fl, ndigits, neg, newndigits;
int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
Rune r, *rs, *rt;
if(fmt->flags&FmtLong)
f = va_arg(fmt->args, long double);
else
f = va_arg(fmt->args, double);
/*
* extract formatting flags
*/
fl = fmt->flags;
fmt->flags = 0;
prec = FDEFLT;
if(fl & FmtPrec)
prec = fmt->prec;
chr = fmt->r;
ucase = 0;
switch(chr) {
case 'A':
case 'E':
case 'F':
case 'G':
chr += 'a'-'A';
ucase = 1;
break;
}
/*
* pick off special numbers.
*/
if(__isNaN(f)) {
s = special[0+ucase];
special:
fmt->flags = fl & (FmtWidth|FmtLeft);
return __fmtcpy(fmt, s, strlen(s), strlen(s));
}
if(__isInf(f, 1)) {
s = special[2+ucase];
goto special;
}
if(__isInf(f, -1)) {
s = special[4+ucase];
goto special;
}
/*
* get exact representation.
*/
digits = buf;
xdtoa(f, digits, &exp, &neg, &ndigits);
/*
* get locale's decimal point.
*/
dot = fmt->decimal;
if(dot == nil)
dot = ".";
dotwid = utflen(dot);
/*
* now the formatting fun begins.
* compute parameters for actual fmt:
*
* pad: number of spaces to insert before/after field.
* z1: number of zeros to insert before digits
* z2: number of zeros to insert after digits
* point: number of digits to print before decimal point
* ndigits: number of digits to use from digits[]
* suf: trailing suffix, like "e-5"
*/
realchr = chr;
switch(chr){
case 'g':
/*
* convert to at most prec significant digits. (prec=0 means 1)
*/
if(prec == 0)
prec = 1;
if(ndigits > prec) {
if(digits[prec] >= '5' && xadd1(digits, prec))
exp++;
exp += ndigits-prec;
ndigits = prec;
}
/*
* extra rules for %g (implemented below):
* trailing zeros removed after decimal unless FmtSharp.
* decimal point only if digit follows.
*/
/* fall through to %e */
default:
case 'e':
/*
* one significant digit before decimal, no leading zeros.
*/
point = 1;
z1 = 0;
/*
* decimal point is after ndigits digits right now.
* slide to be after first.
*/
e = exp + (ndigits-1);
/*
* if this is %g, check exponent and convert prec
*/
if(realchr == 'g') {
if(-4 <= e && e < prec)
goto casef;
prec--; /* one digit before decimal; rest after */
}
/*
* compute trailing zero padding or truncate digits.
*/
if(1+prec >= ndigits)
z2 = 1+prec - ndigits;
else {
/*
* truncate digits
*/
assert(realchr != 'g');
newndigits = 1+prec;
if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
/*
* had 999e4, now have 100e5
*/
e++;
}
ndigits = newndigits;
z2 = 0;
}
xfmtexp(suf, e, ucase);
sufwid = strlen(suf);
break;
casef:
case 'f':
/*
* determine where digits go with respect to decimal point
*/
if(ndigits+exp > 0) {
point = ndigits+exp;
z1 = 0;
} else {
point = 1;
z1 = 1 + -(ndigits+exp);
}
/*
* %g specifies prec = number of significant digits
* convert to number of digits after decimal point
*/
if(realchr == 'g')
prec += z1 - point;
/*
* compute trailing zero padding or truncate digits.
*/
if(point+prec >= z1+ndigits)
z2 = point+prec - (z1+ndigits);
else {
/*
* truncate digits
*/
assert(realchr != 'g');
newndigits = point+prec - z1;
if(newndigits < 0) {
z1 += newndigits;
newndigits = 0;
} else if(newndigits == 0) {
/* perhaps round up */
if(digits[0] >= '5'){
digits[0] = '1';
newndigits = 1;
goto newdigit;
}
} else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
/*
* digits was 999, is now 100; make it 1000
*/
digits[newndigits++] = '0';
newdigit:
/*
* account for new digit
*/
if(z1) /* 0.099 => 0.100 or 0.99 => 1.00*/
z1--;
else /* 9.99 => 10.00 */
point++;
}
z2 = 0;
ndigits = newndigits;
}
sufwid = 0;
break;
}
/*
* if %g is given without FmtSharp, remove trailing zeros.
* must do after truncation, so that e.g. print %.3g 1.001
* produces 1, not 1.00. sorry, but them's the rules.
*/
if(realchr == 'g' && !(fl & FmtSharp)) {
if(z1+ndigits+z2 >= point) {
if(z1+ndigits < point)
z2 = point - (z1+ndigits);
else{
z2 = 0;
while(z1+ndigits > point && digits[ndigits-1] == '0')
ndigits--;
}
}
}
/*
* compute width of all digits and decimal point and suffix if any
*/
wid = z1+ndigits+z2;
if(wid > point)
wid += dotwid;
else if(wid == point){
if(fl & FmtSharp)
wid += dotwid;
else
point++; /* do not print any decimal point */
}
wid += sufwid;
/*
* determine sign
*/
sign = 0;
if(neg)
sign = '-';
else if(fl & FmtSign)
sign = '+';
else if(fl & FmtSpace)
sign = ' ';
if(sign)
wid++;
/*
* compute padding
*/
pad = 0;
if((fl & FmtWidth) && fmt->width > wid)
pad = fmt->width - wid;
if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
z1 += pad;
point += pad;
pad = 0;
}
/*
* format the actual field. too bad about doing this twice.
*/
if(fmt->runes){
if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
return -1;
rt = (Rune*)fmt->to;
rs = (Rune*)fmt->stop;
if(sign)
FMTRCHAR(fmt, rt, rs, sign);
while(z1>0 || ndigits>0 || z2>0) {
if(z1 > 0){
z1--;
c = '0';
}else if(ndigits > 0){
ndigits--;
c = *digits++;
}else{
z2--;
c = '0';
}
FMTRCHAR(fmt, rt, rs, c);
if(--point == 0) {
for(p = dot; *p; ){
p += chartorune(&r, p);
FMTRCHAR(fmt, rt, rs, r);
}
}
}
fmt->nfmt += rt - (Rune*)fmt->to;
fmt->to = rt;
if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
return -1;
if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
return -1;
}else{
if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
return -1;
t = (char*)fmt->to;
s = (char*)fmt->stop;
if(sign)
FMTCHAR(fmt, t, s, sign);
while(z1>0 || ndigits>0 || z2>0) {
if(z1 > 0){
z1--;
c = '0';
}else if(ndigits > 0){
ndigits--;
c = *digits++;
}else{
z2--;
c = '0';
}
FMTCHAR(fmt, t, s, c);
if(--point == 0)
for(p=dot; *p; p++)
FMTCHAR(fmt, t, s, *p);
}
fmt->nfmt += t - (char*)fmt->to;
fmt->to = t;
if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
return -1;
if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
return -1;
}
return 0;
}
|
Added lib/libfmt/fmt.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
enum
{
Maxfmt = 64
};
typedef struct Convfmt Convfmt;
struct Convfmt
{
int c;
volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
};
struct
{
/* lock by calling __fmtlock, __fmtunlock */
int nfmt;
Convfmt fmt[Maxfmt];
} fmtalloc;
static Convfmt knownfmt[] = {
' ', __flagfmt,
'#', __flagfmt,
'%', __percentfmt,
'\'', __flagfmt,
'+', __flagfmt,
',', __flagfmt,
'-', __flagfmt,
'C', __runefmt, /* Plan 9 addition */
'E', __efgfmt,
'G', __efgfmt,
'S', __runesfmt, /* Plan 9 addition */
'X', __ifmt,
'b', __ifmt, /* Plan 9 addition */
'c', __charfmt,
'd', __ifmt,
'e', __efgfmt,
'f', __efgfmt,
'g', __efgfmt,
'h', __flagfmt,
'l', __flagfmt,
'n', __countfmt,
'o', __ifmt,
'p', __ifmt,
'r', __errfmt,
's', __strfmt,
'u', __flagfmt,
'x', __ifmt,
0, nil,
};
int (*fmtdoquote)(int);
/*
* __fmtlock() must be set
*/
static int
__fmtinstall(int c, Fmts f)
{
Convfmt *p, *ep;
if(c<=0 || c>=65536)
return -1;
if(!f)
f = __badfmt;
ep = &fmtalloc.fmt[fmtalloc.nfmt];
for(p=fmtalloc.fmt; p<ep; p++)
if(p->c == c)
break;
if(p == &fmtalloc.fmt[Maxfmt])
return -1;
p->fmt = f;
if(p == ep){ /* installing a new format character */
fmtalloc.nfmt++;
p->c = c;
}
return 0;
}
int
fmtinstall(int c, int (*f)(Fmt*))
{
int ret;
__fmtlock();
ret = __fmtinstall(c, f);
__fmtunlock();
return ret;
}
static Fmts
fmtfmt(int c)
{
Convfmt *p, *ep;
ep = &fmtalloc.fmt[fmtalloc.nfmt];
for(p=fmtalloc.fmt; p<ep; p++)
if(p->c == c){
while(p->fmt == nil) /* loop until value is updated */
;
return p->fmt;
}
/* is this a predefined format char? */
__fmtlock();
for(p=knownfmt; p->c; p++)
if(p->c == c){
__fmtinstall(p->c, p->fmt);
__fmtunlock();
return p->fmt;
}
__fmtunlock();
return __badfmt;
}
void*
__fmtdispatch(Fmt *f, const void *fmt, int isrunes)
{
Rune rune, r;
int i, n;
f->flags = 0;
f->width = f->prec = 0;
for(;;){
if(isrunes){
r = *(Rune*)fmt;
fmt = (Rune*)fmt + 1;
}else{
fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
r = rune;
}
f->r = r;
switch(r){
case '\0':
return nil;
case '.':
f->flags |= FmtWidth|FmtPrec;
continue;
case '0':
if(!(f->flags & FmtWidth)){
f->flags |= FmtZero;
continue;
}
/* fall through */
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
i = 0;
while(r >= '0' && r <= '9'){
i = i * 10 + r - '0';
if(isrunes){
r = *(Rune*)fmt;
fmt = (Rune*)fmt + 1;
}else{
r = *(char*)fmt;
fmt = (char*)fmt + 1;
}
}
if(isrunes)
fmt = (Rune*)fmt - 1;
else
fmt = (char*)fmt - 1;
numflag:
if(f->flags & FmtWidth){
f->flags |= FmtPrec;
f->prec = i;
}else{
f->flags |= FmtWidth;
f->width = i;
}
continue;
case '*':
i = va_arg(f->args, int);
if(i < 0){
/*
* negative precision =>
* ignore the precision.
*/
if(f->flags & FmtPrec){
f->flags &= ~FmtPrec;
f->prec = 0;
continue;
}
i = -i;
f->flags |= FmtLeft;
}
goto numflag;
}
n = (*fmtfmt(r))(f);
if(n < 0)
return nil;
if(n == 0)
return (void*)fmt;
}
}
|
Added lib/libfmt/fmtdef.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
/*
* dofmt -- format to a buffer
* the number of characters formatted is returned,
* or -1 if there was an error.
* if the buffer is ever filled, flush is called.
* it should reset the buffer and return whether formatting should continue.
*/
typedef int (*Fmts)(Fmt*);
typedef struct Quoteinfo Quoteinfo;
struct Quoteinfo
{
int quoted; /* if set, string must be quoted */
int nrunesin; /* number of input runes that can be accepted */
int nbytesin; /* number of input bytes that can be accepted */
int nrunesout; /* number of runes that will be generated */
int nbytesout; /* number of bytes that will be generated */
};
/* Edit .+1,/^$/ |cfn |grep -v static | grep __ */
double __Inf(int sign);
double __NaN(void);
int __badfmt(Fmt *f);
int __charfmt(Fmt *f);
int __countfmt(Fmt *f);
int __efgfmt(Fmt *fmt);
int __errfmt(Fmt *f);
int __flagfmt(Fmt *f);
int __fmtFdFlush(Fmt *f);
int __fmtcpy(Fmt *f, const void *vm, int n, int sz);
void* __fmtdispatch(Fmt *f, const void *fmt, int isrunes);
void * __fmtflush(Fmt *f, void *t, int len);
void __fmtlock(void);
int __fmtpad(Fmt *f, int n);
double __fmtpow10(int n);
int __fmtrcpy(Fmt *f, const void *vm, int n);
void __fmtunlock(void);
int __ifmt(Fmt *f);
int __isInf(double d, int sign);
int __isNaN(double d);
int __needsep(int *ndig, char **grouping);
int __needsquotes(char *s, int *quotelenp);
int __percentfmt(Fmt *f);
void __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout);
int __quotestrfmt(int runesin, Fmt *f);
int __rfmtpad(Fmt *f, int n);
int __runefmt(Fmt *f);
int __runeneedsquotes(Rune *r, int *quotelenp);
int __runesfmt(Fmt *f);
int __strfmt(Fmt *f);
#define FMTCHAR(f, t, s, c)\
do{\
if(t + 1 > (char*)s){\
t = __fmtflush(f, t, 1);\
if(t != nil)\
s = f->stop;\
else\
return -1;\
}\
*t++ = c;\
}while(0)
#define FMTRCHAR(f, t, s, c)\
do{\
if(t + 1 > (Rune*)s){\
t = __fmtflush(f, t, sizeof(Rune));\
if(t != nil)\
s = f->stop;\
else\
return -1;\
}\
*t++ = c;\
}while(0)
#define FMTRUNE(f, t, s, r)\
do{\
Rune _rune;\
int _runelen;\
if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
t = __fmtflush(f, t, _runelen);\
if(t != nil)\
s = f->stop;\
else\
return -1;\
}\
if(r < Runeself)\
*t++ = r;\
else{\
_rune = r;\
t += runetochar(t, &_rune);\
}\
}while(0)
#ifndef va_copy
# define va_copy(a,b) (a) = (b)
#endif
|
Added lib/libfmt/fmtfd.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
/*
* public routine for final flush of a formatting buffer
* to a file descriptor; returns total char count.
*/
int
fmtfdflush(Fmt *f)
{
if(__fmtFdFlush(f) <= 0)
return -1;
return f->nfmt;
}
/*
* initialize an output buffer for buffered printing
*/
int
fmtfdinit(Fmt *f, int fd, char *buf, int size)
{
f->runes = 0;
f->start = buf;
f->to = buf;
f->stop = buf + size;
f->flush = __fmtFdFlush;
f->farg = (void*)(uintptr_t)fd;
f->flags = 0;
f->nfmt = 0;
fmtlocaleinit(f, nil, nil, nil);
return 0;
}
|
Added lib/libfmt/fmtfdflush.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <unistd.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
/*
* generic routine for flushing a formatting buffer
* to a file descriptor
*/
int
__fmtFdFlush(Fmt *f)
{
int n;
n = (char*)f->to - (char*)f->start;
if(n && write((uintptr_t)f->farg, f->start, n) != n)
return 0;
f->to = f->start;
return 1;
}
|
Added lib/libfmt/fmtinstall.3.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
.deEX
.ift .ft5
.nf
..
.deEE
.ft1
.fi
..
.TH FMTINSTALL 3
.SH NAME
fmtinstall, dofmt, dorfmt, fmtprint, fmtvprint, fmtrune, fmtstrcpy, fmtrunestrcpy, fmtfdinit, fmtfdflush, fmtstrinit, fmtstrflush, runefmtstrinit, runefmtstrflush, errfmt \- support for user-defined print formats and output routines
.SH SYNOPSIS
.B #include <utf.h>
.br
.B #include <fmt.h>
.PP
.ft L
.nf
.ta \w' 'u +\w' 'u +\w' 'u +\w' 'u +\w' 'u
typedef struct Fmt Fmt;
struct Fmt{
uchar runes; /* output buffer is runes or chars? */
void *start; /* of buffer */
void *to; /* current place in the buffer */
void *stop; /* end of the buffer; overwritten if flush fails */
int (*flush)(Fmt*); /* called when to == stop */
void *farg; /* to make flush a closure */
int nfmt; /* num chars formatted so far */
va_list args; /* args passed to dofmt */
int r; /* % format Rune */
int width;
int prec;
ulong flags;
};
enum{
FmtWidth = 1,
FmtLeft = FmtWidth << 1,
FmtPrec = FmtLeft << 1,
FmtSharp = FmtPrec << 1,
FmtSpace = FmtSharp << 1,
FmtSign = FmtSpace << 1,
FmtZero = FmtSign << 1,
FmtUnsigned = FmtZero << 1,
FmtShort = FmtUnsigned << 1,
FmtLong = FmtShort << 1,
FmtVLong = FmtLong << 1,
FmtComma = FmtVLong << 1,
FmtFlag = FmtComma << 1
};
.fi
.PP
.B
.ta \w'\fLchar* 'u
.PP
.B
int fmtfdinit(Fmt *f, int fd, char *buf, int nbuf);
.PP
.B
int fmtfdflush(Fmt *f);
.PP
.B
int fmtstrinit(Fmt *f);
.PP
.B
char* fmtstrflush(Fmt *f);
.PP
.B
int runefmtstrinit(Fmt *f);
.PP
.B
Rune* runefmtstrflush(Fmt *f);
.PP
.B
int fmtinstall(int c, int (*fn)(Fmt*));
.PP
.B
int dofmt(Fmt *f, char *fmt);
.PP
.B
int dorfmt(Fmt*, Rune *fmt);
.PP
.B
int fmtprint(Fmt *f, char *fmt, ...);
.PP
.B
int fmtvprint(Fmt *f, char *fmt, va_list v);
.PP
.B
int fmtrune(Fmt *f, int r);
.PP
.B
int fmtstrcpy(Fmt *f, char *s);
.PP
.B
int fmtrunestrcpy(Fmt *f, Rune *s);
.PP
.B
int errfmt(Fmt *f);
.SH DESCRIPTION
The interface described here allows the construction of custom
.IR print (3)
verbs and output routines.
In essence, they provide access to the workings of the formatted print code.
.PP
The
.IR print (3)
suite maintains its state with a data structure called
.BR Fmt .
A typical call to
.IR print (3)
or its relatives initializes a
.B Fmt
structure, passes it to subsidiary routines to process the output,
and finishes by emitting any saved state recorded in the
.BR Fmt .
The details of the
.B Fmt
are unimportant to outside users, except insofar as the general
design influences the interface.
The
.B Fmt
records whether the output is in runes or bytes,
the verb being processed, its precision and width,
and buffering parameters.
Most important, it also records a
.I flush
routine that the library will call if a buffer overflows.
When printing to a file descriptor, the flush routine will
emit saved characters and reset the buffer; when printing
to an allocated string, it will resize the string to receive more output.
The flush routine is nil when printing to fixed-size buffers.
User code need never provide a flush routine; this is done internally
by the library.
.SS Custom output routines
To write a custom output routine, such as an error handler that
formats and prints custom error messages, the output sequence can be run
from outside the library using the routines described here.
There are two main cases: output to an open file descriptor
and output to a string.
.PP
To write to a file descriptor, call
.I fmtfdinit
to initialize the local
.B Fmt
structure
.IR f ,
giving the file descriptor
.IR fd ,
the buffer
.IR buf ,
and its size
.IR nbuf .
Then call
.IR fmtprint
or
.IR fmtvprint
to generate the output.
These behave like
.B fprint
(see
.IR print (3))
or
.B vfprint
except that the characters are buffered until
.I fmtfdflush
is called and the return value is either 0 or \-1.
A typical example of this sequence appears in the Examples section.
.PP
The same basic sequence applies when outputting to an allocated string:
call
.I fmtstrinit
to initialize the
.BR Fmt ,
then call
.I fmtprint
and
.I fmtvprint
to generate the output.
Finally,
.I fmtstrflush
will return the allocated string, which should be freed after use.
To output to a rune string, use
.I runefmtstrinit
and
.IR runefmtstrflush .
Regardless of the output style or type,
.I fmtprint
or
.I fmtvprint
generates the characters.
.SS Custom format verbs
.I Fmtinstall
is used to install custom verbs and flags labeled by character
.IR c ,
which may be any non-zero Unicode character.
.I Fn
should be declared as
.IP
.EX
int fn(Fmt*)
.EE
.PP
.IB Fp ->r
is the flag or verb character to cause
.I fn
to be called.
In
.IR fn ,
.IB fp ->width ,
.IB fp ->prec
are the width and precision, and
.IB fp ->flags
the decoded flags for the verb (see
.IR print (3)
for a description of these items).
The standard flag values are:
.B FmtSign
.RB ( + ),
.B FmtLeft
.RB ( - ),
.B FmtSpace
.RB ( '\ ' ),
.B FmtSharp
.RB ( # ),
.B FmtComma
.RB ( , ),
.B FmtLong
.RB ( l ),
.B FmtShort
.RB ( h ),
.B FmtUnsigned
.RB ( u ),
and
.B FmtVLong
.RB ( ll ).
The flag bits
.B FmtWidth
and
.B FmtPrec
identify whether a width and precision were specified.
.PP
.I Fn
is passed a pointer to the
.B Fmt
structure recording the state of the output.
If
.IB fp ->r
is a verb (rather than a flag),
.I fn
should use
.B Fmt->args
to fetch its argument from the list,
then format it, and return zero.
If
.IB fp ->r
is a flag,
.I fn
should return one.
All interpretation of
.IB fp ->width\f1,
.IB fp ->prec\f1,
and
.IB fp-> flags
is left up to the conversion routine.
.I Fmtinstall
returns 0 if the installation succeeds, \-1 if it fails.
.PP
.IR Fmtprint
and
.IR fmtvprint
may be called to
help prepare output in custom conversion routines.
However, these functions clear the width, precision, and flags.
Both functions return 0 for success and \-1 for failure.
.PP
The functions
.I dofmt
and
.I dorfmt
are the underlying formatters; they
use the existing contents of
.B Fmt
and should be called only by sophisticated conversion routines.
These routines return the number of characters (bytes of UTF or runes)
produced.
.PP
Some internal functions may be useful to format primitive types.
They honor the width, precision and flags as described in
.IR print (3).
.I Fmtrune
formats a single character
.BR r .
.I Fmtstrcpy
formats a string
.BR s ;
.I fmtrunestrcpy
formats a rune string
.BR s .
.I Errfmt
formats the system error string.
All these routines return zero for successful execution.
Conversion routines that call these functions will work properly
regardless of whether the output is bytes or runes.
.\" .PP
.\" .IR 2c (1)
.\" describes the C directive
.\" .B #pragma
.\" .B varargck
.\" that can be used to provide type-checking for custom print verbs and output routines.
.SH EXAMPLES
This function prints an error message with a variable
number of arguments and then quits.
Compared to the corresponding example in
.IR print (3),
this version uses a smaller buffer, will never truncate
the output message, but might generate multiple
.B write
system calls to produce its output.
.IP
.EX
.ta 6n +6n +6n +6n +6n +6n +6n +6n +6n
#pragma varargck argpos error 1
void fatal(char *fmt, ...)
{
Fmt f;
char buf[64];
va_list arg;
fmtfdinit(&f, 1, buf, sizeof buf);
fmtprint(&f, "fatal: ");
va_start(arg, fmt);
fmtvprint(&f, fmt, arg);
va_end(arg);
fmtprint(&f, "\en");
fmtfdflush(&f);
exits("fatal error");
}
.EE
.PP
This example adds a verb to print complex numbers.
.IP
.EX
typedef
struct {
double r, i;
} Complex;
#pragma varargck type "X" Complex
int
Xfmt(Fmt *f)
{
Complex c;
c = va_arg(f->args, Complex);
return fmtprint(f, "(%g,%g)", c.r, c.i);
}
main(...)
{
Complex x = (Complex){ 1.5, -2.3 };
fmtinstall('X', Xfmt);
print("x = %X\en", x);
}
.EE
.SH SOURCE
.B http://swtch.com/plan9port/unix
.SH SEE ALSO
.IR print (3),
.IR utf (7)
.SH DIAGNOSTICS
These routines return negative numbers or nil for errors and set
.IR errstr .
|
Added lib/libfmt/fmtlocale.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
/* Copyright (c) 2004 Google Inc.; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
/*
* Fill in the internationalization stuff in the State structure.
* For nil arguments, provide the sensible defaults:
* decimal is a period
* thousands separator is a comma
* thousands are marked every three digits
*/
void
fmtlocaleinit(Fmt *f, char *decimal, char *thousands, char *grouping)
{
if(decimal == nil || decimal[0] == '\0')
decimal = ".";
if(thousands == nil)
thousands = ",";
if(grouping == nil)
grouping = "\3";
f->decimal = decimal;
f->thousands = thousands;
f->grouping = grouping;
}
/*
* We are about to emit a digit in e.g. %'d. If that digit would
* overflow a thousands (e.g.) grouping, tell the caller to emit
* the thousands separator. Always advance the digit counter
* and pointer into the grouping descriptor.
*/
int
__needsep(int *ndig, char **grouping)
{
int group;
(*ndig)++;
group = *(unsigned char*)*grouping;
/* CHAR_MAX means no further grouping. \0 means we got the empty string */
if(group == 0xFF || group == 0x7f || group == 0x00)
return 0;
if(*ndig > group){
/* if we're at end of string, continue with this grouping; else advance */
if((*grouping)[1] != '\0')
(*grouping)++;
*ndig = 1;
return 1;
}
return 0;
}
|
Added lib/libfmt/fmtlock.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
void
__fmtlock(void)
{
}
void
__fmtunlock(void)
{
}
|
Added lib/libfmt/fmtprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
/*
* format a string into the output buffer
* designed for formats which themselves call fmt,
* but ignore any width flags
*/
int
fmtprint(Fmt *f, const char *fmt, ...)
{
va_list va;
int n;
f->flags = 0;
f->width = 0;
f->prec = 0;
va_copy(va, f->args);
va_end(f->args);
va_start(f->args, fmt);
n = dofmt(f, fmt);
va_end(f->args);
f->flags = 0;
f->width = 0;
f->prec = 0;
va_copy(f->args,va);
va_end(va);
if(n >= 0)
return 0;
return n;
}
|
Added lib/libfmt/fmtquote.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
/*
* How many bytes of output UTF will be produced by quoting (if necessary) this string?
* How many runes? How much of the input will be consumed?
* The parameter q is filled in by __quotesetup.
* The string may be UTF or Runes (s or r).
* Return count does not include NUL.
* Terminate the scan at the first of:
* NUL in input
* count exceeded in input
* count exceeded on output
* *ninp is set to number of input bytes accepted.
* nin may be <0 initially, to avoid checking input by count.
*/
void
__quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
{
int w;
Rune c;
q->quoted = 0;
q->nbytesout = 0;
q->nrunesout = 0;
q->nbytesin = 0;
q->nrunesin = 0;
if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
if(nout < 2)
return;
q->quoted = 1;
q->nbytesout = 2;
q->nrunesout = 2;
}
for(; nin!=0; nin--){
if(s)
w = chartorune(&c, s);
else{
c = *r;
w = runelen(c);
}
if(c == '\0')
break;
if(runesout){
if(q->nrunesout+1 > nout)
break;
}else{
if(q->nbytesout+w > nout)
break;
}
if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote(c))){
if(!q->quoted){
if(runesout){
if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
break;
}else{
if(1+q->nbytesout+w+1 > nout) /* no room for quotes */
break;
}
q->nrunesout += 2; /* include quotes */
q->nbytesout += 2; /* include quotes */
q->quoted = 1;
}
if(c == '\'') {
if(runesout){
if(1+q->nrunesout+1 > nout) /* no room for quotes */
break;
}else{
if(1+q->nbytesout+w > nout) /* no room for quotes */
break;
}
q->nbytesout++;
q->nrunesout++; /* quotes reproduce as two characters */
}
}
/* advance input */
if(s)
s += w;
else
r++;
q->nbytesin += w;
q->nrunesin++;
/* advance output */
q->nbytesout += w;
q->nrunesout++;
}
}
static int
qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
{
Rune r, *rm, *rme;
char *t, *s, *m, *me;
Rune *rt, *rs;
ulong fl;
int nc, w;
m = sin;
me = m + q->nbytesin;
rm = rin;
rme = rm + q->nrunesin;
fl = f->flags;
w = 0;
if(fl & FmtWidth)
w = f->width;
if(f->runes){
if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
return -1;
}else{
if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
return -1;
}
t = (char*)f->to;
s = (char*)f->stop;
rt = (Rune*)f->to;
rs = (Rune*)f->stop;
if(f->runes)
FMTRCHAR(f, rt, rs, '\'');
else
FMTRUNE(f, t, s, '\'');
for(nc = q->nrunesin; nc > 0; nc--){
if(sin){
r = *(uchar*)m;
if(r < Runeself)
m++;
else if((me - m) >= UTFmax || fullrune(m, me-m))
m += chartorune(&r, m);
else
break;
}else{
if(rm >= rme)
break;
r = *(uchar*)rm++;
}
if(f->runes){
FMTRCHAR(f, rt, rs, r);
if(r == '\'')
FMTRCHAR(f, rt, rs, r);
}else{
FMTRUNE(f, t, s, r);
if(r == '\'')
FMTRUNE(f, t, s, r);
}
}
if(f->runes){
FMTRCHAR(f, rt, rs, '\'');
USED(rs);
f->nfmt += rt - (Rune *)f->to;
f->to = rt;
if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
return -1;
}else{
FMTRUNE(f, t, s, '\'');
USED(s);
f->nfmt += t - (char *)f->to;
f->to = t;
if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
return -1;
}
return 0;
}
int
__quotestrfmt(int runesin, Fmt *f)
{
int nin, outlen;
Rune *r;
char *s;
Quoteinfo q;
nin = -1;
if(f->flags&FmtPrec)
nin = f->prec;
if(runesin){
r = va_arg(f->args, Rune *);
s = nil;
}else{
s = va_arg(f->args, char *);
r = nil;
}
if(!s && !r)
return __fmtcpy(f, (void*)"<nil>", 5, 5);
if(f->flush)
outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
else if(f->runes)
outlen = (Rune*)f->stop - (Rune*)f->to;
else
outlen = (char*)f->stop - (char*)f->to;
__quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
/*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */
if(runesin){
if(!q.quoted)
return __fmtrcpy(f, r, q.nrunesin);
return qstrfmt(nil, r, &q, f);
}
if(!q.quoted)
return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
return qstrfmt(s, nil, &q, f);
}
int
quotestrfmt(Fmt *f)
{
return __quotestrfmt(0, f);
}
int
quoterunestrfmt(Fmt *f)
{
return __quotestrfmt(1, f);
}
void
quotefmtinstall(void)
{
fmtinstall('q', quotestrfmt);
fmtinstall('Q', quoterunestrfmt);
}
int
__needsquotes(char *s, int *quotelenp)
{
Quoteinfo q;
__quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
*quotelenp = q.nbytesout;
return q.quoted;
}
int
__runeneedsquotes(Rune *r, int *quotelenp)
{
Quoteinfo q;
__quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
*quotelenp = q.nrunesout;
return q.quoted;
}
|
Added lib/libfmt/fmtrune.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
fmtrune(Fmt *f, int r)
{
Rune *rt;
char *t;
int n;
if(f->runes){
rt = (Rune*)f->to;
FMTRCHAR(f, rt, f->stop, r);
f->to = rt;
n = 1;
}else{
t = (char*)f->to;
FMTRUNE(f, t, f->stop, r);
n = t - (char*)f->to;
f->to = t;
}
f->nfmt += n;
return 0;
}
|
Added lib/libfmt/fmtstr.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdlib.h>
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
char*
fmtstrflush(Fmt *f)
{
if(f->start == nil)
return nil;
*(char*)f->to = '\0';
f->to = f->start;
return (char*)f->start;
}
|
Added lib/libfmt/fmtvprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
/*
* format a string into the output buffer
* designed for formats which themselves call fmt,
* but ignore any width flags
*/
int
fmtvprint(Fmt *f, const char *fmt, va_list args)
{
va_list va;
int n;
f->flags = 0;
f->width = 0;
f->prec = 0;
va_copy(va,f->args);
va_end(f->args);
va_copy(f->args,args);
n = dofmt(f, fmt);
f->flags = 0;
f->width = 0;
f->prec = 0;
va_end(f->args);
va_copy(f->args,va);
va_end(va);
if(n >= 0)
return 0;
return n;
}
|
Added lib/libfmt/fprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
fprint(int fd, const char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = vfprint(fd, fmt, args);
va_end(args);
return n;
}
|
Added lib/libfmt/libfmt.a.
cannot compute difference between binary files
Added lib/libfmt/nan64.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
/*
* 64-bit IEEE not-a-number routines.
* This is big/little-endian portable assuming that
* the 64-bit doubles and 64-bit integers have the
* same byte ordering.
*/
#include "plan9.h"
#include <assert.h>
#include "fmt.h"
#include "fmtdef.h"
static uvlong uvnan = ((uvlong)0x7FF00000<<32)|0x00000001;
static uvlong uvinf = ((uvlong)0x7FF00000<<32)|0x00000000;
static uvlong uvneginf = ((uvlong)0xFFF00000<<32)|0x00000000;
/* gcc sees through the obvious casts. */
static uvlong
d2u(double d)
{
union {
uvlong v;
double d;
} u;
assert(sizeof(u.d) == sizeof(u.v));
u.d = d;
return u.v;
}
static double
u2d(uvlong v)
{
union {
uvlong v;
double d;
} u;
assert(sizeof(u.d) == sizeof(u.v));
u.v = v;
return u.d;
}
double
__NaN(void)
{
return u2d(uvnan);
}
int
__isNaN(double d)
{
uvlong x;
x = d2u(d);
/* IEEE 754: exponent bits 0x7FF and non-zero mantissa */
return (x&uvinf) == uvinf && (x&~uvneginf) != 0;
}
double
__Inf(int sign)
{
return u2d(sign < 0 ? uvneginf : uvinf);
}
int
__isInf(double d, int sign)
{
uvlong x;
x = d2u(d);
if(sign == 0)
return x==uvinf || x==uvneginf;
else if(sign > 0)
return x==uvinf;
else
return x==uvneginf;
}
|
Added lib/libfmt/pow10.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
/*
* this table might overflow 127-bit exponent representations.
* in that case, truncate it after 1.0e38.
* it is important to get all one can from this
* routine since it is used in atof to scale numbers.
* the presumption is that C converts fp numbers better
* than multipication of lower powers of 10.
*/
static
double tab[] =
{
1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
1.0e10,1.0e11,1.0e12,1.0e13,1.0e14,1.0e15,1.0e16,1.0e17,1.0e18,1.0e19,
1.0e20,1.0e21,1.0e22,1.0e23,1.0e24,1.0e25,1.0e26,1.0e27,1.0e28,1.0e29,
1.0e30,1.0e31,1.0e32,1.0e33,1.0e34,1.0e35,1.0e36,1.0e37,1.0e38,1.0e39,
1.0e40,1.0e41,1.0e42,1.0e43,1.0e44,1.0e45,1.0e46,1.0e47,1.0e48,1.0e49,
1.0e50,1.0e51,1.0e52,1.0e53,1.0e54,1.0e55,1.0e56,1.0e57,1.0e58,1.0e59,
1.0e60,1.0e61,1.0e62,1.0e63,1.0e64,1.0e65,1.0e66,1.0e67,1.0e68,1.0e69,
};
double
__fmtpow10(int n)
{
int m;
if(n < 0) {
n = -n;
if(n < (int)(sizeof(tab)/sizeof(tab[0])))
return 1/tab[n];
m = n/2;
return __fmtpow10(-m) * __fmtpow10(m-n);
}
if(n < (int)(sizeof(tab)/sizeof(tab[0])))
return tab[n];
m = n/2;
return __fmtpow10(m) * __fmtpow10(n-m);
}
|
Added lib/libfmt/print.3.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
.deEX
.ift .ft5
.nf
..
.deEE
.ft1
.fi
..
.\" diffs from /usr/local/plan9/man/man3/print.3:
.\"
.\" - include different headers
.\" - drop reference to bio(3)
.\" - change exits to exit
.\" - text about unsigned verbs
.\" - source pointer
.\"
.TH PRINT 3
.SH NAME
print, fprint, sprint, snprint, seprint, smprint, runesprint, runesnprint, runeseprint, runesmprint, vfprint, vsnprint, vseprint, vsmprint, runevsnprint, runevseprint, runevsmprint \- print formatted output
.SH SYNOPSIS
.B #include <utf.h>
.PP
.B #include <fmt.h>
.PP
.ta \w'\fLchar* 'u
.B
int print(char *format, ...)
.PP
.B
int fprint(int fd, char *format, ...)
.PP
.B
int sprint(char *s, char *format, ...)
.PP
.B
int snprint(char *s, int len, char *format, ...)
.PP
.B
char* seprint(char *s, char *e, char *format, ...)
.PP
.B
char* smprint(char *format, ...)
.PP
.B
int runesprint(Rune *s, char *format, ...)
.PP
.B
int runesnprint(Rune *s, int len, char *format, ...)
.PP
.B
Rune* runeseprint(Rune *s, Rune *e, char *format, ...)
.PP
.B
Rune* runesmprint(char *format, ...)
.PP
.B
int vfprint(int fd, char *format, va_list v)
.PP
.B
int vsnprint(char *s, int len, char *format, va_list v)
.PP
.B
char* vseprint(char *s, char *e, char *format, va_list v)
.PP
.B
char* vsmprint(char *format, va_list v)
.PP
.B
int runevsnprint(Rune *s, int len, char *format, va_list v)
.PP
.B
Rune* runevseprint(Rune *s, Rune *e, char *format, va_list v)
.PP
.B
Rune* runevsmprint(Rune *format, va_list v)
.PP
.B
.SH DESCRIPTION
.I Print
writes text to the standard output.
.I Fprint
writes to the named output
file descriptor:
a buffered form
is described in
.IR bio (3).
.I Sprint
places text
followed by the NUL character
.RB ( \e0 )
in consecutive bytes starting at
.IR s ;
it is the user's responsibility to ensure that
enough storage is available.
Each function returns the number of bytes
transmitted (not including the NUL
in the case of
.IR sprint ),
or
a negative value if an output error was encountered.
.PP
.I Snprint
is like
.IR sprint ,
but will not place more than
.I len
bytes in
.IR s .
Its result is always NUL-terminated and holds the maximal
number of complete UTF-8 characters that can fit.
.I Seprint
is like
.IR snprint ,
except that the end is indicated by a pointer
.I e
rather than a count and the return value points to the terminating NUL of the
resulting string.
.I Smprint
is like
.IR sprint ,
except that it prints into and returns a string of the required length, which is
allocated by
.IR malloc (3).
.PP
The routines
.IR runesprint ,
.IR runesnprint ,
.IR runeseprint ,
and
.I runesmprint
are the same as
.IR sprint ,
.IR snprint ,
.IR seprint
and
.I smprint
except that their output is rune strings instead of byte strings.
.PP
Finally, the routines
.IR vfprint ,
.IR vsnprint ,
.IR vseprint ,
.IR vsmprint ,
.IR runevsnprint ,
.IR runevseprint ,
and
.I runevsmprint
are like their
.BR v-less
relatives except they take as arguments a
.B va_list
parameter, so they can be called within a variadic function.
The Example section shows a representative usage.
.PP
Each of these functions
converts, formats, and prints its
trailing arguments
under control of a
.IR format
string.
The
format
contains two types of objects:
plain characters, which are simply copied to the
output stream,
and conversion specifications,
each of which results in fetching of
zero or more
arguments.
The results are undefined if there are arguments of the
wrong type or too few
arguments for the format.
If the format is exhausted while
arguments remain, the excess
is ignored.
.PP
Each conversion specification has the following format:
.IP
.B "% [flags] verb
.PP
The verb is a single character and each flag is a single character or a
(decimal) numeric string.
Up to two numeric strings may be used;
the first is called
.IR width ,
the second
.IR precision .
A period can be used to separate them, and if the period is
present then
.I width
and
.I precision
are taken to be zero if missing, otherwise they are `omitted'.
Either or both of the numbers may be replaced with the character
.BR * ,
meaning that the actual number will be obtained from the argument list
as an integer.
The flags and numbers are arguments to
the
.I verb
described below.
.PP
The numeric verbs
.BR d ,
.BR i ,
.BR u ,
.BR o ,
.BR b ,
.BR x ,
and
.B X
format their arguments in decimal, decimal,
unsigned decimal, octal, binary, hexadecimal, and upper case hexadecimal.
Each interprets the flags
.BR 0 ,
.BR h ,
.BR hh ,
.BR l ,
.BR + ,
.BR - ,
.BR , ,
and
.B #
to mean pad with zeros,
short, byte, long, always print a sign, left justified, commas every three digits,
and alternate format.
Also, a space character in the flag
position is like
.BR + ,
but prints a space instead of a plus sign for non-negative values.
If neither
short nor long is specified,
then the argument is an
.BR int .
If an unsigned verb is specified,
then the argument is interpreted as a
positive number and no sign is output;
space and
.B +
flags are ignored for unsigned verbs.
If two
.B l
flags are given,
then the argument is interpreted as a
.B vlong
(usually an 8-byte, sometimes a 4-byte integer).
If
.I precision
is not omitted, the number is padded on the left with zeros
until at least
.I precision
digits appear.
If
.I precision
is explicitly 0, and the number is 0,
no digits are generated, and alternate formatting
does not apply.
Then, if alternate format is specified,
for
.B o
conversion, the number is preceded by a
.B 0
if it doesn't already begin with one.
For non-zero numbers and
.B x
conversion, the number is preceded by
.BR 0x ;
for
.B X
conversion, the number is preceded by
.BR 0X .
Finally, if
.I width
is not omitted, the number is padded on the left (or right, if
left justification is specified) with enough blanks to
make the field at least
.I width
characters long.
.PP
The floating point verbs
.BR f ,
.BR e ,
.BR E ,
.BR g ,
and
.B G
take a
.B double
argument.
Each interprets the flags
.BR 0 ,
.BR L
.BR + ,
.BR - ,
and
.B #
to mean pad with zeros,
long double argument,
always print a sign,
left justified,
and
alternate format.
.I Width
is the minimum field width and,
if the converted value takes up less than
.I width
characters, it is padded on the left (or right, if `left justified')
with spaces.
.I Precision
is the number of digits that are converted after the decimal place for
.BR e ,
.BR E ,
and
.B f
conversions,
and
.I precision
is the maximum number of significant digits for
.B g
and
.B G
conversions.
The
.B f
verb produces output of the form
.RB [ - ] digits [ .digits\fR].
.B E
conversion appends an exponent
.BR E [ - ] digits ,
and
.B e
conversion appends an exponent
.BR e [ - ] digits .
The
.B g
verb will output the argument in either
.B e
or
.B f
with the goal of producing the smallest output.
Also, trailing zeros are omitted from the fraction part of
the output, and a trailing decimal point appears only if it is followed
by a digit.
The
.B G
verb is similar, but uses
.B E
format instead of
.BR e .
When alternate format is specified, the result will always contain a decimal point,
and for
.B g
and
.B G
conversions, trailing zeros are not removed.
.PP
The
.B s
verb copies a string
(pointer to
.BR char )
to the output.
The number of characters copied
.RI ( n )
is the minimum
of the size of the string and
.IR precision .
These
.I n
characters are justified within a field of
.I width
characters as described above.
If a
.I precision
is given, it is safe for the string not to be nul-terminated
as long as it is at least
.I precision
characters (not bytes!) long.
The
.B S
verb is similar, but it interprets its pointer as an array
of runes (see
.IR utf (7));
the runes are converted to
.SM UTF
before output.
.PP
The
.B c
verb copies a single
.B char
(promoted to
.BR int )
justified within a field of
.I width
characters as described above.
The
.B C
verb is similar, but works on runes.
.PP
The
.B p
verb formats a pointer value.
At the moment, it is a synonym for
.BR x ,
but that will change if pointers and integers are different sizes.
.PP
The
.B r
verb takes no arguments; it copies the error string returned by a call to
.IR strerror (3)
with an argument of
.IR errno.
.PP
Custom verbs may be installed using
.IR fmtinstall (3).
.SH EXAMPLE
This function prints an error message with a variable
number of arguments and then quits.
.IP
.EX
.ta 6n +6n +6n
void fatal(char *msg, ...)
{
char buf[1024], *out;
va_list arg;
out = seprint(buf, buf+sizeof buf, "Fatal error: ");
va_start(arg, msg);
out = vseprint(out, buf+sizeof buf, msg, arg);
va_end(arg);
write(2, buf, out-buf);
exit(1);
}
.EE
.SH SOURCE
.B http://swtch.com/plan9port/unix
.SH SEE ALSO
.IR fmtinstall (3),
.IR fprintf (3),
.IR utf (7)
.SH DIAGNOSTICS
Routines that write to a file descriptor or call
.IR malloc
set
.IR errstr .
.SH BUGS
The formatting is close to that specified for ANSI
.IR fprintf (3);
the main difference is that
.B b
and
.B r
are not in ANSI and some
.B C9X
verbs and syntax are missing.
Also, and distinctly not a bug,
.I print
and friends generate
.SM UTF
rather than
.SM ASCII.
.PP
There is no
.IR runeprint ,
.IR runefprint ,
etc. because runes are byte-order dependent and should not be written directly to a file; use the
UTF output of
.I print
or
.I fprint
instead.
Also,
.I sprint
is deprecated for safety reasons; use
.IR snprint ,
.IR seprint ,
or
.I smprint
instead.
Safety also precludes the existence of
.IR runesprint .
|
Added lib/libfmt/print.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
print(const char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = vfprint(1, fmt, args);
va_end(args);
return n;
}
|
Added lib/libfmt/runefmtstr.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <stdlib.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
Rune*
runefmtstrflush(Fmt *f)
{
if(f->start == nil)
return nil;
*(Rune*)f->to = '\0';
f->to = f->start;
return f->start;
}
|
Added lib/libfmt/runeseprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
Rune*
runeseprint(Rune *buf, Rune *e, const char *fmt, ...)
{
Rune *p;
va_list args;
va_start(args, fmt);
p = runevseprint(buf, e, fmt, args);
va_end(args);
return p;
}
|
Added lib/libfmt/runesmprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
Rune*
runesmprint(const char *fmt, ...)
{
va_list args;
Rune *p;
va_start(args, fmt);
p = runevsmprint(fmt, args);
va_end(args);
return p;
}
|
Added lib/libfmt/runesnprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
runesnprint(Rune *buf, int len, const char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = runevsnprint(buf, len, fmt, args);
va_end(args);
return n;
}
|
Added lib/libfmt/runesprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
runesprint(Rune *buf, const char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = runevsnprint(buf, 256, fmt, args);
va_end(args);
return n;
}
|
Added lib/libfmt/runevseprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
Rune*
runevseprint(Rune *buf, Rune *e, const char *fmt, va_list args)
{
Fmt f;
if(e <= buf)
return nil;
f.runes = 1;
f.start = buf;
f.to = buf;
f.stop = e - 1;
f.flush = nil;
f.farg = nil;
f.nfmt = 0;
va_copy(f.args,args);
fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
va_end(f.args);
*(Rune*)f.to = '\0';
return (Rune*)f.to;
}
|
Added lib/libfmt/runevsmprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
/*
* Plan 9 port version must include libc.h in order to
* get Plan 9 debugging malloc, which sometimes returns
* different pointers than the standard malloc.
*/
#include <stdlib.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
static int
runeFmtStrFlush(Fmt *f)
{
Rune *s;
int n;
if(f->start == nil)
return 0;
n = (uintptr_t)f->farg;
n *= 2;
s = (Rune*)f->start;
f->start = realloc(s, sizeof(Rune)*n);
if(f->start == nil){
f->farg = nil;
f->to = nil;
f->stop = nil;
free(s);
return 0;
}
f->farg = (void*)(uintptr_t)n;
f->to = (Rune*)f->start + ((Rune*)f->to - s);
f->stop = (Rune*)f->start + n - 1;
return 1;
}
int
runefmtstrinit(Fmt *f)
{
int n;
memset(f, 0, sizeof *f);
f->runes = 1;
n = 32;
f->start = malloc(sizeof(Rune)*n);
if(f->start == nil)
return -1;
f->to = f->start;
f->stop = (Rune*)f->start + n - 1;
f->flush = runeFmtStrFlush;
f->farg = (void*)(uintptr_t)n;
f->nfmt = 0;
fmtlocaleinit(f, nil, nil, nil);
return 0;
}
/*
* print into an allocated string buffer
*/
Rune*
runevsmprint(const char *fmt, va_list args)
{
Fmt f;
int n;
if(runefmtstrinit(&f) < 0)
return nil;
va_copy(f.args,args);
n = dofmt(&f, fmt);
va_end(f.args);
if(f.start == nil)
return nil;
if(n < 0){
free(f.start);
return nil;
}
*(Rune*)f.to = '\0';
return (Rune*)f.start;
}
|
Added lib/libfmt/runevsnprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
runevsnprint(Rune *buf, int len, const char *fmt, va_list args)
{
Fmt f;
if(len <= 0)
return -1;
f.runes = 1;
f.start = buf;
f.to = buf;
f.stop = buf + len - 1;
f.flush = nil;
f.farg = nil;
f.nfmt = 0;
va_copy(f.args,args);
fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
va_end(f.args);
*(Rune*)f.to = '\0';
return (Rune*)f.to - buf;
}
|
Added lib/libfmt/seprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
char*
seprint(char *buf, char *e, const char *fmt, ...)
{
char *p;
va_list args;
va_start(args, fmt);
p = vseprint(buf, e, fmt, args);
va_end(args);
return p;
}
|
Added lib/libfmt/smprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
char*
smprint(const char *fmt, ...)
{
va_list args;
char *p;
va_start(args, fmt);
p = vsmprint(fmt, args);
va_end(args);
return p;
}
|
Added lib/libfmt/snprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
snprint(char *buf, int len, const char *fmt, ...)
{
int n;
va_list args;
va_start(args, fmt);
n = vsnprint(buf, len, fmt, args);
va_end(args);
return n;
}
|
Added lib/libfmt/sprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.h"
#include "fmtdef.h"
int
sprint(char *buf, const char *fmt, ...)
{
int n;
uint len;
va_list args;
len = 1<<30; /* big number, but sprint is deprecated anyway */
/*
* on PowerPC, the stack is near the top of memory, so
* we must be sure not to overflow a 32-bit pointer.
*
* careful! gcc-4.2 assumes buf+len < buf can never be true and
* optimizes the test away. casting to uintptr works around this bug.
*/
if((uintptr_t)buf+len < (uintptr_t)buf)
len = -(uintptr_t)buf-1;
va_start(args, fmt);
n = vsnprint(buf, len, fmt, args);
va_end(args);
return n;
}
|
Added lib/libfmt/strtod.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
static ulong
umuldiv(ulong a, ulong b, ulong c)
{
double d;
d = ((double)a * (double)b) / (double)c;
if(d >= 4294967295.)
d = 4294967295.;
return (ulong)d;
}
/*
* This routine will convert to arbitrary precision
* floating point entirely in multi-precision fixed.
* The answer is the closest floating point number to
* the given decimal number. Exactly half way are
* rounded ala ieee rules.
* Method is to scale input decimal between .500 and .999...
* with external power of 2, then binary search for the
* closest mantissa to this decimal number.
* Nmant is is the required precision. (53 for ieee dp)
* Nbits is the max number of bits/word. (must be <= 28)
* Prec is calculated - the number of words of fixed mantissa.
*/
enum
{
Nbits = 28, /* bits safely represented in a ulong */
Nmant = 53, /* bits of precision required */
Prec = (Nmant+Nbits+1)/Nbits, /* words of Nbits each to represent mantissa */
Sigbit = 1<<(Prec*Nbits-Nmant), /* first significant bit of Prec-th word */
Ndig = 1500,
One = (ulong)(1<<Nbits),
Half = (ulong)(One>>1),
Maxe = 310,
Fsign = 1<<0, /* found - */
Fesign = 1<<1, /* found e- */
Fdpoint = 1<<2, /* found . */
S0 = 0, /* _ _S0 +S1 #S2 .S3 */
S1, /* _+ #S2 .S3 */
S2, /* _+# #S2 .S4 eS5 */
S3, /* _+. #S4 */
S4, /* _+#.# #S4 eS5 */
S5, /* _+#.#e +S6 #S7 */
S6, /* _+#.#e+ #S7 */
S7 /* _+#.#e+# #S7 */
};
static int xcmp(char*, char*);
static int fpcmp(char*, ulong*);
static void frnorm(ulong*);
static void divascii(char*, int*, int*, int*);
static void mulascii(char*, int*, int*, int*);
typedef struct Tab Tab;
struct Tab
{
int bp;
int siz;
char* cmp;
};
double
fmtstrtod(const char *as, char **aas)
{
int na, ex, dp, bp, c, i, flag, state;
ulong low[Prec], hig[Prec], mid[Prec];
double d;
char *s, a[Ndig];
flag = 0; /* Fsign, Fesign, Fdpoint */
na = 0; /* number of digits of a[] */
dp = 0; /* na of decimal point */
ex = 0; /* exonent */
state = S0;
for(s=(char*)as;; s++) {
c = *s;
if(c >= '0' && c <= '9') {
switch(state) {
case S0:
case S1:
case S2:
state = S2;
break;
case S3:
case S4:
state = S4;
break;
case S5:
case S6:
case S7:
state = S7;
ex = ex*10 + (c-'0');
continue;
}
if(na == 0 && c == '0') {
dp--;
continue;
}
if(na < Ndig-50)
a[na++] = c;
continue;
}
switch(c) {
case '\t':
case '\n':
case '\v':
case '\f':
case '\r':
case ' ':
if(state == S0)
continue;
break;
case '-':
if(state == S0)
flag |= Fsign;
else
flag |= Fesign;
case '+':
if(state == S0)
state = S1;
else
if(state == S5)
state = S6;
else
break; /* syntax */
continue;
case '.':
flag |= Fdpoint;
dp = na;
if(state == S0 || state == S1) {
state = S3;
continue;
}
if(state == S2) {
state = S4;
continue;
}
break;
case 'e':
case 'E':
if(state == S2 || state == S4) {
state = S5;
continue;
}
break;
}
break;
}
/*
* clean up return char-pointer
*/
switch(state) {
case S0:
if(xcmp(s, "nan") == 0) {
if(aas != nil)
*aas = s+3;
goto retnan;
}
case S1:
if(xcmp(s, "infinity") == 0) {
if(aas != nil)
*aas = s+8;
goto retinf;
}
if(xcmp(s, "inf") == 0) {
if(aas != nil)
*aas = s+3;
goto retinf;
}
case S3:
if(aas != nil)
*aas = (char*)as;
goto ret0; /* no digits found */
case S6:
s--; /* back over +- */
case S5:
s--; /* back over e */
break;
}
if(aas != nil)
*aas = s;
if(flag & Fdpoint)
while(na > 0 && a[na-1] == '0')
na--;
if(na == 0)
goto ret0; /* zero */
a[na] = 0;
if(!(flag & Fdpoint))
dp = na;
if(flag & Fesign)
ex = -ex;
dp += ex;
if(dp < -Maxe){
errno = ERANGE;
goto ret0; /* underflow by exp */
} else
if(dp > +Maxe)
goto retinf; /* overflow by exp */
/*
* normalize the decimal ascii number
* to range .[5-9][0-9]* e0
*/
bp = 0; /* binary exponent */
while(dp > 0)
divascii(a, &na, &dp, &bp);
while(dp < 0 || a[0] < '5')
mulascii(a, &na, &dp, &bp);
/* close approx by naive conversion */
mid[0] = 0;
mid[1] = 1;
for(i=0; (c=a[i]) != '\0'; i++) {
mid[0] = mid[0]*10 + (c-'0');
mid[1] = mid[1]*10;
if(i >= 8)
break;
}
low[0] = umuldiv(mid[0], One, mid[1]);
hig[0] = umuldiv(mid[0]+1, One, mid[1]);
for(i=1; i<Prec; i++) {
low[i] = 0;
hig[i] = One-1;
}
/* binary search for closest mantissa */
for(;;) {
/* mid = (hig + low) / 2 */
c = 0;
for(i=0; i<Prec; i++) {
mid[i] = hig[i] + low[i];
if(c)
mid[i] += One;
c = mid[i] & 1;
mid[i] >>= 1;
}
frnorm(mid);
/* compare */
c = fpcmp(a, mid);
if(c > 0) {
c = 1;
for(i=0; i<Prec; i++)
if(low[i] != mid[i]) {
c = 0;
low[i] = mid[i];
}
if(c)
break; /* between mid and hig */
continue;
}
if(c < 0) {
for(i=0; i<Prec; i++)
hig[i] = mid[i];
continue;
}
/* only hard part is if even/odd roundings wants to go up */
c = mid[Prec-1] & (Sigbit-1);
if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
mid[Prec-1] -= c;
break; /* exactly mid */
}
/* normal rounding applies */
c = mid[Prec-1] & (Sigbit-1);
mid[Prec-1] -= c;
if(c >= Sigbit/2) {
mid[Prec-1] += Sigbit;
frnorm(mid);
}
goto out;
ret0:
return 0;
retnan:
return __NaN();
retinf:
/*
* Unix strtod requires these. Plan 9 would return Inf(0) or Inf(-1). */
errno = ERANGE;
if(flag & Fsign)
return -HUGE_VAL;
return HUGE_VAL;
out:
d = 0;
for(i=0; i<Prec; i++)
d = d*One + mid[i];
if(flag & Fsign)
d = -d;
d = ldexp(d, bp - Prec*Nbits);
if(d == 0){ /* underflow */
errno = ERANGE;
}
return d;
}
static void
frnorm(ulong *f)
{
int i, c;
c = 0;
for(i=Prec-1; i>0; i--) {
f[i] += c;
c = f[i] >> Nbits;
f[i] &= One-1;
}
f[0] += c;
}
static int
fpcmp(char *a, ulong* f)
{
ulong tf[Prec];
int i, d, c;
for(i=0; i<Prec; i++)
tf[i] = f[i];
for(;;) {
/* tf *= 10 */
for(i=0; i<Prec; i++)
tf[i] = tf[i]*10;
frnorm(tf);
d = (tf[0] >> Nbits) + '0';
tf[0] &= One-1;
/* compare next digit */
c = *a;
if(c == 0) {
if('0' < d)
return -1;
if(tf[0] != 0)
goto cont;
for(i=1; i<Prec; i++)
if(tf[i] != 0)
goto cont;
return 0;
}
if(c > d)
return +1;
if(c < d)
return -1;
a++;
cont:;
}
}
static void
divby(char *a, int *na, int b)
{
int n, c;
char *p;
p = a;
n = 0;
while(n>>b == 0) {
c = *a++;
if(c == 0) {
while(n) {
c = n*10;
if(c>>b)
break;
n = c;
}
goto xx;
}
n = n*10 + c-'0';
(*na)--;
}
for(;;) {
c = n>>b;
n -= c<<b;
*p++ = c + '0';
c = *a++;
if(c == 0)
break;
n = n*10 + c-'0';
}
(*na)++;
xx:
while(n) {
n = n*10;
c = n>>b;
n -= c<<b;
*p++ = c + '0';
(*na)++;
}
*p = 0;
}
static Tab tab1[] =
{
1, 0, "",
3, 1, "7",
6, 2, "63",
9, 3, "511",
13, 4, "8191",
16, 5, "65535",
19, 6, "524287",
23, 7, "8388607",
26, 8, "67108863",
27, 9, "134217727",
};
static void
divascii(char *a, int *na, int *dp, int *bp)
{
int b, d;
Tab *t;
d = *dp;
if(d >= (int)(nelem(tab1)))
d = (int)(nelem(tab1))-1;
t = tab1 + d;
b = t->bp;
if(memcmp(a, t->cmp, t->siz) > 0)
d--;
*dp -= d;
*bp += b;
divby(a, na, b);
}
static void
mulby(char *a, char *p, char *q, int b)
{
int n, c;
n = 0;
*p = 0;
for(;;) {
q--;
if(q < a)
break;
c = *q - '0';
c = (c<<b) + n;
n = c/10;
c -= n*10;
p--;
*p = c + '0';
}
while(n) {
c = n;
n = c/10;
c -= n*10;
p--;
*p = c + '0';
}
}
static Tab tab2[] =
{
1, 1, "", /* dp = 0-0 */
3, 3, "125",
6, 5, "15625",
9, 7, "1953125",
13, 10, "1220703125",
16, 12, "152587890625",
19, 14, "19073486328125",
23, 17, "11920928955078125",
26, 19, "1490116119384765625",
27, 19, "7450580596923828125", /* dp 8-9 */
};
static void
mulascii(char *a, int *na, int *dp, int *bp)
{
char *p;
int d, b;
Tab *t;
d = -*dp;
if(d >= (int)(nelem(tab2)))
d = (int)(nelem(tab2))-1;
t = tab2 + d;
b = t->bp;
if(memcmp(a, t->cmp, t->siz) < 0)
d--;
p = a + *na;
*bp -= b;
*dp += d;
*na += d;
mulby(a, p+d, p, b);
}
static int
xcmp(char *a, char *b)
{
int c1, c2;
while((c1 = *b++) != '\0') {
c2 = *a++;
if(isupper(c2))
c2 = tolower(c2);
if(c1 != c2)
return 1;
}
return 0;
}
|
Added lib/libfmt/test.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdio.h>
#include <stdarg.h>
#include <utf.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
main(int argc, char *argv[])
{
quotefmtinstall();
print("hello world\n");
print("x: %x\n", 0x87654321);
print("u: %u\n", 0x87654321);
print("d: %d\n", 0x87654321);
print("s: %s\n", "hi there");
print("q: %q\n", "hi i'm here");
print("c: %c\n", '!');
print("g: %g %g %g\n", 3.14159, 3.14159e10, 3.14159e-10);
print("e: %e %e %e\n", 3.14159, 3.14159e10, 3.14159e-10);
print("f: %f %f %f\n", 3.14159, 3.14159e10, 3.14159e-10);
print("smiley: %C\n", (Rune)0x263a);
print("%g %.18g\n", 2e25, 2e25);
print("%2.18g\n", 1.0);
print("%2.18f\n", 1.0);
print("%f\n", 3.1415927/4);
print("%d\n", 23);
print("%i\n", 23);
print("%0.10d\n", 12345);
/* test %4$d formats */
print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
print("%3$d %4$*5$06d %2$d %1$d\n", 444, 333, 111, 222, 20);
print("%3$hd %4$*5$06d %2$d %1$d\n", 444, 333, (short)111, 222, 20);
print("%3$lld %4$*5$06d %2$d %1$d\n", 444, 333, 111LL, 222, 20);
/* test %'d formats */
print("%'d %'d %'d\n", 1, 2222, 33333333);
print("%'019d\n", 0);
print("%08d %08d %08d\n", 1, 2222, 33333333);
print("%'08d %'08d %'08d\n", 1, 2222, 33333333);
print("%'x %'X %'b\n", 0x11111111, 0xabcd1234, 12345);
print("%'lld %'lld %'lld\n", 1LL, 222222222LL, 3333333333333LL);
print("%019lld %019lld %019lld\n", 1LL, 222222222LL, 3333333333333LL);
print("%'019lld %'019lld %'019lld\n", 1LL, 222222222LL, 3333333333333LL);
print("%'020lld %'020lld %'020lld\n", 1LL, 222222222LL, 3333333333333LL);
print("%'llx %'llX %'llb\n", 0x111111111111LL, 0xabcd12345678LL, 112342345LL);
return 0;
}
|
Added lib/libfmt/test2.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
#include <stdarg.h>
#include <utf.h>
#include <fmt.h>
int
main(int argc, char **argv)
{
print("%020.10d\n", 100);
}
|
Added lib/libfmt/test3.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
#include <u.h>
#include <libc.h>
#include <stdio.h>
void
test(char *fmt, ...)
{
va_list arg;
char fmtbuf[100], stdbuf[100];
va_start(arg, fmt);
vsnprint(fmtbuf, sizeof fmtbuf, fmt, arg);
va_end(arg);
va_start(arg, fmt);
vsnprint(stdbuf, sizeof stdbuf, fmt, arg);
va_end(arg);
if(strcmp(fmtbuf, stdbuf) != 0)
print("fmt %s: fmt=\"%s\" std=\"%s\"\n", fmt, fmtbuf, stdbuf);
print("fmt %s: %s\n", fmt, fmtbuf);
}
int
main(int argc, char *argv[])
{
test("%f", 3.14159);
test("%f", 3.14159e10);
test("%f", 3.14159e-10);
test("%e", 3.14159);
test("%e", 3.14159e10);
test("%e", 3.14159e-10);
test("%g", 3.14159);
test("%g", 3.14159e10);
test("%g", 3.14159e-10);
test("%g", 2e25);
test("%.18g", 2e25);
test("%2.18g", 1.0);
test("%2.18f", 1.0);
test("%f", 3.1415927/4);
test("%20.10d", 12345);
test("%0.10d", 12345);
return 0;
}
|
Added lib/libfmt/vfprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
vfprint(int fd, const char *fmt, va_list args)
{
Fmt f;
char buf[256];
int n;
fmtfdinit(&f, fd, buf, sizeof(buf));
va_copy(f.args,args);
n = dofmt(&f, fmt);
va_end(f.args);
if(n > 0 && __fmtFdFlush(&f) == 0)
return -1;
return n;
}
|
Added lib/libfmt/vseprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
char*
vseprint(char *buf, char *e, const char *fmt, va_list args)
{
Fmt f;
if(e <= buf)
return nil;
f.runes = 0;
f.start = buf;
f.to = buf;
f.stop = e - 1;
f.flush = 0;
f.farg = nil;
f.nfmt = 0;
va_copy(f.args,args);
fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
va_end(f.args);
*(char*)f.to = '\0';
return (char*)f.to;
}
|
Added lib/libfmt/vsmprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
/*
* Plan 9 port version must include libc.h in order to
* get Plan 9 debugging malloc, which sometimes returns
* different pointers than the standard malloc.
*/
#include <stdlib.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
static int
fmtStrFlush(Fmt *f)
{
char *s;
int n;
if(f->start == nil)
return 0;
n = (uintptr_t)f->farg;
n *= 2;
s = (char*)f->start;
f->start = realloc(s, n);
if(f->start == nil){
f->farg = nil;
f->to = nil;
f->stop = nil;
free(s);
return 0;
}
f->farg = (void*)(uintptr_t)n;
f->to = (char*)f->start + ((char*)f->to - s);
f->stop = (char*)f->start + n - 1;
return 1;
}
int
fmtstrinit(Fmt *f)
{
int n;
memset(f, 0, sizeof *f);
f->runes = 0;
n = 32;
f->start = malloc(n);
if(f->start == nil)
return -1;
f->to = f->start;
f->stop = (char*)f->start + n - 1;
f->flush = fmtStrFlush;
f->farg = (void*)(uintptr_t)n;
f->nfmt = 0;
fmtlocaleinit(f, nil, nil, nil);
return 0;
}
/*
* print into an allocated string buffer
*/
char*
vsmprint(const char *fmt, va_list args)
{
Fmt f;
int n;
if(fmtstrinit(&f) < 0)
return nil;
va_copy(f.args,args);
n = dofmt(&f, fmt);
va_end(f.args);
if(n < 0){
free(f.start);
return nil;
}
return fmtstrflush(&f);
}
|
Added lib/libfmt/vsnprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdlib.h>
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
int
vsnprint(char *buf, int len, const char *fmt, va_list args)
{
Fmt f;
if(len <= 0)
return -1;
f.runes = 0;
f.start = buf;
f.to = buf;
f.stop = buf + len - 1;
f.flush = 0;
f.farg = nil;
f.nfmt = 0;
va_copy(f.args,args);
fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
va_end(f.args);
*(char*)f.to = '\0';
return (char*)f.to - buf;
}
|
Added lib/libregexp/Makefile.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ROOT= ../.. include $(ROOT)/mk/hdr.mk VERSION=2.0 TARG=libregexp9 OBJ=\ regcomp\ regerror\ regexec\ regsub\ regaux\ rregexec\ rregsub include $(ROOT)/mk/lib.mk |
Added lib/libregexp/NOTICE.
> > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /* * The authors of this software is Rob Pike. * Copyright (c) 2002 by Lucent Technologies. * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ This is a Unix port of the Plan 9 regular expression library. Please send comments about the packaging to Russ Cox <rsc@swtch.com>. ---- This software is also made available under the Lucent Public License version 1.02; see http://plan9.bell-labs.com/plan9dist/license.html |
Added lib/libregexp/README.
> > > > > | 1 2 3 4 5 | This software was packaged for Unix by Russ Cox. Please send comments to rsc@swtch.com. http://swtch.com/plan9port/unix |
Added lib/libregexp/regaux.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
#include "plan9.h"
#include "regexp9.h"
#include "regcomp.h"
/*
* save a new match in mp
*/
extern void
_renewmatch(Resub *mp, int ms, Resublist *sp)
{
int i;
if(mp==0 || ms<=0)
return;
if(mp[0].s.sp==0 || sp->m[0].s.sp<mp[0].s.sp ||
(sp->m[0].s.sp==mp[0].s.sp && sp->m[0].e.ep>mp[0].e.ep)){
for(i=0; i<ms && i<NSUBEXP; i++)
mp[i] = sp->m[i];
for(; i<ms; i++)
mp[i].s.sp = mp[i].e.ep = 0;
}
}
/*
* Note optimization in _renewthread:
* *lp must be pending when _renewthread called; if *l has been looked
* at already, the optimization is a bug.
*/
extern Relist*
_renewthread(Relist *lp, /* _relist to add to */
Reinst *ip, /* instruction to add */
int ms,
Resublist *sep) /* pointers to subexpressions */
{
Relist *p;
for(p=lp; p->inst; p++){
if(p->inst == ip){
if(sep->m[0].s.sp < p->se.m[0].s.sp){
if(ms > 1)
p->se = *sep;
else
p->se.m[0] = sep->m[0];
}
return 0;
}
}
p->inst = ip;
if(ms > 1)
p->se = *sep;
else
p->se.m[0] = sep->m[0];
(++p)->inst = 0;
return p;
}
/*
* same as renewthread, but called with
* initial empty start pointer.
*/
extern Relist*
_renewemptythread(Relist *lp, /* _relist to add to */
Reinst *ip, /* instruction to add */
int ms,
char *sp) /* pointers to subexpressions */
{
Relist *p;
for(p=lp; p->inst; p++){
if(p->inst == ip){
if(sp < p->se.m[0].s.sp) {
if(ms > 1)
memset(&p->se, 0, sizeof(p->se));
p->se.m[0].s.sp = sp;
}
return 0;
}
}
p->inst = ip;
if(ms > 1)
memset(&p->se, 0, sizeof(p->se));
p->se.m[0].s.sp = sp;
(++p)->inst = 0;
return p;
}
extern Relist*
_rrenewemptythread(Relist *lp, /* _relist to add to */
Reinst *ip, /* instruction to add */
int ms,
Rune *rsp) /* pointers to subexpressions */
{
Relist *p;
for(p=lp; p->inst; p++){
if(p->inst == ip){
if(rsp < p->se.m[0].s.rsp) {
if(ms > 1)
memset(&p->se, 0, sizeof(p->se));
p->se.m[0].s.rsp = rsp;
}
return 0;
}
}
p->inst = ip;
if(ms > 1)
memset(&p->se, 0, sizeof(p->se));
p->se.m[0].s.rsp = rsp;
(++p)->inst = 0;
return p;
}
|
Added lib/libregexp/regcomp.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 |
#include <setjmp.h>
#include <stdlib.h>
#include "plan9.h"
#include "regexp9.h"
#include "regcomp.h"
enum {
FALSE,
TRUE,
};
/*
* Parser Information
*/
typedef struct Node Node;
struct Node
{
Reinst* first;
Reinst* last;
};
#define NSTACK 20
static Node andstack[NSTACK];
static Node *andp;
static int atorstack[NSTACK];
static int* atorp;
static int cursubid; /* id of current subexpression */
static int subidstack[NSTACK]; /* parallel to atorstack */
static int* subidp;
static int lastwasand; /* Last token was operand */
static int nbra;
static char* exprp; /* pointer to next character in source expression */
static int lexdone;
static int nclass;
static Reclass*classp;
static Reinst* freep;
static int errors;
static Rune yyrune; /* last lex'd rune */
static Reclass*yyclassp; /* last lex'd class */
/* predeclared crap */
static void operator(int);
static void pushand(Reinst*, Reinst*);
static void pushator(int);
static void evaluntil(int);
static int bldcclass(void);
static jmp_buf regkaboom;
static void
rcerror(char *s)
{
errors++;
regerror(s);
longjmp(regkaboom, 1);
}
static Reinst*
newinst(int t)
{
freep->type = t;
freep->u2.left = 0;
freep->u1.right = 0;
return freep++;
}
static void
operand(int t)
{
Reinst *i;
if(lastwasand)
operator(CAT); /* catenate is implicit */
i = newinst(t);
if(t == CCLASS || t == NCCLASS)
i->u1.cp = yyclassp;
if(t == RUNE)
i->u1.r = yyrune;
pushand(i, i);
lastwasand = TRUE;
}
static void
operator(int t)
{
if(t==RBRA && --nbra<0)
rcerror("unmatched right paren");
if(t==LBRA){
if(++cursubid >= NSUBEXP)
rcerror ("too many subexpressions");
nbra++;
if(lastwasand)
operator(CAT);
} else
evaluntil(t);
if(t != RBRA)
pushator(t);
lastwasand = FALSE;
if(t==STAR || t==QUEST || t==PLUS || t==RBRA)
lastwasand = TRUE; /* these look like operands */
}
static void
regerr2(char *s, int c)
{
char buf[100];
char *cp = buf;
while(*s)
*cp++ = *s++;
*cp++ = c;
*cp = '\0';
rcerror(buf);
}
static void
cant(char *s)
{
char buf[100];
strcpy(buf, "can't happen: ");
strcat(buf, s);
rcerror(buf);
}
static void
pushand(Reinst *f, Reinst *l)
{
if(andp >= &andstack[NSTACK])
cant("operand stack overflow");
andp->first = f;
andp->last = l;
andp++;
}
static void
pushator(int t)
{
if(atorp >= &atorstack[NSTACK])
cant("operator stack overflow");
*atorp++ = t;
*subidp++ = cursubid;
}
static Node*
popand(int op)
{
Reinst *inst;
if(andp <= &andstack[0]){
regerr2("missing operand for ", op);
inst = newinst(NOP);
pushand(inst,inst);
}
return --andp;
}
static int
popator(void)
{
if(atorp <= &atorstack[0])
cant("operator stack underflow");
--subidp;
return *--atorp;
}
static void
evaluntil(int pri)
{
Node *op1, *op2;
Reinst *inst1, *inst2;
while(pri==RBRA || atorp[-1]>=pri){
switch(popator()){
default:
rcerror("unknown operator in evaluntil");
break;
case LBRA: /* must have been RBRA */
op1 = popand('(');
inst2 = newinst(RBRA);
inst2->u1.subid = *subidp;
op1->last->u2.next = inst2;
inst1 = newinst(LBRA);
inst1->u1.subid = *subidp;
inst1->u2.next = op1->first;
pushand(inst1, inst2);
return;
case OR:
op2 = popand('|');
op1 = popand('|');
inst2 = newinst(NOP);
op2->last->u2.next = inst2;
op1->last->u2.next = inst2;
inst1 = newinst(OR);
inst1->u1.right = op1->first;
inst1->u2.left = op2->first;
pushand(inst1, inst2);
break;
case CAT:
op2 = popand(0);
op1 = popand(0);
op1->last->u2.next = op2->first;
pushand(op1->first, op2->last);
break;
case STAR:
op2 = popand('*');
inst1 = newinst(OR);
op2->last->u2.next = inst1;
inst1->u1.right = op2->first;
pushand(inst1, inst1);
break;
case PLUS:
op2 = popand('+');
inst1 = newinst(OR);
op2->last->u2.next = inst1;
inst1->u1.right = op2->first;
pushand(op2->first, inst1);
break;
case QUEST:
op2 = popand('?');
inst1 = newinst(OR);
inst2 = newinst(NOP);
inst1->u2.left = inst2;
inst1->u1.right = op2->first;
op2->last->u2.next = inst2;
pushand(inst1, inst2);
break;
}
}
}
static Reprog*
optimize(Reprog *pp)
{
Reinst *inst, *target;
int size;
Reprog *npp;
Reclass *cl;
int diff;
/*
* get rid of NOOP chains
*/
for(inst=pp->firstinst; inst->type!=END; inst++){
target = inst->u2.next;
while(target->type == NOP)
target = target->u2.next;
inst->u2.next = target;
}
/*
* The original allocation is for an area larger than
* necessary. Reallocate to the actual space used
* and then relocate the code.
*/
size = sizeof(Reprog) + (freep - pp->firstinst)*sizeof(Reinst);
npp = realloc(pp, size);
if(npp==0 || npp==pp)
return pp;
diff = (char *)npp - (char *)pp;
freep = (Reinst *)((char *)freep + diff);
for(inst=npp->firstinst; inst<freep; inst++){
switch(inst->type){
case OR:
case STAR:
case PLUS:
case QUEST:
*(char **)&inst->u1.right += diff;
break;
case CCLASS:
case NCCLASS:
*(char **)&inst->u1.right += diff;
cl = inst->u1.cp;
*(char **)&cl->end += diff;
break;
}
*(char **)&inst->u2.left += diff;
}
*(char **)&npp->startinst += diff;
return npp;
}
#ifdef DEBUG
static void
dumpstack(void){
Node *stk;
int *ip;
print("operators\n");
for(ip=atorstack; ip<atorp; ip++)
print("0%o\n", *ip);
print("operands\n");
for(stk=andstack; stk<andp; stk++)
print("0%o\t0%o\n", stk->first->type, stk->last->type);
}
static void
dump(Reprog *pp)
{
Reinst *l;
Rune *p;
l = pp->firstinst;
do{
print("%d:\t0%o\t%d\t%d", l-pp->firstinst, l->type,
l->u2.left-pp->firstinst, l->u1.right-pp->firstinst);
if(l->type == RUNE)
print("\t%C\n", l->u1.r);
else if(l->type == CCLASS || l->type == NCCLASS){
print("\t[");
if(l->type == NCCLASS)
print("^");
for(p = l->u1.cp->spans; p < l->u1.cp->end; p += 2)
if(p[0] == p[1])
print("%C", p[0]);
else
print("%C-%C", p[0], p[1]);
print("]\n");
} else
print("\n");
}while(l++->type);
}
#endif
static Reclass*
newclass(void)
{
if(nclass >= NCLASS)
regerr2("too many character classes; limit", NCLASS+'0');
return &(classp[nclass++]);
}
static int
nextc(Rune *rp)
{
if(lexdone){
*rp = 0;
return 1;
}
exprp += chartorune(rp, exprp);
if(*rp == '\\'){
exprp += chartorune(rp, exprp);
return 1;
}
if(*rp == 0)
lexdone = 1;
return 0;
}
static int
lex(int literal, int dot_type)
{
int quoted;
quoted = nextc(&yyrune);
if(literal || quoted){
if(yyrune == 0)
return END;
return RUNE;
}
switch(yyrune){
case 0:
return END;
case '*':
return STAR;
case '?':
return QUEST;
case '+':
return PLUS;
case '|':
return OR;
case '.':
return dot_type;
case '(':
return LBRA;
case ')':
return RBRA;
case '^':
return BOL;
case '$':
return EOL;
case '[':
return bldcclass();
}
return RUNE;
}
static int
bldcclass(void)
{
int type;
Rune r[NCCRUNE];
Rune *p, *ep, *np;
Rune rune;
int quoted;
/* we have already seen the '[' */
type = CCLASS;
yyclassp = newclass();
/* look ahead for negation */
/* SPECIAL CASE!!! negated classes don't match \n */
ep = r;
quoted = nextc(&rune);
if(!quoted && rune == '^'){
type = NCCLASS;
quoted = nextc(&rune);
*ep++ = '\n';
*ep++ = '\n';
}
/* parse class into a set of spans */
for(; ep<&r[NCCRUNE];){
if(rune == 0){
rcerror("malformed '[]'");
return 0;
}
if(!quoted && rune == ']')
break;
if(!quoted && rune == '-'){
if(ep == r){
rcerror("malformed '[]'");
return 0;
}
quoted = nextc(&rune);
if((!quoted && rune == ']') || rune == 0){
rcerror("malformed '[]'");
return 0;
}
*(ep-1) = rune;
} else {
*ep++ = rune;
*ep++ = rune;
}
quoted = nextc(&rune);
}
/* sort on span start */
for(p = r; p < ep; p += 2){
for(np = p; np < ep; np += 2)
if(*np < *p){
rune = np[0];
np[0] = p[0];
p[0] = rune;
rune = np[1];
np[1] = p[1];
p[1] = rune;
}
}
/* merge spans */
np = yyclassp->spans;
p = r;
if(r == ep)
yyclassp->end = np;
else {
np[0] = *p++;
np[1] = *p++;
for(; p < ep; p += 2)
if(p[0] <= np[1]){
if(p[1] > np[1])
np[1] = p[1];
} else {
np += 2;
np[0] = p[0];
np[1] = p[1];
}
yyclassp->end = np+2;
}
return type;
}
static Reprog*
regcomp1(char *s, int literal, int dot_type)
{
int token;
Reprog *volatile pp;
/* get memory for the program */
pp = malloc(sizeof(Reprog) + 6*sizeof(Reinst)*strlen(s));
if(pp == 0){
regerror("out of memory");
return 0;
}
freep = pp->firstinst;
classp = pp->class;
errors = 0;
if(setjmp(regkaboom))
goto out;
/* go compile the sucker */
lexdone = 0;
exprp = s;
nclass = 0;
nbra = 0;
atorp = atorstack;
andp = andstack;
subidp = subidstack;
lastwasand = FALSE;
cursubid = 0;
/* Start with a low priority operator to prime parser */
pushator(START-1);
while((token = lex(literal, dot_type)) != END){
if((token&0300) == OPERATOR)
operator(token);
else
operand(token);
}
/* Close with a low priority operator */
evaluntil(START);
/* Force END */
operand(END);
evaluntil(START);
#ifdef DEBUG
dumpstack();
#endif
if(nbra)
rcerror("unmatched left paren");
--andp; /* points to first and only operand */
pp->startinst = andp->first;
#ifdef DEBUG
dump(pp);
#endif
pp = optimize(pp);
#ifdef DEBUG
print("start: %d\n", andp->first-pp->firstinst);
dump(pp);
#endif
out:
if(errors){
free(pp);
pp = 0;
}
return pp;
}
extern Reprog*
regcomp(char *s)
{
return regcomp1(s, 0, ANY);
}
extern Reprog*
regcomplit(char *s)
{
return regcomp1(s, 1, ANY);
}
extern Reprog*
regcompnl(char *s)
{
return regcomp1(s, 0, ANYNL);
}
|
Added lib/libregexp/regerror.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <stdlib.h>
#include <plan9.h>
#include <regexp9.h>
void
regerror(char *s)
{
char buf[132];
strcpy(buf, "regerror: ");
strcat(buf, s);
strcat(buf, "\n");
write(2, buf, strlen(buf));
exits("regerr");
}
|
Added lib/libregexp/regexec.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
#include <stdlib.h>
#include "plan9.h"
#include "regexp9.h"
#include "regcomp.h"
/*
* return 0 if no match
* >0 if a match
* <0 if we ran out of _relist space
*/
static int
regexec1(Reprog *progp, /* program to run */
char *bol, /* string to run machine on */
Resub *mp, /* subexpression elements */
int ms, /* number of elements at mp */
Reljunk *j
)
{
int flag=0;
Reinst *inst;
Relist *tlp;
char *s;
int i, checkstart;
Rune r, *rp, *ep;
int n;
Relist* tl; /* This list, next list */
Relist* nl;
Relist* tle; /* ends of this and next list */
Relist* nle;
int match;
char *p;
match = 0;
checkstart = j->starttype;
if(mp)
for(i=0; i<ms; i++) {
mp[i].s.sp = 0;
mp[i].e.ep = 0;
}
j->relist[0][0].inst = 0;
j->relist[1][0].inst = 0;
/* Execute machine once for each character, including terminal NUL */
s = j->starts;
do{
/* fast check for first char */
if(checkstart) {
switch(j->starttype) {
case RUNE:
p = utfrune(s, j->startchar);
if(p == 0 || s == j->eol)
return match;
s = p;
break;
case BOL:
if(s == bol)
break;
p = utfrune(s, '\n');
if(p == 0 || s == j->eol)
return match;
s = p;
break;
}
}
r = *(uchar*)s;
if(r < Runeself)
n = 1;
else
n = chartorune(&r, s);
/* switch run lists */
tl = j->relist[flag];
tle = j->reliste[flag];
nl = j->relist[flag^=1];
nle = j->reliste[flag];
nl->inst = 0;
/* Add first instruction to current list */
if(match == 0)
_renewemptythread(tl, progp->startinst, ms, s);
/* Execute machine until current list is empty */
for(tlp=tl; tlp->inst; tlp++){ /* assignment = */
for(inst = tlp->inst; ; inst = inst->u2.next){
switch(inst->type){
case RUNE: /* regular character */
if(inst->u1.r == r){
if(_renewthread(nl, inst->u2.next, ms, &tlp->se)==nle)
return -1;
}
break;
case LBRA:
tlp->se.m[inst->u1.subid].s.sp = s;
continue;
case RBRA:
tlp->se.m[inst->u1.subid].e.ep = s;
continue;
case ANY:
if(r != '\n')
if(_renewthread(nl, inst->u2.next, ms, &tlp->se)==nle)
return -1;
break;
case ANYNL:
if(_renewthread(nl, inst->u2.next, ms, &tlp->se)==nle)
return -1;
break;
case BOL:
if(s == bol || *(s-1) == '\n')
continue;
break;
case EOL:
if(s == j->eol || r == 0 || r == '\n')
continue;
break;
case CCLASS:
ep = inst->u1.cp->end;
for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
if(r >= rp[0] && r <= rp[1]){
if(_renewthread(nl, inst->u2.next, ms, &tlp->se)==nle)
return -1;
break;
}
break;
case NCCLASS:
ep = inst->u1.cp->end;
for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
if(r >= rp[0] && r <= rp[1])
break;
if(rp == ep)
if(_renewthread(nl, inst->u2.next, ms, &tlp->se)==nle)
return -1;
break;
case OR:
/* evaluate right choice later */
if(_renewthread(tlp, inst->u1.right, ms, &tlp->se) == tle)
return -1;
/* efficiency: advance and re-evaluate */
continue;
case END: /* Match! */
match = 1;
tlp->se.m[0].e.ep = s;
if(mp != 0)
_renewmatch(mp, ms, &tlp->se);
break;
}
break;
}
}
if(s == j->eol)
break;
checkstart = j->starttype && nl->inst==0;
s += n;
}while(r);
return match;
}
static int
regexec2(Reprog *progp, /* program to run */
char *bol, /* string to run machine on */
Resub *mp, /* subexpression elements */
int ms, /* number of elements at mp */
Reljunk *j
)
{
int rv;
Relist *relist0, *relist1;
/* mark space */
relist0 = malloc(BIGLISTSIZE*sizeof(Relist));
if(relist0 == nil)
return -1;
relist1 = malloc(BIGLISTSIZE*sizeof(Relist));
if(relist1 == nil){
free(relist1);
return -1;
}
j->relist[0] = relist0;
j->relist[1] = relist1;
j->reliste[0] = relist0 + BIGLISTSIZE - 2;
j->reliste[1] = relist1 + BIGLISTSIZE - 2;
rv = regexec1(progp, bol, mp, ms, j);
free(relist0);
free(relist1);
return rv;
}
extern int
regexec(Reprog *progp, /* program to run */
char *bol, /* string to run machine on */
Resub *mp, /* subexpression elements */
int ms) /* number of elements at mp */
{
Reljunk j;
Relist relist0[LISTSIZE], relist1[LISTSIZE];
int rv;
/*
* use user-specified starting/ending location if specified
*/
j.starts = bol;
j.eol = 0;
if(mp && ms>0){
if(mp->s.sp)
j.starts = mp->s.sp;
if(mp->e.ep)
j.eol = mp->e.ep;
}
j.starttype = 0;
j.startchar = 0;
if(progp->startinst->type == RUNE && progp->startinst->u1.r < Runeself) {
j.starttype = RUNE;
j.startchar = progp->startinst->u1.r;
}
if(progp->startinst->type == BOL)
j.starttype = BOL;
/* mark space */
j.relist[0] = relist0;
j.relist[1] = relist1;
j.reliste[0] = relist0 + nelem(relist0) - 2;
j.reliste[1] = relist1 + nelem(relist1) - 2;
rv = regexec1(progp, bol, mp, ms, &j);
if(rv >= 0)
return rv;
rv = regexec2(progp, bol, mp, ms, &j);
if(rv >= 0)
return rv;
return -1;
}
|
Added lib/libregexp/regexp9.3.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
.deEX
.ift .ft5
.nf
..
.deEE
.ft1
.fi
..
.TH REGEXP9 3
.SH NAME
regcomp, regcomplit, regcompnl, regexec, regsub, rregexec, rregsub, regerror \- regular expression
.SH SYNOPSIS
.B #include <utf.h>
.br
.B #include <fmt.h>
.br
.B #include <regexp9.h>
.PP
.ta \w'\fLRegprog 'u
.B
Reprog *regcomp(char *exp)
.PP
.B
Reprog *regcomplit(char *exp)
.PP
.B
Reprog *regcompnl(char *exp)
.PP
.nf
.B
int regexec(Reprog *prog, char *string, Resub *match, int msize)
.PP
.nf
.B
void regsub(char *source, char *dest, int dlen, Resub *match, int msize)
.PP
.nf
.B
int rregexec(Reprog *prog, Rune *string, Resub *match, int msize)
.PP
.nf
.B
void rregsub(Rune *source, Rune *dest, int dlen, Resub *match, int msize)
.PP
.B
void regerror(char *msg)
.SH DESCRIPTION
.I Regcomp
compiles a
regular expression and returns
a pointer to the generated description.
The space is allocated by
.IR malloc (3)
and may be released by
.IR free .
Regular expressions are exactly as in
.IR regexp9 (7).
.PP
.I Regcomplit
is like
.I regcomp
except that all characters are treated literally.
.I Regcompnl
is like
.I regcomp
except that the
.B .
metacharacter matches all characters, including newlines.
.PP
.I Regexec
matches a null-terminated
.I string
against the compiled regular expression in
.IR prog .
If it matches,
.I regexec
returns
.B 1
and fills in the array
.I match
with character pointers to the substrings of
.I string
that correspond to the
parenthesized subexpressions of
.IR exp :
.BI match[ i ].sp
points to the beginning and
.BI match[ i ].ep
points just beyond
the end of the
.IR i th
substring.
(Subexpression
.I i
begins at the
.IR i th
left parenthesis, counting from 1.)
Pointers in
.B match[0]
pick out the substring that corresponds to
the whole regular expression.
Unused elements of
.I match
are filled with zeros.
Matches involving
.LR * ,
.LR + ,
and
.L ?
are extended as far as possible.
The number of array elements in
.I match
is given by
.IR msize .
The structure of elements of
.I match
is:
.IP
.EX
typedef struct {
union {
char *sp;
Rune *rsp;
};
union {
char *ep;
Rune *rep;
};
} Resub;
.EE
.LP
If
.B match[0].sp
is nonzero on entry,
.I regexec
starts matching at that point within
.IR string .
If
.B match[0].ep
is nonzero on entry,
the last character matched is the one
preceding that point.
.PP
.I Regsub
places in
.I dest
a substitution instance of
.I source
in the context of the last
.I regexec
performed using
.IR match .
Each instance of
.BI \e n\f1,
where
.I n
is a digit, is replaced by the
string delimited by
.BI match[ n ].sp
and
.BI match[ n ].ep\f1.
Each instance of
.L &
is replaced by the string delimited by
.B match[0].sp
and
.BR match[0].ep .
The substitution will always be null terminated and
trimmed to fit into dlen bytes.
.PP
.IR Regerror ,
called whenever an error is detected in
.IR regcomp ,
writes the string
.I msg
on the standard error file and exits.
.I Regerror
can be replaced to perform
special error processing.
If the user supplied
.I regerror
returns rather than exits,
.I regcomp
will return 0.
.PP
.I Rregexec
and
.I rregsub
are variants of
.I regexec
and
.I regsub
that use strings of
.B Runes
instead of strings of
.BR chars .
With these routines, the
.I rsp
and
.I rep
fields of the
.I match
array elements should be used.
.SH SOURCE
.B http://swtch.com/plan9port/unix
.SH "SEE ALSO"
.IR grep (1)
.SH DIAGNOSTICS
.I Regcomp
returns
.B 0
for an illegal expression
or other failure.
.I Regexec
returns 0
if
.I string
is not matched.
.SH BUGS
There is no way to specify or match a NUL character; NULs terminate patterns and strings.
|
Added lib/libregexp/regexp9.7.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
.deEX
.ift .ft5
.nf
..
.deEE
.ft1
.fi
..
.TH REGEXP9 7
.SH NAME
regexp \- Plan 9 regular expression notation
.SH DESCRIPTION
This manual page describes the regular expression
syntax used by the Plan 9 regular expression library
.IR regexp9 (3).
It is the form used by
.IR egrep (1)
before
.I egrep
got complicated.
.PP
A
.I "regular expression"
specifies
a set of strings of characters.
A member of this set of strings is said to be
.I matched
by the regular expression. In many applications
a delimiter character, commonly
.LR / ,
bounds a regular expression.
In the following specification for regular expressions
the word `character' means any character (rune) but newline.
.PP
The syntax for a regular expression
.B e0
is
.IP
.EX
e3: literal | charclass | '.' | '^' | '$' | '(' e0 ')'
e2: e3
| e2 REP
REP: '*' | '+' | '?'
e1: e2
| e1 e2
e0: e1
| e0 '|' e1
.EE
.PP
A
.B literal
is any non-metacharacter, or a metacharacter
(one of
.BR .*+?[]()|\e^$ ),
or the delimiter
preceded by
.LR \e .
.PP
A
.B charclass
is a nonempty string
.I s
bracketed
.BI [ \|s\| ]
(or
.BI [^ s\| ]\fR);
it matches any character in (or not in)
.IR s .
A negated character class never
matches newline.
A substring
.IB a - b\f1,
with
.I a
and
.I b
in ascending
order, stands for the inclusive
range of
characters between
.I a
and
.IR b .
In
.IR s ,
the metacharacters
.LR - ,
.LR ] ,
an initial
.LR ^ ,
and the regular expression delimiter
must be preceded by a
.LR \e ;
other metacharacters
have no special meaning and
may appear unescaped.
.PP
A
.L .
matches any character.
.PP
A
.L ^
matches the beginning of a line;
.L $
matches the end of the line.
.PP
The
.B REP
operators match zero or more
.RB ( * ),
one or more
.RB ( + ),
zero or one
.RB ( ? ),
instances respectively of the preceding regular expression
.BR e2 .
.PP
A concatenated regular expression,
.BR "e1\|e2" ,
matches a match to
.B e1
followed by a match to
.BR e2 .
.PP
An alternative regular expression,
.BR "e0\||\|e1" ,
matches either a match to
.B e0
or a match to
.BR e1 .
.PP
A match to any part of a regular expression
extends as far as possible without preventing
a match to the remainder of the regular expression.
.SH "SEE ALSO
.IR regexp9 (3)
|
Added lib/libregexp/regsub.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
#include "plan9.h"
#include "regexp9.h"
/* substitute into one string using the matches from the last regexec() */
extern void
regsub(char *sp, /* source string */
char *dp, /* destination string */
int dlen,
Resub *mp, /* subexpression elements */
int ms) /* number of elements pointed to by mp */
{
char *ssp, *ep;
int i;
ep = dp+dlen-1;
while(*sp != '\0'){
if(*sp == '\\'){
switch(*++sp){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
i = *sp-'0';
if(mp[i].s.sp != 0 && mp!=0 && ms>i)
for(ssp = mp[i].s.sp;
ssp < mp[i].e.ep;
ssp++)
if(dp < ep)
*dp++ = *ssp;
break;
case '\\':
if(dp < ep)
*dp++ = '\\';
break;
case '\0':
sp--;
break;
default:
if(dp < ep)
*dp++ = *sp;
break;
}
}else if(*sp == '&'){
if(mp[0].s.sp != 0 && mp!=0 && ms>0)
if(mp[0].s.sp != 0)
for(ssp = mp[0].s.sp;
ssp < mp[0].e.ep; ssp++)
if(dp < ep)
*dp++ = *ssp;
}else{
if(dp < ep)
*dp++ = *sp;
}
sp++;
}
*dp = '\0';
}
|
Added lib/libregexp/rregexec.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
#include "plan9.h"
#include "regexp9.h"
#include "regcomp.h"
/*
* return 0 if no match
* >0 if a match
* <0 if we ran out of _relist space
*/
static int
rregexec1(Reprog *progp, /* program to run */
Rune *bol, /* string to run machine on */
Resub *mp, /* subexpression elements */
int ms, /* number of elements at mp */
Reljunk *j)
{
int flag=0;
Reinst *inst;
Relist *tlp;
Rune *s;
int i, checkstart;
Rune r, *rp, *ep;
Relist* tl; /* This list, next list */
Relist* nl;
Relist* tle; /* ends of this and next list */
Relist* nle;
int match;
Rune *p;
match = 0;
checkstart = j->startchar;
if(mp)
for(i=0; i<ms; i++) {
mp[i].s.rsp = 0;
mp[i].e.rep = 0;
}
j->relist[0][0].inst = 0;
j->relist[1][0].inst = 0;
/* Execute machine once for each character, including terminal NUL */
s = j->rstarts;
do{
/* fast check for first char */
if(checkstart) {
switch(j->starttype) {
case RUNE:
p = runestrchr(s, j->startchar);
if(p == 0 || p == j->reol)
return match;
s = p;
break;
case BOL:
if(s == bol)
break;
p = runestrchr(s, '\n');
if(p == 0 || s == j->reol)
return match;
s = p+1;
break;
}
}
r = *s;
/* switch run lists */
tl = j->relist[flag];
tle = j->reliste[flag];
nl = j->relist[flag^=1];
nle = j->reliste[flag];
nl->inst = 0;
/* Add first instruction to current list */
_rrenewemptythread(tl, progp->startinst, ms, s);
/* Execute machine until current list is empty */
for(tlp=tl; tlp->inst; tlp++){
for(inst=tlp->inst; ; inst = inst->u2.next){
switch(inst->type){
case RUNE: /* regular character */
if(inst->u1.r == r)
if(_renewthread(nl, inst->u2.next, ms, &tlp->se)==nle)
return -1;
break;
case LBRA:
tlp->se.m[inst->u1.subid].s.rsp = s;
continue;
case RBRA:
tlp->se.m[inst->u1.subid].e.rep = s;
continue;
case ANY:
if(r != '\n')
if(_renewthread(nl, inst->u2.next, ms, &tlp->se)==nle)
return -1;
break;
case ANYNL:
if(_renewthread(nl, inst->u2.next, ms, &tlp->se)==nle)
return -1;
break;
case BOL:
if(s == bol || *(s-1) == '\n')
continue;
break;
case EOL:
if(s == j->reol || r == 0 || r == '\n')
continue;
break;
case CCLASS:
ep = inst->u1.cp->end;
for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
if(r >= rp[0] && r <= rp[1]){
if(_renewthread(nl, inst->u2.next, ms, &tlp->se)==nle)
return -1;
break;
}
break;
case NCCLASS:
ep = inst->u1.cp->end;
for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
if(r >= rp[0] && r <= rp[1])
break;
if(rp == ep)
if(_renewthread(nl, inst->u2.next, ms, &tlp->se)==nle)
return -1;
break;
case OR:
/* evaluate right choice later */
if(_renewthread(tlp, inst->u1.right, ms, &tlp->se) == tle)
return -1;
/* efficiency: advance and re-evaluate */
continue;
case END: /* Match! */
match = 1;
tlp->se.m[0].e.rep = s;
if(mp != 0)
_renewmatch(mp, ms, &tlp->se);
break;
}
break;
}
}
if(s == j->reol)
break;
checkstart = j->startchar && nl->inst==0;
s++;
}while(r);
return match;
}
static int
rregexec2(Reprog *progp, /* program to run */
Rune *bol, /* string to run machine on */
Resub *mp, /* subexpression elements */
int ms, /* number of elements at mp */
Reljunk *j
)
{
Relist relist0[5*LISTSIZE], relist1[5*LISTSIZE];
/* mark space */
j->relist[0] = relist0;
j->relist[1] = relist1;
j->reliste[0] = relist0 + nelem(relist0) - 2;
j->reliste[1] = relist1 + nelem(relist1) - 2;
return rregexec1(progp, bol, mp, ms, j);
}
extern int
rregexec(Reprog *progp, /* program to run */
Rune *bol, /* string to run machine on */
Resub *mp, /* subexpression elements */
int ms) /* number of elements at mp */
{
Reljunk j;
Relist relist0[LISTSIZE], relist1[LISTSIZE];
int rv;
/*
* use user-specified starting/ending location if specified
*/
j.rstarts = bol;
j.reol = 0;
if(mp && ms>0){
if(mp->s.sp)
j.rstarts = mp->s.rsp;
if(mp->e.ep)
j.reol = mp->e.rep;
}
j.starttype = 0;
j.startchar = 0;
if(progp->startinst->type == RUNE && progp->startinst->u1.r < Runeself) {
j.starttype = RUNE;
j.startchar = progp->startinst->u1.r;
}
if(progp->startinst->type == BOL)
j.starttype = BOL;
/* mark space */
j.relist[0] = relist0;
j.relist[1] = relist1;
j.reliste[0] = relist0 + nelem(relist0) - 2;
j.reliste[1] = relist1 + nelem(relist1) - 2;
rv = rregexec1(progp, bol, mp, ms, &j);
if(rv >= 0)
return rv;
rv = rregexec2(progp, bol, mp, ms, &j);
if(rv >= 0)
return rv;
return -1;
}
|
Added lib/libregexp/rregsub.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
#include "plan9.h"
#include "regexp9.h"
/* substitute into one string using the matches from the last regexec() */
extern void
rregsub(Rune *sp, /* source string */
Rune *dp, /* destination string */
int dlen,
Resub *mp, /* subexpression elements */
int ms) /* number of elements pointed to by mp */
{
Rune *ssp, *ep;
int i;
ep = dp+(dlen/sizeof(Rune))-1;
while(*sp != '\0'){
if(*sp == '\\'){
switch(*++sp){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
i = *sp-'0';
if(mp[i].s.rsp != 0 && mp!=0 && ms>i)
for(ssp = mp[i].s.rsp;
ssp < mp[i].e.rep;
ssp++)
if(dp < ep)
*dp++ = *ssp;
break;
case '\\':
if(dp < ep)
*dp++ = '\\';
break;
case '\0':
sp--;
break;
default:
if(dp < ep)
*dp++ = *sp;
break;
}
}else if(*sp == '&'){
if(mp[0].s.rsp != 0 && mp!=0 && ms>0)
if(mp[0].s.rsp != 0)
for(ssp = mp[0].s.rsp;
ssp < mp[0].e.rep; ssp++)
if(dp < ep)
*dp++ = *ssp;
}else{
if(dp < ep)
*dp++ = *sp;
}
sp++;
}
*dp = '\0';
}
|
Added lib/libregexp/test.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include "plan9.h"
#include <regexp9.h>
struct x
{
char *re;
char *s;
Reprog *p;
};
struct x t[] = {
{ "^[^!@]+$", "/bin/upas/aliasmail '&'", 0 },
{ "^local!(.*)$", "/mail/box/\\1/mbox", 0 },
{ "^plan9!(.*)$", "\\1", 0 },
{ "^helix!(.*)$", "\\1", 0 },
{ "^([^!]+)@([^!@]+)$", "\\2!\\1", 0 },
{ "^(uk\\.[^!]*)(!.*)$", "/bin/upas/uk2uk '\\1' '\\2'", 0 },
{ "^[^!]*\\.[^!]*!.*$", "inet!&", 0 },
{ "^\xE2\x98\xBA$", "smiley", 0 },
{ "^(coma|research|pipe|pyxis|inet|hunny|gauss)!(.*)$", "/mail/lib/qmail '\\s' 'net!\\1' '\\2'", 0 },
{ "^.*$", "/mail/lib/qmail '\\s' 'net!research' '&'", 0 },
{ 0, 0, 0 },
};
main(int ac, char **av)
{
Resub rs[10];
char dst[128];
int n;
struct x *tp;
for(tp = t; tp->re; tp++)
tp->p = regcomp(tp->re);
for(tp = t; tp->re; tp++){
print("%s VIA %s", av[1], tp->re);
memset(rs, 0, sizeof rs);
if(regexec(tp->p, av[1], rs, 10)){
regsub(tp->s, dst, sizeof dst, rs, 10);
print(" sub %s -> %s", tp->s, dst);
}
print("\n");
}
exit(0);
}
|
Added lib/libregexp/test2.c.
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include "plan9.h"
#include <regexp9.h>
main(int ac, char **av)
{
Resub rs[10];
Reprog *p;
char *s;
int i;
p = regcomp("[^a-z]");
s = "\n";
if(regexec(p, s, rs, 10))
print("%s %lux %lux %lux\n", s, s, rs[0].sp, rs[0].ep);
s = "0";
if(regexec(p, s, rs, 10))
print("%s %lux %lux %lux\n", s, s, rs[0].sp, rs[0].ep);
exit(0);
}
|
Added lib/libstuff/Makefile.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
ROOT= ../..
include $(ROOT)/mk/hdr.mk
TARG=libstuff
PACKAGES += $(X11PACKAGES) xext xrandr xrender xinerama
OBJ=\
buffer \
clientutil \
client_readconfig \
event/buttonpress \
event/buttonrelease \
event/clientmessage \
event/configurenotify \
event/configurerequest \
event/destroynotify \
event/enternotify \
event/event \
event/expose \
event/focusin \
event/focusout \
event/ixp \
event/keypress \
event/keyrelease \
event/leavenotify \
event/mapnotify \
event/maprequest \
event/mappingnotify \
event/motionnotify \
event/propertynotify \
event/reparentnotify \
event/selection \
event/selectionclear \
event/selectionrequest \
event/unmapnotify \
event/xtime \
fmt/blprint \
fmt/bvlprint \
fmt/fmtbuf \
fmt/localefmt \
fmt/localelen \
fmt/lprint \
fmt/vlprint \
geom/get_sticky \
geom/quadrant \
geom/rect_contains_p \
geom/rect_haspoint_p \
geom/rect_intersect_p \
geom/rect_intersection \
init_screens \
map \
printevent \
util/_die \
util/closeexec \
util/comm \
util/doublefork \
util/emalloc \
util/emallocz \
util/erealloc \
util/estrdup \
util/estrndup \
util/fatal \
util/freelater \
util/getbase \
util/getint \
util/getlong \
util/getulong \
util/grep \
util/join \
util/max \
util/mfatal \
util/min \
util/nsec \
util/pathsearch \
util/refree \
util/reinit \
util/spawn3 \
util/spawn3l \
util/stokenize \
util/strcasestr \
util/strend \
util/strlcat \
util/strlcatprint \
util/sxprint \
util/tokenize \
util/trim \
util/uniq \
util/unmask \
util/unquote \
util/utflcpy \
util/vector \
util/vsxprint \
x11/convpts \
x11/errors \
x11/ignored_xerrors \
x11/freestringlist \
x11/initdisplay \
x11/selection \
x11/sendevent \
x11/sendmessage \
x11/sync \
x11/x11 \
x11/xatom \
x11/xft \
x11/colors/loadcolor \
x11/colors/parsecolor \
x11/colors/xftcolor \
x11/drawing/border \
x11/drawing/drawline \
x11/drawing/drawpoly \
x11/drawing/drawstring \
x11/drawing/fill \
x11/drawing/fillpoly \
x11/drawing/setgccol \
x11/focus/getfocus \
x11/focus/setfocus \
x11/geometry/XRect \
x11/geometry/addpt \
x11/geometry/divpt \
x11/geometry/eqpt \
x11/geometry/eqrect \
x11/geometry/insetrect \
x11/geometry/mulpt \
x11/geometry/rectaddpt \
x11/geometry/rectsetorigin \
x11/geometry/rectsubpt \
x11/geometry/subpt \
x11/images/allocimage \
x11/images/copyimage \
x11/images/freeimage \
x11/images/xftdrawable \
x11/insanity/gravitate \
x11/insanity/gethints \
x11/insanity/sethints \
x11/insanity/sizehint \
x11/keyboard/grabkeyboard \
x11/keyboard/ungrabkeyboard \
x11/keys/keycode \
x11/keys/parsekey \
x11/mouse/grabpointer \
x11/mouse/pointerscreen \
x11/mouse/querypointer \
x11/mouse/translate \
x11/mouse/ungrabpointer \
x11/mouse/warppointer \
x11/properties/changeprop_char \
x11/properties/changeprop_long \
x11/properties/changeprop_short \
x11/properties/changeprop_string \
x11/properties/changeprop_textlist \
x11/properties/changeprop_ulong \
x11/properties/changeproperty \
x11/properties/delproperty \
x11/properties/getprop \
x11/properties/getprop_long \
x11/properties/getprop_string \
x11/properties/getprop_textlist \
x11/properties/getproperty \
x11/properties/strlistdup \
x11/properties/windowname \
x11/shape/setshapemask \
x11/text/freefont \
x11/text/labelh \
x11/text/loadfont \
x11/text/textextents_l \
x11/text/textwidth \
x11/text/textwidth_l \
x11/windows/configwin \
x11/windows/createwindow \
x11/windows/createwindow_rgba \
x11/windows/createwindow_visual \
x11/windows/destroywindow \
x11/windows/findwin \
x11/windows/getwinrect \
x11/windows/lowerwin \
x11/windows/mapwin \
x11/windows/movewin \
x11/windows/raisewin \
x11/windows/reparentwindow \
x11/windows/reshapewin \
x11/windows/selectinput \
x11/windows/setborder \
x11/windows/sethandler \
x11/windows/setwinattr \
x11/windows/unmapwin \
x11/windows/window \
xext
include $(ROOT)/mk/lib.mk
|
Added lib/libstuff/buffer.c.
> > > > > > > > | 1 2 3 4 5 6 7 8 | /* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail> * See LICENSE file for license details. */ char buffer[8092]; char* _buffer; char* const _buf_end = buffer + sizeof buffer; |
Added lib/libstuff/client_readconfig.c.
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* Copyright ©2009-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <ixp.h>
#include <stuff/clientutil.h>
#include <stuff/util.h>
#include <stuff/x.h>
#include <stdio.h>
void
client_readconfig(CTuple *norm, CTuple *focus, Font **font) {
if(norm)
loadcolor(norm, readctl("/ctl", "normcolors "), nil);
if(focus)
loadcolor(focus, readctl("/ctl", "focuscolors "), nil);
*font = loadfont(readctl("/ctl", "font "));
if(!*font)
fatal("Can't load font %q", readctl("/ctl", "font "));
sscanf(readctl("/ctl", "fontpad "), "%d %d %d %d",
&(*font)->pad.min.x, &(*font)->pad.max.x,
&(*font)->pad.min.x, &(*font)->pad.max.y);
}
|
Added lib/libstuff/clientutil.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
/* Copyright ©2009-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#define IXP_NO_P9_
#define IXP_P9_STRUCTS
#define CLIENTEXTERN
#include <stdlib.h>
#include <string.h>
#include <ixp.h>
#include <stuff/clientutil.h>
#include <stuff/util.h>
char*
readctl(char *ctlname, char *key) {
static char ctlfile[128];
static char ctl[1024];
static char* ectl;
IxpCFid *fid;
char *s, *p;
int nkey, n;
if(strcmp(ctlname, ctlfile)) {
strncpy(ctlfile, ctlname, sizeof ctlfile);
fid = ixp_open(client, ctlfile, OREAD);
n = ixp_read(fid, ctl, sizeof ctl - 1);
ectl = ctl + n;
ixp_close(fid);
}
nkey = strlen(key);
p = ctl - 1;
do {
p++;
if(!strncmp(p, key, nkey)) {
p += nkey;
s = strchr(p, '\n');
n = (s ? s : ectl) - p;
s = freelater(emalloc(n + 1));
s[n] = '\0';
return memcpy(s, p, n);
}
} while((p = strchr(p, '\n')));
return "";
}
void
client_init(char* address) {
IXP_ASSERT_VERSION;
if(address == nil)
address = getenv("WMII_ADDRESS");
if(address && *address)
client = ixp_mount(address);
else
client = ixp_nsmount("wmii");
if(client == nil)
fatal("can't mount wmii filesystem: %r\n");
}
|
Added lib/libstuff/event/buttonpress.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_buttonpress(XButtonPressedEvent *ev) {
Window *w;
if((w = findwin(ev->window)))
event_handle(w, bdown, ev);
else
XAllowEvents(display, ReplayPointer, ev->time);
}
|
Added lib/libstuff/event/buttonrelease.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_buttonrelease(XButtonPressedEvent *ev) {
Window *w;
if((w = findwin(ev->window)))
event_handle(w, bup, ev);
}
|
Added lib/libstuff/event/clientmessage.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_clientmessage(XClientMessageEvent *ev) {
Window *w;
if((w = findwin(ev->window)))
event_handle(w, message, ev);
}
|
Added lib/libstuff/event/configurenotify.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_configurenotify(XConfigureEvent *ev) {
Window *w;
if(!ev->send_event)
event_lastconfigure = ev->serial;
if((w = findwin(ev->window)))
event_handle(w, config, ev);
}
|
Added lib/libstuff/event/configurerequest.c.
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_configurerequest(XConfigureRequestEvent *ev) {
XWindowChanges wc;
Window *w;
if((w = findwin(ev->window)))
event_handle(w, configreq, ev);
else{
wc.x = ev->x;
wc.y = ev->y;
wc.width = ev->width;
wc.height = ev->height;
wc.border_width = ev->border_width;
wc.sibling = ev->above;
wc.stack_mode = ev->detail;
XConfigureWindow(display, ev->window, ev->value_mask, &wc);
}
}
|
Added lib/libstuff/event/destroynotify.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_destroynotify(XDestroyWindowEvent *ev) {
Window *w;
if(!ev->send_event)
event_lastconfigure = ev->serial;
if((w = findwin(ev->window)))
event_handle(w, destroy, ev);
}
|
Added lib/libstuff/event/enternotify.c.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_enternotify(XCrossingEvent *ev) {
Window *w;
if(!ev->send_event)
event_xtime = ev->time;
if(ev->mode != NotifyNormal)
return;
if((w = findwin(ev->window)))
event_handle(w, enter, ev);
}
|
Added lib/libstuff/event/event.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
typedef bool (*Handler)(Window*, void*, XEvent*);
void (*event_debug)(XEvent*);
long event_lastconfigure;
long event_xtime;
bool event_looprunning;
EventHandler event_handler[LASTEvent] = {
[ButtonPress] = (EventHandler)event_buttonpress,
[ButtonRelease] = (EventHandler)event_buttonrelease,
[ClientMessage] = (EventHandler)event_clientmessage,
[ConfigureNotify] = (EventHandler)event_configurenotify,
[ConfigureRequest] = (EventHandler)event_configurerequest,
[DestroyNotify] = (EventHandler)event_destroynotify,
[EnterNotify] = (EventHandler)event_enternotify,
[Expose] = (EventHandler)event_expose,
[FocusIn] = (EventHandler)event_focusin,
[FocusOut] = (EventHandler)event_focusout,
[KeyPress] = (EventHandler)event_keypress,
[KeyRelease] = (EventHandler)event_keyrelease,
[LeaveNotify] = (EventHandler)event_leavenotify,
[MapNotify] = (EventHandler)event_mapnotify,
[MapRequest] = (EventHandler)event_maprequest,
[MappingNotify] = (EventHandler)event_mappingnotify,
[MotionNotify] = (EventHandler)event_motionnotify,
[PropertyNotify] = (EventHandler)event_propertynotify,
[ReparentNotify] = (EventHandler)event_reparentnotify,
[SelectionClear] = (EventHandler)event_selectionclear,
[SelectionNotify] = (EventHandler)event_selection,
[UnmapNotify] = (EventHandler)event_unmapnotify,
};
void
_event_handle(Window *w, ulong offset, XEvent *event) {
Handler f;
HandlersLink *l;
if(w->handler && (f = structmember(w->handler, Handler, offset)))
if(!f(w, w->aux, event))
return;
for(l=w->handler_link; l; l=l->next)
if((f = structmember(l->handler, Handler, offset)))
if(!f(w, l->aux, event))
return;
}
void
event_dispatch(XEvent *e) {
if(event_debug)
event_debug(e);
if(e->type < nelem(event_handler)) {
if(event_handler[e->type])
event_handler[e->type](e);
}else
xext_event(e);
}
void
event_check(void) {
XEvent ev;
while(XPending(display)) {
XNextEvent(display, &ev);
event_dispatch(&ev);
}
}
void
event_loop(void) {
XEvent ev;
event_looprunning = true;
while(event_looprunning) {
XNextEvent(display, &ev);
event_dispatch(&ev);
}
}
uint
event_flush(long event_mask, bool dispatch) {
XEvent ev;
uint n = 0;
while(XCheckMaskEvent(display, event_mask, &ev)) {
if(dispatch)
event_dispatch(&ev);
n++;
}
return n;
}
static int
findenter(Display *d, XEvent *e, XPointer v) {
long *l;
USED(d);
l = (long*)v;
if(*l)
return false;
if(e->type == EnterNotify)
return true;
if(e->type == MotionNotify)
(*l)++;
return false;
}
/* This isn't perfect. If there were motion events in the queue
* before this was called, then it flushes nothing. If we don't
* check for them, we might lose a legitamate enter event.
*/
uint
event_flushenter(void) {
XEvent e;
long l;
int n;
l = 0;
n = 0;
while(XCheckIfEvent(display, &e, findenter, (void*)&l))
n++;
return n;
}
|
Added lib/libstuff/event/event.h.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | #include <stuff/x.h> typedef void (*EventHandler)(XEvent*); #define handle(w, fn, ev) \ BLOCK(if((w)->handler->fn) (w)->handler->fn((w), ev)) extern EventHandler event_handler[LASTEvent]; |
Added lib/libstuff/event/expose.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_expose(XExposeEvent *ev) {
Window *w;
if(ev->count == 0 && (w = findwin(ev->window)))
event_handle(w, expose, ev);
}
|
Added lib/libstuff/event/focusin.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_focusin(XFocusChangeEvent *ev) {
Window *w;
/* Yes, we're focusing in on nothing, here. */
if(ev->detail == NotifyDetailNone) {
/* FIXME: Do something. */
return;
}
if(!((ev->detail == NotifyNonlinear)
||(ev->detail == NotifyNonlinearVirtual)
||(ev->detail == NotifyVirtual)
||(ev->detail == NotifyInferior)
||(ev->detail == NotifyAncestor)))
return;
if((ev->mode == NotifyWhileGrabbed))
return;
if((w = findwin(ev->window)))
event_handle(w, focusin, ev);
}
|
Added lib/libstuff/event/focusout.c.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_focusout(XFocusChangeEvent *ev) {
Window *w;
if(!((ev->detail == NotifyNonlinear)
||(ev->detail == NotifyNonlinearVirtual)
||(ev->detail == NotifyVirtual)
||(ev->detail == NotifyInferior)
||(ev->detail == NotifyAncestor)))
return;
if((w = findwin(ev->window)))
event_handle(w, focusout, ev);
}
|
Added lib/libstuff/event/ixp.c.
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <ixp.h>
#include "event.h"
void
event_preselect(IxpServer *s) {
USED(s);
event_check();
XFlush(display);
}
void
event_fdready(IxpConn *c) {
USED(c);
event_check();
}
void
event_fdclosed(IxpConn *c) {
c->srv->running = false;
}
|
Added lib/libstuff/event/keypress.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_keypress(XKeyEvent *ev) {
Window *w;
if(!ev->send_event)
event_xtime = ev->time;
if((w = findwin(ev->window)))
event_handle(w, kdown, ev);
}
|
Added lib/libstuff/event/keyrelease.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_keyrelease(XKeyEvent *ev) {
Window *w;
if(!ev->send_event)
event_xtime = ev->time;
if((w = findwin(ev->window)))
event_handle(w, kup, ev);
}
|
Added lib/libstuff/event/leavenotify.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_leavenotify(XCrossingEvent *ev) {
Window *w;
if(!ev->send_event)
event_xtime = ev->time;
if((w = findwin(ev->window)))
event_handle(w, leave, ev);
}
|
Added lib/libstuff/event/mapnotify.c.
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_mapnotify(XMapEvent *ev) {
Window *w;
if(!ev->send_event)
event_lastconfigure = ev->serial;
if((w = findwin(ev->event)))
event_handle(w, map, ev);
if(ev->send_event && (w = findwin(ev->event)))
event_handle(w, map, ev);
}
|
Added lib/libstuff/event/mappingnotify.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_mappingnotify(XMappingEvent *ev) {
/* Why do you need me to tell you this? */
XRefreshKeyboardMapping(ev);
}
|
Added lib/libstuff/event/maprequest.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_maprequest(XMapRequestEvent *ev) {
Window *w;
if((w = findwin(ev->parent)))
event_handle(w, mapreq, ev);
}
|
Added lib/libstuff/event/motionnotify.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_motionnotify(XMotionEvent *ev) {
Window *w;
if(!ev->send_event)
event_xtime = ev->time;
if((w = findwin(ev->window)))
event_handle(w, motion, ev);
}
|
Added lib/libstuff/event/propertynotify.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_propertynotify(XPropertyEvent *ev) {
Window *w;
if(!ev->send_event)
event_xtime = ev->time;
if((w = findwin(ev->window)))
event_handle(w, property, ev);
}
|
Added lib/libstuff/event/reparentnotify.c.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_reparentnotify(XReparentEvent *ev) {
Window *target, *w;
if(!ev->send_event)
event_lastconfigure = ev->serial;
w = nil;
if((target = findwin(ev->window)) && (w = findwin(ev->parent)))
target->parent = w;
if((w = findwin(ev->event)))
event_handle(w, reparent, ev);
if(ev->send_event && target)
event_handle(target, reparent, ev);
}
|
Added lib/libstuff/event/selection.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_selection(XSelectionEvent *ev) {
Window *w;
if(!ev->send_event)
event_xtime = ev->time;
if((w = findwin(ev->requestor)))
event_handle(w, selection, ev);
}
|
Added lib/libstuff/event/selectionclear.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_selectionclear(XSelectionClearEvent *ev) {
Window *w;
if(!ev->send_event)
event_xtime = ev->time;
if((w = findwin(ev->window)))
event_handle(w, selectionclear, ev);
}
|
Added lib/libstuff/event/selectionrequest.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_selectionrequest(XSelectionRequestEvent *ev) {
Window *w;
if(!ev->send_event)
event_xtime = ev->time;
if((w = findwin(ev->owner)))
event_handle(w, selectionrequest, ev);
}
|
Added lib/libstuff/event/unmapnotify.c.
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "event.h"
void
event_unmapnotify(XUnmapEvent *ev) {
Window *w;
if(!ev->send_event)
event_lastconfigure = ev->serial;
if((w = findwin(ev->window))) {
if(!ev->send_event)
w->mapped = false;
if(!ev->send_event && ev->event == ev->window)
w->unmapped--;
if(ev->send_event && ev->event != ev->window)
event_handle(w, unmap, ev);
}
if((w = findwin(ev->event)))
event_handle(w, unmap, ev);
}
|
Added lib/libstuff/event/xtime.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <stuff/x.h>
static int
findtime(Display *d, XEvent *e, XPointer v) {
Window *w;
w = (Window*)v;
if(e->type == PropertyNotify && e->xproperty.window == w->xid) {
event_xtime = e->xproperty.time;
return true;
}
return false;
}
long
event_updatextime(void) {
Window *w;
WinAttr wa;
XEvent e;
long l;
w = createwindow(&scr.root, Rect(0, 0, 1, 1), 0, InputOnly, &wa, 0);
XSelectInput(display, w->xid, PropertyChangeMask);
changeprop_long(w, "ATOM", "ATOM", &l, 0);
XIfEvent(display, &e, findtime, (void*)w);
destroywindow(w);
return event_xtime;
}
|
Added lib/libstuff/fmt/blprint.c.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
#include <bio.h>
int
Blprint(Biobuf *bp, const char *fmt, ...)
{
va_list arg;
int n;
va_start(arg, fmt);
n = Bvlprint(bp, fmt, arg);
va_end(arg);
return n;
}
|
Added lib/libstuff/fmt/bvlprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
#include <bio.h>
static int
fmtBlflush(Fmt *f)
{
mbstate_t state;
Biobuf *bp;
Rune *rp, *rend;
int res;
bp = f->farg;
rend = f->to;
state = (mbstate_t){0};
for(rp=(Rune*)f->start; rp < rend; rp++) {
if(MB_LEN_MAX + bp->ocount > 0 && Bflush(bp) < 0)
return 0;
res = wcrtomb((char*)bp->ebuf + bp->ocount, *rp, &state);
if(res == -1)
Bputc(bp, '?');
else
bp->ocount += res;
}
f->to = f->start;
return 1;
}
int
Bvlprint(Biobuf *bp, const char *fmt, va_list args)
{
Fmt f;
Rune buf[256];
int res;
if(utf8locale())
return Bvprint(bp, fmt, args);
f.runes = 1;
f.start = (char*)buf;
f.to = (char*)buf;
f.stop = (char*)(buf + nelem(buf) - 1);
f.flush = fmtBlflush;
f.farg = bp;
f.nfmt = 0;
va_copy(f.args, args);
res = dofmt(&f, fmt);
va_end(f.args);
if(res > 0 && fmtBlflush(&f) == 0)
return -1;
return res;
}
|
Added lib/libstuff/fmt/fmtbuf.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include "fmtdef.h"
Fmt
fmtbuf(char *buf, int len) {
Fmt f;
f.runes = 0;
f.start = buf;
f.to = buf;
f.stop = buf + len - 1;
f.flush = 0;
f.farg = nil;
f.nfmt = 0;
return f;
}
|
Added lib/libstuff/fmt/fmtdef.h.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 | #include <stuff/util.h> #include <langinfo.h> #include <limits.h> #include <string.h> #include <wchar.h> extern void* __fmtflush(Fmt *f, void *t, int len); extern int __fmtpad(Fmt *f, int n); extern int __rfmtpad(Fmt *f, int n); |
Added lib/libstuff/fmt/localefmt.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
static bool
pad(Fmt *f, int len) {
if(f->flags & FmtWidth) {
if(f->runes)
return __rfmtpad(f, f->width - len) >= 0;
return __fmtpad(f, f->width - len) >= 0;
}
return true;
}
int
localefmt(Fmt *f) {
mbstate_t state;
Rune *rp, *rend;
char *sp, *send, *str, *end;
Rune r;
wchar_t w;
int res, count, rlen;
str = va_arg(f->args, char*);
if(utf8locale()) {
/* We handle precision in bytes, fmtstrcpy in characters */
if(f->flags & FmtPrec)
f->prec = utfnlen(str, f->prec);
return fmtstrcpy(f, str);
}
end = 0;
if(f->flags & FmtPrec)
end = str + f->prec;
if(!(f->flags & FmtLeft) && !pad(f, localelen(str, end)))
return -1;
sp = f->to;
send = f->stop;
rp = (Rune*)f->to;
rend = (Rune*)f->stop;
count = 0;
for(state = (mbstate_t){0}; ; str += res) {
switch((res = mbrtowc(&w, str, end ? end - str : MB_LEN_MAX, &state))) {
case 0:
case -2:
break;
case -1:
w = Runesync;
res = 1;
/* Fallthrough. */
default:
count++;
if(w > Runemax)
w = Runesync;
r = w;
// print("%d %C\n", res, r);
if(f->runes) {
if(rp >= rend) {
// print("flush\n");
rp = (Rune*)__fmtflush(f, rp, sizeof *rp);
rend = (Rune*)f->stop;
if(rp == nil)
return -1;
}
*rp++ = r;
}else {
if(sp + UTFmax > send && sp + (rlen = runelen(r)) > send) {
// print("flush %d\n", rlen);
sp = __fmtflush(f, sp, rlen);
send = f->stop;
if(sp == nil)
return -1;
}
if(r < Runeself)
*sp++ = (char)r;
else
sp += runetochar(sp, &r);
}
continue;
}
if(f->runes) {
f->nfmt += rp - (Rune*)f->to;
f->to = (char*)rp;
}else {
f->nfmt += sp - (char*)f->to;
f->to = sp;
}
break;
}
if((f->flags & FmtLeft) && !pad(f, count))
return -1;
return 0;
}
void
localefmtinstall(void) {
fmtinstall('L', localefmt);
}
|
Added lib/libstuff/fmt/localelen.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
int
localelen(char *str, char *end) {
mbstate_t state;
size_t n, res;
if(utf8locale()) {
if(end)
return utfnlen(str, end - str);
return utflen(str);
}
state = (mbstate_t){0};
n = 0;
for(n=0;;)
switch((res = mbrtowc(nil, str, end ? end - str : MB_LEN_MAX, &state))) {
case -1:
return -1;
case 0:
case -2:
return n;
default:
n++;
str += res;
}
return n; /* Not reached. */
}
|
Added lib/libstuff/fmt/lprint.c.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
int
lprint(int fd, const char *fmt, ...) {
va_list ap;
int res;
va_start(ap, fmt);
res = vlprint(fd, fmt, ap);
va_end(ap);
return res;
}
|
Added lib/libstuff/fmt/vlprint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* Copyright ©2002 by Lucent Technologies.
* See LICENSE file for license details.
*/
#include "fmtdef.h"
#include <unistd.h>
static int
fmtlfdflush(Fmt *f) {
mbstate_t state;
char buf[256];
Rune *rp, *rend;
char *sp, *send;
int res;
sp = buf;
send = buf + sizeof buf - UTFmax;
rend = f->to;
state = (mbstate_t){0};
for(rp=(Rune*)f->start; rp < rend; rp++) {
res = wcrtomb(sp, *rp, &state);
if(res == -1)
*sp++ = '?'; /* Fixme? */
else
sp += res;
if(sp >= send || rp == rend - 1) {
if(write((uintptr_t)f->farg, buf, sp - buf) != sp - buf)
return 0;
sp = buf;
}
}
f->to = f->start;
return 1;
}
int
vlprint(int fd, const char *fmt, va_list args) {
Fmt f;
Rune buf[256];
int res;
if(utf8locale())
return vfprint(fd, fmt, args);
f.runes = 1;
f.start = (char*)buf;
f.to = (char*)buf;
f.stop = (char*)(buf + nelem(buf) - 1);
f.flush = fmtlfdflush;
f.farg = (void*)(uintptr_t)fd;
f.nfmt = 0;
va_copy(f.args, args);
res = dofmt(&f, fmt);
va_end(f.args);
if(res > 0 && fmtlfdflush(&f) == 0)
return -1;
return res;
}
|
Added lib/libstuff/geom/get_sticky.c.
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <stuff/geom.h>
Align
get_sticky(Rectangle src, Rectangle dst) {
Align corner;
corner = 0;
if(src.min.x != dst.min.x
&& src.max.x == dst.max.x)
corner |= East;
else
corner |= West;
if(src.min.y != dst.min.y
&& src.max.y == dst.max.y)
corner |= South;
else
corner |= North;
return corner;
}
|
Added lib/libstuff/geom/quadrant.c.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <stuff/geom.h>
Align
quadrant(Rectangle r, Point pt) {
Align ret;
pt = subpt(pt, r.min);
ret = East * (pt.x >= Dx(r) * .7)
| West * (pt.x <= Dx(r) * .3)
| South * (pt.y >= Dy(r) * .7)
| North * (pt.y <= Dy(r) * .3);
return ret;
}
|
Added lib/libstuff/geom/rect_contains_p.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <stuff/geom.h>
bool
rect_contains_p(Rectangle r, Rectangle r2) {
return r2.min.x >= r.min.x
&& r2.max.x <= r.max.x
&& r2.min.y >= r.min.y
&& r2.max.y <= r.max.y;
}
|
Added lib/libstuff/geom/rect_haspoint_p.c.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <stuff/geom.h>
bool
rect_haspoint_p(Rectangle r, Point pt) {
return (pt.x >= r.min.x) && (pt.x < r.max.x)
&& (pt.y >= r.min.y) && (pt.y < r.max.y);
}
|
Added lib/libstuff/geom/rect_intersect_p.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <stuff/geom.h>
bool
rect_intersect_p(Rectangle r, Rectangle r2) {
return r.min.x <= r2.max.x
&& r.max.x >= r2.min.x
&& r.min.y <= r2.max.y
&& r.max.y >= r2.min.y;
}
|
Added lib/libstuff/geom/rect_intersection.c.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <stuff/geom.h>
#include <stuff/util.h>
Rectangle
rect_intersection(Rectangle r, Rectangle r2) {
Rectangle ret;
/* ret != canonrect(ret) ≡ no intersection. */
ret.min.x = max(r.min.x, r2.min.x);
ret.max.x = min(r.max.x, r2.max.x);
ret.min.y = max(r.min.y, r2.min.y);
ret.max.y = min(r.max.y, r2.max.y);
return ret;
}
|
Added lib/libstuff/init_screens.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
void init_screens(void);
void
init_screens(void) {
}
|
Added lib/libstuff/map.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
/* Written by Kris Maglione */
/* Public domain */
#include <assert.h>
#include <string.h>
#include <stuff/util.h>
/* Edit s/^([a-zA-Z].*)\n([a-z].*) {/\1 \2;/g x/^([^a-zA-Z]|static|$)/-+d s/ (\*map|val|*str)//g */
struct MapEnt {
ulong hash;
const char* key;
void* val;
MapEnt* next;
};
MapEnt *NM;
/* By Dan Bernstein. Public domain. */
static ulong
hash(const char *str) {
ulong h;
h = 5381;
while (*str != '\0') {
h += h << 5; /* h *= 33 */
h ^= *str++;
}
return h;
}
static void
insert(Map *m, MapEnt **e, ulong val, const char *key) {
MapEnt *te;
m->nmemb++;
te = emallocz(sizeof *te);
te->hash = val;
te->key = key;
te->next = *e;
*e = te;
}
static MapEnt**
map_getp(Map *map, ulong val, int create) {
MapEnt **e;
e = &map->bucket[val%map->nhash];
for(; *e; e = &(*e)->next)
if((*e)->hash >= val) break;
if(*e == nil || (*e)->hash != val) {
if(create)
insert(map, e, val, nil);
else
e = &NM;
}
return e;
}
static MapEnt**
hash_getp(Map *map, const char *str, int create) {
MapEnt **e;
ulong h;
int cmp;
h = hash(str);
e = map_getp(map, h, create);
if(*e && (*e)->key == nil)
(*e)->key = estrdup(str);
else {
SET(cmp);
for(; *e; e = &(*e)->next)
if((*e)->hash > h || (cmp = strcmp((*e)->key, str)) >= 0)
break;
if(*e == nil || (*e)->hash > h || cmp > 0)
if(create)
insert(map, e, h, estrdup(str));
}
return e;
}
void**
map_get(Map *map, ulong val, bool create) {
MapEnt *e;
e = *map_getp(map, val, create);
return e ? &e->val : nil;
}
void**
hash_get(Map *map, const char *str, bool create) {
MapEnt *e;
e = *hash_getp(map, str, create);
return e ? &e->val : nil;
}
void*
map_rm(Map *map, ulong val) {
MapEnt **e, *te;
void *ret;
ret = nil;
e = map_getp(map, val, 0);
if(*e) {
te = *e;
ret = te->val;
*e = te->next;
assert(map->nmemb-- > 0);
free(te);
}
return ret;
}
void*
hash_rm(Map *map, const char *str) {
MapEnt **e, *te;
void *ret;
ret = nil;
e = hash_getp(map, str, 0);
if(*e) {
te = *e;
ret = te->val;
*e = te->next;
assert(map->nmemb-- > 0);
free((void*)(uintptr_t)te->key);
free(te);
}
return ret;
}
|
Added lib/libstuff/printevent.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 |
/*
* Original code posted to comp.sources.x
* Modifications by Russ Cox <rsc@swtch.com>.
* Further modifications by Kris Maglione <maglione.k at Gmail>
*/
/*
* Path: uunet!wyse!mikew From: mikew@wyse.wyse.com (Mike Wexler) Newsgroups:
* comp.sources.x Subject: v02i056: subroutine to print events in human
* readable form, Part01/01 Message-ID: <1935@wyse.wyse.com> Date: 22 Dec 88
* 19:28:25 GMT Organization: Wyse Technology, San Jose Lines: 1093 Approved:
* mikew@wyse.com
*
* Submitted-by: richsun!darkstar!ken Posting-number: Volume 2, Issue 56
* Archive-name: showevent/part01
*
*
* There are times during debugging when it would be real useful to be able to
* print the fields of an event in a human readable form. Too many times I
* found myself scrounging around in section 8 of the Xlib manual looking for
* the valid fields for the events I wanted to see, then adding printf's to
* display the numeric values of the fields, and then scanning through X.h
* trying to decode the cryptic detail and state fields. After playing with
* xev, I decided to write a couple of standard functions that I could keep
* in a library and call on whenever I needed a little debugging verbosity.
* The first function, GetType(), is useful for returning the string
* representation of the type of an event. The second function, ShowEvent(),
* is used to display all the fields of an event in a readable format. The
* functions are not complicated, in fact, they are mind-numbingly boring -
* but that's just the point nobody wants to spend the time writing functions
* like this, they just want to have them when they need them.
*
* A simple, sample program is included which does little else but to
* demonstrate the use of these two functions. These functions have saved me
* many an hour during debugging and I hope you find some benefit to these.
* If you have any comments, suggestions, improvements, or if you find any
* blithering errors you can get it touch with me at the following location:
*
* ken@richsun.UUCP
*/
#include <stdarg.h>
#include <bio.h>
#include <stuff/x.h>
#include <stuff/util.h>
#include "printevent.h"
#define Window XWindow
#define unmask _unmask
#define nil ((void*)0)
typedef struct Pair Pair;
struct Pair {
int key;
char *val;
};
static char* sep = " ";
static char *
search(Pair *lst, int key, char *(*def)(int)) {
for(; lst->val; lst++)
if(lst->key == key)
return lst->val;
return def(key);
}
static char*
unmask(Pair *list, uint val)
{
Pair *p;
char *s, *end;
int n;
buffer[0] = '\0';
end = buffer + sizeof buffer;
s = buffer;
n = 0;
s = utfecpy(s, end, "(");
for (p = list; p->val; p++)
if (val & p->key) {
if(n++)
s = utfecpy(s, end, "|");
s = utfecpy(s, end, p->val);
}
utfecpy(s, end, ")");
return buffer;
}
static char *
strhex(int key) {
sprint(buffer, "0x%x", key);
return buffer;
}
static char *
strdec(int key) {
sprint(buffer, "%d", key);
return buffer;
}
static char *
strign(int key) {
USED(key);
return "?";
}
/******************************************************************************/
/**** Miscellaneous routines to convert values to their string equivalents ****/
/******************************************************************************/
static void
TInt(Fmt *b, va_list *ap) {
fmtprint(b, "%d", va_arg(*ap, int));
}
static void
TWindow(Fmt *b, va_list *ap) {
Window w;
w = va_arg(*ap, Window);
fmtprint(b, "0x%ux", (uint)w);
}
static void
TData(Fmt *b, va_list *ap) {
long *l;
int i;
l = va_arg(*ap, long*);
fmtprint(b, "{");
for (i = 0; i < 5; i++) {
if(i > 0)
fmtprint(b, ", ");
fmtprint(b, "0x%08lx", l[i]);
}
fmtprint(b, "}");
}
/* Returns the string equivalent of a timestamp */
static void
TTime(Fmt *b, va_list *ap) {
ldiv_t d;
ulong msec;
ulong sec;
ulong min;
ulong hr;
ulong day;
Time time;
time = va_arg(*ap, Time);
msec = time/1000;
d = ldiv(msec, 60);
msec = time-msec*1000;
sec = d.rem;
d = ldiv(d.quot, 60);
min = d.rem;
d = ldiv(d.quot, 24);
hr = d.rem;
day = d.quot;
#ifdef notdef
sprintf(buffer, "%lu day%s %02lu:%02lu:%02lu.%03lu",
day, day == 1 ? "" : "(s)", hr, min, sec, msec);
#endif
fmtprint(b, "%ludd_%ludh_%ludm_%lud.%03luds", day, hr, min, sec, msec);
}
/* Returns the string equivalent of a boolean parameter */
static void
TBool(Fmt *b, va_list *ap) {
static Pair list[] = {
{True, "True"},
{False, "False"},
{0, nil},
};
Bool key;
key = va_arg(*ap, Bool);
fmtprint(b, "%s", search(list, key, strign));
}
/* Returns the string equivalent of a property notify state */
static void
TPropState(Fmt *b, va_list *ap) {
static Pair list[] = {
{PropertyNewValue, "PropertyNewValue"},
{PropertyDelete, "PropertyDelete"},
{0, nil},
};
uint key;
key = va_arg(*ap, uint);
fmtprint(b, "%s", search(list, key, strign));
}
/* Returns the string equivalent of a visibility notify state */
static void
TVis(Fmt *b, va_list *ap) {
static Pair list[] = {
{VisibilityUnobscured, "VisibilityUnobscured"},
{VisibilityPartiallyObscured, "VisibilityPartiallyObscured"},
{VisibilityFullyObscured, "VisibilityFullyObscured"},
{0, nil},
};
int key;
key = va_arg(*ap, int);
fmtprint(b, "%s", search(list, key, strign));
}
/* Returns the string equivalent of a mask of buttons and/or modifier keys */
static void
TModState(Fmt *b, va_list *ap) {
static Pair list[] = {
{Button1Mask, "Button1Mask"},
{Button2Mask, "Button2Mask"},
{Button3Mask, "Button3Mask"},
{Button4Mask, "Button4Mask"},
{Button5Mask, "Button5Mask"},
{ShiftMask, "ShiftMask"},
{LockMask, "LockMask"},
{ControlMask, "ControlMask"},
{Mod1Mask, "Mod1Mask"},
{Mod2Mask, "Mod2Mask"},
{Mod3Mask, "Mod3Mask"},
{Mod4Mask, "Mod4Mask"},
{Mod5Mask, "Mod5Mask"},
{0, nil},
};
uint state;
state = va_arg(*ap, uint);
fmtprint(b, "%s", unmask(list, state));
}
/* Returns the string equivalent of a mask of configure window values */
static void
TConfMask(Fmt *b, va_list *ap) {
static Pair list[] = {
{CWX, "CWX"},
{CWY, "CWY"},
{CWWidth, "CWWidth"},
{CWHeight, "CWHeight"},
{CWBorderWidth, "CWBorderWidth"},
{CWSibling, "CWSibling"},
{CWStackMode, "CWStackMode"},
{0, nil},
};
uint valuemask;
valuemask = va_arg(*ap, uint);
fmtprint(b, "%s", unmask(list, valuemask));
}
/* Returns the string equivalent of a motion hint */
#if 0
static void
IsHint(Fmt *b, va_list *ap) {
static Pair list[] = {
{NotifyNormal, "NotifyNormal"},
{NotifyHint, "NotifyHint"},
{0, nil},
};
char key;
key = va_arg(*ap, char);
fmtprint(b, "%s", search(list, key, strign));
}
#endif
/* Returns the string equivalent of an id or the value "None" */
static void
TIntNone(Fmt *b, va_list *ap) {
static Pair list[] = {
{None, "None"},
{0, nil},
};
int key;
key = va_arg(*ap, int);
fmtprint(b, "%s", search(list, key, strhex));
}
/* Returns the string equivalent of a colormap state */
static void
TColMap(Fmt *b, va_list *ap) {
static Pair list[] = {
{ColormapInstalled, "ColormapInstalled"},
{ColormapUninstalled, "ColormapUninstalled"},
{0, nil},
};
int key;
key = va_arg(*ap, int);
fmtprint(b, "%s", search(list, key, strign));
}
/* Returns the string equivalent of a crossing detail */
static void
TXing(Fmt *b, va_list *ap) {
static Pair list[] = {
{NotifyAncestor, "NotifyAncestor"},
{NotifyInferior, "NotifyInferior"},
{NotifyVirtual, "NotifyVirtual"},
{NotifyNonlinear, "NotifyNonlinear"},
{NotifyNonlinearVirtual, "NotifyNonlinearVirtual"},
{0, nil},
};
int key;
key = va_arg(*ap, int);
fmtprint(b, "%s", search(list, key, strign));
}
/* Returns the string equivalent of a focus change detail */
static void
TFocus(Fmt *b, va_list *ap) {
static Pair list[] = {
{NotifyAncestor, "NotifyAncestor"},
{NotifyInferior, "NotifyInferior"},
{NotifyVirtual, "NotifyVirtual"},
{NotifyNonlinear, "NotifyNonlinear"},
{NotifyNonlinearVirtual, "NotifyNonlinearVirtual"},
{NotifyPointer, "NotifyPointer"},
{NotifyPointerRoot, "NotifyPointerRoot"},
{NotifyDetailNone, "NotifyDetailNone"},
{0, nil},
};
int key;
key = va_arg(*ap, int);
fmtprint(b, "%s", search(list, key, strign));
}
/* Returns the string equivalent of a configure detail */
static void
TConfDetail(Fmt *b, va_list *ap) {
static Pair list[] = {
{Above, "Above"},
{Below, "Below"},
{TopIf, "TopIf"},
{BottomIf, "BottomIf"},
{Opposite, "Opposite"},
{0, nil},
};
int key;
key = va_arg(*ap, int);
fmtprint(b, "%s", search(list, key, strign));
}
/* Returns the string equivalent of a grab mode */
static void
TGrabMode(Fmt *b, va_list *ap) {
static Pair list[] = {
{NotifyNormal, "NotifyNormal"},
{NotifyGrab, "NotifyGrab"},
{NotifyUngrab, "NotifyUngrab"},
{NotifyWhileGrabbed, "NotifyWhileGrabbed"},
{0, nil},
};
int key;
key = va_arg(*ap, int);
fmtprint(b, "%s", search(list, key, strign));
}
/* Returns the string equivalent of a mapping request */
static void
TMapping(Fmt *b, va_list *ap) {
static Pair list[] = {
{MappingModifier, "MappingModifier"},
{MappingKeyboard, "MappingKeyboard"},
{MappingPointer, "MappingPointer"},
{0, nil},
};
int key;
key = va_arg(*ap, int);
fmtprint(b, "%s", search(list, key, strign));
}
/* Returns the string equivalent of a stacking order place */
static void
TPlace(Fmt *b, va_list *ap) {
static Pair list[] = {
{PlaceOnTop, "PlaceOnTop"},
{PlaceOnBottom, "PlaceOnBottom"},
{0, nil},
};
int key;
key = va_arg(*ap, int);
fmtprint(b, "%s", search(list, key, strign));
}
/* Returns the string equivalent of a major code */
static void
TMajor(Fmt *b, va_list *ap) {
static char *list[] = { XMajors };
char *s;
uint key;
key = va_arg(*ap, uint);
s = "<nil>";
if(key < nelem(list))
s = list[key];
fmtprint(b, "%s", s);
}
static char*
eventtype(int key) {
static Pair list[] = {
{ButtonPress, "ButtonPress"},
{ButtonRelease, "ButtonRelease"},
{CirculateNotify, "CirculateNotify"},
{CirculateRequest, "CirculateRequest"},
{ClientMessage, "ClientMessage"},
{ColormapNotify, "ColormapNotify"},
{ConfigureNotify, "ConfigureNotify"},
{ConfigureRequest, "ConfigureRequest"},
{CreateNotify, "CreateNotify"},
{DestroyNotify, "DestroyNotify"},
{EnterNotify, "EnterNotify"},
{Expose, "Expose"},
{FocusIn, "FocusIn"},
{FocusOut, "FocusOut"},
{GraphicsExpose, "GraphicsExpose"},
{GravityNotify, "GravityNotify"},
{KeyPress, "KeyPress"},
{KeyRelease, "KeyRelease"},
{KeymapNotify, "KeymapNotify"},
{LeaveNotify, "LeaveNotify"},
{MapNotify, "MapNotify"},
{MapRequest, "MapRequest"},
{MappingNotify, "MappingNotify"},
{MotionNotify, "MotionNotify"},
{NoExpose, "NoExpose"},
{PropertyNotify, "PropertyNotify"},
{ReparentNotify, "ReparentNotify"},
{ResizeRequest, "ResizeRequest"},
{SelectionClear, "SelectionClear"},
{SelectionNotify, "SelectionNotify"},
{SelectionRequest, "SelectionRequest"},
{UnmapNotify, "UnmapNotify"},
{VisibilityNotify, "VisibilityNotify"},
{0, nil},
};
return search(list, key, strdec);
}
/* Returns the string equivalent the keycode contained in the key event */
static void
TKeycode(Fmt *b, va_list *ap) {
KeySym keysym_str;
XKeyEvent *ev;
char *keysym_name;
ev = va_arg(*ap, XKeyEvent*);
XLookupString(ev, buffer, sizeof buffer, &keysym_str, nil);
if (keysym_str == NoSymbol)
keysym_name = "NoSymbol";
else
keysym_name = XKeysymToString(keysym_str);
if(keysym_name == nil)
keysym_name = "(no name)";
fmtprint(b, "%ud (keysym 0x%x \"%s\")", (int)ev->keycode,
(int)keysym_str, keysym_name);
}
/* Returns the string equivalent of an atom or "None" */
static void
TAtom(Fmt *b, va_list *ap) {
fmtstrcpy(b, atomname(va_arg(*ap, Atom)));
}
#define _(m) #m, ev->m
#define TEnd nil
typedef void (*Tfn)(Fmt*, va_list*);
static int
pevent(Fmt *fmt, void *e, ...) {
va_list ap;
Tfn fn;
XAnyEvent *ev;
char *key;
int n;
ev = e;
fmtprint(fmt, "%3ld %-20s ", ev->serial, eventtype(ev->type));
if(ev->send_event)
fmtstrcpy(fmt, "(sendevent) ");
n = 0;
va_start(ap, e);
for(;;) {
fn = va_arg(ap, Tfn);
if(fn == TEnd)
break;
if(n++ != 0)
fmtprint(fmt, "%s", sep);
key = va_arg(ap, char*);
fmtprint(fmt, "%s=", key);
fn(fmt, &ap);
}
va_end(ap);
return 0;
}
/*****************************************************************************/
/*** Routines to print out readable values for the field of various events ***/
/*****************************************************************************/
static int
VerbMotion(Fmt *fmt, XEvent *e) {
XMotionEvent *ev = &e->xmotion;
return pevent(fmt, ev,
TWindow, _(window),
TWindow, _(root),
TWindow, _(subwindow),
TTime, _(time),
TInt, _(x), TInt, _(y),
TInt, _(x_root), TInt, _(y_root),
TModState, _(state),
TBool, _(same_screen),
TEnd
);
//fprintf(stderr, "is_hint=%s%s", IsHint(ev->is_hint), sep);
}
static int
VerbButton(Fmt *fmt, XEvent *e) {
XButtonEvent *ev = &e->xbutton;
return pevent(fmt, ev,
TWindow, _(window),
TWindow, _(root),
TWindow, _(subwindow),
TTime, _(time),
TInt, _(x), TInt, _(y),
TInt, _(x_root), TInt, _(y_root),
TModState, _(state),
TInt, _(button),
TBool, _(same_screen),
TEnd
);
}
static int
VerbColormap(Fmt *fmt, XEvent *e) {
XColormapEvent *ev = &e->xcolormap;
return pevent(fmt, ev,
TWindow, _(window),
TIntNone, _(colormap),
TBool, _(new),
TColMap, _(state),
TEnd
);
}
static int
VerbCrossing(Fmt *fmt, XEvent *e) {
XCrossingEvent *ev = &e->xcrossing;
return pevent(fmt, ev,
TWindow, _(window),
TWindow, _(root),
TWindow, _(subwindow),
TTime, _(time),
TInt, _(x), TInt, _(y),
TInt, _(x_root), TInt, _(y_root),
TGrabMode, _(mode),
TXing, _(detail),
TBool, _(same_screen),
TBool, _(focus),
TModState, _(state),
TEnd
);
}
static int
VerbExpose(Fmt *fmt, XEvent *e) {
XExposeEvent *ev = &e->xexpose;
return pevent(fmt, ev,
TWindow, _(window),
TInt, _(x), TInt, _(y),
TInt, _(width), TInt, _(height),
TInt, _(count),
TEnd
);
}
static int
VerbGraphicsExpose(Fmt *fmt, XEvent *e) {
XGraphicsExposeEvent *ev = &e->xgraphicsexpose;
return pevent(fmt, ev,
TWindow, _(drawable),
TInt, _(x), TInt, _(y),
TInt, _(width), TInt, _(height),
TMajor, _(major_code),
TInt, _(minor_code),
TEnd
);
}
static int
VerbNoExpose(Fmt *fmt, XEvent *e) {
XNoExposeEvent *ev = &e->xnoexpose;
return pevent(fmt, ev,
TWindow, _(drawable),
TMajor, _(major_code),
TInt, _(minor_code),
TEnd
);
}
static int
VerbFocus(Fmt *fmt, XEvent *e) {
XFocusChangeEvent *ev = &e->xfocus;
return pevent(fmt, ev,
TWindow, _(window),
TGrabMode, _(mode),
TFocus, _(detail),
TEnd
);
}
static int
VerbKeymap(Fmt *fmt, XEvent *e) {
XKeymapEvent *ev = &e->xkeymap;
int i;
fmtprint(fmt, "window=0x%x%s", (int)ev->window, sep);
fmtprint(fmt, "key_vector=");
for (i = 0; i < 32; i++)
fmtprint(fmt, "%02x", ev->key_vector[i]);
fmtprint(fmt, "\n");
return 0;
}
static int
VerbKey(Fmt *fmt, XEvent *e) {
XKeyEvent *ev = &e->xkey;
return pevent(fmt, ev,
TWindow, _(window),
TWindow, _(root),
TWindow, _(subwindow),
TTime, _(time),
TInt, _(x), TInt, _(y),
TInt, _(x_root), TInt, _(y_root),
TModState, _(state),
TKeycode, "keycode", ev,
TBool, _(same_screen),
TEnd
);
}
static int
VerbProperty(Fmt *fmt, XEvent *e) {
XPropertyEvent *ev = &e->xproperty;
return pevent(fmt, ev,
TWindow, _(window),
TAtom, _(atom),
TTime, _(time),
TPropState, _(state),
TEnd
);
}
static int
VerbResizeRequest(Fmt *fmt, XEvent *e) {
XResizeRequestEvent *ev = &e->xresizerequest;
return pevent(fmt, ev,
TWindow, _(window),
TInt, _(width), TInt, _(height),
TEnd
);
}
static int
VerbCirculate(Fmt *fmt, XEvent *e) {
XCirculateEvent *ev = &e->xcirculate;
return pevent(fmt, ev,
TWindow, _(event),
TWindow, _(window),
TPlace, _(place),
TEnd
);
}
static int
VerbConfigure(Fmt *fmt, XEvent *e) {
XConfigureEvent *ev = &e->xconfigure;
return pevent(fmt, ev,
TWindow, _(event),
TWindow, _(window),
TInt, _(x), TInt, _(y),
TInt, _(width), TInt, _(height),
TInt, _(border_width),
TIntNone, _(above),
TBool, _(override_redirect),
TEnd
);
}
static int
VerbCreateWindow(Fmt *fmt, XEvent *e) {
XCreateWindowEvent *ev = &e->xcreatewindow;
return pevent(fmt, ev,
TWindow, _(parent),
TWindow, _(window),
TInt, _(x), TInt, _(y),
TInt, _(width), TInt, _(height),
TInt, _(border_width),
TBool, _(override_redirect),
TEnd
);
}
static int
VerbDestroyWindow(Fmt *fmt, XEvent *e) {
XDestroyWindowEvent *ev = &e->xdestroywindow;
return pevent(fmt, ev,
TWindow, _(event),
TWindow, _(window),
TEnd
);
}
static int
VerbGravity(Fmt *fmt, XEvent *e) {
XGravityEvent *ev = &e->xgravity;
return pevent(fmt, ev,
TWindow, _(event),
TWindow, _(window),
TInt, _(x), TInt, _(y),
TEnd
);
}
static int
VerbMap(Fmt *fmt, XEvent *e) {
XMapEvent *ev = &e->xmap;
return pevent(fmt, ev,
TWindow, _(event),
TWindow, _(window),
TBool, _(override_redirect),
TEnd
);
}
static int
VerbReparent(Fmt *fmt, XEvent *e) {
XReparentEvent *ev = &e->xreparent;
return pevent(fmt, ev,
TWindow, _(event),
TWindow, _(window),
TWindow, _(parent),
TInt, _(x), TInt, _(y),
TBool, _(override_redirect),
TEnd
);
}
static int
VerbUnmap(Fmt *fmt, XEvent *e) {
XUnmapEvent *ev = &e->xunmap;
return pevent(fmt, ev,
TWindow, _(event),
TWindow, _(window),
TBool, _(from_configure),
TEnd
);
}
static int
VerbCirculateRequest(Fmt *fmt, XEvent *e) {
XCirculateRequestEvent *ev = &e->xcirculaterequest;
return pevent(fmt, ev,
TWindow, _(parent),
TWindow, _(window),
TPlace, _(place),
TEnd
);
}
static int
VerbConfigureRequest(Fmt *fmt, XEvent *e) {
XConfigureRequestEvent *ev = &e->xconfigurerequest;
return pevent(fmt, ev,
TWindow, _(parent),
TWindow, _(window),
TInt, _(x), TInt, _(y),
TInt, _(width), TInt, _(height),
TInt, _(border_width),
TIntNone, _(above),
TConfDetail, _(detail),
TConfMask, _(value_mask),
TEnd
);
}
static int
VerbMapRequest(Fmt *fmt, XEvent *e) {
XMapRequestEvent *ev = &e->xmaprequest;
return pevent(fmt, ev,
TWindow, _(parent),
TWindow, _(window),
TEnd
);
}
static int
VerbClient(Fmt *fmt, XEvent *e) {
XClientMessageEvent *ev = &e->xclient;
return pevent(fmt, ev,
TWindow, _(window),
TAtom, _(message_type),
TInt, _(format),
TData, "data (as longs)", &ev->data,
TEnd
);
}
static int
VerbMapping(Fmt *fmt, XEvent *e) {
XMappingEvent *ev = &e->xmapping;
return pevent(fmt, ev,
TWindow, _(window),
TMapping, _(request),
TWindow, _(first_keycode),
TWindow, _(count),
TEnd
);
}
static int
VerbSelectionClear(Fmt *fmt, XEvent *e) {
XSelectionClearEvent *ev = &e->xselectionclear;
return pevent(fmt, ev,
TWindow, _(window),
TAtom, _(selection),
TTime, _(time),
TEnd
);
}
static int
VerbSelection(Fmt *fmt, XEvent *e) {
XSelectionEvent *ev = &e->xselection;
return pevent(fmt, ev,
TWindow, _(requestor),
TAtom, _(selection),
TAtom, _(target),
TAtom, _(property),
TTime, _(time),
TEnd
);
}
static int
VerbSelectionRequest(Fmt *fmt, XEvent *e) {
XSelectionRequestEvent *ev = &e->xselectionrequest;
return pevent(fmt, ev,
TWindow, _(owner),
TWindow, _(requestor),
TAtom, _(selection),
TAtom, _(target),
TAtom, _(property),
TTime, _(time),
TEnd
);
}
static int
VerbVisibility(Fmt *fmt, XEvent *e) {
XVisibilityEvent *ev = &e->xvisibility;
return pevent(fmt, ev,
TWindow, _(window),
TVis, _(state),
TEnd
);
}
/******************************************************************************/
/**************** Print the values of all fields for any event ****************/
/******************************************************************************/
typedef struct Handler Handler;
struct Handler {
int key;
int (*fn)(Fmt*, XEvent*);
};
int
fmtevent(Fmt *fmt) {
XEvent *e;
XAnyEvent *ev;
/*
fprintf(stderr, "type=%s%s", eventtype(e->xany.type), sep);
fprintf(stderr, "serial=%lu%s", ev->serial, sep);
fprintf(stderr, "send_event=%s%s", TorF(ev->send_event), sep);
fprintf(stderr, "display=0x%p%s", ev->display, sep);
*/
static Handler fns[] = {
{MotionNotify, VerbMotion},
{ButtonPress, VerbButton},
{ButtonRelease, VerbButton},
{ColormapNotify, VerbColormap},
{EnterNotify, VerbCrossing},
{LeaveNotify, VerbCrossing},
{Expose, VerbExpose},
{GraphicsExpose, VerbGraphicsExpose},
{NoExpose, VerbNoExpose},
{FocusIn, VerbFocus},
{FocusOut, VerbFocus},
{KeymapNotify, VerbKeymap},
{KeyPress, VerbKey},
{KeyRelease, VerbKey},
{PropertyNotify, VerbProperty},
{ResizeRequest, VerbResizeRequest},
{CirculateNotify, VerbCirculate},
{ConfigureNotify, VerbConfigure},
{CreateNotify, VerbCreateWindow},
{DestroyNotify, VerbDestroyWindow},
{GravityNotify, VerbGravity},
{MapNotify, VerbMap},
{ReparentNotify, VerbReparent},
{UnmapNotify, VerbUnmap},
{CirculateRequest, VerbCirculateRequest},
{ConfigureRequest, VerbConfigureRequest},
{MapRequest, VerbMapRequest},
{ClientMessage, VerbClient},
{MappingNotify, VerbMapping},
{SelectionClear, VerbSelectionClear},
{SelectionNotify, VerbSelection},
{SelectionRequest, VerbSelectionRequest},
{VisibilityNotify, VerbVisibility},
{0, nil},
};
Handler *p;
e = va_arg(fmt->args, XEvent*);
ev = &e->xany;
for (p = fns; p->fn; p++)
if (p->key == ev->type)
return p->fn(fmt, e);
return 1;
}
|
Added lib/libstuff/printevent.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
int fmtevent(Fmt *fmt);
enum {
X_CreateWindow = 1,
X_ChangeWindowAttributes,
X_GetWindowAttributes,
X_DestroyWindow,
X_DestroySubwindows,
X_ChangeSaveSet,
X_ReparentWindow,
X_MapWindow,
X_MapSubwindows,
X_UnmapWindow,
X_UnmapSubwindows,
X_ConfigureWindow,
X_CirculateWindow,
X_GetGeometry,
X_QueryTree,
X_InternAtom,
X_GetAtomName,
X_ChangeProperty,
X_DeleteProperty,
X_GetProperty,
X_ListProperties,
X_SetSelectionOwner,
X_GetSelectionOwner,
X_ConvertSelection,
X_SendEvent,
X_GrabPointer,
X_UngrabPointer,
X_GrabButton,
X_UngrabButton,
X_ChangeActivePointerGrab,
X_GrabKeyboard,
X_UngrabKeyboard,
X_GrabKey,
X_UngrabKey,
X_AllowEvents,
X_GrabServer,
X_UngrabServer,
X_QueryPointer,
X_GetMotionEvents,
X_TranslateCoords,
X_WarpPointer,
X_SetInputFocus,
X_GetInputFocus,
X_QueryKeymap,
X_OpenFont,
X_CloseFont,
X_QueryFont,
X_QueryTextExtents,
X_ListFonts,
X_ListFontsWithInfo,
X_SetFontPath,
X_GetFontPath,
X_CreatePixmap,
X_FreePixmap,
X_CreateGC,
X_ChangeGC,
X_CopyGC,
X_SetDashes,
X_SetClipRectangles,
X_FreeGC,
X_ClearArea,
X_CopyArea,
X_CopyPlane,
X_PolyPoint,
X_PolyLine,
X_PolySegment,
X_PolyRectangle,
X_PolyArc,
X_FillPoly,
X_PolyFillRectangle,
X_PolyFillArc,
X_PutImage,
X_GetImage,
X_PolyText8,
X_PolyText16,
X_ImageText8,
X_ImageText16,
X_CreateColormap,
X_FreeColormap,
X_CopyColormapAndFree,
X_InstallColormap,
X_UninstallColormap,
X_ListInstalledColormaps,
X_AllocColor,
X_AllocNamedColor,
X_AllocColorCells,
X_AllocColorPlanes,
X_FreeColors,
X_StoreColors,
X_StoreNamedColor,
X_QueryColors,
X_LookupColor,
X_CreateCursor,
X_CreateGlyphCursor,
X_FreeCursor,
X_RecolorCursor,
X_QueryBestSize,
X_QueryExtension,
X_ListExtensions,
X_ChangeKeyboardMapping,
X_GetKeyboardMapping,
X_ChangeKeyboardControl,
X_GetKeyboardControl,
X_Bell,
X_ChangePointerControl,
X_GetPointerControl,
X_SetScreenSaver,
X_GetScreenSaver,
X_ChangeHosts,
X_ListHosts,
X_SetAccessControl,
X_SetCloseDownMode,
X_KillClient,
X_RotateProperties,
X_ForceScreenSaver,
X_SetPointerMapping,
X_GetPointerMapping,
X_SetModifierMapping,
X_GetModifierMapping,
X_NoOperation,
};
#define XMajors \
"<nil>",\
"CreateWindow",\
"ChangeWindowAttributes",\
"GetWindowAttributes",\
"DestroyWindow",\
"DestroySubwindows",\
"ChangeSaveSet",\
"ReparentWindow",\
"MapWindow",\
"MapSubwindows",\
"UnmapWindow",\
"UnmapSubwindows",\
"ConfigureWindow",\
"CirculateWindow",\
"GetGeometry",\
"QueryTree",\
"InternAtom",\
"GetAtomName",\
"ChangeProperty",\
"DeleteProperty",\
"GetProperty",\
"ListProperties",\
"SetSelectionOwner",\
"GetSelectionOwner",\
"ConvertSelection",\
"SendEvent",\
"GrabPointer",\
"UngrabPointer",\
"GrabButton",\
"UngrabButton",\
"ChangeActivePointerGrab",\
"GrabKeyboard",\
"UngrabKeyboard",\
"GrabKey",\
"UngrabKey",\
"AllowEvents",\
"GrabServer",\
"UngrabServer",\
"QueryPointer",\
"GetMotionEvents",\
"TranslateCoords",\
"WarpPointer",\
"SetInputFocus",\
"GetInputFocus",\
"QueryKeymap",\
"OpenFont",\
"CloseFont",\
"QueryFont",\
"QueryTextExtents",\
"ListFonts",\
"ListFontsWithInfo",\
"SetFontPath",\
"GetFontPath",\
"CreatePixmap",\
"FreePixmap",\
"CreateGC",\
"ChangeGC",\
"CopyGC",\
"SetDashes",\
"SetClipRectangles",\
"FreeGC",\
"ClearArea",\
"CopyArea",\
"CopyPlane",\
"PolyPoint",\
"PolyLine",\
"PolySegment",\
"PolyRectangle",\
"PolyArc",\
"FillPoly",\
"PolyFillRectangle",\
"PolyFillArc",\
"PutImage",\
"GetImage",\
"PolyText8",\
"PolyText16",\
"ImageText8",\
"ImageText16",\
"CreateColormap",\
"FreeColormap",\
"CopyColormapAndFree",\
"InstallColormap",\
"UninstallColormap",\
"ListInstalledColormaps",\
"AllocColor",\
"AllocNamedColor",\
"AllocColorCells",\
"AllocColorPlanes",\
"FreeColors",\
"StoreColors",\
"StoreNamedColor",\
"QueryColors",\
"LookupColor",\
"CreateCursor",\
"CreateGlyphCursor",\
"FreeCursor",\
"RecolorCursor",\
"QueryBestSize",\
"QueryExtension",\
"ListExtensions",\
"ChangeKeyboardMapping",\
"GetKeyboardMapping",\
"ChangeKeyboardControl",\
"GetKeyboardControl",\
"Bell",\
"ChangePointerControl",\
"GetPointerControl",\
"SetScreenSaver",\
"GetScreenSaver",\
"ChangeHosts",\
"ListHosts",\
"SetAccessControl",\
"SetCloseDownMode",\
"KillClient",\
"RotateProperties",\
"ForceScreenSaver",\
"SetPointerMapping",\
"GetPointerMapping",\
"SetModifierMapping",\
"GetModifierMapping",\
"NoOperation",\
|
Added lib/libstuff/util/_die.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <fmt.h>
#include "util.h"
void
_die(char *file, int line, char *msg, ...) {
va_list ap;
va_start(ap, msg);
fprint(2, "%s: dieing at %s:%d: %s\n",
argv0, file, line,
vsxprint(msg, ap));
va_end(ap);
kill(getpid(), SIGABRT);
abort(); /* Adds too many frames:
* _die()
* abort()
* raise(SIGABRT)
* kill(getpid(), SIGABRT)
*/
}
|
Added lib/libstuff/util/closeexec.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <unistd.h>
#include <fcntl.h>
#include "util.h"
void
closeexec(int fd) {
if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
fatal("can't set %d close on exec: %r", fd);
}
|
Added lib/libstuff/util/comm.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include "util.h"
#include <stuff/x11.h>
char**
comm(int cols, char **toka, char **tokb) {
Vector_ptr vec;
char **ret;
int cmp;
vector_pinit(&vec);
while(*toka || *tokb) {
if(!*toka)
cmp = 1;
else if(!*tokb)
cmp = -1;
else
cmp = strcmp(*toka, *tokb);
if(cmp < 0) {
if(cols & CLeft)
vector_ppush(&vec, *toka);
toka++;
}else if(cmp > 0) {
if(cols & CRight)
vector_ppush(&vec, *tokb);
tokb++;
}else {
if(cols & CCenter)
vector_ppush(&vec, *toka);
toka++;
tokb++;
}
}
vector_ppush(&vec, nil);
ret = strlistdup((char**)vec.ary);
free(vec.ary);
return ret;
}
|
Added lib/libstuff/util/doublefork.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <sys/wait.h>
#include <unistd.h>
#include "util.h"
int
doublefork(void) {
pid_t pid;
int status;
switch(pid=fork()) {
case -1:
fatal("Can't fork(): %r");
case 0:
switch(pid=fork()) {
case -1:
fatal("Can't fork(): %r");
case 0:
return 0;
default:
exit(0);
}
default:
waitpid(pid, &status, 0);
return pid;
}
/* NOTREACHED */
}
|
Added lib/libstuff/util/emalloc.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include "util.h"
void *
emalloc(uint size) {
void *ret = malloc(size);
if(!ret)
mfatal("malloc", size);
return ret;
}
|
Added lib/libstuff/util/emallocz.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include <string.h>
#include "util.h"
void*
emallocz(uint size) {
void *ret = emalloc(size);
memset(ret, 0, size);
return ret;
}
|
Added lib/libstuff/util/erealloc.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include "util.h"
void *
erealloc(void *ptr, uint size) {
void *ret = realloc(ptr, size);
if(!ret)
mfatal("realloc", size);
return ret;
}
|
Added lib/libstuff/util/estrdup.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include <string.h>
#include "util.h"
char*
estrdup(const char *str) {
void *ret = strdup(str);
if(!ret)
mfatal("strdup", strlen(str));
return ret;
}
|
Added lib/libstuff/util/estrndup.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include <string.h>
#include "util.h"
char*
estrndup(const char *str, uint len) {
char *ret;
len = min(len, strlen(str));
ret = emalloc(len + 1);
memcpy(ret, str, len);
ret[len] = '\0';
return ret;
}
|
Added lib/libstuff/util/fatal.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include <fmt.h>
#include "util.h"
typedef struct VFmt VFmt;
struct VFmt {
const char *fmt;
va_list args;
};
#ifdef VARARGCK
# pragma varargck type "V" VFmt*
#endif
static int
Vfmt(Fmt *f) {
VFmt *vf;
int i;
vf = va_arg(f->args, VFmt*);
i = fmtvprint(f, vf->fmt, vf->args);
return i;
}
void
fatal(const char *fmt, ...) {
VFmt fp;
fmtinstall('V', Vfmt);
fmtinstall('', Vfmt);
fp.fmt = fmt;
va_start(fp.args, fmt);
fprint(2, "%s: fatal: %V\n", argv0, &fp);
va_end(fp.args);
exit(1);
}
|
Added lib/libstuff/util/freelater.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include "util.h"
void*
freelater(void *p) {
static char* obj[16];
static long nobj;
int id;
id = nobj++ % nelem(obj);
free(obj[id]);
obj[id] = p;
return p;
}
|
Added lib/libstuff/util/getbase.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <ctype.h>
#include <string.h>
#include <stuff/util.h>
#define strbcmp(str, const) (strncmp((str), (const), sizeof(const)-1))
int
getbase(const char **s, long *sign) {
const char *p;
int ret;
ret = 10;
*sign = 1;
if(**s == '-') {
*sign = -1;
*s += 1;
}else if(**s == '+')
*s += 1;
p = *s;
if(!strbcmp(p, "0x")) {
*s += 2;
ret = 16;
}
else if(isdigit(p[0])) {
if(p[1] == 'r') {
*s += 2;
ret = p[0] - '0';
}
else if(isdigit(p[1]) && p[2] == 'r') {
*s += 3;
ret = 10*(p[0]-'0') + (p[1]-'0');
}
}
else if(p[0] == '0') {
ret = 8;
}
if(ret != 10 && (**s == '-' || **s == '+'))
*sign = 0;
return ret;
}
|
Added lib/libstuff/util/getint.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <stuff/util.h>
bool
getint(const char *s, int *ret) {
long l;
bool res;
res = getlong(s, &l);
*ret = l;
return res;
}
|
Added lib/libstuff/util/getlong.c.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include <stuff/util.h>
bool
getlong(const char *s, long *ret) {
const char *end;
char *rend;
int base;
long sign;
if(s == nil)
return false;
end = s+strlen(s);
base = getbase(&s, &sign);
if(sign == 0)
return false;
*ret = sign * strtol(s, &rend, base);
return (end == rend);
}
|
Added lib/libstuff/util/getulong.c.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include <stuff/util.h>
bool
getulong(const char *s, ulong *ret) {
const char *end;
char *rend;
int base;
long sign;
if(s == nil)
return false;
end = s+strlen(s);
base = getbase(&s, &sign);
if(sign < 1)
return false;
*ret = strtoul(s, &rend, base);
return (end == rend);
}
|
Added lib/libstuff/util/grep.c.
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "util.h"
void
grep(char **list, Reprog *re, int flags) {
char **p, **q;
int res;
q = list;
for(p=q; *p; p++) {
res = 0;
if(re)
res = regexec(re, *p, nil, 0);
if(res && !(flags & GInvert)
|| !res && (flags & GInvert))
*q++ = *p;
}
*q = nil;
}
|
Added lib/libstuff/util/join.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <fmt.h>
#include "util.h"
char*
join(char **list, char *sep, Fmt *f) {
Fmt fmt;
char **p;
if(f == nil) {
f = &fmt;
if(fmtstrinit(f) < 0)
abort();
}
for(p=list; *p; p++) {
if(p != list)
fmtstrcpy(f, sep);
fmtstrcpy(f, *p);
}
if(f != &fmt)
return nil;
return fmtstrflush(f);
}
|
Added lib/libstuff/util/max.c.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include "util.h"
int
max(int a, int b) {
if(a > b)
return a;
return b;
}
|
Added lib/libstuff/util/mfatal.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include <string.h>
#include <unistd.h>
#include "util.h"
/* Can't malloc */
void
mfatal(char *name, uint size) {
const char
couldnot[] = ": fatal: Could not ",
paren[] = "() ",
bytes[] = " bytes\n";
char buf[1024];
char sizestr[8];
int i;
i = sizeof sizestr;
do {
sizestr[--i] = '0' + (size%10);
size /= 10;
} while(size > 0);
strlcat(buf, argv0, sizeof buf);
strlcat(buf, couldnot, sizeof buf);
strlcat(buf, name, sizeof buf);
strlcat(buf, paren, sizeof buf);
strlcat(buf, sizestr+i, sizeof buf);
strlcat(buf, bytes, sizeof buf);
write(2, buf, strlen(buf));
exit(1);
}
|
Added lib/libstuff/util/min.c.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include "util.h"
int
min(int a, int b) {
if(a < b)
return a;
return b;
}
|
Added lib/libstuff/util/nsec.c.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include "util.h"
#include <sys/time.h>
uvlong
nsec(void) {
struct timeval tv;
gettimeofday(&tv, nil);
return (uvlong)tv.tv_sec * 1000000000 + (uvlong)tv.tv_usec * 1000;
}
|
Added lib/libstuff/util/pathsearch.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include <unistd.h>
#include <fmt.h>
#include "util.h"
char*
pathsearch(const char *path, const char *file, bool slashok) {
char *orig, *p, *s;
if(!slashok && strchr(file, '/') > file)
file = sxprint("%s/%s", getcwd(buffer, sizeof buffer), file);
else if(!strncmp(file, "./", 2))
file = sxprint("%s/%s", getcwd(buffer, sizeof buffer), file+2);
if(file[0] == '/') {
if(access(file, X_OK))
return strdup(file);
return nil;
}
orig = estrdup(path ? path : getenv("PATH"));
for(p=orig; (s=strtok(p, ":")); p=nil) {
s = smprint("%s/%s", s, file);
if(!access(s, X_OK))
break;
free(s);
}
free(orig);
return s;
}
|
Added lib/libstuff/util/refree.c.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "util.h"
void
refree(Regex *r) {
free(r->regex);
free(r->regc);
r->regex = nil;
r->regc = nil;
}
|
Added lib/libstuff/util/reinit.c.
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "util.h"
void
reinit(Regex *r, char *regx) {
refree(r);
if(regx[0] != '\0') {
r->regex = estrdup(regx);
r->regc = regcomp(regx);
}
}
|
Added lib/libstuff/util/spawn3.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <errno.h>
#include <unistd.h>
#include "util.h"
int
spawn3(int fd[3], const char *file, char *argv[]) {
/* Some ideas from Russ Cox's libthread port. */
int p[2];
int pid;
if(pipe(p) < 0)
return -1;
closeexec(p[1]);
switch(pid = doublefork()) {
case 0:
dup2(fd[0], 0);
dup2(fd[1], 1);
dup2(fd[2], 2);
execvp(file, argv);
write(p[1], &errno, sizeof errno);
exit(1);
break;
default:
close(p[1]);
if(read(p[0], &errno, sizeof errno) == sizeof errno)
pid = -1;
close(p[0]);
break;
case -1: /* can't happen */
break;
}
close(fd[0]);
/* These could fail if any of these was also a previous fd. */
close(fd[1]);
close(fd[2]);
return pid;
}
|
Added lib/libstuff/util/spawn3l.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <fmt.h>
#include "util.h"
int
spawn3l(int fd[3], const char *file, ...) {
va_list ap;
char **argv;
int i, n;
va_start(ap, file);
for(n=0; va_arg(ap, char*); n++)
;
va_end(ap);
argv = emalloc((n+1) * sizeof *argv);
va_start(ap, file);
quotefmtinstall();
for(i=0; i <= n; i++)
argv[i] = va_arg(ap, char*);
va_end(ap);
i = spawn3(fd, file, argv);
free(argv);
return i;
}
|
Added lib/libstuff/util/stokenize.c.
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include <string.h>
#include "util.h"
uint
stokenize(char *res[], uint reslen, char *str, char *delim) {
char *s;
uint i;
i = 0;
s = str;
while(i < reslen && *s) {
while(*s && strchr(delim, *s))
*(s++) = '\0';
if(*s)
res[i++] = s;
while(*s && !strchr(delim, *s))
s++;
}
return i;
}
|
Added lib/libstuff/util/strcasestr.c.
> > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include <ctype.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include "util.h"
/* TODO: Make this UTF-8 compliant. */
char*
strcasestr(const char *dst, const char *src) {
int len, dc, sc;
if(src[0] == '\0')
return (char*)(uintptr_t)dst;
len = strlen(src) - 1;
sc = tolower(src[0]);
for(; (dc = *dst); dst++) {
dc = tolower(dc);
if(sc == dc && (len == 0 || !strncasecmp(dst+1, src+1, len)))
return (char*)(uintptr_t)dst;
}
return nil;
}
|
Added lib/libstuff/util/strend.c.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include <stuff/util.h>
char*
strend(char *s, int n) {
int len;
len = strlen(s);
return s + max(0, len - n);
}
|
Added lib/libstuff/util/strlcat.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include "util.h"
uint
strlcat(char *dst, const char *src, uint size) {
const char *s;
char *d;
int n, len;
d = dst;
s = src;
n = size;
while(n-- > 0 && *d != '\0')
d++;
len = n;
while(*s != '\0') {
if(n-- > 0)
*d++ = *s;
s++;
}
if(len > 0)
*d = '\0';
return size - n - 1;
}
|
Added lib/libstuff/util/strlcatprint.c.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include <fmt.h>
#include "util.h"
int
strlcatprint(char *buf, int len, const char *fmt, ...) {
va_list ap;
int buflen;
int ret;
va_start(ap, fmt);
buflen = strlen(buf);
ret = vsnprint(buf+buflen, len-buflen, fmt, ap);
va_end(ap);
return ret;
}
|
Added lib/libstuff/util/sxprint.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include "util.h"
char*
sxprint(const char *fmt, ...) {
va_list ap;
char *ret;
va_start(ap, fmt);
ret = vsxprint(fmt, ap);
va_end(ap);
return ret;
}
|
Added lib/libstuff/util/tokenize.c.
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include "util.h"
uint
tokenize(char *res[], uint reslen, char *str, char delim) {
char *s;
uint i;
i = 0;
s = str;
while(i < reslen && *s) {
while(*s == delim)
*(s++) = '\0';
if(*s)
res[i++] = s;
while(*s && *s != delim)
s++;
}
return i;
}
|
Added lib/libstuff/util/trim.c.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include "util.h"
void
trim(char *str, const char *chars) {
const char *r;
char *p, *q;
for(p=str, q=str; *p; p++) {
for(r=chars; *r; r++)
if(*p == *r)
break;
if(!*r)
*q++ = *p;
}
*q = '\0';
}
|
Added lib/libstuff/util/uniq.c.
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include "util.h"
void
uniq(char **toks) {
char **p, **q;
q = toks;
if(*q == nil)
return;
for(p=q+1; *p; p++)
if(strcmp(*q, *p))
*++q = *p;
*++q = nil;
}
|
Added lib/libstuff/util/unmask.c.
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <fmt.h>
#include "util.h"
int
unmask(Fmt *f, long mask, char **table, long sep) {
int i, nfmt;
nfmt = f->nfmt;
for(i=0; table[i]; i++)
if(*table[i] && (mask & (1<<i))) {
if(f->nfmt > nfmt)
fmtrune(f, sep);
if(fmtstrcpy(f, table[i]))
return -1;
}
return 0;
}
|
Added lib/libstuff/util/unquote.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "util.h"
int
unquote(char *buf, char *toks[], int ntoks) {
char *s, *t;
bool inquote;
int n;
n = 0;
s = buf;
while(*s && n < ntoks) {
while(*s && utfrune(" \t\r\n", *s))
s++;
inquote = false;
toks[n] = s;
t = s;
while(*s && (inquote || !utfrune(" \t\r\n", *s))) {
if(*s == '\'') {
if(inquote && s[1] == '\'')
*t++ = *s++;
else
inquote = !inquote;
}
else
*t++ = *s;
s++;
}
if(*s)
s++;
*t = '\0';
if(s != toks[n])
n++;
}
return n;
}
|
Added lib/libstuff/util/utflcpy.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include "util.h"
int
utflcpy(char *to, const char *from, int l) {
char *p;
p = utfecpy(to, to+l, from);
return p-to;
}
|
Added lib/libstuff/util/util.h.
> > > > > | 1 2 3 4 5 | /* Written by Kris Maglione <maglione.k at Gmail> */ /* Public domain */ #include <stuff/util.h> void mfatal(char*, uint); |
Added lib/libstuff/util/vector.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include "util.h"
/* Blech. */
#define VECTOR(type, nam, c) \
void \
vector_##c##init(Vector_##nam *v) { \
memset(v, 0, sizeof *v); \
} \
\
void \
vector_##c##free(Vector_##nam *v) { \
free(v->ary); \
memset(v, 0, sizeof *v); \
} \
\
void \
vector_##c##push(Vector_##nam *v, type val) { \
if(v->n == v->size) { \
if(v->size == 0) \
v->size = 2; \
v->size <<= 2; \
v->ary = erealloc(v->ary, v->size * sizeof *v->ary); \
} \
v->ary[v->n++] = val; \
} \
VECTOR(long, long, l)
VECTOR(Rectangle, rect, r)
VECTOR(void*, ptr, p)
|
Added lib/libstuff/util/vsxprint.c.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* Written by Kris Maglione <maglione.k at Gmail> */
/* Public domain */
#include <fmt.h>
#include "util.h"
char*
vsxprint(const char *fmt, va_list ap) {
char *s;
s = vsmprint(fmt, ap);
freelater(s);
return s;
}
|
Added lib/libstuff/x11/colors/loadcolor.c.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include "../x11.h"
int
loadcolor(CTuple *c, const char *str, const char *end) {
char buf[128];
char *toks[4];
utflcpy(buf, str, end ? min(end - str + 1, sizeof buf) : sizeof buf);
if(3 > stokenize(toks, nelem(toks), buf, " \t\r\n"))
return 0;
if(!(parsecolor(toks[0], &c->fg)
&& parsecolor(toks[1], &c->bg)
&& parsecolor(toks[2], &c->border)))
return 0;
snprint(c->colstr, sizeof c->colstr, "%L %L %L", c->fg, c->bg, c->border);
return toks[2] + strlen(toks[2]) - buf;
}
|
Added lib/libstuff/x11/colors/parsecolor.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
ulong
pixelvalue(Window *w, Color *c) {
XColor xc;
if(w->visual == nil || w->visual->class != TrueColor) {
if(c->pixel != ~0UL)
return c->pixel;
xc.red = c->red;
xc.green = c->green;
xc.blue = c->blue;
XAllocColor(display, w->colormap, &xc);
return c->pixel = xc.pixel;
}
if(w->depth == 32 || c->alpha == 0)
return (((ulong)c->alpha & 0xff00) << 16)
| (((ulong)c->red & 0xff00) << 8)
| (((ulong)c->green & 0xff00) << 0)
| (((ulong)c->blue & 0xff00) >> 8);
else
return ((ulong)c->red * 0xffff / c->alpha & 0xff00) << 8
| ((ulong)c->green * 0xffff / c->alpha & 0xff00) << 0
| ((ulong)c->blue * 0xffff / c->alpha & 0xff00) >> 8;
}
bool
parsecolor(const char *name, Color *ret) {
ret->pixel = ~0UL;
return XRenderParseColor(display, (char*)(uintptr_t)name, (XRenderColor*)ret);
}
|
Added lib/libstuff/x11/colors/xftcolor.c.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
XftColor*
xftcolor(Image *i, Color *c) {
XftColor *xc;
xc = emallocz(sizeof *c);
*xc = (XftColor){ pixelvalue(i, c), c->red, c->green, c->blue, c->alpha };
return freelater(xc);
}
|
Added lib/libstuff/x11/convpts.c.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "x11.h"
XPoint*
convpts(Point *pt, int np) {
XPoint *rp;
int i;
rp = emalloc(np * sizeof *rp);
for(i = 0; i < np; i++) {
rp[i].x = pt[i].x;
rp[i].y = pt[i].y;
}
return rp;
}
|
Added lib/libstuff/x11/drawing/border.c.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
border(Image *dst, Rectangle r, int w, Color *col) {
if(w == 0)
return;
r = insetrect(r, w/2);
r.max.x -= w%2;
r.max.y -= w%2;
XSetLineAttributes(display, dst->gc, w, LineSolid, CapButt, JoinMiter);
setgccol(dst, col);
XDrawRectangle(display, dst->xid, dst->gc,
r.min.x, r.min.y, Dx(r), Dy(r));
}
|
Added lib/libstuff/x11/drawing/drawline.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
drawline(Image *dst, Point p1, Point p2, int cap, int w, Color *col) {
XSetLineAttributes(display, dst->gc, w, LineSolid, cap, JoinMiter);
setgccol(dst, col);
XDrawLine(display, dst->xid, dst->gc, p1.x, p1.y, p2.x, p2.y);
}
|
Added lib/libstuff/x11/drawing/drawpoly.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
drawpoly(Image *dst, Point *pt, int np, int cap, int w, Color *col) {
XPoint *xp;
xp = convpts(pt, np);
XSetLineAttributes(display, dst->gc, w, LineSolid, cap, JoinMiter);
setgccol(dst, col);
XDrawLines(display, dst->xid, dst->gc, xp, np, CoordModeOrigin);
free(xp);
}
|
Added lib/libstuff/x11/drawing/drawstring.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include "../x11.h"
uint
fillstring(Image *dst, Font *font,
Rectangle r, Align align,
const char *text, CTuple *col, int borderw) {
fill(dst, r, &col->bg);
if(borderw)
border(dst, r, borderw, &col->border);
return drawstring(dst, font, r, align, text, &col->fg);
}
uint
drawstring(Image *dst, Font *font,
Rectangle r, Align align,
const char *text, Color *col) {
Rectangle tr;
char *buf;
uint x, y, width, height, len;
int shortened;
shortened = 0;
len = strlen(text);
buf = emalloc(len+1);
memcpy(buf, text, len+1);
r.max.y -= font->pad.min.y;
r.min.y += font->pad.max.y;
height = font->ascent + font->descent;
y = r.min.y + Dy(r) / 2 - height / 2 + font->ascent;
width = Dx(r) - font->pad.min.x - font->pad.max.x - (font->height & ~1);
r.min.x += font->pad.min.x;
r.max.x -= font->pad.max.x;
/* shorten text if necessary */
tr = ZR;
while(len > 0) {
tr = textextents_l(font, buf, len + min(shortened, 3), nil);
if(Dx(tr) <= width)
break;
while(len > 0 && (buf[--len]&0xC0) == 0x80)
buf[len] = '.';
buf[len] = '.';
shortened++;
}
if(len == 0 || Dx(tr) > width)
goto done;
/* mark shortened info in the string */
if(shortened)
len += min(shortened, 3);
switch (align) {
case East:
x = r.max.x - (tr.max.x + (font->height / 2));
break;
case Center:
x = r.min.x + (Dx(r) - Dx(tr)) / 2 - tr.min.x;
break;
default:
x = r.min.x + (font->height / 2) - tr.min.x;
break;
}
setgccol(dst, col);
switch(font->type) {
case FFontSet:
Xutf8DrawString(display, dst->xid,
font->font.set, dst->gc,
x, y,
buf, len);
break;
case FXft:
xft->drawstring(xftdrawable(dst), xftcolor(dst, col),
font->font.xft,
x, y, buf, len);
break;
case FX11:
XSetFont(display, dst->gc, font->font.x11->fid);
XDrawString(display, dst->xid, dst->gc,
x, y, buf, len);
break;
default:
die("Invalid font type.");
}
done:
free(buf);
return Dx(tr);
}
|
Added lib/libstuff/x11/drawing/fill.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
fill(Image *dst, Rectangle r, Color *col) {
setgccol(dst, col);
XFillRectangle(display, dst->xid, dst->gc,
r.min.x, r.min.y, Dx(r), Dy(r));
}
|
Added lib/libstuff/x11/drawing/fillpoly.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
fillpoly(Image *dst, Point *pt, int np, Color *col) {
XPoint *xp;
xp = convpts(pt, np);
setgccol(dst, col);
XFillPolygon(display, dst->xid, dst->gc, xp, np, Complex, CoordModeOrigin);
free(xp);
}
|
Added lib/libstuff/x11/drawing/setgccol.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
setgccol(Image *dst, Color *c) {
XSetForeground(display, dst->gc, pixelvalue(dst, c));
}
|
Added lib/libstuff/x11/errors.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "x11.h"
extern ErrorCode ignored_xerrors[];
static bool _trap_errors;
static long nerrors;
int
errorhandler(Display *dpy, XErrorEvent *error) {
ErrorCode *e;
USED(dpy);
if(_trap_errors) {
nerrors++;
return 0;
}
e = ignored_xerrors;
if(e)
for(; e->rcode || e->ecode; e++)
if((e->rcode == 0 || e->rcode == error->request_code)
&& (e->ecode == 0 || e->ecode == error->error_code))
return 0;
fprint(2, "%s: fatal error: Xrequest code=%d, Xerror code=%d\n",
argv0, error->request_code, error->error_code);
return xlib_errorhandler(display, error); /* calls exit() */
}
int
traperrors(bool enable) {
sync();
_trap_errors = enable;
if (enable)
nerrors = 0;
return nerrors;
}
|
Added lib/libstuff/x11/focus/getfocus.c.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
XWindow
getfocus(void) {
XWindow ret;
int revert;
XGetInputFocus(display, &ret, &revert);
return ret;
}
|
Added lib/libstuff/x11/focus/setfocus.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
setfocus(Window *w, int mode) {
XSetInputFocus(display, w->xid, mode, CurrentTime);
}
|
Added lib/libstuff/x11/freestringlist.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "x11.h"
void
freestringlist(char *list[]) {
XFreeStringList(list);
}
|
Added lib/libstuff/x11/geometry/XRect.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
XRectangle
XRect(Rectangle r) {
XRectangle xr;
xr.x = r.min.x;
xr.y = r.min.y;
xr.width = Dx(r);
xr.height = Dy(r);
return xr;
}
|
Added lib/libstuff/x11/geometry/addpt.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Point
addpt(Point p, Point q) {
p.x += q.x;
p.y += q.y;
return p;
}
|
Added lib/libstuff/x11/geometry/divpt.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Point
divpt(Point p, Point q) {
p.x /= q.x;
p.y /= q.y;
return p;
}
|
Added lib/libstuff/x11/geometry/eqpt.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
int
eqpt(Point p, Point q) {
return p.x==q.x && p.y==q.y;
}
|
Added lib/libstuff/x11/geometry/eqrect.c.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
int
eqrect(Rectangle a, Rectangle b) {
return a.min.x==b.min.x && a.max.x==b.max.x
&& a.min.y==b.min.y && a.max.y==b.max.y;
}
|
Added lib/libstuff/x11/geometry/insetrect.c.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Rectangle
insetrect(Rectangle r, int n) {
r.min.x += n;
r.min.y += n;
r.max.x -= n;
r.max.y -= n;
return r;
}
|
Added lib/libstuff/x11/geometry/mulpt.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Point
mulpt(Point p, Point q) {
p.x *= q.x;
p.y *= q.y;
return p;
}
|
Added lib/libstuff/x11/geometry/rectaddpt.c.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Rectangle
rectaddpt(Rectangle r, Point p) {
r.min.x += p.x;
r.max.x += p.x;
r.min.y += p.y;
r.max.y += p.y;
return r;
}
|
Added lib/libstuff/x11/geometry/rectsetorigin.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Rectangle
rectsetorigin(Rectangle r, Point p) {
Rectangle ret;
ret.min.x = p.x;
ret.min.y = p.y;
ret.max.x = p.x + Dx(r);
ret.max.y = p.y + Dy(r);
return ret;
}
|
Added lib/libstuff/x11/geometry/rectsubpt.c.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Rectangle
rectsubpt(Rectangle r, Point p) {
r.min.x -= p.x;
r.max.x -= p.x;
r.min.y -= p.y;
r.max.y -= p.y;
return r;
}
|
Added lib/libstuff/x11/geometry/subpt.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Point
subpt(Point p, Point q) {
p.x -= q.x;
p.y -= q.y;
return p;
}
|
Added lib/libstuff/x11/ignored_xerrors.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "x11.h"
ErrorCode ignored_xerrors[] = {
{ 0, },
};
|
Added lib/libstuff/x11/images/allocimage.c.
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Image*
allocimage(int w, int h, int depth) {
Image *img;
img = emallocz(sizeof *img);
img->type = WImage;
img->xid = XCreatePixmap(display, scr.root.xid, w, h, depth);
img->gc = XCreateGC(display, img->xid, 0, nil);
img->colormap = scr.colormap;
img->visual = scr.visual;
if(depth == 32)
img->visual = scr.visual32;
img->depth = depth;
img->r = Rect(0, 0, w, h);
return img;
}
|
Added lib/libstuff/x11/images/copyimage.c.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
copyimage(Image *dst, Rectangle r, Image *src, Point p) {
XCopyArea(display,
src->xid, dst->xid,
dst->gc,
r.min.x, r.min.y, Dx(r), Dy(r),
p.x, p.y);
}
|
Added lib/libstuff/x11/images/freeimage.c.
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
freeimage(Image *img) {
if(img == nil)
return;
assert(img->type == WImage);
if(img->xft)
xft->drawdestroy(img->xft);
XFreePixmap(display, img->xid);
XFreeGC(display, img->gc);
free(img);
}
|
Added lib/libstuff/x11/images/xftdrawable.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
XftDraw*
xftdrawable(Image *img) {
if(img->xft == nil)
img->xft = xft->drawcreate(display, img->xid, img->visual, img->colormap);
return img->xft;
}
|
Added lib/libstuff/x11/initdisplay.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "x11.h"
int (*xlib_errorhandler) (Display*, XErrorEvent*);
Map windowmap;
Map atommap;
Map atomnamemap;
static MapEnt* wbucket[137];
static MapEnt* abucket[137];
static MapEnt* anamebucket[137];
static int
Afmt(Fmt *f) {
return fmtstrcpy(f, atomname(va_arg(f->args, Atom)));
}
static int
Lfmt(Fmt *f) {
Color c;
#define fix(c, m) (ushort)((c.alpha ? (ulong)c.m * 0xffff / c.alpha : 0) >> 8)
c = va_arg(f->args, Color);
return fmtprint(f, c.alpha < 0xff00 ? "rgba:%02uhx/%02uhx/%02uhx/%02uhx"
: "#%02uhx%02uhx%02uhx",
fix(c, red), fix(c, green), fix(c, blue), c.alpha >> 8);
#undef fix
}
static int
Pfmt(Fmt *f) {
Point p;
p = va_arg(f->args, Point);
return fmtprint(f, "(%d,%d)", p.x, p.y);
}
static int
Rfmt(Fmt *f) {
Rectangle r;
r = va_arg(f->args, Rectangle);
return fmtprint(f, "%P+%dx%d", r.min, Dx(r), Dy(r));
}
static int
Wfmt(Fmt *f) {
Window *w;
w = va_arg(f->args, Window*);
if(w == nil)
return fmtstrcpy(f, "<nil>");
return fmtprint(f, "0x%ulx", w->xid);
}
void
initdisplay(void) {
display = XOpenDisplay(nil);
if(display == nil)
fatal("Can't open display");
scr.screen = DefaultScreen(display);
scr.colormap = DefaultColormap(display, scr.screen);
scr.visual = DefaultVisual(display, scr.screen);
scr.gc = DefaultGC(display, scr.screen);
scr.depth = DefaultDepth(display, scr.screen);
scr.root.xid = RootWindow(display, scr.screen);
scr.root.visual = scr.visual;
scr.root.r = Rect(0, 0,
DisplayWidth(display, scr.screen),
DisplayHeight(display, scr.screen));
scr.rect = scr.root.r;
scr.root.parent = &scr.root;
scr.xim = XOpenIM(display, nil, nil, nil);
windowmap.bucket = wbucket;
windowmap.nhash = nelem(wbucket);
atommap.bucket = abucket;
atommap.nhash = nelem(abucket);
atomnamemap.bucket = anamebucket;
atomnamemap.nhash = nelem(anamebucket);
fmtinstall('A', Afmt);
fmtinstall('L', Lfmt);
fmtinstall('R', Rfmt);
fmtinstall('P', Pfmt);
fmtinstall('W', Wfmt);
xlib_errorhandler = XSetErrorHandler(errorhandler);
}
|
Added lib/libstuff/x11/insanity/gethints.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include "../x11.h"
void
gethints(Window *w) {
XSizeHints xs;
XWMHints *wmh;
WinHints *h;
Point p;
long size;
if(w->hints == nil)
w->hints = emalloc(sizeof *h);
h = w->hints;
*h = ZWinHints;
wmh = XGetWMHints(display, w->xid);
if(wmh) {
if(wmh->flags & WindowGroupHint)
h->group = wmh->window_group;
free(wmh);
}
if(!XGetWMNormalHints(display, w->xid, &xs, &size))
return;
if(xs.flags & PMinSize) {
h->min.x = xs.min_width;
h->min.y = xs.min_height;
}
if(xs.flags & PMaxSize) {
h->max.x = xs.max_width;
h->max.y = xs.max_height;
}
/* Goddamn buggy clients. */
if(h->max.x < h->min.x)
h->max.x = h->min.x;
if(h->max.y < h->min.y)
h->max.y = h->min.y;
h->base = h->min;
if(xs.flags & PBaseSize) {
p.x = xs.base_width;
p.y = xs.base_height;
h->base = p;
h->baspect = p;
}
if(xs.flags & PResizeInc) {
h->inc.x = max(xs.width_inc, 1);
h->inc.y = max(xs.height_inc, 1);
}
if(xs.flags & PAspect) {
h->aspect.min.x = xs.min_aspect.x;
h->aspect.min.y = xs.min_aspect.y;
h->aspect.max.x = xs.max_aspect.x;
h->aspect.max.y = xs.max_aspect.y;
}
h->position = (xs.flags & (USPosition|PPosition)) != 0;
if(!(xs.flags & PWinGravity))
xs.win_gravity = NorthWestGravity;
p = ZP;
switch (xs.win_gravity) {
case EastGravity:
case CenterGravity:
case WestGravity:
p.y = 1;
break;
case SouthEastGravity:
case SouthGravity:
case SouthWestGravity:
p.y = 2;
break;
}
switch (xs.win_gravity) {
case NorthGravity:
case CenterGravity:
case SouthGravity:
p.x = 1;
break;
case NorthEastGravity:
case EastGravity:
case SouthEastGravity:
p.x = 2;
break;
}
h->grav = p;
h->gravstatic = (xs.win_gravity == StaticGravity);
}
|
Added lib/libstuff/x11/insanity/gravitate.c.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Rectangle
gravitate(Rectangle rc, Rectangle rf, Point grav) {
Point d;
/* Get delta between frame and client rectangles */
d = subpt(subpt(rf.max, rf.min),
subpt(rc.max, rc.min));
/* Divide by 2 and apply gravity */
d = divpt(d, Pt(2, 2));
d = mulpt(d, grav);
return rectsubpt(rc, d);
}
|
Added lib/libstuff/x11/insanity/sethints.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
#include <string.h>
const WinHints ZWinHints = {
.inc = {1, 1},
.max = {INT_MAX, INT_MAX},
};
typedef struct GravityMap GravityMap;
struct GravityMap {
Point point;
int gravity;
};
static GravityMap gravity_map[] = {
{ {0, 0}, NorthWestGravity },
{ {0, 1}, WestGravity },
{ {0, 2}, SouthWestGravity },
{ {1, 0}, NorthGravity },
{ {1, 1}, CenterGravity },
{ {1, 2}, SouthGravity },
{ {2, 0}, NorthEastGravity },
{ {2, 1}, EastGravity },
{ {2, 2}, SouthEastGravity },
};
void
sethints(Window *w, WinHints *h) {
XSizeHints xhints = { 0, };
int i;
/* TODO: Group hint */
if(w->hints == nil)
w->hints = emalloc(sizeof *h);
*w->hints = *h;
if(!eqpt(h->min, ZP)) {
xhints.flags |= PMinSize;
xhints.min_width = h->min.x;
xhints.min_height = h->min.y;
}
if(!eqpt(h->max, Pt(INT_MAX, INT_MAX))) {
xhints.flags |= PMaxSize;
xhints.max_width = h->max.x;
xhints.max_height = h->max.y;
}
if(!eqpt(h->base, ZP)) {
xhints.flags |= PBaseSize;
xhints.base_width = h->baspect.x;
xhints.base_height = h->baspect.y;
}
if(!eqrect(h->aspect, ZR)) {
xhints.flags |= PAspect;
xhints.base_width = h->baspect.x;
xhints.base_height = h->baspect.y;
xhints.min_aspect.x = h->aspect.min.x;
xhints.min_aspect.y = h->aspect.min.y;
xhints.max_aspect.x = h->aspect.max.x;
xhints.max_aspect.y = h->aspect.max.y;
}
if(!eqpt(h->inc, Pt(1, 1))) {
xhints.flags |= PResizeInc;
xhints.width_inc = h->inc.x;
xhints.height_inc = h->inc.y;
}
/* USPosition is probably an evil assumption, but it holds in our use cases. */
if(h->position)
xhints.flags |= USPosition | PPosition;
xhints.flags |= PWinGravity;
if(h->gravstatic)
xhints.win_gravity = StaticGravity;
else
for(i=0; i < nelem(gravity_map); i++)
if(h->grav.x == gravity_map[i].point.x &&
h->grav.y == gravity_map[i].point.y) {
xhints.win_gravity = gravity_map[i].gravity;
break;
}
XSetWMNormalHints(display, w->xid, &xhints);
}
|
Added lib/libstuff/x11/insanity/sizehint.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Rectangle
sizehint(WinHints *h, Rectangle r) {
Point p, aspect, origin;
if(h == nil)
return r;
origin = r.min;
r = rectsubpt(r, origin);
/* Min/max */
r.max.x = max(r.max.x, h->min.x);
r.max.y = max(r.max.y, h->min.y);
r.max.x = min(r.max.x, h->max.x);
r.max.y = min(r.max.y, h->max.y);
/* Increment */
p = subpt(r.max, h->base);
r.max.x -= p.x % h->inc.x;
r.max.y -= p.y % h->inc.y;
/* Aspect */
p = subpt(r.max, h->baspect);
p.y = max(p.y, 1);
aspect = h->aspect.min;
if(p.x * aspect.y / p.y < aspect.x)
r.max.y = h->baspect.y
+ p.x * aspect.y / aspect.x;
aspect = h->aspect.max;
if(p.x * aspect.y / p.y > aspect.x)
r.max.x = h->baspect.x
+ p.y * aspect.x / aspect.y;
return rectaddpt(r, origin);
}
|
Added lib/libstuff/x11/keyboard/grabkeyboard.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
int
grabkeyboard(Window *w) {
return XGrabKeyboard(display, w->xid, true /* owner events */,
GrabModeAsync, GrabModeAsync, CurrentTime
) == GrabSuccess;
}
|
Added lib/libstuff/x11/keyboard/ungrabkeyboard.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
ungrabkeyboard(void) {
XUngrabKeyboard(display, CurrentTime);
}
|
Added lib/libstuff/x11/keys/keycode.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
KeyCode
keycode(const char *name) {
return XKeysymToKeycode(display, XStringToKeysym(name));
}
|
Added lib/libstuff/x11/keys/parsekey.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
char *modkey_names[] = {
"Shift",
"",
"Control",
"Mod1",
"Mod2",
"Mod3",
"Mod4",
"Mod5",
nil
};
bool
parsekey(char *str, int *mask, char **key) {
static char *keys[16];
int i, j, nkeys;
*mask = 0;
nkeys = tokenize(keys, nelem(keys), str, '-');
for(i=0; i < nkeys; i++) {
for(j=0; modkey_names[j]; j++)
if(!strcasecmp(modkey_names[j], keys[i])) {
*mask |= 1 << j;
goto next;
}
break;
next: continue;
}
if(key) {
if(nkeys)
*key = keys[i];
return i == nkeys - 1;
}
else
return i == nkeys;
}
int
numlockmask(void) {
static int masks[] = {
ShiftMask, LockMask, ControlMask, Mod1Mask,
Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
};
XModifierKeymap *modmap;
KeyCode kcode;
int i, max, numlock;
numlock = 0;
modmap = XGetModifierMapping(display);
kcode = keycode("Num_Lock");
if(kcode && modmap && modmap->max_keypermod > 0) {
max = nelem(masks) * modmap->max_keypermod;
for(i = 0; i < max && !numlock; i++)
if(modmap->modifiermap[i] == kcode)
numlock = masks[i / modmap->max_keypermod];
}
XFreeModifiermap(modmap);
return numlock;
}
int
fmtkey(Fmt *f) {
XKeyEvent *ev;
char *key;
int nfmt;
ev = va_arg(f->args, XKeyEvent*);
key = XKeysymToString(XKeycodeToKeysym(display, ev->keycode, 0));
nfmt = f->nfmt;
unmask(f, ev->state, modkey_names, '-');
if(f->nfmt > nfmt)
fmtrune(f, '-');
return fmtstrcpy(f, key);
}
|
Added lib/libstuff/x11/mouse/grabpointer.c.
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
int
grabpointer(Window *w, Window *confine, Cursor cur, int mask) {
XWindow cw;
cw = None;
if(confine)
cw = confine->xid;
return XGrabPointer(display, w->xid, false /* owner events */, mask,
GrabModeAsync, GrabModeAsync, cw, cur, CurrentTime
) == GrabSuccess;
}
|
Added lib/libstuff/x11/mouse/pointerscreen.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
int
pointerscreen(void) {
XWindow win;
Point pt;
uint ui;
int i;
return XQueryPointer(display, scr.root.xid, &win, &win, &i, &i,
&pt.x, &pt.y, &ui);
}
|
Added lib/libstuff/x11/mouse/querypointer.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Point
querypointer(Window *w) {
XWindow win;
Point pt;
uint ui;
int i;
XQueryPointer(display, w->xid, &win, &win, &i, &i, &pt.x, &pt.y, &ui);
return pt;
}
|
Added lib/libstuff/x11/mouse/translate.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Point
translate(Window *src, Window *dst, Point sp) {
Point pt;
XWindow w;
XTranslateCoordinates(display, src->xid, dst->xid, sp.x, sp.y,
&pt.x, &pt.y, &w);
return pt;
}
|
Added lib/libstuff/x11/mouse/ungrabpointer.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
ungrabpointer(void) {
XUngrabPointer(display, CurrentTime);
}
|
Added lib/libstuff/x11/mouse/warppointer.c.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
warppointer(Point pt) {
/* Nasty kludge for xephyr, xnest. */
static int havereal = -1;
static char* real;
if(havereal == -1) {
real = getenv("REALDISPLAY");
havereal = real != nil;
}
if(havereal)
system(sxprint("DISPLAY=%s wiwarp %d %d", real, pt.x, pt.y));
XWarpPointer(display,
/* src, dest w */ None, scr.root.xid,
/* src_rect */ 0, 0, 0, 0,
/* target */ pt.x, pt.y);
}
|
Added lib/libstuff/x11/properties/changeprop_char.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
changeprop_char(Window *w, const char *prop, const char *type, const char data[], int len) {
changeproperty(w, prop, type, 8, (const uchar*)data, len);
}
|
Added lib/libstuff/x11/properties/changeprop_long.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
changeprop_long(Window *w, const char *prop, const char *type, long data[], int len) {
changeproperty(w, prop, type, 32, (uchar*)data, len);
}
|
Added lib/libstuff/x11/properties/changeprop_short.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
changeprop_short(Window *w, const char *prop, const char *type, short data[], int len) {
changeproperty(w, prop, type, 16, (uchar*)data, len);
}
|
Added lib/libstuff/x11/properties/changeprop_string.c.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include "../x11.h"
void
changeprop_string(Window *w, const char *prop, const char *string) {
changeprop_char(w, prop, "UTF8_STRING", string, strlen(string));
}
|
Added lib/libstuff/x11/properties/changeprop_textlist.c.
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include "../x11.h"
void
changeprop_textlist(Window *w, const char *prop, const char *type, char *data[]) {
char **p, *s, *t;
int len, n;
len = 0;
for(p=data; *p; p++)
len += strlen(*p) + 1;
s = emalloc(len);
t = s;
for(p=data; *p; p++) {
n = strlen(*p) + 1;
memcpy(t, *p, n);
t += n;
}
changeprop_char(w, prop, type, s, len - 1);
free(s);
}
|
Added lib/libstuff/x11/properties/changeprop_ulong.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
changeprop_ulong(Window *w, const char *prop, const char *type, ulong data[], int len) {
changeproperty(w, prop, type, 32, (uchar*)data, len);
}
|
Added lib/libstuff/x11/properties/changeproperty.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
changeproperty(Window *w, const char *prop, const char *type,
int width, const uchar data[], int n) {
XChangeProperty(display, w->xid, xatom(prop), xatom(type), width,
PropModeReplace, data, n);
}
|
Added lib/libstuff/x11/properties/delproperty.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
delproperty(Window *w, const char *prop) {
XDeleteProperty(display, w->xid, xatom(prop));
}
|
Added lib/libstuff/x11/properties/getprop.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
ulong
getprop(Window *w, const char *prop, const char *type, Atom *actual, int *format,
ulong offset, uchar **ret, ulong length) {
Atom typea;
ulong n, extra;
int status;
typea = (type ? xatom(type) : 0L);
status = XGetWindowProperty(display, w->xid,
xatom(prop), offset, length, false /* delete */,
typea, actual, format, &n, &extra, ret);
if(status != Success) {
*ret = nil;
return 0;
}
if(n == 0) {
free(*ret);
*ret = nil;
}
return n;
}
|
Added lib/libstuff/x11/properties/getprop_long.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
ulong
getprop_long(Window *w, const char *prop, const char *type,
ulong offset, long **ret, ulong length) {
Atom actual;
ulong n;
int format;
n = getprop(w, prop, type, &actual, &format, offset, (uchar**)ret, length);
if(n == 0 || format == 32 && xatom(type) == actual)
return n;
free(*ret);
*ret = 0;
return 0;
}
ulong
getprop_ulong(Window *w, const char *prop, const char *type,
ulong offset, ulong **ret, ulong length) {
return getprop_long(w, prop, type, offset, (long**)ret, length);
}
|
Added lib/libstuff/x11/properties/getprop_string.c.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
char*
getprop_string(Window *w, const char *name) {
char **list, *str;
int n;
str = nil;
n = getprop_textlist(w, name, &list);
if(n > 0)
str = estrdup(*list);
freestringlist(list);
return str;
}
|
Added lib/libstuff/x11/properties/getprop_textlist.c.
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
int
getprop_textlist(Window *w, const char *name, char **ret[]) {
XTextProperty prop;
char **list;
int n;
*ret = nil;
n = 0;
XGetTextProperty(display, w->xid, &prop, xatom(name));
if(prop.nitems > 0) {
if(Xutf8TextPropertyToTextList(display, &prop, &list, &n) == Success)
*ret = list;
XFree(prop.value);
}
return n;
}
|
Added lib/libstuff/x11/properties/getproperty.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
ulong
getproperty(Window *w, char *prop, char *type, Atom *actual,
ulong offset, uchar **ret, ulong length) {
int format;
return getprop(w, prop, type, actual, &format, offset, ret, length);
}
|
Added lib/libstuff/x11/properties/strlistdup.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include "../x11.h"
char**
strlistdup(char *list[]) {
char **p;
char *q;
int i, m, n;
n = 0;
m = 0;
for(p=list; *p; p++, n++)
m += strlen(*p) + 1;
p = malloc((n+1) * sizeof(*p) + m);
q = (char*)&p[n+1];
for(i=0; i < n; i++) {
p[i] = q;
m = strlen(list[i]) + 1;
memcpy(q, list[i], m);
q += m;
}
p[n] = nil;
return p;
}
|
Added lib/libstuff/x11/properties/windowname.c.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
char*
windowname(Window *w) {
char *str;
str = getprop_string(w, "_NET_WM_NAME");
if(str == nil)
str = getprop_string(w, "WM_NAME");
if(str == nil)
str = estrdup("");
return str;
}
|
Added lib/libstuff/x11/selection.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "x11.h"
static Handlers handlers;
typedef struct Data Data;
struct Data {
long selection;
void (*callback)(void*, char*);
void* aux;
};
static bool
_getselection(Window *w, long selection, char *type) {
XConvertSelection(display, selection, xatom(type),
selection, w->xid, CurrentTime);
return true;
}
void
getselection(char *selection, void (*callback)(void*, char*), void *aux) {
Window *w;
Data *d;
d = emallocz(sizeof *d);
d->selection = xatom(selection);
d->callback = callback;
d->aux = aux;
w = createwindow(&scr.root, Rect(0, 0, 1, 1), 0, InputOnly, nil, 0);
w->aux = d;
sethandler(w, &handlers);
_getselection(w, d->selection, "UTF8_STRING");
}
static bool
selection_event(Window *w, void *aux, XSelectionEvent *ev) {
Data *d;
char **ret;
d = aux;
if(ev->property == None && ev->target != xatom("STRING"))
return _getselection(w, d->selection, "STRING");
else if(ev->property == None)
d->callback(d->aux, nil);
else {
getprop_textlist(w, atomname(ev->property), &ret);
delproperty(w, atomname(ev->property));
d->callback(d->aux, ret ? *ret : nil);
free(ret);
}
destroywindow(w);
return false;
}
static Handlers handlers = {
.selection = selection_event,
};
|
Added lib/libstuff/x11/sendevent.c.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "x11.h"
void
sendevent(Window *w, bool propagate, long mask, void *e) {
XSendEvent(display, w->xid, propagate, mask, e);
}
|
Added lib/libstuff/x11/sendmessage.c.
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "x11.h"
#include <string.h>
void
sendmessage(Window *w, const char *name, long l0, long l1, long l2, long l3, long l4) {
clientmessage(w, name, NoEventMask, 32, (ClientMessageData){ .l = { l0, l1, l2, l3, l4 } });
}
void
clientmessage(Window *w, const char *name, long mask, int format, ClientMessageData data) {
XClientMessageEvent e;
e.type = ClientMessage;
e.window = w->xid;
e.message_type = xatom(name);
e.format = format;
bcopy(&data, &e.data, sizeof(data));
sendevent(w, false, mask, (XEvent*)&e);
}
|
Added lib/libstuff/x11/shape/setshapemask.c.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
setshapemask(Window *dst, Image *src, Point pt) {
/* Assumes that we have the shape extension... */
XShapeCombineMask (display, dst->xid,
ShapeBounding, pt.x, pt.y, src->xid, ShapeSet);
}
|
Added lib/libstuff/x11/sync.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "x11.h"
void
sync(void) {
XSync(display, false);
}
|
Added lib/libstuff/x11/text/freefont.c.
> > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
freefont(Font *f) {
switch(f->type) {
case FFontSet:
XFreeFontSet(display, f->font.set);
break;
case FXft:
xft->fontclose(display, f->font.xft);
break;
case FX11:
XFreeFont(display, f->font.x11);
break;
default:
break;
}
free(f->name);
free(f);
}
|
Added lib/libstuff/x11/text/labelh.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
uint
labelh(Font *font) {
return max(font->height + font->descent + font->pad.min.y + font->pad.max.y, 1);
}
|
Added lib/libstuff/x11/text/loadfont.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include "../x11.h"
Font*
loadfont(const char *name) {
XFontStruct **xfonts;
char **missing, **font_names;
Biobuf *b;
Font *f;
int n, i;
missing = nil;
f = emallocz(sizeof *f);
f->name = estrdup(name);
if(!strncmp(f->name, "xft:", 4)) {
f->type = FXft;
if(!havexft())
goto error;
f->font.xft = xft->fontopen(display, scr.screen, f->name + 4);
if(!f->font.xft)
f->font.xft = xft->fontopenname(display, scr.screen, f->name + 4);
if(!f->font.xft)
goto error;
f->ascent = f->font.xft->ascent;
f->descent = f->font.xft->descent;
}else {
f->font.set = XCreateFontSet(display, name, &missing, &n, nil);
if(missing) {
if(false) {
b = Bfdopen(dup(2), O_WRONLY);
Bprint(b, "%s: note: missing fontset%s for '%s':", argv0,
(n > 1 ? "s" : ""), name);
for(i = 0; i < n; i++)
Bprint(b, "%s %s", (i ? "," : ""), missing[i]);
Bprint(b, "\n");
Bterm(b);
}
freestringlist(missing);
}
if(f->font.set) {
f->type = FFontSet;
XFontsOfFontSet(f->font.set, &xfonts, &font_names);
f->ascent = xfonts[0]->ascent;
f->descent = xfonts[0]->descent;
}else {
f->type = FX11;
f->font.x11 = XLoadQueryFont(display, name);
if(!f->font.x11)
goto error;
f->ascent = f->font.x11->ascent;
f->descent = f->font.x11->descent;
}
}
f->height = f->ascent + f->descent;
return f;
error:
fprint(2, "%s: cannot load font: %s\n", argv0, name);
f->type = 0;
freefont(f);
return nil;
}
|
Added lib/libstuff/x11/text/textextents_l.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Rectangle
textextents_l(Font *font, const char *text, uint len, int *offset) {
Rectangle rect;
XRectangle r;
XGlyphInfo i;
int unused;
if(!offset)
offset = &unused;
switch(font->type) {
case FFontSet:
*offset = Xutf8TextExtents(font->font.set, text, len, &r, nil);
return Rect(r.x, -r.y - r.height, r.x + r.width, -r.y);
case FXft:
xft->textextents(display, font->font.xft, text, len, &i);
*offset = i.xOff;
return Rect(-i.x, i.y - i.height, -i.x + i.width, i.y);
case FX11:
rect = ZR;
rect.max.x = XTextWidth(font->font.x11, text, len);
rect.max.y = font->ascent;
*offset = rect.max.x;
return rect;
default:
die("Invalid font type");
return ZR; /* shut up ken */
}
}
|
Added lib/libstuff/x11/text/textwidth.c.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <string.h>
#include "../x11.h"
uint
textwidth(Font *font, const char *text) {
return textwidth_l(font, text, strlen(text));
}
|
Added lib/libstuff/x11/text/textwidth_l.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
uint
textwidth_l(Font *font, const char *text, uint len) {
Rectangle r;
r = textextents_l(font, text, len, nil);
return Dx(r);
}
|
Added lib/libstuff/x11/windows/configwin.c.
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
configwin(Window *w, Rectangle r, int border) {
XWindowChanges wc;
if(eqrect(r, w->r) && border == w->border)
return;
wc.x = r.min.x - border;
wc.y = r.min.y - border;
wc.width = Dx(r);
wc.height = Dy(r);
wc.border_width = border;
XConfigureWindow(display, w->xid, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
w->r = r;
w->border = border;
}
|
Added lib/libstuff/x11/windows/createwindow.c.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Window*
createwindow(Window *parent, Rectangle r, int depth, uint class, WinAttr *wa, int valmask) {
return createwindow_visual(parent, r, depth, scr.visual, class, wa, valmask);
}
|
Added lib/libstuff/x11/windows/createwindow_rgba.c.
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Window*
createwindow_rgba(Window *parent, Rectangle r, WinAttr *wa, int valmask) {
WinAttr attr;
if(scr.visual32 == nil)
return createwindow(parent, r, scr.depth, InputOutput, wa, valmask);
attr = wa ? *wa : (WinAttr){0};
valmask |= CWBorderPixel | CWColormap;
attr.border_pixel = 0;
attr.colormap = scr.colormap32;
return createwindow_visual(parent, r, 32, scr.visual32, InputOutput, &attr, valmask);
}
|
Added lib/libstuff/x11/windows/createwindow_visual.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
#include <string.h>
#include <unistd.h>
static char hostname[HOST_NAME_MAX + 1];
static long pid;
Window*
createwindow_visual(Window *parent, Rectangle r,
int depth, Visual *vis, uint class,
WinAttr *wa, int valmask) {
Window *w;
WinAttr wa_empty;
assert(parent->type == WWindow);
if(wa == nil)
wa = &wa_empty;
w = emallocz(sizeof *w);
w->visual = vis;
w->type = WWindow;
w->parent = parent;
if(valmask & CWColormap)
w->colormap = wa->colormap;
if(valmask & CWEventMask)
w->eventmask = wa->event_mask;
w->xid = XCreateWindow(display, parent->xid, r.min.x, r.min.y, Dx(r), Dy(r),
0 /* border */, depth, class, vis, valmask, wa);
#if 0
print("createwindow_visual(%W, %R, %d, %p, %ud, %p, %x) = %W\n",
parent, r, depth, vis, class, wa, valmask, w);
#endif
if(class != InputOnly)
w->gc = XCreateGC(display, w->xid, 0, nil);
if(pid == 0)
pid = getpid();
changeprop_long(w, "_NET_WM_PID", "CARDINAL", &pid, 1);
if(!hostname[0])
gethostname(hostname, sizeof(hostname) - 1);
if(hostname[0])
changeprop_char(w, "WM_CLIENT_MACHINE", "STRING", hostname, strlen(hostname));
w->r = r;
w->depth = depth;
return w;
}
|
Added lib/libstuff/x11/windows/destroywindow.c.
> > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
cleanupwindow(Window *w) {
assert(w->type == WWindow);
sethandler(w, nil);
while(w->handler_link)
pophandler(w, w->handler_link->handler);
free(w->hints);
free(w->dnd);
if(w->xft)
xft->drawdestroy(w->xft);
if(w->gc)
XFreeGC(display, w->gc);
}
void
destroywindow(Window *w) {
cleanupwindow(w);
XDestroyWindow(display, w->xid);
free(w);
}
|
Added lib/libstuff/x11/windows/findwin.c.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
#include <assert.h>
Window*
findwin(XWindow xw) {
Window *w;
void **e;
e = map_get(&windowmap, (ulong)xw, false);
if(e) {
w = *e;
assert(w->xid == xw);
return w;
}
return nil;
}
|
Added lib/libstuff/x11/windows/getwinrect.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Rectangle
getwinrect(Window *w) {
XWindowAttributes wa;
Point p;
if(!XGetWindowAttributes(display, w->xid, &wa))
return ZR;
p = translate(w, &scr.root, ZP);
return rectaddpt(Rect(0, 0, wa.width, wa.height), p);
}
|
Added lib/libstuff/x11/windows/lowerwin.c.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
lowerwin(Window *w) {
assert(w->type == WWindow);
XLowerWindow(display, w->xid);
}
|
Added lib/libstuff/x11/windows/mapwin.c.
> > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
int
mapwin(Window *w) {
assert(w->type == WWindow);
if(!w->mapped) {
XMapWindow(display, w->xid);
w->mapped = 1;
return 1;
}
return 0;
}
|
Added lib/libstuff/x11/windows/movewin.c.
> > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
movewin(Window *w, Point pt) {
Rectangle r;
assert(w->type == WWindow);
r = rectsetorigin(w->r, pt);
reshapewin(w, r);
}
|
Added lib/libstuff/x11/windows/raisewin.c.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
raisewin(Window *w) {
assert(w->type == WWindow);
XRaiseWindow(display, w->xid);
}
|
Added lib/libstuff/x11/windows/reparentwindow.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
reparentwindow(Window *w, Window *par, Point p) {
assert(w->type == WWindow);
XReparentWindow(display, w->xid, par->xid, p.x, p.y);
w->r = rectsubpt(w->r, w->r.min);
w->r = rectaddpt(w->r, p);
}
|
Added lib/libstuff/x11/windows/reshapewin.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
reshapewin(Window *w, Rectangle r) {
assert(w->type == WWindow);
assert(Dx(r) > 0 && Dy(r) > 0); /* Rather than an X error. */
configwin(w, r, w->border);
}
|
Added lib/libstuff/x11/windows/selectinput.c.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
selectinput(Window *w, long mask) {
w->eventmask = mask;
XSelectInput(display, w->xid, mask);
}
|
Added lib/libstuff/x11/windows/setborder.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
setborder(Window *w, int width, Color *col) {
assert(w->type == WWindow);
if(width)
XSetWindowBorder(display, w->xid, pixelvalue(w, col));
if(width != w->border)
configwin(w, w->r, width);
}
|
Added lib/libstuff/x11/windows/sethandler.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
static void
updatemap(Window *w) {
void **e;
assert(w->type == WWindow);
assert((w->prev != nil && w->next != nil) || w->next == w->prev);
if(w->handler == nil && w->handler_link == nil)
map_rm(&windowmap, (ulong)w->xid);
else {
e = map_get(&windowmap, (ulong)w->xid, true);
*e = w;
}
}
Handlers*
sethandler(Window *w, Handlers *new) {
Handlers *old;
old = w->handler;
w->handler = new;
updatemap(w);
return old;
}
static HandlersLink* free_link;
void
pushhandler(Window *w, Handlers *new, void *aux) {
HandlersLink *l;
int i;
if(free_link == nil) {
l = emalloc(16 * sizeof *l);
for(i=0; i < 16; i++) {
l[i].next = free_link;
free_link = l;
}
}
l = free_link;
free_link = l->next;
/* TODO: Maybe: pophandler(w, new); */
l->next = w->handler_link;
l->handler = new;
l->aux = aux;
w->handler_link = l;
updatemap(w);
}
bool
pophandler(Window *w, Handlers *old) {
HandlersLink **lp;
HandlersLink *l;
for(lp=&w->handler_link; (l=*lp); lp=&l->next)
if(l->handler == old) {
*lp = l->next;
l->next = free_link;
free_link = l;
updatemap(w);
return true;
}
return false;
}
|
Added lib/libstuff/x11/windows/setwinattr.c.
> > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
void
setwinattr(Window *w, WinAttr *wa, int valmask) {
assert(w->type == WWindow);
XChangeWindowAttributes(display, w->xid, valmask, wa);
}
|
Added lib/libstuff/x11/windows/unmapwin.c.
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
int
unmapwin(Window *w) {
assert(w->type == WWindow);
if(w->mapped) {
XUnmapWindow(display, w->xid);
w->mapped = 0;
w->unmapped++;
return 1;
}
return 0;
}
|
Added lib/libstuff/x11/windows/window.c.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "../x11.h"
Window*
window(XWindow xw) {
Window *w;
w = emallocz(sizeof *w);
w->type = WWindow;
w->xid = xw;
return freelater(w);
}
|
Added lib/libstuff/x11/x11.c.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "x11.h"
const Point ZP = {0, 0};
const Rectangle ZR = {{0, 0}, {0, 0}};
const Window _pointerwin = { .xid = PointerRoot };
Window* const pointerwin = (Window*)&_pointerwin;
|
Added lib/libstuff/x11/x11.h.
> > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail> * See LICENSE file for license details. */ #define _X11_VISIBLE #define pointerwin __pointerwin #include <assert.h> #include <limits.h> #include <math.h> #include <strings.h> #include <unistd.h> #include <bio.h> #include <stuff/x.h> #include <stuff/util.h> #undef pointerwin extern int (*xlib_errorhandler) (Display*, XErrorEvent*); void configwin(Window*, Rectangle, int); XPoint* convpts(Point*, int); int errorhandler(Display*, XErrorEvent*); void setgccol(Image*, Color*); XftColor* xftcolor(Image*, Color*); XftDraw* xftdrawable(Image*); |
Added lib/libstuff/x11/xatom.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "x11.h"
Atom
xatom(const char *name) {
void **e, **f;
e = hash_get(&atommap, name, true);
if(*e == nil) {
*e = (void*)XInternAtom(display, name, false);
f = map_get(&atomnamemap, (ulong)*e, true);
if(*f == nil)
*f = (void*)(uintptr_t)name;
}
return (Atom)*e;
}
char*
atomname(ulong atom) {
void **e;
e = map_get(&atomnamemap, atom, true);
if(*e == nil) {
*e = XGetAtomName(display, atom);
if(*e == nil) {
map_rm(&atomnamemap, atom);
return nil;
}
*hash_get(&atommap, *e, true) = (void*)atom;
}
return *e;
}
|
Added lib/libstuff/x11/xft.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/* Copyright ©2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <stuff/x.h>
#include <stuff/util.h>
Xft *xft;
#ifdef HAVE_RTLD
#include <dlfcn.h>
bool
havexft(void) {
void *libxft;
if(xft == nil) {
libxft = dlopen("libXft.so", RTLD_LAZY);
if(libxft == nil)
return false;
xft = emalloc(sizeof *xft);
*(void**)(uintptr_t)&xft->drawcreate = dlsym(libxft, "XftDrawCreate");
*(void**)(uintptr_t)&xft->drawdestroy = dlsym(libxft, "XftDrawDestroy");
*(void**)(uintptr_t)&xft->fontopen = dlsym(libxft, "XftFontOpenXlfd");
*(void**)(uintptr_t)&xft->fontopenname = dlsym(libxft, "XftFontOpenName");
*(void**)(uintptr_t)&xft->fontclose = dlsym(libxft, "XftFontClose");
*(void**)(uintptr_t)&xft->textextents = dlsym(libxft, "XftTextExtentsUtf8");
*(void**)(uintptr_t)&xft->drawstring = dlsym(libxft, "XftDrawStringUtf8");
}
return xft && xft->drawcreate && xft->drawdestroy && xft->fontopen
&& xft->fontopenname && xft->fontclose && xft->textextents && xft->drawstring;
}
#else
bool
havexft(void) {
return false;
}
#endif
|
Added lib/libstuff/xext.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
/* Copyright ©2008-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#define _X11_VISIBLE
#include <stuff/x.h>
#include <stuff/util.h>
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/Xinerama.h>
#if RANDR_MAJOR < 1
# error XRandR versions less than 1.0 are not supported
#endif
static void randr_screenchange(XRRScreenChangeNotifyEvent*);
static bool randr_event_p(XEvent *e);
static void randr_init(void);
static void render_init(void);
static void xinerama_init(void);
typedef void (*EvHandler)(XEvent*);
static EvHandler randr_handlers[RRNumberEvents];
bool have_RandR;
bool have_render;
bool have_xinerama;
int randr_eventbase;
Visual* render_visual;
static void
handle(XEvent *e, EvHandler h[], int base) {
if(h[e->type-base])
h[e->type-base](e);
}
void
xext_init(void) {
randr_init();
render_init();
xinerama_init();
}
void
xext_event(XEvent *e) {
if(randr_event_p(e))
handle(e, randr_handlers, randr_eventbase);
}
static void
randr_init(void) {
int errorbase, major, minor;
have_RandR = XRRQueryExtension(display, &randr_eventbase, &errorbase);
if(have_RandR)
if(XRRQueryVersion(display, &major, &minor) && major < 1)
have_RandR = false;
if(have_RandR)
XRRSelectInput(display, scr.root.xid, RRScreenChangeNotifyMask);
}
static bool
randr_event_p(XEvent *e) {
return have_RandR
&& (uint)e->type - randr_eventbase < RRNumberEvents;
}
static void
randr_screenchange(XRRScreenChangeNotifyEvent *ev) {
XRRUpdateConfiguration((XEvent*)ev);
if(ev->rotation*90 % 180)
scr.rect = Rect(0, 0, ev->width, ev->height);
else
scr.rect = Rect(0, 0, ev->height, ev->width);
init_screens();
}
static EvHandler randr_handlers[] = {
[RRScreenChangeNotify] = (EvHandler)randr_screenchange,
};
/* Ripped most graciously from ecore_x. XRender documentation
* is sparse.
*/
static void
render_init(void) {
XVisualInfo *vip;
XVisualInfo vi;
int base, i, n;
have_render = XRenderQueryExtension(display, &base, &base);
if(!have_render)
return;
vi.class = TrueColor;
vi.depth = 32;
vi.screen = scr.screen;
vip = XGetVisualInfo(display, VisualClassMask
| VisualDepthMask
| VisualScreenMask,
&vi, &n);
for(i=0; i < n; i++)
if(render_argb_p(vip[i].visual)) {
render_visual = vip[i].visual;
scr.visual32 = render_visual;
break;
}
XFree(vip);
if(render_visual)
scr.colormap32 = XCreateColormap(display, scr.root.xid, render_visual, AllocNone);
}
bool
render_argb_p(Visual *v) {
XRenderPictFormat *f;
if(!have_render)
return false;
f = XRenderFindVisualFormat(display, v);
return f
&& f->type == PictTypeDirect
&& f->direct.alphaMask;
}
static void
xinerama_init(void) {
int base;
have_xinerama = XineramaQueryExtension(display, &base, &base);
}
static bool
xinerama_active(void) {
return have_xinerama && XineramaIsActive(display);
}
Rectangle*
xinerama_screens(int *np) {
static Rectangle *rects;
XineramaScreenInfo *res;
int i, n;
if(!xinerama_active()) {
*np = 1;
return &scr.rect;
}
free(rects);
res = XineramaQueryScreens(display, &n);
rects = emalloc(n * sizeof *rects);
for(i=0; i < n; i++) {
rects[i].min.x = res[i].x_org;
rects[i].min.y = res[i].y_org;
rects[i].max.x = res[i].x_org + res[i].width;
rects[i].max.y = res[i].y_org + res[i].height;
}
XFree(res);
*np = n;
return rects;
}
|
Added lib/libutf/Makefile.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ROOT= ../.. include $(ROOT)/mk/hdr.mk VERSION=2.0 TARG=libutf OBJ=\ rune\ runestrcat\ runestrchr\ runestrcmp\ runestrcpy\ runestrdup\ runestrlen\ runestrecpy\ runestrncat\ runestrncmp\ runestrncpy\ runestrrchr\ runestrstr\ runetype\ utfecpy\ utflen\ utfnlen\ utfrrune\ utfrune\ utfutf include $(ROOT)/mk/lib.mk |
Added lib/libutf/NOTICE.
> > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /* * The authors of this software are Rob Pike and Ken Thompson. * Copyright (c) 2002 by Lucent Technologies. * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ This is a Unix port of the Plan 9 formatted I/O package. Please send comments about the packaging to Russ Cox <rsc@swtch.com>. ---- This software is also made available under the Lucent Public License version 1.02; see http://plan9.bell-labs.com/plan9dist/license.html |
Added lib/libutf/README.
> > > > > | 1 2 3 4 5 | This software was packaged for Unix by Russ Cox. Please send comments to rsc@swtch.com. http://swtch.com/plan9port/unix |
Added lib/libutf/isalpharune.3.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | .deEX .ift .ft5 .nf .. .deEE .ft1 .fi .. .TH ISALPHARUNE 3 .SH NAME isalpharune, islowerrune, isspacerune, istitlerune, isupperrune, tolowerrune, totitlerune, toupperrune \- Unicode character classes and cases .SH SYNOPSIS .B #include <utf.h> .PP .B int isalpharune(Rune c) .PP .B int islowerrune(Rune c) .PP .B int isspacerune(Rune c) .PP .B int istitlerune(Rune c) .PP .B int isupperrune(Rune c) .PP .B Rune tolowerrune(Rune c) .PP .B Rune totitlerune(Rune c) .PP .B Rune toupperrune(Rune c) .SH DESCRIPTION These routines examine and operate on Unicode characters, in particular a subset of their properties as defined in the Unicode standard. Unicode defines some characters as alphabetic and specifies three cases: upper, lower, and title. Analogously to .IR isalpha (3) for .SM ASCII\c , these routines test types and modify cases for Unicode characters. The names are self-explanatory. .PP The case-conversion routines return the character unchanged if it has no case. .SH SOURCE .B http://swtch.com/plan9port/unix .SH "SEE ALSO .IR isalpha (3) , .IR "The Unicode Standard" . |
Added lib/libutf/libutf.a.
cannot compute difference between binary files
Added lib/libutf/rune.3.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | .deEX .ift .ft5 .nf .. .deEE .ft1 .fi .. .TH RUNE 3 .SH NAME runetochar, chartorune, runelen, runenlen, fullrune, utfecpy, utflen, utfnlen, utfrune, utfrrune, utfutf \- rune/UTF conversion .SH SYNOPSIS .ta \w'\fLchar*xx'u .B #include <utf.h> .PP .B int runetochar(char *s, Rune *r) .PP .B int chartorune(Rune *r, char *s) .PP .B int runelen(long r) .PP .B int runenlen(Rune *r, int n) .PP .B int fullrune(char *s, int n) .PP .B char* utfecpy(char *s1, char *es1, char *s2) .PP .B int utflen(char *s) .PP .B int utfnlen(char *s, long n) .PP .B char* utfrune(char *s, long c) .PP .B char* utfrrune(char *s, long c) .PP .B char* utfutf(char *s1, char *s2) .SH DESCRIPTION These routines convert to and from a .SM UTF byte stream and runes. .PP .I Runetochar copies one rune at .I r to at most .B UTFmax bytes starting at .I s and returns the number of bytes copied. .BR UTFmax , defined as .B 3 in .BR <libc.h> , is the maximum number of bytes required to represent a rune. .PP .I Chartorune copies at most .B UTFmax bytes starting at .I s to one rune at .I r and returns the number of bytes copied. If the input is not exactly in .SM UTF format, .I chartorune will convert to 0x80 and return 1. .PP .I Runelen returns the number of bytes required to convert .I r into .SM UTF. .PP .I Runenlen returns the number of bytes required to convert the .I n runes pointed to by .I r into .SM UTF. .PP .I Fullrune returns 1 if the string .I s of length .I n is long enough to be decoded by .I chartorune and 0 otherwise. This does not guarantee that the string contains a legal .SM UTF encoding. This routine is used by programs that obtain input a byte at a time and need to know when a full rune has arrived. .PP The following routines are analogous to the corresponding string routines with .B utf substituted for .B str and .B rune substituted for .BR chr . .PP .I Utfecpy copies UTF sequences until a null sequence has been copied, but writes no sequences beyond .IR es1 . If any sequences are copied, .I s1 is terminated by a null sequence, and a pointer to that sequence is returned. Otherwise, the original .I s1 is returned. .PP .I Utflen returns the number of runes that are represented by the .SM UTF string .IR s . .PP .I Utfnlen returns the number of complete runes that are represented by the first .I n bytes of .SM UTF string .IR s . If the last few bytes of the string contain an incompletely coded rune, .I utfnlen will not count them; in this way, it differs from .IR utflen , which includes every byte of the string. .PP .I Utfrune .RI ( utfrrune ) returns a pointer to the first (last) occurrence of rune .I c in the .SM UTF string .IR s , or 0 if .I c does not occur in the string. The NUL byte terminating a string is considered to be part of the string .IR s . .PP .I Utfutf returns a pointer to the first occurrence of the .SM UTF string .I s2 as a .SM UTF substring of .IR s1 , or 0 if there is none. If .I s2 is the null string, .I utfutf returns .IR s1 . .SH SOURCE .B http://swtch.com/plan9port/unix .SH SEE ALSO .IR utf (7), .IR tcs (1) |
Added lib/libutf/rune.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
enum
{
Bit1 = 7,
Bitx = 6,
Bit2 = 5,
Bit3 = 4,
Bit4 = 3,
Bit5 = 2,
T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */
Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */
Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0000 0000 0111 1111 1111 */
Rune3 = (1<<(Bit3+2*Bitx))-1, /* 0000 0000 1111 1111 1111 1111 */
Rune4 = (1<<(Bit4+3*Bitx))-1, /* 0011 1111 1111 1111 1111 1111 */
Maskx = (1<<Bitx)-1, /* 0011 1111 */
Testx = Maskx ^ 0xFF, /* 1100 0000 */
Bad = Runeerror
};
int
chartorune(Rune *rune, const char *str)
{
int c, c1, c2, c3;
long l;
/*
* one character sequence
* 00000-0007F => T1
*/
c = *(uchar*)str;
if(c < Tx) {
*rune = c;
return 1;
}
/*
* two character sequence
* 0080-07FF => T2 Tx
*/
c1 = *(uchar*)(str+1) ^ Tx;
if(c1 & Testx)
goto bad;
if(c < T3) {
if(c < T2)
goto bad;
l = ((c << Bitx) | c1) & Rune2;
if(l <= Rune1)
goto bad;
*rune = l;
return 2;
}
/*
* three character sequence
* 0800-FFFF => T3 Tx Tx
*/
c2 = *(uchar*)(str+2) ^ Tx;
if(c2 & Testx)
goto bad;
if(c < T4) {
l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
if(l <= Rune2)
goto bad;
*rune = l;
return 3;
}
/*
* four character sequence
* 10000-10FFFF => T4 Tx Tx Tx
*/
if(UTFmax >= 4) {
c3 = *(uchar*)(str+3) ^ Tx;
if(c3 & Testx)
goto bad;
if(c < T5) {
l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
if(l <= Rune3)
goto bad;
if(l > Runemax)
goto bad;
*rune = l;
return 4;
}
}
/*
* bad decoding
*/
bad:
*rune = Bad;
return 1;
}
int
runetochar(char *str, const Rune *rune)
{
long c;
/*
* one character sequence
* 00000-0007F => 00-7F
*/
c = *rune;
if(c <= Rune1) {
str[0] = c;
return 1;
}
/*
* two character sequence
* 00080-007FF => T2 Tx
*/
if(c <= Rune2) {
str[0] = T2 | (c >> 1*Bitx);
str[1] = Tx | (c & Maskx);
return 2;
}
/*
* three character sequence
* 00800-0FFFF => T3 Tx Tx
*/
if(c > Runemax)
c = Runeerror;
if(c <= Rune3) {
str[0] = T3 | (c >> 2*Bitx);
str[1] = Tx | ((c >> 1*Bitx) & Maskx);
str[2] = Tx | (c & Maskx);
return 3;
}
/*
* four character sequence
* 010000-1FFFFF => T4 Tx Tx Tx
*/
str[0] = T4 | (c >> 3*Bitx);
str[1] = Tx | ((c >> 2*Bitx) & Maskx);
str[2] = Tx | ((c >> 1*Bitx) & Maskx);
str[3] = Tx | (c & Maskx);
return 4;
}
int
runelen(long c)
{
Rune rune;
char str[10];
rune = c;
return runetochar(str, &rune);
}
int
runenlen(const Rune *r, int nrune)
{
int nb, c;
nb = 0;
while(nrune--) {
c = *r++;
if(c <= Rune1)
nb++;
else
if(c <= Rune2)
nb += 2;
else
if(c <= Rune3 || c > Runemax)
nb += 3;
else
nb += 4;
}
return nb;
}
int
fullrune(const char *str, int n)
{
int c;
if(n <= 0)
return 0;
c = *(uchar*)str;
if(c < Tx)
return 1;
if(c < T3)
return n >= 2;
if(UTFmax == 3 || c < T4)
return n >= 3;
return n >= 4;
}
|
Added lib/libutf/runestrcat.3.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | .deEX .ift .ft5 .nf .. .deEE .ft1 .fi .. .TH RUNESTRCAT 3 .SH NAME runestrcat, runestrncat, runestrcmp, runestrncmp, runestrcpy, runestrncpy, runestrecpy, runestrlen, runestrchr, runestrrchr, runestrdup, runestrstr \- rune string operations .SH SYNOPSIS .B #include <u.h> .br .B #include <libc.h> .PP .ta \w'\fLRune* \fP'u .B Rune* runestrcat(Rune *s1, Rune *s2) .PP .B Rune* runestrncat(Rune *s1, Rune *s2, long n) .PP .B int runestrcmp(Rune *s1, Rune *s2) .PP .B int runestrncmp(Rune *s1, Rune *s2, long n) .PP .B Rune* runestrcpy(Rune *s1, Rune *s2) .PP .B Rune* runestrncpy(Rune *s1, Rune *s2, long n) .PP .B Rune* runestrecpy(Rune *s1, Rune *es1, Rune *s2) .PP .B long runestrlen(Rune *s) .PP .B Rune* runestrchr(Rune *s, Rune c) .PP .B Rune* runestrrchr(Rune *s, Rune c) .PP .B Rune* runestrdup(Rune *s) .PP .B Rune* runestrstr(Rune *s1, Rune *s2) .SH DESCRIPTION These functions are rune string analogues of the corresponding functions in .IR strcat (3). .SH SOURCE .B http://swtch.com/plan9port/unix .SH SEE ALSO .IR rune (3), .IR strcat (3) .SH BUGS The outcome of overlapping moves varies among implementations. |
Added lib/libutf/runestrcat.c.
> > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include <plan9.h>
Rune*
runestrcat(Rune *s1, const Rune *s2)
{
runestrcpy(runestrchr(s1, 0), s2);
return s1;
}
|
Added lib/libutf/runestrchr.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
Rune*
runestrchr(const Rune *s, Rune c)
{
Rune c0 = c;
Rune c1;
if(c == 0) {
while(*s++)
;
return (Rune*)s-1;
}
while(c1 = *s++)
if(c1 == c0)
return (Rune*)s-1;
return 0;
}
|
Added lib/libutf/runestrcmp.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
int
runestrcmp(const Rune *s1, const Rune *s2)
{
Rune c1, c2;
for(;;) {
c1 = *s1++;
c2 = *s2++;
if(c1 != c2) {
if(c1 > c2)
return 1;
return -1;
}
if(c1 == 0)
return 0;
}
}
|
Added lib/libutf/runestrcpy.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
Rune*
runestrcpy(Rune *s1, const Rune *s2)
{
Rune *os1;
os1 = s1;
while(*s1++ = *s2++)
;
return os1;
}
|
Added lib/libutf/runestrdup.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdlib.h>
#include <plan9.h>
Rune*
runestrdup(const Rune *s)
{
Rune *ns;
ns = malloc(sizeof(Rune)*(runestrlen(s) + 1));
if(ns == 0)
return 0;
return runestrcpy(ns, s);
}
|
Added lib/libutf/runestrecpy.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
Rune*
runestrecpy(Rune *s1, Rune *es1, const Rune *s2)
{
if(s1 >= es1)
return s1;
while(*s1++ = *s2++){
if(s1 == es1){
*--s1 = '\0';
break;
}
}
return s1;
}
|
Added lib/libutf/runestrlen.c.
> > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <plan9.h>
long
runestrlen(const Rune *s)
{
return runestrchr(s, 0) - s;
}
|
Added lib/libutf/runestrncat.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
Rune*
runestrncat(Rune *s1, const Rune *s2, long n)
{
Rune *os1;
os1 = s1;
s1 = runestrchr(s1, 0);
while(*s1++ = *s2++)
if(--n < 0) {
s1[-1] = 0;
break;
}
return os1;
}
|
Added lib/libutf/runestrncmp.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
int
runestrncmp(const Rune *s1, const Rune *s2, long n)
{
Rune c1, c2;
while(n > 0) {
c1 = *s1++;
c2 = *s2++;
n--;
if(c1 != c2) {
if(c1 > c2)
return 1;
return -1;
}
if(c1 == 0)
break;
}
return 0;
}
|
Added lib/libutf/runestrncpy.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
Rune*
runestrncpy(Rune *s1, const Rune *s2, long n)
{
int i;
Rune *os1;
os1 = s1;
for(i = 0; i < n; i++)
if((*s1++ = *s2++) == 0) {
while(++i < n)
*s1++ = 0;
return os1;
}
return os1;
}
|
Added lib/libutf/runestrrchr.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
Rune*
runestrrchr(const Rune *s, Rune c)
{
const Rune *r;
if(c == 0)
return runestrchr(s, 0);
r = 0;
while(s = runestrchr(s, c))
r = s++;
return (Rune*)r;
}
|
Added lib/libutf/runestrstr.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
/*
* Return pointer to first occurrence of s2 in s1,
* 0 if none
*/
Rune*
runestrstr(const Rune *s1, const Rune *s2)
{
const Rune *pa, *pb;
Rune *p;
int c0, c;
c0 = *s2;
if(c0 == 0)
return (Rune*)s1;
s2++;
for(p=runestrchr(s1, c0); p; p=runestrchr(p+1, c0)) {
pa = p;
for(pb=s2;; pb++) {
c = *pb;
if(c == 0)
return p;
if(c != *++pa)
break;
}
}
return 0;
}
|
Added lib/libutf/runetype.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
/*
* alpha ranges -
* only covers ranges not in lower||upper
*/
static
Rune __alpha2[] =
{
0x00d8, 0x00f6, /* Ø - ö */
0x00f8, 0x01f5, /* ø - ǵ */
0x0250, 0x02a8, /* ɐ - ʨ */
0x038e, 0x03a1, /* Ύ - Ρ */
0x03a3, 0x03ce, /* Σ - ώ */
0x03d0, 0x03d6, /* ϐ - ϖ */
0x03e2, 0x03f3, /* Ϣ - ϳ */
0x0490, 0x04c4, /* Ґ - ӄ */
0x0561, 0x0587, /* ա - և */
0x05d0, 0x05ea, /* א - ת */
0x05f0, 0x05f2, /* װ - ײ */
0x0621, 0x063a, /* ء - غ */
0x0640, 0x064a, /* ـ - ي */
0x0671, 0x06b7, /* ٱ - ڷ */
0x06ba, 0x06be, /* ں - ھ */
0x06c0, 0x06ce, /* ۀ - ێ */
0x06d0, 0x06d3, /* ې - ۓ */
0x0905, 0x0939, /* अ - ह */
0x0958, 0x0961, /* क़ - ॡ */
0x0985, 0x098c, /* অ - ঌ */
0x098f, 0x0990, /* এ - ঐ */
0x0993, 0x09a8, /* ও - ন */
0x09aa, 0x09b0, /* প - র */
0x09b6, 0x09b9, /* শ - হ */
0x09dc, 0x09dd, /* ড় - ঢ় */
0x09df, 0x09e1, /* য় - ৡ */
0x09f0, 0x09f1, /* ৰ - ৱ */
0x0a05, 0x0a0a, /* ਅ - ਊ */
0x0a0f, 0x0a10, /* ਏ - ਐ */
0x0a13, 0x0a28, /* ਓ - ਨ */
0x0a2a, 0x0a30, /* ਪ - ਰ */
0x0a32, 0x0a33, /* ਲ - ਲ਼ */
0x0a35, 0x0a36, /* ਵ - ਸ਼ */
0x0a38, 0x0a39, /* ਸ - ਹ */
0x0a59, 0x0a5c, /* ਖ਼ - ੜ */
0x0a85, 0x0a8b, /* અ - ઋ */
0x0a8f, 0x0a91, /* એ - ઑ */
0x0a93, 0x0aa8, /* ઓ - ન */
0x0aaa, 0x0ab0, /* પ - ર */
0x0ab2, 0x0ab3, /* લ - ળ */
0x0ab5, 0x0ab9, /* વ - હ */
0x0b05, 0x0b0c, /* ଅ - ଌ */
0x0b0f, 0x0b10, /* ଏ - ଐ */
0x0b13, 0x0b28, /* ଓ - ନ */
0x0b2a, 0x0b30, /* ପ - ର */
0x0b32, 0x0b33, /* ଲ - ଳ */
0x0b36, 0x0b39, /* ଶ - ହ */
0x0b5c, 0x0b5d, /* ଡ଼ - ଢ଼ */
0x0b5f, 0x0b61, /* ୟ - ୡ */
0x0b85, 0x0b8a, /* அ - ஊ */
0x0b8e, 0x0b90, /* எ - ஐ */
0x0b92, 0x0b95, /* ஒ - க */
0x0b99, 0x0b9a, /* ங - ச */
0x0b9e, 0x0b9f, /* ஞ - ட */
0x0ba3, 0x0ba4, /* ண - த */
0x0ba8, 0x0baa, /* ந - ப */
0x0bae, 0x0bb5, /* ம - வ */
0x0bb7, 0x0bb9, /* ஷ - ஹ */
0x0c05, 0x0c0c, /* అ - ఌ */
0x0c0e, 0x0c10, /* ఎ - ఐ */
0x0c12, 0x0c28, /* ఒ - న */
0x0c2a, 0x0c33, /* ప - ళ */
0x0c35, 0x0c39, /* వ - హ */
0x0c60, 0x0c61, /* ౠ - ౡ */
0x0c85, 0x0c8c, /* ಅ - ಌ */
0x0c8e, 0x0c90, /* ಎ - ಐ */
0x0c92, 0x0ca8, /* ಒ - ನ */
0x0caa, 0x0cb3, /* ಪ - ಳ */
0x0cb5, 0x0cb9, /* ವ - ಹ */
0x0ce0, 0x0ce1, /* ೠ - ೡ */
0x0d05, 0x0d0c, /* അ - ഌ */
0x0d0e, 0x0d10, /* എ - ഐ */
0x0d12, 0x0d28, /* ഒ - ന */
0x0d2a, 0x0d39, /* പ - ഹ */
0x0d60, 0x0d61, /* ൠ - ൡ */
0x0e01, 0x0e30, /* ก - ะ */
0x0e32, 0x0e33, /* า - ำ */
0x0e40, 0x0e46, /* เ - ๆ */
0x0e5a, 0x0e5b, /* ๚ - ๛ */
0x0e81, 0x0e82, /* ກ - ຂ */
0x0e87, 0x0e88, /* ງ - ຈ */
0x0e94, 0x0e97, /* ດ - ທ */
0x0e99, 0x0e9f, /* ນ - ຟ */
0x0ea1, 0x0ea3, /* ມ - ຣ */
0x0eaa, 0x0eab, /* ສ - ຫ */
0x0ead, 0x0eae, /* ອ - ຮ */
0x0eb2, 0x0eb3, /* າ - ຳ */
0x0ec0, 0x0ec4, /* ເ - ໄ */
0x0edc, 0x0edd, /* ໜ - ໝ */
0x0f18, 0x0f19, /* ༘ - ༙ */
0x0f40, 0x0f47, /* ཀ - ཇ */
0x0f49, 0x0f69, /* ཉ - ཀྵ */
0x10d0, 0x10f6, /* ა - ჶ */
0x1100, 0x1159, /* ᄀ - ᅙ */
0x115f, 0x11a2, /* ᅟ - ᆢ */
0x11a8, 0x11f9, /* ᆨ - ᇹ */
0x1e00, 0x1e9b, /* Ḁ - ẛ */
0x1f50, 0x1f57, /* ὐ - ὗ */
0x1f80, 0x1fb4, /* ᾀ - ᾴ */
0x1fb6, 0x1fbc, /* ᾶ - ᾼ */
0x1fc2, 0x1fc4, /* ῂ - ῄ */
0x1fc6, 0x1fcc, /* ῆ - ῌ */
0x1fd0, 0x1fd3, /* ῐ - ΐ */
0x1fd6, 0x1fdb, /* ῖ - Ί */
0x1fe0, 0x1fec, /* ῠ - Ῥ */
0x1ff2, 0x1ff4, /* ῲ - ῴ */
0x1ff6, 0x1ffc, /* ῶ - ῼ */
0x210a, 0x2113, /* ℊ - ℓ */
0x2115, 0x211d, /* ℕ - ℝ */
0x2120, 0x2122, /* ℠ - ™ */
0x212a, 0x2131, /* K - ℱ */
0x2133, 0x2138, /* ℳ - ℸ */
0x3041, 0x3094, /* ぁ - ゔ */
0x30a1, 0x30fa, /* ァ - ヺ */
0x3105, 0x312c, /* ㄅ - ㄬ */
0x3131, 0x318e, /* ㄱ - ㆎ */
0x3192, 0x319f, /* ㆒ - ㆟ */
0x3260, 0x327b, /* ㉠ - ㉻ */
0x328a, 0x32b0, /* ㊊ - ㊰ */
0x32d0, 0x32fe, /* ㋐ - ㋾ */
0x3300, 0x3357, /* ㌀ - ㍗ */
0x3371, 0x3376, /* ㍱ - ㍶ */
0x337b, 0x3394, /* ㍻ - ㎔ */
0x3399, 0x339e, /* ㎙ - ㎞ */
0x33a9, 0x33ad, /* ㎩ - ㎭ */
0x33b0, 0x33c1, /* ㎰ - ㏁ */
0x33c3, 0x33c5, /* ㏃ - ㏅ */
0x33c7, 0x33d7, /* ㏇ - ㏗ */
0x33d9, 0x33dd, /* ㏙ - ㏝ */
0x4e00, 0x9fff, /* 一 - 鿿 */
0xac00, 0xd7a3, /* 가 - 힣 */
0xf900, 0xfb06, /* 豈 - st */
0xfb13, 0xfb17, /* ﬓ - ﬗ */
0xfb1f, 0xfb28, /* ײַ - ﬨ */
0xfb2a, 0xfb36, /* שׁ - זּ */
0xfb38, 0xfb3c, /* טּ - לּ */
0xfb40, 0xfb41, /* נּ - סּ */
0xfb43, 0xfb44, /* ףּ - פּ */
0xfb46, 0xfbb1, /* צּ - ﮱ */
0xfbd3, 0xfd3d, /* ﯓ - ﴽ */
0xfd50, 0xfd8f, /* ﵐ - ﶏ */
0xfd92, 0xfdc7, /* ﶒ - ﷇ */
0xfdf0, 0xfdf9, /* ﷰ - ﷹ */
0xfe70, 0xfe72, /* ﹰ - ﹲ */
0xfe76, 0xfefc, /* ﹶ - ﻼ */
0xff66, 0xff6f, /* ヲ - ッ */
0xff71, 0xff9d, /* ア - ン */
0xffa0, 0xffbe, /* ᅠ - ᄒ */
0xffc2, 0xffc7, /* ᅡ - ᅦ */
0xffca, 0xffcf, /* ᅧ - ᅬ */
0xffd2, 0xffd7, /* ᅭ - ᅲ */
0xffda, 0xffdc, /* ᅳ - ᅵ */
};
/*
* alpha singlets -
* only covers ranges not in lower||upper
*/
static
Rune __alpha1[] =
{
0x00aa, /* ª */
0x00b5, /* µ */
0x00ba, /* º */
0x03da, /* Ϛ */
0x03dc, /* Ϝ */
0x03de, /* Ϟ */
0x03e0, /* Ϡ */
0x06d5, /* ە */
0x09b2, /* ল */
0x0a5e, /* ਫ਼ */
0x0a8d, /* ઍ */
0x0ae0, /* ૠ */
0x0b9c, /* ஜ */
0x0cde, /* ೞ */
0x0e4f, /* ๏ */
0x0e84, /* ຄ */
0x0e8a, /* ຊ */
0x0e8d, /* ຍ */
0x0ea5, /* ລ */
0x0ea7, /* ວ */
0x0eb0, /* ະ */
0x0ebd, /* ຽ */
0x1fbe, /* ι */
0x207f, /* ⁿ */
0x20a8, /* ₨ */
0x2102, /* ℂ */
0x2107, /* ℇ */
0x2124, /* ℤ */
0x2126, /* Ω */
0x2128, /* ℨ */
0xfb3e, /* מּ */
0xfe74, /* ﹴ */
};
/*
* space ranges
*/
static
Rune __space2[] =
{
0x0009, 0x000a, /* tab and newline */
0x0020, 0x0020, /* space */
0x00a0, 0x00a0, /* */
0x2000, 0x200b, /* - */
0x2028, 0x2029, /*
-
*/
0x3000, 0x3000, /* */
0xfeff, 0xfeff, /* */
};
/*
* lower case ranges
* 3rd col is conversion excess 500
*/
static
Rune __toupper2[] =
{
0x0061, 0x007a, 468, /* a-z A-Z */
0x00e0, 0x00f6, 468, /* à-ö À-Ö */
0x00f8, 0x00fe, 468, /* ø-þ Ø-Þ */
0x0256, 0x0257, 295, /* ɖ-ɗ Ɖ-Ɗ */
0x0258, 0x0259, 298, /* ɘ-ə Ǝ-Ə */
0x028a, 0x028b, 283, /* ʊ-ʋ Ʊ-Ʋ */
0x03ad, 0x03af, 463, /* έ-ί Έ-Ί */
0x03b1, 0x03c1, 468, /* α-ρ Α-Ρ */
0x03c3, 0x03cb, 468, /* σ-ϋ Σ-Ϋ */
0x03cd, 0x03ce, 437, /* ύ-ώ Ύ-Ώ */
0x0430, 0x044f, 468, /* а-я А-Я */
0x0451, 0x045c, 420, /* ё-ќ Ё-Ќ */
0x045e, 0x045f, 420, /* ў-џ Ў-Џ */
0x0561, 0x0586, 452, /* ա-ֆ Ա-Ֆ */
0x1f00, 0x1f07, 508, /* ἀ-ἇ Ἀ-Ἇ */
0x1f10, 0x1f15, 508, /* ἐ-ἕ Ἐ-Ἕ */
0x1f20, 0x1f27, 508, /* ἠ-ἧ Ἠ-Ἧ */
0x1f30, 0x1f37, 508, /* ἰ-ἷ Ἰ-Ἷ */
0x1f40, 0x1f45, 508, /* ὀ-ὅ Ὀ-Ὅ */
0x1f60, 0x1f67, 508, /* ὠ-ὧ Ὠ-Ὧ */
0x1f70, 0x1f71, 574, /* ὰ-ά Ὰ-Ά */
0x1f72, 0x1f75, 586, /* ὲ-ή Ὲ-Ή */
0x1f76, 0x1f77, 600, /* ὶ-ί Ὶ-Ί */
0x1f78, 0x1f79, 628, /* ὸ-ό Ὸ-Ό */
0x1f7a, 0x1f7b, 612, /* ὺ-ύ Ὺ-Ύ */
0x1f7c, 0x1f7d, 626, /* ὼ-ώ Ὼ-Ώ */
0x1f80, 0x1f87, 508, /* ᾀ-ᾇ ᾈ-ᾏ */
0x1f90, 0x1f97, 508, /* ᾐ-ᾗ ᾘ-ᾟ */
0x1fa0, 0x1fa7, 508, /* ᾠ-ᾧ ᾨ-ᾯ */
0x1fb0, 0x1fb1, 508, /* ᾰ-ᾱ Ᾰ-Ᾱ */
0x1fd0, 0x1fd1, 508, /* ῐ-ῑ Ῐ-Ῑ */
0x1fe0, 0x1fe1, 508, /* ῠ-ῡ Ῠ-Ῡ */
0x2170, 0x217f, 484, /* ⅰ-ⅿ Ⅰ-Ⅿ */
0x24d0, 0x24e9, 474, /* ⓐ-ⓩ Ⓐ-Ⓩ */
0xff41, 0xff5a, 468, /* a-z A-Z */
};
/*
* lower case singlets
* 2nd col is conversion excess 500
*/
static
Rune __toupper1[] =
{
0x00ff, 621, /* ÿ Ÿ */
0x0101, 499, /* ā Ā */
0x0103, 499, /* ă Ă */
0x0105, 499, /* ą Ą */
0x0107, 499, /* ć Ć */
0x0109, 499, /* ĉ Ĉ */
0x010b, 499, /* ċ Ċ */
0x010d, 499, /* č Č */
0x010f, 499, /* ď Ď */
0x0111, 499, /* đ Đ */
0x0113, 499, /* ē Ē */
0x0115, 499, /* ĕ Ĕ */
0x0117, 499, /* ė Ė */
0x0119, 499, /* ę Ę */
0x011b, 499, /* ě Ě */
0x011d, 499, /* ĝ Ĝ */
0x011f, 499, /* ğ Ğ */
0x0121, 499, /* ġ Ġ */
0x0123, 499, /* ģ Ģ */
0x0125, 499, /* ĥ Ĥ */
0x0127, 499, /* ħ Ħ */
0x0129, 499, /* ĩ Ĩ */
0x012b, 499, /* ī Ī */
0x012d, 499, /* ĭ Ĭ */
0x012f, 499, /* į Į */
0x0131, 268, /* ı I */
0x0133, 499, /* ij IJ */
0x0135, 499, /* ĵ Ĵ */
0x0137, 499, /* ķ Ķ */
0x013a, 499, /* ĺ Ĺ */
0x013c, 499, /* ļ Ļ */
0x013e, 499, /* ľ Ľ */
0x0140, 499, /* ŀ Ŀ */
0x0142, 499, /* ł Ł */
0x0144, 499, /* ń Ń */
0x0146, 499, /* ņ Ņ */
0x0148, 499, /* ň Ň */
0x014b, 499, /* ŋ Ŋ */
0x014d, 499, /* ō Ō */
0x014f, 499, /* ŏ Ŏ */
0x0151, 499, /* ő Ő */
0x0153, 499, /* œ Œ */
0x0155, 499, /* ŕ Ŕ */
0x0157, 499, /* ŗ Ŗ */
0x0159, 499, /* ř Ř */
0x015b, 499, /* ś Ś */
0x015d, 499, /* ŝ Ŝ */
0x015f, 499, /* ş Ş */
0x0161, 499, /* š Š */
0x0163, 499, /* ţ Ţ */
0x0165, 499, /* ť Ť */
0x0167, 499, /* ŧ Ŧ */
0x0169, 499, /* ũ Ũ */
0x016b, 499, /* ū Ū */
0x016d, 499, /* ŭ Ŭ */
0x016f, 499, /* ů Ů */
0x0171, 499, /* ű Ű */
0x0173, 499, /* ų Ų */
0x0175, 499, /* ŵ Ŵ */
0x0177, 499, /* ŷ Ŷ */
0x017a, 499, /* ź Ź */
0x017c, 499, /* ż Ż */
0x017e, 499, /* ž Ž */
0x017f, 200, /* ſ S */
0x0183, 499, /* ƃ Ƃ */
0x0185, 499, /* ƅ Ƅ */
0x0188, 499, /* ƈ Ƈ */
0x018c, 499, /* ƌ Ƌ */
0x0192, 499, /* ƒ Ƒ */
0x0199, 499, /* ƙ Ƙ */
0x01a1, 499, /* ơ Ơ */
0x01a3, 499, /* ƣ Ƣ */
0x01a5, 499, /* ƥ Ƥ */
0x01a8, 499, /* ƨ Ƨ */
0x01ad, 499, /* ƭ Ƭ */
0x01b0, 499, /* ư Ư */
0x01b4, 499, /* ƴ Ƴ */
0x01b6, 499, /* ƶ Ƶ */
0x01b9, 499, /* ƹ Ƹ */
0x01bd, 499, /* ƽ Ƽ */
0x01c5, 499, /* Dž DŽ */
0x01c6, 498, /* dž DŽ */
0x01c8, 499, /* Lj LJ */
0x01c9, 498, /* lj LJ */
0x01cb, 499, /* Nj NJ */
0x01cc, 498, /* nj NJ */
0x01ce, 499, /* ǎ Ǎ */
0x01d0, 499, /* ǐ Ǐ */
0x01d2, 499, /* ǒ Ǒ */
0x01d4, 499, /* ǔ Ǔ */
0x01d6, 499, /* ǖ Ǖ */
0x01d8, 499, /* ǘ Ǘ */
0x01da, 499, /* ǚ Ǚ */
0x01dc, 499, /* ǜ Ǜ */
0x01df, 499, /* ǟ Ǟ */
0x01e1, 499, /* ǡ Ǡ */
0x01e3, 499, /* ǣ Ǣ */
0x01e5, 499, /* ǥ Ǥ */
0x01e7, 499, /* ǧ Ǧ */
0x01e9, 499, /* ǩ Ǩ */
0x01eb, 499, /* ǫ Ǫ */
0x01ed, 499, /* ǭ Ǭ */
0x01ef, 499, /* ǯ Ǯ */
0x01f2, 499, /* Dz DZ */
0x01f3, 498, /* dz DZ */
0x01f5, 499, /* ǵ Ǵ */
0x01fb, 499, /* ǻ Ǻ */
0x01fd, 499, /* ǽ Ǽ */
0x01ff, 499, /* ǿ Ǿ */
0x0201, 499, /* ȁ Ȁ */
0x0203, 499, /* ȃ Ȃ */
0x0205, 499, /* ȅ Ȅ */
0x0207, 499, /* ȇ Ȇ */
0x0209, 499, /* ȉ Ȉ */
0x020b, 499, /* ȋ Ȋ */
0x020d, 499, /* ȍ Ȍ */
0x020f, 499, /* ȏ Ȏ */
0x0211, 499, /* ȑ Ȑ */
0x0213, 499, /* ȓ Ȓ */
0x0215, 499, /* ȕ Ȕ */
0x0217, 499, /* ȗ Ȗ */
0x0253, 290, /* ɓ Ɓ */
0x0254, 294, /* ɔ Ɔ */
0x025b, 297, /* ɛ Ɛ */
0x0260, 295, /* ɠ Ɠ */
0x0263, 293, /* ɣ Ɣ */
0x0268, 291, /* ɨ Ɨ */
0x0269, 289, /* ɩ Ɩ */
0x026f, 289, /* ɯ Ɯ */
0x0272, 287, /* ɲ Ɲ */
0x0283, 282, /* ʃ Ʃ */
0x0288, 282, /* ʈ Ʈ */
0x0292, 281, /* ʒ Ʒ */
0x03ac, 462, /* ά Ά */
0x03cc, 436, /* ό Ό */
0x03d0, 438, /* ϐ Β */
0x03d1, 443, /* ϑ Θ */
0x03d5, 453, /* ϕ Φ */
0x03d6, 446, /* ϖ Π */
0x03e3, 499, /* ϣ Ϣ */
0x03e5, 499, /* ϥ Ϥ */
0x03e7, 499, /* ϧ Ϧ */
0x03e9, 499, /* ϩ Ϩ */
0x03eb, 499, /* ϫ Ϫ */
0x03ed, 499, /* ϭ Ϭ */
0x03ef, 499, /* ϯ Ϯ */
0x03f0, 414, /* ϰ Κ */
0x03f1, 420, /* ϱ Ρ */
0x0461, 499, /* ѡ Ѡ */
0x0463, 499, /* ѣ Ѣ */
0x0465, 499, /* ѥ Ѥ */
0x0467, 499, /* ѧ Ѧ */
0x0469, 499, /* ѩ Ѩ */
0x046b, 499, /* ѫ Ѫ */
0x046d, 499, /* ѭ Ѭ */
0x046f, 499, /* ѯ Ѯ */
0x0471, 499, /* ѱ Ѱ */
0x0473, 499, /* ѳ Ѳ */
0x0475, 499, /* ѵ Ѵ */
0x0477, 499, /* ѷ Ѷ */
0x0479, 499, /* ѹ Ѹ */
0x047b, 499, /* ѻ Ѻ */
0x047d, 499, /* ѽ Ѽ */
0x047f, 499, /* ѿ Ѿ */
0x0481, 499, /* ҁ Ҁ */
0x0491, 499, /* ґ Ґ */
0x0493, 499, /* ғ Ғ */
0x0495, 499, /* ҕ Ҕ */
0x0497, 499, /* җ Җ */
0x0499, 499, /* ҙ Ҙ */
0x049b, 499, /* қ Қ */
0x049d, 499, /* ҝ Ҝ */
0x049f, 499, /* ҟ Ҟ */
0x04a1, 499, /* ҡ Ҡ */
0x04a3, 499, /* ң Ң */
0x04a5, 499, /* ҥ Ҥ */
0x04a7, 499, /* ҧ Ҧ */
0x04a9, 499, /* ҩ Ҩ */
0x04ab, 499, /* ҫ Ҫ */
0x04ad, 499, /* ҭ Ҭ */
0x04af, 499, /* ү Ү */
0x04b1, 499, /* ұ Ұ */
0x04b3, 499, /* ҳ Ҳ */
0x04b5, 499, /* ҵ Ҵ */
0x04b7, 499, /* ҷ Ҷ */
0x04b9, 499, /* ҹ Ҹ */
0x04bb, 499, /* һ Һ */
0x04bd, 499, /* ҽ Ҽ */
0x04bf, 499, /* ҿ Ҿ */
0x04c2, 499, /* ӂ Ӂ */
0x04c4, 499, /* ӄ Ӄ */
0x04c8, 499, /* ӈ Ӈ */
0x04cc, 499, /* ӌ Ӌ */
0x04d1, 499, /* ӑ Ӑ */
0x04d3, 499, /* ӓ Ӓ */
0x04d5, 499, /* ӕ Ӕ */
0x04d7, 499, /* ӗ Ӗ */
0x04d9, 499, /* ә Ә */
0x04db, 499, /* ӛ Ӛ */
0x04dd, 499, /* ӝ Ӝ */
0x04df, 499, /* ӟ Ӟ */
0x04e1, 499, /* ӡ Ӡ */
0x04e3, 499, /* ӣ Ӣ */
0x04e5, 499, /* ӥ Ӥ */
0x04e7, 499, /* ӧ Ӧ */
0x04e9, 499, /* ө Ө */
0x04eb, 499, /* ӫ Ӫ */
0x04ef, 499, /* ӯ Ӯ */
0x04f1, 499, /* ӱ Ӱ */
0x04f3, 499, /* ӳ Ӳ */
0x04f5, 499, /* ӵ Ӵ */
0x04f9, 499, /* ӹ Ӹ */
0x1e01, 499, /* ḁ Ḁ */
0x1e03, 499, /* ḃ Ḃ */
0x1e05, 499, /* ḅ Ḅ */
0x1e07, 499, /* ḇ Ḇ */
0x1e09, 499, /* ḉ Ḉ */
0x1e0b, 499, /* ḋ Ḋ */
0x1e0d, 499, /* ḍ Ḍ */
0x1e0f, 499, /* ḏ Ḏ */
0x1e11, 499, /* ḑ Ḑ */
0x1e13, 499, /* ḓ Ḓ */
0x1e15, 499, /* ḕ Ḕ */
0x1e17, 499, /* ḗ Ḗ */
0x1e19, 499, /* ḙ Ḙ */
0x1e1b, 499, /* ḛ Ḛ */
0x1e1d, 499, /* ḝ Ḝ */
0x1e1f, 499, /* ḟ Ḟ */
0x1e21, 499, /* ḡ Ḡ */
0x1e23, 499, /* ḣ Ḣ */
0x1e25, 499, /* ḥ Ḥ */
0x1e27, 499, /* ḧ Ḧ */
0x1e29, 499, /* ḩ Ḩ */
0x1e2b, 499, /* ḫ Ḫ */
0x1e2d, 499, /* ḭ Ḭ */
0x1e2f, 499, /* ḯ Ḯ */
0x1e31, 499, /* ḱ Ḱ */
0x1e33, 499, /* ḳ Ḳ */
0x1e35, 499, /* ḵ Ḵ */
0x1e37, 499, /* ḷ Ḷ */
0x1e39, 499, /* ḹ Ḹ */
0x1e3b, 499, /* ḻ Ḻ */
0x1e3d, 499, /* ḽ Ḽ */
0x1e3f, 499, /* ḿ Ḿ */
0x1e41, 499, /* ṁ Ṁ */
0x1e43, 499, /* ṃ Ṃ */
0x1e45, 499, /* ṅ Ṅ */
0x1e47, 499, /* ṇ Ṇ */
0x1e49, 499, /* ṉ Ṉ */
0x1e4b, 499, /* ṋ Ṋ */
0x1e4d, 499, /* ṍ Ṍ */
0x1e4f, 499, /* ṏ Ṏ */
0x1e51, 499, /* ṑ Ṑ */
0x1e53, 499, /* ṓ Ṓ */
0x1e55, 499, /* ṕ Ṕ */
0x1e57, 499, /* ṗ Ṗ */
0x1e59, 499, /* ṙ Ṙ */
0x1e5b, 499, /* ṛ Ṛ */
0x1e5d, 499, /* ṝ Ṝ */
0x1e5f, 499, /* ṟ Ṟ */
0x1e61, 499, /* ṡ Ṡ */
0x1e63, 499, /* ṣ Ṣ */
0x1e65, 499, /* ṥ Ṥ */
0x1e67, 499, /* ṧ Ṧ */
0x1e69, 499, /* ṩ Ṩ */
0x1e6b, 499, /* ṫ Ṫ */
0x1e6d, 499, /* ṭ Ṭ */
0x1e6f, 499, /* ṯ Ṯ */
0x1e71, 499, /* ṱ Ṱ */
0x1e73, 499, /* ṳ Ṳ */
0x1e75, 499, /* ṵ Ṵ */
0x1e77, 499, /* ṷ Ṷ */
0x1e79, 499, /* ṹ Ṹ */
0x1e7b, 499, /* ṻ Ṻ */
0x1e7d, 499, /* ṽ Ṽ */
0x1e7f, 499, /* ṿ Ṿ */
0x1e81, 499, /* ẁ Ẁ */
0x1e83, 499, /* ẃ Ẃ */
0x1e85, 499, /* ẅ Ẅ */
0x1e87, 499, /* ẇ Ẇ */
0x1e89, 499, /* ẉ Ẉ */
0x1e8b, 499, /* ẋ Ẋ */
0x1e8d, 499, /* ẍ Ẍ */
0x1e8f, 499, /* ẏ Ẏ */
0x1e91, 499, /* ẑ Ẑ */
0x1e93, 499, /* ẓ Ẓ */
0x1e95, 499, /* ẕ Ẕ */
0x1ea1, 499, /* ạ Ạ */
0x1ea3, 499, /* ả Ả */
0x1ea5, 499, /* ấ Ấ */
0x1ea7, 499, /* ầ Ầ */
0x1ea9, 499, /* ẩ Ẩ */
0x1eab, 499, /* ẫ Ẫ */
0x1ead, 499, /* ậ Ậ */
0x1eaf, 499, /* ắ Ắ */
0x1eb1, 499, /* ằ Ằ */
0x1eb3, 499, /* ẳ Ẳ */
0x1eb5, 499, /* ẵ Ẵ */
0x1eb7, 499, /* ặ Ặ */
0x1eb9, 499, /* ẹ Ẹ */
0x1ebb, 499, /* ẻ Ẻ */
0x1ebd, 499, /* ẽ Ẽ */
0x1ebf, 499, /* ế Ế */
0x1ec1, 499, /* ề Ề */
0x1ec3, 499, /* ể Ể */
0x1ec5, 499, /* ễ Ễ */
0x1ec7, 499, /* ệ Ệ */
0x1ec9, 499, /* ỉ Ỉ */
0x1ecb, 499, /* ị Ị */
0x1ecd, 499, /* ọ Ọ */
0x1ecf, 499, /* ỏ Ỏ */
0x1ed1, 499, /* ố Ố */
0x1ed3, 499, /* ồ Ồ */
0x1ed5, 499, /* ổ Ổ */
0x1ed7, 499, /* ỗ Ỗ */
0x1ed9, 499, /* ộ Ộ */
0x1edb, 499, /* ớ Ớ */
0x1edd, 499, /* ờ Ờ */
0x1edf, 499, /* ở Ở */
0x1ee1, 499, /* ỡ Ỡ */
0x1ee3, 499, /* ợ Ợ */
0x1ee5, 499, /* ụ Ụ */
0x1ee7, 499, /* ủ Ủ */
0x1ee9, 499, /* ứ Ứ */
0x1eeb, 499, /* ừ Ừ */
0x1eed, 499, /* ử Ử */
0x1eef, 499, /* ữ Ữ */
0x1ef1, 499, /* ự Ự */
0x1ef3, 499, /* ỳ Ỳ */
0x1ef5, 499, /* ỵ Ỵ */
0x1ef7, 499, /* ỷ Ỷ */
0x1ef9, 499, /* ỹ Ỹ */
0x1f51, 508, /* ὑ Ὑ */
0x1f53, 508, /* ὓ Ὓ */
0x1f55, 508, /* ὕ Ὕ */
0x1f57, 508, /* ὗ Ὗ */
0x1fb3, 509, /* ᾳ ᾼ */
0x1fc3, 509, /* ῃ ῌ */
0x1fe5, 507, /* ῥ Ῥ */
0x1ff3, 509, /* ῳ ῼ */
};
/*
* upper case ranges
* 3rd col is conversion excess 500
*/
static
Rune __tolower2[] =
{
0x0041, 0x005a, 532, /* A-Z a-z */
0x00c0, 0x00d6, 532, /* À-Ö à-ö */
0x00d8, 0x00de, 532, /* Ø-Þ ø-þ */
0x0189, 0x018a, 705, /* Ɖ-Ɗ ɖ-ɗ */
0x018e, 0x018f, 702, /* Ǝ-Ə ɘ-ə */
0x01b1, 0x01b2, 717, /* Ʊ-Ʋ ʊ-ʋ */
0x0388, 0x038a, 537, /* Έ-Ί έ-ί */
0x038e, 0x038f, 563, /* Ύ-Ώ ύ-ώ */
0x0391, 0x03a1, 532, /* Α-Ρ α-ρ */
0x03a3, 0x03ab, 532, /* Σ-Ϋ σ-ϋ */
0x0401, 0x040c, 580, /* Ё-Ќ ё-ќ */
0x040e, 0x040f, 580, /* Ў-Џ ў-џ */
0x0410, 0x042f, 532, /* А-Я а-я */
0x0531, 0x0556, 548, /* Ա-Ֆ ա-ֆ */
0x10a0, 0x10c5, 548, /* Ⴀ-Ⴥ ა-ჵ */
0x1f08, 0x1f0f, 492, /* Ἀ-Ἇ ἀ-ἇ */
0x1f18, 0x1f1d, 492, /* Ἐ-Ἕ ἐ-ἕ */
0x1f28, 0x1f2f, 492, /* Ἠ-Ἧ ἠ-ἧ */
0x1f38, 0x1f3f, 492, /* Ἰ-Ἷ ἰ-ἷ */
0x1f48, 0x1f4d, 492, /* Ὀ-Ὅ ὀ-ὅ */
0x1f68, 0x1f6f, 492, /* Ὠ-Ὧ ὠ-ὧ */
0x1f88, 0x1f8f, 492, /* ᾈ-ᾏ ᾀ-ᾇ */
0x1f98, 0x1f9f, 492, /* ᾘ-ᾟ ᾐ-ᾗ */
0x1fa8, 0x1faf, 492, /* ᾨ-ᾯ ᾠ-ᾧ */
0x1fb8, 0x1fb9, 492, /* Ᾰ-Ᾱ ᾰ-ᾱ */
0x1fba, 0x1fbb, 426, /* Ὰ-Ά ὰ-ά */
0x1fc8, 0x1fcb, 414, /* Ὲ-Ή ὲ-ή */
0x1fd8, 0x1fd9, 492, /* Ῐ-Ῑ ῐ-ῑ */
0x1fda, 0x1fdb, 400, /* Ὶ-Ί ὶ-ί */
0x1fe8, 0x1fe9, 492, /* Ῠ-Ῡ ῠ-ῡ */
0x1fea, 0x1feb, 388, /* Ὺ-Ύ ὺ-ύ */
0x1ff8, 0x1ff9, 372, /* Ὸ-Ό ὸ-ό */
0x1ffa, 0x1ffb, 374, /* Ὼ-Ώ ὼ-ώ */
0x2160, 0x216f, 516, /* Ⅰ-Ⅿ ⅰ-ⅿ */
0x24b6, 0x24cf, 526, /* Ⓐ-Ⓩ ⓐ-ⓩ */
0xff21, 0xff3a, 532, /* A-Z a-z */
};
/*
* upper case singlets
* 2nd col is conversion excess 500
*/
static
Rune __tolower1[] =
{
0x0100, 501, /* Ā ā */
0x0102, 501, /* Ă ă */
0x0104, 501, /* Ą ą */
0x0106, 501, /* Ć ć */
0x0108, 501, /* Ĉ ĉ */
0x010a, 501, /* Ċ ċ */
0x010c, 501, /* Č č */
0x010e, 501, /* Ď ď */
0x0110, 501, /* Đ đ */
0x0112, 501, /* Ē ē */
0x0114, 501, /* Ĕ ĕ */
0x0116, 501, /* Ė ė */
0x0118, 501, /* Ę ę */
0x011a, 501, /* Ě ě */
0x011c, 501, /* Ĝ ĝ */
0x011e, 501, /* Ğ ğ */
0x0120, 501, /* Ġ ġ */
0x0122, 501, /* Ģ ģ */
0x0124, 501, /* Ĥ ĥ */
0x0126, 501, /* Ħ ħ */
0x0128, 501, /* Ĩ ĩ */
0x012a, 501, /* Ī ī */
0x012c, 501, /* Ĭ ĭ */
0x012e, 501, /* Į į */
0x0130, 301, /* İ i */
0x0132, 501, /* IJ ij */
0x0134, 501, /* Ĵ ĵ */
0x0136, 501, /* Ķ ķ */
0x0139, 501, /* Ĺ ĺ */
0x013b, 501, /* Ļ ļ */
0x013d, 501, /* Ľ ľ */
0x013f, 501, /* Ŀ ŀ */
0x0141, 501, /* Ł ł */
0x0143, 501, /* Ń ń */
0x0145, 501, /* Ņ ņ */
0x0147, 501, /* Ň ň */
0x014a, 501, /* Ŋ ŋ */
0x014c, 501, /* Ō ō */
0x014e, 501, /* Ŏ ŏ */
0x0150, 501, /* Ő ő */
0x0152, 501, /* Œ œ */
0x0154, 501, /* Ŕ ŕ */
0x0156, 501, /* Ŗ ŗ */
0x0158, 501, /* Ř ř */
0x015a, 501, /* Ś ś */
0x015c, 501, /* Ŝ ŝ */
0x015e, 501, /* Ş ş */
0x0160, 501, /* Š š */
0x0162, 501, /* Ţ ţ */
0x0164, 501, /* Ť ť */
0x0166, 501, /* Ŧ ŧ */
0x0168, 501, /* Ũ ũ */
0x016a, 501, /* Ū ū */
0x016c, 501, /* Ŭ ŭ */
0x016e, 501, /* Ů ů */
0x0170, 501, /* Ű ű */
0x0172, 501, /* Ų ų */
0x0174, 501, /* Ŵ ŵ */
0x0176, 501, /* Ŷ ŷ */
0x0178, 379, /* Ÿ ÿ */
0x0179, 501, /* Ź ź */
0x017b, 501, /* Ż ż */
0x017d, 501, /* Ž ž */
0x0181, 710, /* Ɓ ɓ */
0x0182, 501, /* Ƃ ƃ */
0x0184, 501, /* Ƅ ƅ */
0x0186, 706, /* Ɔ ɔ */
0x0187, 501, /* Ƈ ƈ */
0x018b, 501, /* Ƌ ƌ */
0x0190, 703, /* Ɛ ɛ */
0x0191, 501, /* Ƒ ƒ */
0x0193, 705, /* Ɠ ɠ */
0x0194, 707, /* Ɣ ɣ */
0x0196, 711, /* Ɩ ɩ */
0x0197, 709, /* Ɨ ɨ */
0x0198, 501, /* Ƙ ƙ */
0x019c, 711, /* Ɯ ɯ */
0x019d, 713, /* Ɲ ɲ */
0x01a0, 501, /* Ơ ơ */
0x01a2, 501, /* Ƣ ƣ */
0x01a4, 501, /* Ƥ ƥ */
0x01a7, 501, /* Ƨ ƨ */
0x01a9, 718, /* Ʃ ʃ */
0x01ac, 501, /* Ƭ ƭ */
0x01ae, 718, /* Ʈ ʈ */
0x01af, 501, /* Ư ư */
0x01b3, 501, /* Ƴ ƴ */
0x01b5, 501, /* Ƶ ƶ */
0x01b7, 719, /* Ʒ ʒ */
0x01b8, 501, /* Ƹ ƹ */
0x01bc, 501, /* Ƽ ƽ */
0x01c4, 502, /* DŽ dž */
0x01c5, 501, /* Dž dž */
0x01c7, 502, /* LJ lj */
0x01c8, 501, /* Lj lj */
0x01ca, 502, /* NJ nj */
0x01cb, 501, /* Nj nj */
0x01cd, 501, /* Ǎ ǎ */
0x01cf, 501, /* Ǐ ǐ */
0x01d1, 501, /* Ǒ ǒ */
0x01d3, 501, /* Ǔ ǔ */
0x01d5, 501, /* Ǖ ǖ */
0x01d7, 501, /* Ǘ ǘ */
0x01d9, 501, /* Ǚ ǚ */
0x01db, 501, /* Ǜ ǜ */
0x01de, 501, /* Ǟ ǟ */
0x01e0, 501, /* Ǡ ǡ */
0x01e2, 501, /* Ǣ ǣ */
0x01e4, 501, /* Ǥ ǥ */
0x01e6, 501, /* Ǧ ǧ */
0x01e8, 501, /* Ǩ ǩ */
0x01ea, 501, /* Ǫ ǫ */
0x01ec, 501, /* Ǭ ǭ */
0x01ee, 501, /* Ǯ ǯ */
0x01f1, 502, /* DZ dz */
0x01f2, 501, /* Dz dz */
0x01f4, 501, /* Ǵ ǵ */
0x01fa, 501, /* Ǻ ǻ */
0x01fc, 501, /* Ǽ ǽ */
0x01fe, 501, /* Ǿ ǿ */
0x0200, 501, /* Ȁ ȁ */
0x0202, 501, /* Ȃ ȃ */
0x0204, 501, /* Ȅ ȅ */
0x0206, 501, /* Ȇ ȇ */
0x0208, 501, /* Ȉ ȉ */
0x020a, 501, /* Ȋ ȋ */
0x020c, 501, /* Ȍ ȍ */
0x020e, 501, /* Ȏ ȏ */
0x0210, 501, /* Ȑ ȑ */
0x0212, 501, /* Ȓ ȓ */
0x0214, 501, /* Ȕ ȕ */
0x0216, 501, /* Ȗ ȗ */
0x0386, 538, /* Ά ά */
0x038c, 564, /* Ό ό */
0x03e2, 501, /* Ϣ ϣ */
0x03e4, 501, /* Ϥ ϥ */
0x03e6, 501, /* Ϧ ϧ */
0x03e8, 501, /* Ϩ ϩ */
0x03ea, 501, /* Ϫ ϫ */
0x03ec, 501, /* Ϭ ϭ */
0x03ee, 501, /* Ϯ ϯ */
0x0460, 501, /* Ѡ ѡ */
0x0462, 501, /* Ѣ ѣ */
0x0464, 501, /* Ѥ ѥ */
0x0466, 501, /* Ѧ ѧ */
0x0468, 501, /* Ѩ ѩ */
0x046a, 501, /* Ѫ ѫ */
0x046c, 501, /* Ѭ ѭ */
0x046e, 501, /* Ѯ ѯ */
0x0470, 501, /* Ѱ ѱ */
0x0472, 501, /* Ѳ ѳ */
0x0474, 501, /* Ѵ ѵ */
0x0476, 501, /* Ѷ ѷ */
0x0478, 501, /* Ѹ ѹ */
0x047a, 501, /* Ѻ ѻ */
0x047c, 501, /* Ѽ ѽ */
0x047e, 501, /* Ѿ ѿ */
0x0480, 501, /* Ҁ ҁ */
0x0490, 501, /* Ґ ґ */
0x0492, 501, /* Ғ ғ */
0x0494, 501, /* Ҕ ҕ */
0x0496, 501, /* Җ җ */
0x0498, 501, /* Ҙ ҙ */
0x049a, 501, /* Қ қ */
0x049c, 501, /* Ҝ ҝ */
0x049e, 501, /* Ҟ ҟ */
0x04a0, 501, /* Ҡ ҡ */
0x04a2, 501, /* Ң ң */
0x04a4, 501, /* Ҥ ҥ */
0x04a6, 501, /* Ҧ ҧ */
0x04a8, 501, /* Ҩ ҩ */
0x04aa, 501, /* Ҫ ҫ */
0x04ac, 501, /* Ҭ ҭ */
0x04ae, 501, /* Ү ү */
0x04b0, 501, /* Ұ ұ */
0x04b2, 501, /* Ҳ ҳ */
0x04b4, 501, /* Ҵ ҵ */
0x04b6, 501, /* Ҷ ҷ */
0x04b8, 501, /* Ҹ ҹ */
0x04ba, 501, /* Һ һ */
0x04bc, 501, /* Ҽ ҽ */
0x04be, 501, /* Ҿ ҿ */
0x04c1, 501, /* Ӂ ӂ */
0x04c3, 501, /* Ӄ ӄ */
0x04c7, 501, /* Ӈ ӈ */
0x04cb, 501, /* Ӌ ӌ */
0x04d0, 501, /* Ӑ ӑ */
0x04d2, 501, /* Ӓ ӓ */
0x04d4, 501, /* Ӕ ӕ */
0x04d6, 501, /* Ӗ ӗ */
0x04d8, 501, /* Ә ә */
0x04da, 501, /* Ӛ ӛ */
0x04dc, 501, /* Ӝ ӝ */
0x04de, 501, /* Ӟ ӟ */
0x04e0, 501, /* Ӡ ӡ */
0x04e2, 501, /* Ӣ ӣ */
0x04e4, 501, /* Ӥ ӥ */
0x04e6, 501, /* Ӧ ӧ */
0x04e8, 501, /* Ө ө */
0x04ea, 501, /* Ӫ ӫ */
0x04ee, 501, /* Ӯ ӯ */
0x04f0, 501, /* Ӱ ӱ */
0x04f2, 501, /* Ӳ ӳ */
0x04f4, 501, /* Ӵ ӵ */
0x04f8, 501, /* Ӹ ӹ */
0x1e00, 501, /* Ḁ ḁ */
0x1e02, 501, /* Ḃ ḃ */
0x1e04, 501, /* Ḅ ḅ */
0x1e06, 501, /* Ḇ ḇ */
0x1e08, 501, /* Ḉ ḉ */
0x1e0a, 501, /* Ḋ ḋ */
0x1e0c, 501, /* Ḍ ḍ */
0x1e0e, 501, /* Ḏ ḏ */
0x1e10, 501, /* Ḑ ḑ */
0x1e12, 501, /* Ḓ ḓ */
0x1e14, 501, /* Ḕ ḕ */
0x1e16, 501, /* Ḗ ḗ */
0x1e18, 501, /* Ḙ ḙ */
0x1e1a, 501, /* Ḛ ḛ */
0x1e1c, 501, /* Ḝ ḝ */
0x1e1e, 501, /* Ḟ ḟ */
0x1e20, 501, /* Ḡ ḡ */
0x1e22, 501, /* Ḣ ḣ */
0x1e24, 501, /* Ḥ ḥ */
0x1e26, 501, /* Ḧ ḧ */
0x1e28, 501, /* Ḩ ḩ */
0x1e2a, 501, /* Ḫ ḫ */
0x1e2c, 501, /* Ḭ ḭ */
0x1e2e, 501, /* Ḯ ḯ */
0x1e30, 501, /* Ḱ ḱ */
0x1e32, 501, /* Ḳ ḳ */
0x1e34, 501, /* Ḵ ḵ */
0x1e36, 501, /* Ḷ ḷ */
0x1e38, 501, /* Ḹ ḹ */
0x1e3a, 501, /* Ḻ ḻ */
0x1e3c, 501, /* Ḽ ḽ */
0x1e3e, 501, /* Ḿ ḿ */
0x1e40, 501, /* Ṁ ṁ */
0x1e42, 501, /* Ṃ ṃ */
0x1e44, 501, /* Ṅ ṅ */
0x1e46, 501, /* Ṇ ṇ */
0x1e48, 501, /* Ṉ ṉ */
0x1e4a, 501, /* Ṋ ṋ */
0x1e4c, 501, /* Ṍ ṍ */
0x1e4e, 501, /* Ṏ ṏ */
0x1e50, 501, /* Ṑ ṑ */
0x1e52, 501, /* Ṓ ṓ */
0x1e54, 501, /* Ṕ ṕ */
0x1e56, 501, /* Ṗ ṗ */
0x1e58, 501, /* Ṙ ṙ */
0x1e5a, 501, /* Ṛ ṛ */
0x1e5c, 501, /* Ṝ ṝ */
0x1e5e, 501, /* Ṟ ṟ */
0x1e60, 501, /* Ṡ ṡ */
0x1e62, 501, /* Ṣ ṣ */
0x1e64, 501, /* Ṥ ṥ */
0x1e66, 501, /* Ṧ ṧ */
0x1e68, 501, /* Ṩ ṩ */
0x1e6a, 501, /* Ṫ ṫ */
0x1e6c, 501, /* Ṭ ṭ */
0x1e6e, 501, /* Ṯ ṯ */
0x1e70, 501, /* Ṱ ṱ */
0x1e72, 501, /* Ṳ ṳ */
0x1e74, 501, /* Ṵ ṵ */
0x1e76, 501, /* Ṷ ṷ */
0x1e78, 501, /* Ṹ ṹ */
0x1e7a, 501, /* Ṻ ṻ */
0x1e7c, 501, /* Ṽ ṽ */
0x1e7e, 501, /* Ṿ ṿ */
0x1e80, 501, /* Ẁ ẁ */
0x1e82, 501, /* Ẃ ẃ */
0x1e84, 501, /* Ẅ ẅ */
0x1e86, 501, /* Ẇ ẇ */
0x1e88, 501, /* Ẉ ẉ */
0x1e8a, 501, /* Ẋ ẋ */
0x1e8c, 501, /* Ẍ ẍ */
0x1e8e, 501, /* Ẏ ẏ */
0x1e90, 501, /* Ẑ ẑ */
0x1e92, 501, /* Ẓ ẓ */
0x1e94, 501, /* Ẕ ẕ */
0x1ea0, 501, /* Ạ ạ */
0x1ea2, 501, /* Ả ả */
0x1ea4, 501, /* Ấ ấ */
0x1ea6, 501, /* Ầ ầ */
0x1ea8, 501, /* Ẩ ẩ */
0x1eaa, 501, /* Ẫ ẫ */
0x1eac, 501, /* Ậ ậ */
0x1eae, 501, /* Ắ ắ */
0x1eb0, 501, /* Ằ ằ */
0x1eb2, 501, /* Ẳ ẳ */
0x1eb4, 501, /* Ẵ ẵ */
0x1eb6, 501, /* Ặ ặ */
0x1eb8, 501, /* Ẹ ẹ */
0x1eba, 501, /* Ẻ ẻ */
0x1ebc, 501, /* Ẽ ẽ */
0x1ebe, 501, /* Ế ế */
0x1ec0, 501, /* Ề ề */
0x1ec2, 501, /* Ể ể */
0x1ec4, 501, /* Ễ ễ */
0x1ec6, 501, /* Ệ ệ */
0x1ec8, 501, /* Ỉ ỉ */
0x1eca, 501, /* Ị ị */
0x1ecc, 501, /* Ọ ọ */
0x1ece, 501, /* Ỏ ỏ */
0x1ed0, 501, /* Ố ố */
0x1ed2, 501, /* Ồ ồ */
0x1ed4, 501, /* Ổ ổ */
0x1ed6, 501, /* Ỗ ỗ */
0x1ed8, 501, /* Ộ ộ */
0x1eda, 501, /* Ớ ớ */
0x1edc, 501, /* Ờ ờ */
0x1ede, 501, /* Ở ở */
0x1ee0, 501, /* Ỡ ỡ */
0x1ee2, 501, /* Ợ ợ */
0x1ee4, 501, /* Ụ ụ */
0x1ee6, 501, /* Ủ ủ */
0x1ee8, 501, /* Ứ ứ */
0x1eea, 501, /* Ừ ừ */
0x1eec, 501, /* Ử ử */
0x1eee, 501, /* Ữ ữ */
0x1ef0, 501, /* Ự ự */
0x1ef2, 501, /* Ỳ ỳ */
0x1ef4, 501, /* Ỵ ỵ */
0x1ef6, 501, /* Ỷ ỷ */
0x1ef8, 501, /* Ỹ ỹ */
0x1f59, 492, /* Ὑ ὑ */
0x1f5b, 492, /* Ὓ ὓ */
0x1f5d, 492, /* Ὕ ὕ */
0x1f5f, 492, /* Ὗ ὗ */
0x1fbc, 491, /* ᾼ ᾳ */
0x1fcc, 491, /* ῌ ῃ */
0x1fec, 493, /* Ῥ ῥ */
0x1ffc, 491, /* ῼ ῳ */
};
/*
* title characters are those between
* upper and lower case. ie DZ Dz dz
*/
static
Rune __totitle1[] =
{
0x01c4, 501, /* DŽ Dž */
0x01c6, 499, /* dž Dž */
0x01c7, 501, /* LJ Lj */
0x01c9, 499, /* lj Lj */
0x01ca, 501, /* NJ Nj */
0x01cc, 499, /* nj Nj */
0x01f1, 501, /* DZ Dz */
0x01f3, 499, /* dz Dz */
};
static Rune*
bsearch(Rune c, Rune *t, int n, int ne)
{
Rune *p;
int m;
while(n > 1) {
m = n/2;
p = t + m*ne;
if(c >= p[0]) {
t = p;
n = n-m;
} else
n = m;
}
if(n && c >= t[0])
return t;
return 0;
}
Rune
tolowerrune(Rune c)
{
Rune *p;
p = bsearch(c, __tolower2, nelem(__tolower2)/3, 3);
if(p && c >= p[0] && c <= p[1])
return c + p[2] - 500;
p = bsearch(c, __tolower1, nelem(__tolower1)/2, 2);
if(p && c == p[0])
return c + p[1] - 500;
return c;
}
Rune
toupperrune(Rune c)
{
Rune *p;
p = bsearch(c, __toupper2, nelem(__toupper2)/3, 3);
if(p && c >= p[0] && c <= p[1])
return c + p[2] - 500;
p = bsearch(c, __toupper1, nelem(__toupper1)/2, 2);
if(p && c == p[0])
return c + p[1] - 500;
return c;
}
Rune
totitlerune(Rune c)
{
Rune *p;
p = bsearch(c, __totitle1, nelem(__totitle1)/2, 2);
if(p && c == p[0])
return c + p[1] - 500;
return c;
}
int
islowerrune(Rune c)
{
Rune *p;
p = bsearch(c, __toupper2, nelem(__toupper2)/3, 3);
if(p && c >= p[0] && c <= p[1])
return 1;
p = bsearch(c, __toupper1, nelem(__toupper1)/2, 2);
if(p && c == p[0])
return 1;
return 0;
}
int
isupperrune(Rune c)
{
Rune *p;
p = bsearch(c, __tolower2, nelem(__tolower2)/3, 3);
if(p && c >= p[0] && c <= p[1])
return 1;
p = bsearch(c, __tolower1, nelem(__tolower1)/2, 2);
if(p && c == p[0])
return 1;
return 0;
}
int
isalpharune(Rune c)
{
Rune *p;
if(isupperrune(c) || islowerrune(c))
return 1;
p = bsearch(c, __alpha2, nelem(__alpha2)/2, 2);
if(p && c >= p[0] && c <= p[1])
return 1;
p = bsearch(c, __alpha1, nelem(__alpha1), 1);
if(p && c == p[0])
return 1;
return 0;
}
int
istitlerune(Rune c)
{
return isupperrune(c) && islowerrune(c);
}
int
isspacerune(Rune c)
{
Rune *p;
p = bsearch(c, __space2, nelem(__space2)/2, 2);
if(p && c >= p[0] && c <= p[1])
return 1;
return 0;
}
|
Added lib/libutf/utf.7.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | .deEX .ift .ft5 .nf .. .deEE .ft1 .fi .. .TH UTF 7 .SH NAME UTF, Unicode, ASCII, rune \- character set and format .SH DESCRIPTION The Plan 9 character set and representation are based on the Unicode Standard and on the ISO multibyte .SM UTF-8 encoding (Universal Character Set Transformation Format, 8 bits wide). The Unicode Standard represents its characters in 16 bits; .SM UTF-8 represents such values in an 8-bit byte stream. Throughout this manual, .SM UTF-8 is shortened to .SM UTF. .PP In Plan 9, a .I rune is a 16-bit quantity representing a Unicode character. Internally, programs may store characters as runes. However, any external manifestation of textual information, in files or at the interface between programs, uses a machine-independent, byte-stream encoding called .SM UTF. .PP .SM UTF is designed so the 7-bit .SM ASCII set (values hexadecimal 00 to 7F), appear only as themselves in the encoding. Runes with values above 7F appear as sequences of two or more bytes with values only from 80 to FF. .PP The .SM UTF encoding of the Unicode Standard is backward compatible with .SM ASCII\c : programs presented only with .SM ASCII work on Plan 9 even if not written to deal with .SM UTF, as do programs that deal with uninterpreted byte streams. However, programs that perform semantic processing on .SM ASCII graphic characters must convert from .SM UTF to runes in order to work properly with non-\c .SM ASCII input. See .IR rune (3). .PP Letting numbers be binary, a rune x is converted to a multibyte .SM UTF sequence as follows: .PP 01. x in [00000000.0bbbbbbb] → 0bbbbbbb .br 10. x in [00000bbb.bbbbbbbb] → 110bbbbb, 10bbbbbb .br 11. x in [bbbbbbbb.bbbbbbbb] → 1110bbbb, 10bbbbbb, 10bbbbbb .br .PP Conversion 01 provides a one-byte sequence that spans the .SM ASCII character set in a compatible way. Conversions 10 and 11 represent higher-valued characters as sequences of two or three bytes with the high bit set. Plan 9 does not support the 4, 5, and 6 byte sequences proposed by X-Open. When there are multiple ways to encode a value, for example rune 0, the shortest encoding is used. .PP In the inverse mapping, any sequence except those described above is incorrect and is converted to rune hexadecimal 0080. .SH "SEE ALSO" .IR ascii (1), .IR tcs (1), .IR rune (3), .IR "The Unicode Standard" . |
Added lib/libutf/utfecpy.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
char*
utfecpy(char *to, char *e, const char *from)
{
char *end;
if(to >= e)
return to;
end = memccpy(to, from, '\0', e - to);
if(end == nil){
end = e-1;
while(end>to && (*--end&0xC0)==0x80)
;
*end = '\0';
}else{
end--;
}
return end;
}
|
Added lib/libutf/utflen.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
int
utflen(const char *s)
{
int c;
long n;
Rune rune;
n = 0;
for(;;) {
c = *(uchar*)s;
if(c < Runeself) {
if(c == 0)
return n;
s++;
} else
s += chartorune(&rune, s);
n++;
}
}
|
Added lib/libutf/utfnlen.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
int
utfnlen(const char *s, long m)
{
int c;
long n;
Rune rune;
const char *es;
es = s + m;
for(n = 0; s < es; n++) {
c = *(uchar*)s;
if(c < Runeself){
if(c == '\0')
break;
s++;
continue;
}
if(!fullrune(s, es-s))
break;
s += chartorune(&rune, s);
}
return n;
}
|
Added lib/libutf/utfrrune.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
char*
utfrrune(const char *s, long c)
{
long c1;
Rune r;
const char *s1;
if(c < Runesync) /* not part of utf sequence */
return strrchr(s, c);
s1 = 0;
for(;;) {
c1 = *(uchar*)s;
if(c1 < Runeself) { /* one byte rune */
if(c1 == 0)
return (char*)s1;
if(c1 == c)
s1 = s;
s++;
continue;
}
c1 = chartorune(&r, s);
if(r == c)
s1 = s;
s += c1;
}
}
|
Added lib/libutf/utfrune.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
char*
utfrune(const char *s, long c)
{
long c1;
Rune r;
int n;
if(c < Runesync) /* not part of utf sequence */
return strchr(s, c);
for(;;) {
c1 = *(uchar*)s;
if(c1 < Runeself) { /* one byte rune */
if(c1 == 0)
return 0;
if(c1 == c)
return (char*)s;
s++;
continue;
}
n = chartorune(&r, s);
if(r == c)
return (char*)s;
s += n;
}
}
|
Added lib/libutf/utfutf.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "utf.h"
/*
* Return pointer to first occurrence of s2 in s1,
* 0 if none
*/
char*
utfutf(const char *s1, const char *s2)
{
const char *p;
long f, n1, n2;
Rune r;
n1 = chartorune(&r, s2);
f = r;
if(f <= Runesync) /* represents self */
return strstr(s1, s2);
n2 = strlen(s2);
for(p=s1; p=utfrune(p, f); p+=n1)
if(strncmp(p, s2, n2) == 0)
return (char*)p;
return 0;
}
|
Added lib/libwmii_hack/Makefile.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ROOT= ../.. include $(ROOT)/mk/hdr.mk hack.o hack.o_pic: util.c hack.h x11.h CFLAGS += $(INCX11) SOLDFLAGS += $(LIBX11) TARG = libwmii_hack # Can't just link libstuff here. We need PIC objects. OBJ = hack \ ../libstuff/util/getbase \ ../libstuff/util/getlong \ ../libstuff/util/tokenize include $(ROOT)/mk/so.mk |
Added lib/libwmii_hack/hack.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
/* Copyright ©2008 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include "hack.h"
#include <dlfcn.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "util.c"
#include "x11.c"
enum {
Timeout = 10,
};
static void* xlib;
static long transient;
static Atom types[32];
static long ntypes;
static char** tags;
static long pid;
static long stime;
static char hostname[256];
static long starttime;
typedef Window (*mapfn)(Display*, Window);
static Window (*mapwindow)(Display*, Window);
static Window (*mapraised)(Display*, Window);
static void
init(Display *d) { /* Hrm... assumes one display... */
char *toks[nelem(types)];
char *s, *p;
long n;
int i;
xlib = dlopen("libX11.so", RTLD_GLOBAL | RTLD_LAZY);
if(xlib == nil)
return;
mapwindow = (mapfn)(uintptr_t)dlsym(xlib, "XMapWindow");
mapraised = (mapfn)(uintptr_t)dlsym(xlib, "XMapRaised");
unsetenv("LD_PRELOAD");
if((s = getenv("WMII_HACK_TRANSIENT"))) {
if(getlong(s, &n))
transient = n;
unsetenv("WMII_HACK_TRANSIENT");
}
if((s = getenv("WMII_HACK_TYPE"))) {
s = strdup(s);
unsetenv("WMII_HACK_TYPE");
n = tokenize(toks, nelem(toks), s, ',');
for(i=0; i < n; i++) {
for(p=toks[i]; *p; p++)
if(*p >= 'a' && *p <= 'z')
*p += 'A' - 'a';
toks[i] = smprint("_NET_WM_WINDOW_TYPE_%s", toks[i]);
}
XInternAtoms(d, toks, n, false, types);
ntypes = n;
for(i=0; i < n; i++)
free(toks[i]);
free(s);
}
if((s = getenv("WMII_HACK_TAGS"))) {
s = strdup(s);
unsetenv("WMII_HACK_TAGS");
n = tokenize(toks, nelem(toks)-1, s, '+');
tags = strlistdup(toks, n);
free(s);
}
if((s = getenv("WMII_HACK_TIME"))) {
getlong(s, &stime);
unsetenv("WMII_HACK_TIME");
}
pid = getpid();
gethostname(hostname, sizeof hostname - 1);
}
static void
setprops(Display *d, Window w) {
long *l;
if(!xlib)
init(d);
if(getprop_long(d, w, "_NET_WM_PID", "CARDINAL", 0L, &l, 1L))
free(l);
else {
changeprop_long(d, w, "_NET_WM_PID", "CARDINAL", &pid, 1);
changeprop_string(d, w, "WM_CLIENT_MACHINE", hostname);
}
/* Kludge. */
if(starttime == 0)
starttime = time(0);
else if(time(0) > starttime + Timeout)
return;
if(transient)
changeprop_long(d, w, "WM_TRANSIENT_FOR", "WINDOW", &transient, 1);
if(ntypes)
changeprop_long(d, w, "_NET_WM_WINDOW_TYPE", "ATOM", (long*)types, ntypes);
if(tags)
changeprop_textlist(d, w, "_WMII_TAGS", "UTF8_STRING", tags);
if(stime)
changeprop_long(d, w, "_WMII_LAUNCH_TIME", "CARDINAL", &stime, 1);
}
int
XMapWindow(Display *d, Window w) {
setprops(d, w);
return mapwindow(d, w);
}
int
XMapRaised(Display *d, Window w) {
setprops(d, w);
return mapraised(d, w);
}
|
Added lib/libwmii_hack/hack.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | typedef unsigned long ulong; typedef unsigned int uint; typedef unsigned char uchar; #define _XOPEN_SOURCE 600 #define IXP_P9_STRUCTS #define IXP_NO_P9_ #include <assert.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <stuff/util.h> #include <X11/Xlib.h> #define strdup my_strdup #define smprint my_smprint #define vsmprint my_vsmprint static char* smprint(const char*, ...); static char* vsmprint(const char*, va_list); static char* strdup(const char*); #define nil ((void*)0) #define nelem(ary) (sizeof(ary) / sizeof(*ary)) |
Added lib/libwmii_hack/util.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include <ctype.h>
#include <stdio.h>
#include <string.h>
static char*
vsmprint(const char *fmt, va_list ap) {
va_list al;
char *buf = "";
int n;
va_copy(al, ap);
n = vsnprintf(buf, 0, fmt, al);
va_end(al);
buf = malloc(++n);
if(buf)
vsnprintf(buf, n, fmt, ap);
return buf;
}
static char*
smprint(const char *fmt, ...) {
va_list ap;
char *ret;
va_start(ap, fmt);
ret = vsmprint(fmt, ap);
va_end(ap);
return ret;
}
static char*
strdup(const char *s) {
char *ret;
int len;
len = strlen(s)+1;
ret = malloc(len);
if(ret)
memcpy(ret, s, len);
return ret;
}
|
Added lib/libwmii_hack/x11.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
/* Copyright ©2007 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <assert.h>
#include "x11.h"
/* Misc */
static Atom
xatom(Display *display, char *name) {
/* Blech. I don't trust Xlib's cacheing.
MapEnt *e;
e = hash_get(&amap, name, 1);
if(e->val == nil)
e->val = (void*)XInternAtom(display, name, False);
return (Atom)e->val;
*/
return XInternAtom(display, name, False);
}
/* Properties */
#if 0
static void
delproperty(Display *display, Window w, char *prop) {
XDeleteProperty(display, w, xatom(display, prop));
}
#endif
static void
changeproperty(Display *display, Window w, char *prop, char *type, int width, uchar data[], int n) {
XChangeProperty(display, w, xatom(display, prop), xatom(display, type), width, PropModeReplace, data, n);
}
static void
changeprop_string(Display *display, Window w, char *prop, char *string) {
changeprop_char(display, w, prop, "UTF8_STRING", string, strlen(string));
}
static void
changeprop_char(Display *display, Window w, char *prop, char *type, char data[], int len) {
changeproperty(display, w, prop, type, 8, (uchar*)data, len);
}
#if 0
static void
changeprop_short(Display *display, Window w, char *prop, char *type, short data[], int len) {
changeproperty(display, w, prop, type, 16, (uchar*)data, len);
}
#endif
static void
changeprop_long(Display *display, Window w, char *prop, char *type, long data[], int len) {
changeproperty(display, w, prop, type, 32, (uchar*)data, len);
}
static void
changeprop_textlist(Display *display, Window w, char *prop, char *type, char *data[]) {
char **p, *s, *t;
int len, n;
len = 0;
for(p=data; *p; p++)
len += strlen(*p) + 1;
s = malloc(len);
if(s == nil)
return;
t = s;
for(p=data; *p; p++) {
n = strlen(*p) + 1;
memcpy(t, *p, n);
t += n;
}
changeprop_char(display, w, prop, type, s, len);
free(s);
}
#if 0
static void
freestringlist(char *list[]) {
XFreeStringList(list);
}
#endif
static ulong
getprop(Display *display, Window w, char *prop, char *type, Atom *actual, int *format, ulong offset, uchar **ret, ulong length) {
Atom typea;
ulong n, extra;
int status;
typea = (type ? xatom(display, type) : 0L);
status = XGetWindowProperty(display, w,
xatom(display, prop), offset, length, False /* delete */,
typea, actual, format, &n, &extra, ret);
if(status != Success) {
*ret = nil;
return 0;
}
if(n == 0) {
free(*ret);
*ret = nil;
}
return n;
}
#if 0
static ulong
getproperty(Display *display, Window w, char *prop, char *type, Atom *actual, ulong offset, uchar **ret, ulong length) {
int format;
return getprop(display, w, prop, type, actual, &format, offset, ret, length);
}
#endif
static ulong
getprop_long(Display *display, Window w, char *prop, char *type, ulong offset, long **ret, ulong length) {
Atom actual;
ulong n;
int format;
n = getprop(display, w, prop, type, &actual, &format, offset, (uchar**)ret, length);
if(n == 0 || format == 32 && xatom(display, type) == actual)
return n;
free(*ret);
*ret = 0;
return 0;
}
#ifdef notdef
static char**
strlistdup(char *list[], int n) {
char **p, *q;
int i, m;
for(i=0, m=0; i < n; i++)
m += strlen(list[i])+1;
p = malloc((n+1)*sizeof(char*) + m);
if(p == nil)
return nil;
q = (char*)&p[n+1];
for(i=0; i < n; i++) {
p[i] = q;
m = strlen(list[i])+1;
memcpy(q, list[i], m);
q += m;
}
p[n] = nil;
return p;
}
#endif
static char**
strlistdup(char *list[], int n) {
char **p, *q;
int i, m;
m = 0;
for(i=0; i < n; i++)
m += strlen(list[i]) + 1;
p = malloc((n+1) * sizeof(*p) + m);
q = (char*)&p[n+1];
for(i=0; i < n; i++) {
p[i] = q;
m = strlen(list[i]) + 1;
memcpy(q, list[i], m);
q += m;
}
p[n] = nil;
return p;
}
#if 0
static int
getprop_textlist(Display *display, Window w, char *name, char **ret[]) {
XTextProperty prop;
char **list;
int n;
n = 0;
XGetTextProperty(display, w, &prop, xatom(display, name));
if(prop.nitems > 0) {
if(Xutf8TextPropertyToTextList(display, &prop, &list, &n) == Success) {
*ret = strlistdup(list, n);
XFreeStringList(list);
}
XFree(prop.value);
}
return n;
}
#endif
#if 0
static char*
getprop_string(Display *display, Window w, char *name) {
char **list, *str;
int n;
str = nil;
n = getprop_textlist(display, w, name, &list);
if(n > 0)
str = strdup(*list);
freestringlist(list);
return str;
}
#endif
|
Added lib/libwmii_hack/x11.h.
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> static void changeprop_char(Display*, Window, char*, char*, char[], int); static void changeprop_long(Display*, Window, char*, char*, long[], int); /* static void changeprop_short(Display*, Window, char*, char*, short[], int); */ static void changeprop_string(Display*, Window, char*, char*); static void changeprop_textlist(Display*, Window, char*, char*, char*[]); static void changeproperty(Display*, Window, char*, char*, int width, uchar*, int); /* static void delproperty(Display*, Window, char*); */ /* static void freestringlist(char**); */ static ulong getprop_long(Display*, Window, char*, char*, ulong, long**, ulong); /* static char* getprop_string(Display*, Window, char*); */ /* static int getprop_textlist(Display*, Window, char*, char**[]); */ /* static ulong getproperty(Display*, Window, char*, char*, Atom*, ulong, uchar**, ulong); */ static Atom xatom(Display*, char*); |
Added man/Makefile.
> > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ROOT=.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk MANPAGES = wmii.1 \ wmiir.1 \ wmii9menu.1\ wihack.1 \ wimenu.1 \ wistrut.1 \ witray.1 $(TARG): Makefile $(ROOT)/mk/wmii.mk header.t2t include $(ROOT)/mk/man.mk |
Added man/header.t2t.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
%!target: man
%!encoding: UTF-8
% Special formatting for certain constructs. They, unfortunately
% have to be post-processed. The _italic_ hack is necessary for
% italicising things like /_foo_/, which txt2tags will ignore.
% The others need to work in ``` lines.
%!preproc(man): \bPROVISIONAL\b **PROVISIONAL**
%!postproc(man): (<.*?>) \\fI\1\\fR
%!postproc(man): \b_(.*?)_ \\fI\1\\fR
%!postproc(man): \\e_ _
%!postproc(man): `(.*?)` \\fB\1\\fR
%!postproc(man): \[(.*?)\] [\\fI\1\\fR]
%!postproc(man): \+$ \n.P
%!postproc(man): (\$[a-zA-Z_]+) \\fB\1\\fR
%!postproc(man): (\${[a-zA-Z_]+)(.*?)} \\fB\1\\fR\2\\fB}\\fR
%!postproc(html): (<.*?>) (:arg \1:)
%!postproc(html): \b_(.*?)_ (:emph \1:)
%!postproc(html): `(.*?)` (:code \1:)
%!postproc(html): \+$ <br/>
%!postproc(html) \(:(\w+)\s*(.*):\) <span class="\1">\2</span>
% Well, it seems that txt2tags isn't particularly well suited
% to troff output. These two hacks make multi-level definition
% lists possible.
%!postproc(man): ^\s*>>$ .RS 8
%!postproc(man): ^\s*<<$ .RS -8
%!postproc(html): ^\s*>>$
%!postproc(html): ^\s*<<$
|
Added man/mkfile.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 |
TARG = `{bmake -VTARG}
default:V: all
all:V: $TARG
%.1: %.tex
latex2man -M $stem.tex $stem.1
|
Added man/wihack.1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | .TH "WIMENU" 1 "May, 2010" "wmii-@VERSION@" .SH NAME .P wihack \- The wmii window hack .SH SYNOPSIS .P wihack \fI[\-transient \fI<window>\fR]\fR \fI[\-type \fI<ewmh window type>\fR]\fR \fI[\-tags \fI<tags>\fR]\fR \fI<program>\fR .SH DESCRIPTION .P \fBwihack\fR is a program which alters the windows created by an arbitrary program. It has the name \fBwihack\fR because it is just that: a hack. It uses LD_PRELOAD to override certain Xlib calls and add properties to newly created windows. .SH ARGUMENTS .TP \-transient \fI<window>\fR Marks created windows as transient for a given \fI<window>\fR. This causes the new window to open in the floating layer of the same tags as \fI<window>\fR. .TP \-type \fI<ewmh window type>\fR Sets the EWMH window type of the created window to the type given. \fBwmii\fR understands the following types: .RS 8 .TP dialog Opens in the floating layer. .TP dock .TP menu .TP toolbar Automatically opens in the floating layer. Does not have a window border or titlebar. .TP splash Automatically floats and does not automatically receive focus. .RS -8 .TP \-tags \fI<tags>\fR The created window opens on the given tags. .SH BUGS .P It is a hack. .P It doesn't work for setuid programs. .P It doesn't work for non\-Xlib programs. .SH SEE ALSO .P wmii(1) .\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net) .\" cmdline: txt2tags -o- wihack.man1 |
Added man/wihack.man1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
WIMENU
wmii-@VERSION@
May, 2010
%!includeconf: header.t2t
= NAME =
wihack - The wmii window hack
= SYNOPSIS =
wihack [-transient <window>] [-type <ewmh window type>] [-tags <tags>] <program>
= DESCRIPTION =
`wihack` is a program which alters the windows created by an
arbitrary program. It has the name `wihack` because it is just that:
a hack. It uses LD_PRELOAD to override certain Xlib calls and add
properties to newly created windows.
= ARGUMENTS =
: -transient <window>
Marks created windows as transient for a given <window>.
This causes the new window to open in the floating layer of
the same tags as <window>.
: -type <ewmh window type>
Sets the EWMH window type of the created window to the type
given. `wmii` understands the following types:
>>
: dialog
Opens in the floating layer.
: dock
: menu
: toolbar
Automatically opens in the floating layer. Does not
have a window border or titlebar.
: splash
Automatically floats and does not automatically
receive focus.
<<
: -tags <tags>
The created window opens on the given tags.
:
= BUGS =
It is a hack.
It doesn't work for setuid programs.
It doesn't work for non-Xlib programs.
= SEE ALSO =
wmii(1)
|
Added man/wimenu.1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
.TH "WIMENU" 1 "Oct, 2009" "wmii-@VERSION@"
.SH NAME
.P
wimenu \- The wmii menu program
.SH SYNOPSIS
.P
wimenu [\fI\-i\fR] [\fI\-h \fI<history file>\fR\fR] [\fI\-n \fI<history count>\fR\fR] [\fI\-p \fI<prompt>\fR\fR]
.P
wimenu \-v
.SH DESCRIPTION
.P
\fBwimenu\fR is \fBwmii\fR's standard menu program. It's used
extensively by \fBwmii\fR and related programs to prompt the user
for input. The standard configuration uses it to launch
programs, select views, and perform standard actions. It
supports basic item completion and history searching.
.SH BASIC ARGUMENTS
.P
Normal use of \fBwimenu\fR shouldn't require any arguments other than the
following. More advanced options are documented below.
.TP
\-h \fI<history file>\fR
Causes \fBwimenu\fR to read its command history from
\fI<history file>\fR and to append its result to that file if
\fI\-n\fR is given.
.TP
\-i
Causes matching of completion items to be performed in a
case insensitive manner.
.TP
\-n \fI<count>\fR
Write at most \fI<count>\fR items back to the history file.
The file is never modified unless this option is
provided. Duplicates are filtered out within a 20 item
sliding window before this limit is imposed.
.TP
\-p \fI<prompt>\fR
The string \fI<prompt>\fR will be show before the input field
when the menu is opened.
.TP
\-r \fI<rows>\fR
Display completion items as a vertical list, one per
row, rather than a horizontal list, side\-by\-side. A
maximum of \fI<rows>\fR rows will be displayed.
.SH ADVANCED ARGUMENTS
.TP
\-a
The address at which to connect to \fBwmii\fR.
.TP
\-K
Prevents \fBwimenu\fR from initializing its default key
bindings. WARNING: If you do this, be sure to bind a key
with the Accept or Reject action, or you will have no way
to exit \fBwimenu\fR.
.TP
\-k \fI<key file>\fR
Key bindings will be read from \fI<key file>\fR. Bindings
appear as:
\fI<key>\fR [\fIaction\fR] [\fIargs\fR]
where \fI<key>\fR is a key name, similar to the format used by
wmii. For action and args, please refer to the default
bindings, provided in the source distribution under
cmd/menu/keys.txt, or use strings(1) on the \fBwimenu\fR
executable (this level of customization is reserved for the
determined).
.TP
\-s \fI<screen>\fR
Suggests that the menu open on Xinerama screen \fI<screen>\fR.
.TP
\-S \fI<command separator>\fR
.RS
Causes each input item to be split at the first occurance of
\fI<command sep>\fR. The text to the left of the separator is displayed
as a menu option, and the text to the right is displayed when a
selection is made.
.RE
.SH KEY BINDINGS
.P
\fBwimenu\fR's default key bindings are based largely on the
movement keys of vi and the standard UNIX shell input bindings.
.TP
Return, C\-j, C\-m
Accept the input, and select the first matching
completion if the cursor is at the end of the input.
.TP
S\-Return, C\-S\-j, C\-S\-m
Accept the input literally.
.TP
Esc, C\-[
Quit without returning any output, and exit with
non\-zero status.
.TP
A\-p
Paste the PRIMARY selection.
.TP
Left, C\-b
Move backward one character.
.TP
Right, C\-f
Move forward one character.
.TP
A\-b
Move backward one word.
.TP
A\-f
Move forward one word.
.TP
C\-a
Move to the beginning of the line.
.TP
C\-e
Move to the end of the line.
.TP
C\-p, Up
Move backward through the input history.
.TP
C\-n, Down
Move forward through the input history.
.TP
Backspace, C\-h
Delete the previous character.
.TP
C\-Backspace, C\-w
Delete the previous word.
.TP
C\-u
Delete the previous portion of the line.
.TP
Tab, C\-i¸ A\-l
Select the next completion.
.TP
S\-Tab, C\-S\-i, A\-h
Select the previous completion.
.TP
PageUp, A\-k
Select the previous completion page.
.TP
PageDown, A\-j
Select the next completion page.
.TP
Home, A\-g
Select the first completion page.
.TP
End, A\-S\-g
Select the last completion page.
.SH CUSTOM COMPLETION
.P
Custom, multipart completion data may be proveded by an
external application. When the standard input is not a TTY,
processing of a set of completions stops at every blank line.
After the first new line or EOF, \fBwimenu\fR displays the first
set of menu items, and waits for further input. The completion
items may be replaced by writing out a new set, again followed
by a new line. Every set following the first must begin with a
line containing a single decimal number specifying where the
new completion results are to be spliced into the input. When
an item is selected, text from this position to the position
of the caret is replaced.
.SS ARGUMENTS
.TP
\-c
Prints the contents of the input buffer each time the
user inputs a character, as such:
\fI<text before caret>\fR\en\fI<text after caret>\fR\en
.SS EXAMPLE
.P
Let's assume that a script would like to provide a menu with
completions first for a command name, then for arguments
to that command. Given three commands and argument sets,
.TP
foo
.RS
1, 2, 3
.RE
.TP
bar
.RS
4, 5, 6
.RE
.TP
baz
.RS
7, 8, 9
.RE
.P
the following script provides the appropriate completions:
.nf
#!/bin/sh -f
rm fifo
mkfifo fifo
# Open wimenu with a fifo as its stdin
wimenu -c <fifo | awk '
BEGIN {
# Define the completion results
cmds = "foo\enbar\enbaz\en"
cmd[\fI"foo"\fR] = "1\en2\en3\en"
cmd[\fI"bar"\fR] = "4\en5\en6\en"
cmd[\fI"baz"\fR] = "7\en8\en9\en"
# Print the first set of completions to wimenu’s fifo
fifo = "fifo"
print cmds >fifo; fflush(fifo)
}
{ print; fflush() }
# Push out a new set of completions
function update(str, opts) {
print length(str) >fifo # Print the length of the preceding string
print opts >fifo # and the options themself
fflush(fifo)
}
# Ensure correct argument count with trailing spaces
/ $/ { $0 = $0 "#"; }
{ # Process the input and provide the completions
if (NF == 1)
update("", cmds) # The first arg, command choices
else
update($1 " ", cmd[\fI$1\fR]) # The second arg, command arguments
# Skip the trailing part of the command
getline rest
}
\&' | tail -1
.fi
.P
In theory, this facility can be used for myriad purposes,
including hijacking the programmable completion facilities of
most shells. See also the provided examples[\fI1\fR].
.SH ENVIRONMENT
.TP
\fB$WMII_ADDRESS\fR
The address at which to connect to wmii.
.TP
\fB$NAMESPACE\fR
The namespace directory to use if no address is
provided.
.SH SEE ALSO
.P
wmii(1), wmiir(1), wistrug(1), wmii9menu(1), dmenu(1)
.P
[\fI1\fR] http://www.suckless.org/wiki/wmii/tips/9p_tips
.P
[\fI2\fR] @EXAMPLES@
.\" man code generated by txt2tags 2.6 (http://txt2tags.org)
.\" cmdline: txt2tags -o- wimenu.man1
|
Added man/wimenu.man1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
WIMENU
wmii-@VERSION@
Oct, 2009
%!includeconf: header.t2t
= NAME =
wimenu - The wmii menu program
= SYNOPSIS =
wimenu [-i] [-h <history file>] [-n <history count>] [-p <prompt>] +
wimenu -v
= DESCRIPTION =
`wimenu` is `wmii`'s standard menu program. It's used
extensively by `wmii` and related programs to prompt the user
for input. The standard configuration uses it to launch
programs, select views, and perform standard actions. It
supports basic item completion and history searching.
= BASIC ARGUMENTS =
Normal use of `wimenu` shouldn't require any arguments other than the
following. More advanced options are documented below.
: -h <history file>
Causes `wimenu` to read its command history from
<history file> and to append its result to that file if
_-n_ is given.
: -i
Causes matching of completion items to be performed in a
case insensitive manner.
: -n <count>
Write at most <count> items back to the history file.
The file is never modified unless this option is
provided. Duplicates are filtered out within a 20 item
sliding window before this limit is imposed.
: -p <prompt>
The string <prompt> will be show before the input field
when the menu is opened.
: -r <rows>
Display completion items as a vertical list, one per
row, rather than a horizontal list, side-by-side. A
maximum of <rows> rows will be displayed.
:
= ADVANCED ARGUMENTS =
: -a
The address at which to connect to `wmii`.
: -K
Prevents `wimenu` from initializing its default key
bindings. WARNING: If you do this, be sure to bind a key
with the Accept or Reject action, or you will have no way
to exit `wimenu`.
: -k <key file>
Key bindings will be read from <key file>. Bindings
appear as:
<key> [action] [args]
where <key> is a key name, similar to the format used by
wmii. For action and args, please refer to the default
bindings, provided in the source distribution under
cmd/menu/keys.txt, or use strings(1) on the `wimenu`
executable (this level of customization is reserved for the
determined).
: -s <screen>
Suggests that the menu open on Xinerama screen <screen>.
: -S <command separator>
Causes each input item to be split at the first occurance of
<command sep>. The text to the left of the separator is displayed
as a menu option, and the text to the right is displayed when a
selection is made.
= KEY BINDINGS =
`wimenu`'s default key bindings are based largely on the
movement keys of vi and the standard UNIX shell input bindings.
: Return, C-j, C-m
Accept the input, and select the first matching
completion if the cursor is at the end of the input.
: S-Return, C-S-j, C-S-m
Accept the input literally.
: Esc, C-[
Quit without returning any output, and exit with
non-zero status.
: A-p
Paste the PRIMARY selection.
: Left, C-b
Move backward one character.
: Right, C-f
Move forward one character.
: A-b
Move backward one word.
: A-f
Move forward one word.
: C-a
Move to the beginning of the line.
: C-e
Move to the end of the line.
: C-p, Up
Move backward through the input history.
: C-n, Down
Move forward through the input history.
: Backspace, C-h
Delete the previous character.
: C-Backspace, C-w
Delete the previous word.
: C-u
Delete the previous portion of the line.
: Tab, C-i¸ A-l
Select the next completion.
: S-Tab, C-S-i, A-h
Select the previous completion.
: PageUp, A-k
Select the previous completion page.
: PageDown, A-j
Select the next completion page.
: Home, A-g
Select the first completion page.
: End, A-S-g
Select the last completion page.
:
= CUSTOM COMPLETION =
Custom, multipart completion data may be proveded by an
external application. When the standard input is not a TTY,
processing of a set of completions stops at every blank line.
After the first new line or EOF, `wimenu` displays the first
set of menu items, and waits for further input. The completion
items may be replaced by writing out a new set, again followed
by a new line. Every set following the first must begin with a
line containing a single decimal number specifying where the
new completion results are to be spliced into the input. When
an item is selected, text from this position to the position
of the caret is replaced.
== ARGUMENTS ==
: -c
Prints the contents of the input buffer each time the
user inputs a character, as such:
<text before caret>\n<text after caret>\n
:
== EXAMPLE ==
Let's assume that a script would like to provide a menu with
completions first for a command name, then for arguments
to that command. Given three commands and argument sets,
: foo
1, 2, 3
: bar
4, 5, 6
: baz
7, 8, 9
the following script provides the appropriate completions:
```
#!/bin/sh -f
rm fifo
mkfifo fifo
# Open wimenu with a fifo as its stdin
wimenu -c <fifo | awk '
BEGIN {
# Define the completion results
cmds = "foo\nbar\nbaz\n"
cmd["foo"] = "1\n2\n3\n"
cmd["bar"] = "4\n5\n6\n"
cmd["baz"] = "7\n8\n9\n"
# Print the first set of completions to wimenu’s fifo
fifo = "fifo"
print cmds >fifo; fflush(fifo)
}
{ print; fflush() }
# Push out a new set of completions
function update(str, opts) {
print length(str) >fifo # Print the length of the preceding string
print opts >fifo # and the options themself
fflush(fifo)
}
# Ensure correct argument count with trailing spaces
/ $/ { $0 = $0 "#"; }
{ # Process the input and provide the completions
if (NF == 1)
update("", cmds) # The first arg, command choices
else
update($1 " ", cmd[$1]) # The second arg, command arguments
# Skip the trailing part of the command
getline rest
}
' | tail -1
```
In theory, this facility can be used for myriad purposes,
including hijacking the programmable completion facilities of
most shells. See also the provided examples[1].
= ENVIRONMENT =
: $WMII_ADDRESS
The address at which to connect to wmii.
: $NAMESPACE
The namespace directory to use if no address is
provided.
:
= SEE ALSO =
wmii(1), wmiir(1), wistrug(1), wmii9menu(1), dmenu(1)
[1] http://www.suckless.org/wiki/wmii/tips/9p_tips +
[2] @EXAMPLES@
|
Added man/wistrut.1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | .TH "WISTRUT" 1 "May, 2010" "wmii-@VERSION@" .SH NAME .P wistrut \- The wmii EWMH strut manager .SH SYNOPSIS .P wistrut \fI[\-HV]\fR \fI<window|class>\fR... .P wistrut \-v .SH DESCRIPTION .P \fBwistrut\fR automatically sets EWMH struts on windows for programs which don't provide such functionality. This allows you to leave utility windows onscreen without obscuring managed clients. Instead, whatever part of the screen is occupied by the window will be left free by wmii, provided it is less than half of the screen width or height. Struts are automatically updated when the managed windows are moved or resized, and are only applied if the window is touching an edge of the screen. .P \fBwistrut\fR may be used with any EWMH compatible window manager. .SH ARGUMENTS .P All non\-option arguments constitute window IDs or regular expressions. In the latter case, the any window whose \fI<name>\fR:\fI<class>\fR:\fI<title>\fR (as used in wmii's colrules and tagrules) will be managed. .TP \-H .RS Only set horizontal struts. Normally, \fBwistrut\fR locates struts in the direction of the narrowest dimension of the window, provided it is touching a screen edge. With this option set, they will always be allocated on either the left or right of the screen. Never the top or bottom. .RE .TP \-V .RS Only set vertical struts. See \-H. .RE .TP \-v .RS Display version information. .RE .SH BUGS .P There is no way to remove struts from a window other than to move it away from the edge of the screen and kill \fBwistrut\fR. .SH SEE ALSO .P wmii(1) .\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net) .\" cmdline: txt2tags -o- wistrut.man1 |
Added man/wistrut.man1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | WISTRUT wmii-@VERSION@ May, 2010 %!includeconf: header.t2t = NAME = wistrut - The wmii EWMH strut manager = SYNOPSIS = wistrut [-HV] <window|class>... + wistrut -v = DESCRIPTION = `wistrut` automatically sets EWMH struts on windows for programs which don't provide such functionality. This allows you to leave utility windows onscreen without obscuring managed clients. Instead, whatever part of the screen is occupied by the window will be left free by wmii, provided it is less than half of the screen width or height. Struts are automatically updated when the managed windows are moved or resized, and are only applied if the window is touching an edge of the screen. `wistrut` may be used with any EWMH compatible window manager. = ARGUMENTS = All non-option arguments constitute window IDs or regular expressions. In the latter case, the any window whose <name>:<class>:<title> (as used in wmii's colrules and tagrules) will be managed. : -H Only set horizontal struts. Normally, `wistrut` locates struts in the direction of the narrowest dimension of the window, provided it is touching a screen edge. With this option set, they will always be allocated on either the left or right of the screen. Never the top or bottom. : -V Only set vertical struts. See -H. : -v Display version information. = BUGS = There is no way to remove struts from a window other than to move it away from the edge of the screen and kill `wistrut`. = SEE ALSO = wmii(1) |
Added man/witray.1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | .TH "WITRAY" 1 "May, 2010" "wmii-@VERSION@" .SH NAME .P witray \- The wmii system tray .SH SYNOPSIS .P witray [\fI\-a \fI<address>\fR\fR] [\fI\-NESW\fR] [\fI\-HV\fR] [\fI\-p \fI<padding>\fR\fR] [\fI\-s \fI<iconsize>\fR\fR] \-t (tags) .P witray \-v .SH DESCRIPTION .P \fBwitray\fR is a simple system tray program meant to be used with wmii. It supports the Freedesktop System Tray Protocol Specification common among all newer applications and desktop environments. The tray is only visible when applications require it. While there are many standalone system tray applications, this one is explicitly tailored to wmii. It's simple, stays out of the user's way, is easy to configure, and generally Just Works. .SH ARGUMENTS .TP \-a The address at which to connect to \fBwmii\fR. .TP \-N \-E \-S \-W .RS Sets the screen edge where \fBwitray\fR is to appear to the \fINorth\fR, \fISouth\fR, \fIEast\fR, or \fIWest\fR edge, respectively. Options may be combined, for instance *\-NE* gives the _North East_ corner of the screen. If no options are given, \fBwitray\fR opens to the West of whichever part of the screen the wmii bar occupies. .RE .TP \-H \-V .RS Specifies whether icons are to be aligned horizontally or vertically, respectively. Also determines from which edge of the screen windows are shunted to make room for the tray. .RE .TP \-n Do not replace an already running system tray. .TP \-p \fI<padding>\fR .RS Sets the padding between icons and around the edge of the tray. In pixels. .RE .TP \-s \fI<iconsize>\fR .RS Sets the size of the icons, in pixels. If not provided, icons are sized so that the tray is the same height as the \fBwmii\fR bar. .RE .TP \-t \fI<tags>\fR .RS The tags on which to open. Default: \fI/./\fR .RE .TP \-v .RS Display version information. .RE .SH CAVEATS .P \fBwitray\fR is not XRandR aware. .SH SEE ALSO .P wmii(1), wimenu(1) .\" man code generated by txt2tags 2.6 (http://txt2tags.org) .\" cmdline: txt2tags -o- witray.man1 |
Added man/witray.man1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
WITRAY
wmii-@VERSION@
May, 2010
%!includeconf: header.t2t
= NAME =
witray - The wmii system tray
= SYNOPSIS =
witray [-a <address>] [-NESW] [-HV] [-p <padding>] [-s <iconsize>] [-t tags] +
witray -v
= DESCRIPTION =
`witray` is a simple system tray program meant to be used with wmii.
It supports the Freedesktop System Tray Protocol Specification
common among all newer applications and desktop environments. The
tray is only visible when applications require it. While there are
many standalone system tray applications, this one is explicitly
tailored to wmii. It's simple, stays out of the user's way, is easy
to configure, and generally Just Works.
= ARGUMENTS =
: -a
The address at which to connect to `wmii`.
: -N -E -S -W
Sets the screen edge where `witray` is to appear to the
_North_, _South_, _East_, or _West_ edge, respectively.
Options may be combined, for instance *-NE* gives the _North
East_ corner of the screen. If no options are given,
`witray` opens to the West of whichever part of the screen
the wmii bar occupies.
: -H -V
Specifies whether icons are to be aligned horizontally or
vertically, respectively. Also determines from which edge of
the screen windows are shunted to make room for the tray.
: -n
Do not replace an already running system tray.
: -p <padding>
Sets the padding between icons and around the edge of the
tray. In pixels.
: -s <iconsize>
Sets the size of the icons, in pixels. If not provided,
icons are sized so that the tray is the same height as the
`wmii` bar.
: -t <tags>
The tags on which to open. Default: _/./_
: -v
Display version information.
= CAVEATS =
`witray` is not XRandR aware.
= SEE ALSO =
wmii(1), wimenu(1)
|
Added man/wmii.1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 |
.TH "WMII" 1 "2010 June" "wmii-@VERSION@"
.SH NAME
.P
wmii \- Window Manager Improved²
.SH SYNOPSIS
.P
wmii \fI[\-a \fI<address>\fR]\fR \fI[\-r \fI<wmiirc>\fR]\fR
.P
wmii \-v
.SH DESCRIPTION
.SS Overview
.P
\fBwmii\fR is a dynamic window manager for X11. In contrast to
static window management the user rarely has to think about how
to organize windows, no matter what he is doing or how many
applications are used at the same time. The window manager
adapts to the current environment and fits to the needs of the
user, rather than forcing him to use a preset, fixed layout and
trying to shoehorn all windows and applications into it.
.P
\fBwmii\fR supports classic and tiled window management with
extended keyboard and mouse control. Classic window management
arranges windows in a floating layer in which tyen can be moved
and resized freely. Tiled window management arranges windows in
vertical columns. Each column holds an arbitrary number
arbitrary windows and arranges them vertically in a
non\-overlapping manner. They can then be moved and resized,
among and within columns, at will.
.P
\fBwmii\fR provides a virtual filesystem which represents the
internal state similar to the procfs of Unix operating systems.
Modifying this virtual filesystem results in changing the state
of the window manager. The virtual filesystem service can be
accessed through 9P\-capable client programs, like
wmiir(1). This allows simple and powerful remote control
of the core window manager.
.SS Command Line Arguments
.TP
\-a \fI<address>\fR
Specifies the address on which \fBwmii\fR should listen for
connections. The address takes the form
\fB\fI<protocol>\fR!\fI<address>\fR\fR. The default is of the form:
.nf
unix!/tmp/ns.\fB$USER\fR.\fB${DISPLAY\fR%.0\fB}\fR/wmii
.fi
which opens a unix socket per Plan 9 Port conventions. To
open a TCP socket, listening at port 4332 on the loopback
interface, use:
.nf
tcp!localhost!4332
.fi
\fB$WMII_NAMESPACE\fR is automatically set to this value.
.TP
\-r \fI<wmiirc>\fR
Specifies which rc script to run. If \fI<wmiirc>\fR consists of a
single argument, \fB$WMII_CONFPATH\fR is searched before \fB$PATH\fR.
Otherwise, it is passed to the shell for evaluation. The
environment variables \fB$WMII_ADDRESS\fR and \fB$WMII_CONFPATH\fR are
preset for the script.
.SS Terminology
.TP
Display
A running X server instance consisting of input
devices and screens.
.TP
Screen
A physical or virtual (Xinerama or Xnest(1))
screen of an X display.
.TP
Window
A (rectangular) drawable X object which is
displayed on a screen, usually an application window.
.TP
Client
An application window surrounded by a frame window
containing a border and a titlebar.
.TP
Floating layer
A screen layer of \fBwmii\fR on top of all other layers,
where clients are arranged in a classic (floating)
manner. They can be resized or moved freely.
.TP
Managed layer
A screen layer of \fBwmii\fR underneath the floating layer,
where clients are arranged in a non\-overlapping
(managed) manner. Here, the window manager dynamically
assigns each client a size and position. The managed
layer consists of columns.
.TP
Tag
Alphanumeric strings which can be assigned to a
client. This provides a mechanism to group clients with
similar properties. Clients can have one tag, e.g.
\fIwork\fR, or several tags, e.g. \fIwork+mail\fR.
Tags are separated with the \fI+\fR character.
.TP
View
A set of clients containing a specific tag, quite
similar to a workspace in other window managers. It
consists of the floating and managed layers.
.TP
Column
A column is a screen area which arranges clients
vertically in a non\-overlapping way. Clients can be
moved and resized between and within columns freely.
.TP
Bar
The bar at the bottom of the screen displays a label
for each view and allows the creation of arbitrary
user\-defined labels.
.TP
Event
An event is a message which can be read from a
special file in the filesystem of \fBwmii\fR, such as a
mouse button press, a key press, or a message written by
a different 9P\-client.
.SS Basic window management
.P
Running a raw \fBwmii\fR process without a wmiirc(1) script provides
basic window management capabilities. However, to use it
effectively, remote control through its filesystem interface is
necessary. Without such a script, it is only possible to move
and resize clients with the mouse, but not to change their tags
or to switch views. Other interactions, such as customizing the
style, killing or retagging clients, and grabbing keys, cannot
be achieved without accessing the filesystem.
.P
The filesystem can be accessed by connecting to the \fIaddress\fR
of \fBwmii\fR with any 9P\-capable client, such as wmiir(1)
.SS Actions
.P
The default configuration provides for a special menu of
actions. These consist of either shell scripts in \fB$WMII_CONFPATH\fR
or action definitions included in wmiirc.
.P
Here is a list of the default actions:
.TS
tab(^); ll.
exec^Replace the window manager with another program
quit^Leave the window manager nicely
rehash^Refresh the program list
showkeys^Display a list of key bindings recognized by wmii
status^Periodically print date and load average to the bar
welcome^Display a welcome message that contains the wmii tutorial
.TE
.SS Default Key Bindings
.P
All of the provided \fBwmiirc\fR scripts accept at least the following key
bindings. They should also provide a \fBshowkeys\fR action to open a
key binding quick\-reference.
.SS Moving Around
.TS
tab(^); ll.
\fBKey\fR^\fBAction\fR
Mod\-h^Move to a window to the \fIleft\fR of the one currently focused
Mod\-l^Move to a window to the \fIright\fR of the one currently focused
Mod\-j^Move to the window \fIbelow\fR the one currently focused
Mod\-k^Move to a window \fIabove\fR the one currently focused
Mod\-space^Toggle between the managed and floating layers
Mod\-t \fI<tag>\fR^Move to the view of the given \fI<tag>\fR
Mod\-n^Move to the next view
Mod\-b^Move to the previous view
Mod\-\fI\fI[0\-9]\fR\fR^Move to the view with the given number
.TE
.SS Moving Things Around
.TS
tab(^); ll.
\fBKey\fR^\fBAction\fR
Mod\-Shift\-h^Move the current window \fIwindow\fR to a column on the \fIleft\fR
Mod\-Shift\-l^Move the current window to a column on the \fIright\fR
Mod\-Shift\-j^Move the current window below the window beneath it.
Mod\-Shift\-k^Move the current window above the window above it.
Mod\-Shift\-space^Toggle the current window between the managed and floating layer
Mod\-Shift\-t \fI<tag>\fR^Move the current window to the view of the given \fI<tag>\fR
Mod\-Shift\-\fI\fI[0\-9]\fR\fR^Move the current window to the view with the given number
.TE
.SS Miscellaneous
.TS
tab(^); ll.
\fBKey\fR^\fBAction\fR
Mod\-m^Switch the current column to \fImax mode\fR
Mod\-s^Switch the current column to \fIstack mode\fR
Mod\-d^Switch the current column to \fIdefault mode\fR
Mod\-Shift\-c^\fBKill\fR the selected client
Mod\-p \fI<program>\fR^\fBExecute\fR \fI<program>\fR
Mod\-a \fI<action>\fR^\fBExecute\fR the named <action
Mod\-Enter^\fBExecute\fR an \fB@TERMINAL@\fR
.TE
.SH Configuration
.P
If you feel the need to change the default configuration, then
customize (as described above) the \fBwmiirc\fR action. This
action is executed at the end of the \fBwmii\fR script and does
all the work of setting up the window manager, the key bindings,
the bar labels, etc.
.SS Filesystem
.P
Most aspects of \fBwmii\fR are controlled via the filesystem. It is
usually accessed via the wmiir(1) command, but it can be
accessed by any 9P, including plan9port's 9P\fI[1]\fR, and can be
mounted natively on Linux via v9fs\fI[1]\fR, and on Inferno (which man
run on top of Linux). All data in the filesystem, including
filenames, is UTF\-8 encoded. However, when accessed via
wmiir(1), text is automatically translated to and from your
locale encoding.
.P
The filesystem is, as are many other 9P filesystems, entirely
synthetic. The files exist only in memory, and are not written
to disk. They are generally initiated on wmii startup via a
script such as wmiirc. Several files are used to issue commands,
others simply act as if they were ordinary files (their contents
are updated and returned exactly as written), though writing
them has side\-effects (such as changing key bindings). A
description of the filesystem layout and control commands
follows.
.SS Hierarchy
.TP
/
Global control files
.TP
/client/\fI*\fR/
Client control files
.TP
/tag/\fI*\fR/
View control files
.TP
/lbar/, /rbar/
Files representing the contents of the bottom bar
.SS The / Hierarchy
.TP
colrules
The \fIcolrules\fR file contains a list of
rules which affect the width of newly created columns.
Rules have the form:
.nf
/\fI<regex>\fR/ -> \fI<width>\fR\fI[+\fI<width>\fR]\fR*
.fi
Where,
.nf
\fI<width>\fR := \fI<percent of screen>\fR | \fI<pixels>\fRpx
.fi
When a new column, \fI<n>\fR, is created on a view whose name
matches \fI<regex>\fR, it is given the \fI<n>\fRth supplied \fI<width>\fR.
If there is no \fI<n>\fRth width, it is given 1/\fI<ncol>\fRth of the
screen.
.TP
rules
\fBPROVISIONAL\fR
The \fIrules\fR file contains a list of rules that may be used
to automatically set properties of new clients. Rules are
specified as:
.nf
/\fI<regex>\fR/ \fI<key>\fR=\fI<value>\fR ...
.fi
where each \fI<key>\fR represents a command in the clients \fIctl\fR
file, and each \fI<value>\fR represents the value to assign to it.
The rules are applied when the client is first started and
the contents of the \fIprops\fR file match the regular
expression \fI<regex>\fR.
Additionally, the following keys are accepted and have
special meaning:
.RS 8
.TP
continue
Normally, when a matching rule is encountered, rule
matching stops. When the continue key is provided
(with any value), matching continues at the next
rule.
.TP
force\-tags=\fI<tags>\fR
Like \fItags\fR, but overrides any settings obtained
obtained from the client's group or from the
\fB_WMII_TAGS\fR window property.
.RS -8
.TP
keys
The \fIkeys\fR file contains a list of keys which
\fBwmii\fR will grab. Whenever these key combinations
are pressed, the string which represents them are
written to '/event' as: Key \fI<string>\fR
.TP
event
The \fIevent\fR file never returns EOF while
\fBwmii\fR is running. It stays open and reports events
as they occur. Included among them are:
.RS 8
.TP
\fI[Not]\fRUrgent \fI<client>\fR \fI[Manager|Client]\fR
\fI<client>\fR's urgent hint has been set or
unset. The second arg is \fI[Client]\fR if it's
been set by the client, and \fI[Manager]\fR if
it's been set by \fBwmii\fR via a control
message.
.TP
\fI[Not]\fRUrgentTag \fI<tag>\fR \fI[Manager|Client]\fR
A client on \fI<tag>\fR has had its urgent hint
set, or the last urgent client has had its
urgent hint unset.
.TP
Client\fI<Click|MouseDown>\fR \fI<client>\fR \fI<button>\fR
A client's titlebar has either been clicked or
has a button pressed over it.
.TP
\fI[Left|Right]\fRBar\fI[Click|MouseDown]\fR \fI<button>\fR \fI<bar>\fR
A left or right bar has been clicked or has a
button pressed over it.
.RS -8
For a more comprehensive list of available events, see
\fIwmii.pdf\fR\fI[2]\fR
.TP
ctl
The \fIctl\fR file takes a number of messages to
change global settings such as color and font, which can
be viewed by reading it. It also takes the following
commands:
.RS 8
.TP
quit
Quit \fBwmii\fR
.TP
exec \fI<prog>\fR
Replace \fBwmii\fR with \fI<prog>\fR
.TP
spawn \fI<prog>\fR
Spawn a new program, as if by the \fI\-r\fR flag.
.RS -8
.SS The /client/ Hierarchy
.P
Each directory under '/client/' represents an X11 client.
Each directory is named for the X window id of the window the
client represents, in the form that most X utilities recognize.
The one exception is the special 'sel' directory, which
represents the currently selected client.
.TP
ctl
When read, the 'ctl' file returns the X window id
of the client. The following commands may be written to
it:
.RS 8
.TP
allow \fI<flags>\fR
The set of unusual actions the client is allowed to
perform, in the same format as the tag set.
.RS 8
.TP
activate
The client is allowed to activate
itself – that is, focus its window and,
as the case may require, uncollapse it
and select a tag it resides on. This
flag must be set on a client if you wish
it able to activate itself from the
system tray.
.RS -8
.TP
floating \fI<on | off | always | never>\fR
Defines whether this client is likely to float when
attached to a new view. Ordinarilly, the value
changes automatically whenever the window is
moved between the floating and managed layers.
However, setting a value of \fIalways\fR or \fInever\fR
overrides this behavior. Additionally, dialogs,
menus, docks, and splash screens will always
float unless this value is set to \fInever\fR.
.TP
fullscreen \fI<on | off | toggle>\fR
Sets the client's fullscreen state.
.TP
group \fI<group id>\fR
The client's group ID, or 0 if not part of a group.
Clients tend to open with the same tags and in the
same columns as the last active member of their
group. Setting this property is only useful when
done via the rules file.
.TP
kill
Close the client's window.
.TP
pid
Read\-only value of the PID of the program that
owns the window, if the value is available and
the process is on the same machine as wmii.
.TP
slay
Forcibly kill the client's connection to the X
server, closing all of its windows. Kill the parent
process if the client's PID is available.
.TP
tags \fI<tags>\fR
The client's tags. The same as the tags file.
.TP
urgent \fI<on | off | toggle>\fR
Set or unset the client's urgent hint.
.RS -8
.TP
label
Set or read a client's label (title).
.TP
props
Returns a clients class and label as:
\fI<instance>\fR:\fI<class>\fR:\fI<label>\fR.
.TP
tags
Set or read a client's tags. Tags are separated by
\fB+\fR, \fB\-\fR, or \fB^\fR. Tags beginning with \fB+\fR are
added, while those beginning with \fB\-\fR are removed and
those beginning with \fB^\fR are toggled. If the tag
string written begins with \fB+\fR, \fB^\fR, or \fB\-\fR, the
written tags are added to or removed from the client's
set, otherwise the set is overwritten.
.SS The /tag/ Hierarchy
.P
Each directory under '/tag/' represents a view, containing
all of the clients with the given tag applied. The special
\&'sel' directory represents the currently selected tag.
.TP
ctl
The 'ctl' file can be read to retrieve the name
of the tag the directory represents, or written with the
following commands:
.RS 8
.TP
select
Select a client:
select \fI[left|right|up|down]\fR
.P
select \fI[\fI<row number>\fR|sel]\fR \fI[\fI<frame number>\fR]\fR
.P
select client \fI<client>\fR
.TP
send
Send a client somewhere:
.RS 8
.TP
send \fI[\fI<client>\fR|sel]\fR \fI[up|down|left|right]\fR
.TP
send \fI[\fI<client>\fR|sel]\fR \fI<area>\fR
Send \fI<client>\fR to the \fIn\fRth \fI<area>\fR
.TP
send \fI[\fI<client>\fR|sel]\fR toggle
Toggle \fI<client>\fR between the floating and managed layer.
.RS -8
.TP
swap
Swap a client with another. Same syntax as send.
.TP
grow
Grow or shrink a client.
.nf
grow \fI<frame>\fR \fI<direction>\fR \fI[\fI<amount>\fR]\fR
.fi
.TP
nudge
Nudge a client in a given direction.
.nf
grow \fI<frame>\fR \fI<direction>\fR \fI[\fI<amount>\fR]\fR
.fi
.RS -8
Where the arguments are defined as follows:
.RS 8
.TP
area
Selects a column or the floating area.
.nf
area ::= \fI<area_spec>\fR | \fI<screen_spec>\fR:\fI<area_spec>\fR
.fi
When \fI<screen_spec>\fR is omitted and \fI<area_spec>\fR is not "sel",
0 is assumed. "sel" by itself represents the selected client no
matter which screen it is on.
.nf
area_spec ::= "~" | \fI<number>\fR | "sel"
.fi
Where "~" represents the floating area and \fI<number>\fR represents a column
index, starting at one.
.nf
screen_spec ::= \fI<number>\fR
.fi
Where \fI<number>\fR representes the 0\-based Xinerama screen number.
.TP
frame
Selects a client window.
.nf
frame ::= \fI<area>\fR \fI<index>\fR | \fI<area>\fR sel | client \fI<window-id>\fR
.fi
Where \fI<index>\fR represents the nth frame of \fI<area>\fR or \fI<window\-id>\fR is
the X11 window id of the given client.
.TP
amount
The amount to grow or nudge something.
.nf
amount ::= \fI<number>\fR | \fI<number>\fRpx
.fi
If "px" is given, \fI<number>\fR is interperated as an exact pixel count.
Otherwise, it's interperated as a "reasonable" amount, which is
usually either the height of a window's title bar, or its sizing
increment (as defined by X11) in a given direction.
.RS -8
.TP
index
Read for a description of the contents of a tag.
.SS The /rbar/, /lbar/ Hierarchy
.P
The files under '/rbar/' and '/lbar/' represent the
items of the bar at the bottom of the screen. Files under
\&'/lbar/' appear on the left side of the bar, while those
under '/rbar/' appear on the right, with the leftmost item
occupying all extra available space. The items are sorted
lexicographically.
.P
The files may be read or written to obtain or alter the colors
and text of the bars. The format is similar to the various \fIctl\fR
files and should be self explanitory.
.SH FILES
.TP
/tmp/ns.\fB$USER\fR.\fB${DISPLAY\fR%.0\fB}\fR/wmii
The wmii socket file which provides a 9P service.
.TP
@GLOBALCONF@
Global action directory.
.TP
@LOCALCONF@
User\-specific action directory. Actions are first searched here.
.SH ENVIRONMENT
.TP
\fB$HOME\fR, \fB$DISPLAY\fR
See the section \fBFILES\fR above.
.P
The following variables are set and exported within \fBwmii\fR and
thus can be used in actions:
.TP
\fB$WMII_ADDRESS\fR
The address on which \fBwmii\fR is listening.
.TP
\fB$WMII_CONFPATH\fR
The path that wmii searches for its configuration
scripts and actions.
.TP
\fB$NAMESPACE\fR
The namespace directory to use if no address is provided.
.SH SEE ALSO
.P
wimenu(1), wmii9menu(1), witray(1), wmiir(1), wihack(1)
.P
@DOCDIR@/wmii.pdf
@DOCDIR@/FAQ
.P
\fI[1]\fR http://www.suckless.org/wiki/wmii/tips/9p_tips
.P
\fI[2]\fR @DOCDIR@/wmii.pdf
.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
.\" cmdline: txt2tags -o- wmii.man1
|
Added man/wmii.man1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 |
WMII
wmii-@VERSION@
2010 June
%!includeconf: header.t2t
= NAME =
wmii - Window Manager Improved²
= SYNOPSIS =
wmii [-a <address>] [-r <wmiirc>] +
wmii -v
= DESCRIPTION =
== Overview ==
`wmii` is a dynamic window manager for X11. In contrast to
static window management the user rarely has to think about how
to organize windows, no matter what he is doing or how many
applications are used at the same time. The window manager
adapts to the current environment and fits to the needs of the
user, rather than forcing him to use a preset, fixed layout and
trying to shoehorn all windows and applications into it.
`wmii` supports classic and tiled window management with
extended keyboard and mouse control. Classic window management
arranges windows in a floating layer in which tyen can be moved
and resized freely. Tiled window management arranges windows in
vertical columns. Each column holds an arbitrary number
arbitrary windows and arranges them vertically in a
non-overlapping manner. They can then be moved and resized,
among and within columns, at will.
`wmii` provides a virtual filesystem which represents the
internal state similar to the procfs of Unix operating systems.
Modifying this virtual filesystem results in changing the state
of the window manager. The virtual filesystem service can be
accessed through 9P-capable client programs, like
wmiir(1). This allows simple and powerful remote control
of the core window manager.
== Command Line Arguments ==
: -a <address>
Specifies the address on which `wmii` should listen for
connections. The address takes the form
`<protocol>!<address>`. The default is of the form:
``` unix!/tmp/ns.$USER.${DISPLAY%.0}/wmii
which opens a unix socket per Plan 9 Port conventions. To
open a TCP socket, listening at port 4332 on the loopback
interface, use:
``` tcp!localhost!4332
$WMII_NAMESPACE is automatically set to this value.
: -r <wmiirc>
Specifies which rc script to run. If <wmiirc> consists of a
single argument, $WMII_CONFPATH is searched before $PATH.
Otherwise, it is passed to the shell for evaluation. The
environment variables $WMII_ADDRESS and $WMII_CONFPATH are
preset for the script.
:
== Terminology ==
: Display
A running X server instance consisting of input
devices and screens.
: Screen
A physical or virtual (Xinerama or Xnest(1))
screen of an X display.
: Window
A (rectangular) drawable X object which is
displayed on a screen, usually an application window.
: Client
An application window surrounded by a frame window
containing a border and a titlebar.
: Floating layer
A screen layer of `wmii` on top of all other layers,
where clients are arranged in a classic (floating)
manner. They can be resized or moved freely.
: Managed layer
A screen layer of `wmii` underneath the floating layer,
where clients are arranged in a non-overlapping
(managed) manner. Here, the window manager dynamically
assigns each client a size and position. The managed
layer consists of columns.
: Tag
Alphanumeric strings which can be assigned to a
client. This provides a mechanism to group clients with
similar properties. Clients can have one tag, e.g.
_work_, or several tags, e.g. _work+mail_.
Tags are separated with the _+_ character.
: View
A set of clients containing a specific tag, quite
similar to a workspace in other window managers. It
consists of the floating and managed layers.
: Column
A column is a screen area which arranges clients
vertically in a non-overlapping way. Clients can be
moved and resized between and within columns freely.
: Bar
The bar at the bottom of the screen displays a label
for each view and allows the creation of arbitrary
user-defined labels.
: Event
An event is a message which can be read from a
special file in the filesystem of `wmii`, such as a
mouse button press, a key press, or a message written by
a different 9P-client.
:
== Basic window management ==
Running a raw `wmii` process without a wmiirc(1) script provides
basic window management capabilities. However, to use it
effectively, remote control through its filesystem interface is
necessary. Without such a script, it is only possible to move
and resize clients with the mouse, but not to change their tags
or to switch views. Other interactions, such as customizing the
style, killing or retagging clients, and grabbing keys, cannot
be achieved without accessing the filesystem.
The filesystem can be accessed by connecting to the //address//
of `wmii` with any 9P-capable client, such as wmiir(1)
== Actions ==
The default configuration provides for a special menu of
actions. These consist of either shell scripts in $WMII_CONFPATH
or action definitions included in wmiirc.
Here is a list of the default actions:
| exec | Replace the window manager with another program
| quit | Leave the window manager nicely
| rehash | Refresh the program list
| showkeys | Display a list of key bindings recognized by wmii
| status | Periodically print date and load average to the bar
| welcome | Display a welcome message that contains the wmii tutorial
== Default Key Bindings ==
All of the provided `wmiirc` scripts accept at least the following key
bindings. They should also provide a `showkeys` action to open a
key binding quick-reference.
=== Moving Around ===
|| Key | Action
| Mod-h | Move to a window to the _left_ of the one currently focused
| Mod-l | Move to a window to the _right_ of the one currently focused
| Mod-j | Move to the window _below_ the one currently focused
| Mod-k | Move to a window _above_ the one currently focused
| Mod-space | Toggle between the managed and floating layers
| Mod-t <tag> | Move to the view of the given <tag>
| Mod-n | Move to the next view
| Mod-b | Move to the previous view
| Mod-//[0-9]// | Move to the view with the given number
=== Moving Things Around ===
|| Key | Action
| Mod-Shift-h | Move the current window _window_ to a column on the _left_
| Mod-Shift-l | Move the current window to a column on the _right_
| Mod-Shift-j | Move the current window below the window beneath it.
| Mod-Shift-k | Move the current window above the window above it.
| Mod-Shift-space | Toggle the current window between the managed and floating layer
| Mod-Shift-t <tag> | Move the current window to the view of the given <tag>
| Mod-Shift-//[0-9]// | Move the current window to the view with the given number
=== Miscellaneous ===
|| Key | Action
| Mod-m | Switch the current column to _max mode_
| Mod-s | Switch the current column to _stack mode_
| Mod-d | Switch the current column to _default mode_
| Mod-Shift-c | `Kill` the selected client
| Mod-p <program> | `Execute` <program>
| Mod-a <action> | `Execute` the named <action
| Mod-Enter | `Execute` an `@TERMINAL@`
= Configuration =
If you feel the need to change the default configuration, then
customize (as described above) the `wmiirc` action. This
action is executed at the end of the `wmii` script and does
all the work of setting up the window manager, the key bindings,
the bar labels, etc.
== Filesystem ==
Most aspects of `wmii` are controlled via the filesystem. It is
usually accessed via the wmiir(1) command, but it can be
accessed by any ``9P``, including plan9port's 9P[1], and can be
mounted natively on Linux via v9fs[1], and on Inferno (which man
run on top of Linux). All data in the filesystem, including
filenames, is UTF-8 encoded. However, when accessed via
wmiir(1), text is automatically translated to and from your
locale encoding.
The filesystem is, as are many other 9P filesystems, entirely
synthetic. The files exist only in memory, and are not written
to disk. They are generally initiated on wmii startup via a
script such as wmiirc. Several files are used to issue commands,
others simply act as if they were ordinary files (their contents
are updated and returned exactly as written), though writing
them has side-effects (such as changing key bindings). A
description of the filesystem layout and control commands
follows.
== Hierarchy ==
: /
Global control files
: /client/_*_/
Client control files
: /tag/_*_/
View control files
: /lbar/, /rbar/
Files representing the contents of the bottom bar
:
== The / Hierarchy ==
: colrules
The _colrules_ file contains a list of
rules which affect the width of newly created columns.
Rules have the form:
``` /<regex>/ -> <width>[+<width>]*
Where,
``` <width> := <percent of screen> | <pixels>px
When a new column, <n>, is created on a view whose name
matches <regex>, it is given the <n>th supplied <width>.
If there is no <n>th width, it is given 1/<ncol>th of the
screen.
: rules
PROVISIONAL
The _rules_ file contains a list of rules that may be used
to automatically set properties of new clients. Rules are
specified as:
``` /<regex>/ <key>=<value> ...
where each <key> represents a command in the clients _ctl_
file, and each <value> represents the value to assign to it.
The rules are applied when the client is first started and
the contents of the _props_ file match the regular
expression <regex>.
Additionally, the following keys are accepted and have
special meaning:
>>
: continue
Normally, when a matching rule is encountered, rule
matching stops. When the continue key is provided
(with any value), matching continues at the next
rule.
: force-tags=<tags>
Like _tags_, but overrides any settings obtained
obtained from the client's group or from the
**\_WMII_TAGS** window property.
<<
: keys
The _keys_ file contains a list of keys which
`wmii` will grab. Whenever these key combinations
are pressed, the string which represents them are
written to '/event' as: Key <string>
: event
The _event_ file never returns EOF while
`wmii` is running. It stays open and reports events
as they occur. Included among them are:
>>
: [Not]Urgent <client> [Manager|Client]
<client>'s urgent hint has been set or
unset. The second arg is [Client] if it's
been set by the client, and [Manager] if
it's been set by `wmii` via a control
message.
: [Not]UrgentTag <tag> [Manager|Client]
A client on <tag> has had its urgent hint
set, or the last urgent client has had its
urgent hint unset.
: Client<Click|MouseDown> <client> <button>
A client's titlebar has either been clicked or
has a button pressed over it.
: [Left|Right]Bar[Click|MouseDown] <button> <bar>
A left or right bar has been clicked or has a
button pressed over it.
:
<<
For a more comprehensive list of available events, see
_wmii.pdf_[2]
: ctl
The _ctl_ file takes a number of messages to
change global settings such as color and font, which can
be viewed by reading it. It also takes the following
commands:
>>
: quit
Quit `wmii`
: exec <prog>
Replace `wmii` with <prog>
: spawn <prog>
Spawn a new program, as if by the _-r_ flag.
:
<<
:
== The /client/ Hierarchy ==
Each directory under '/client/' represents an X11 client.
Each directory is named for the X window id of the window the
client represents, in the form that most X utilities recognize.
The one exception is the special 'sel' directory, which
represents the currently selected client.
: ctl
When read, the 'ctl' file returns the X window id
of the client. The following commands may be written to
it:
>>
: allow <flags>
The set of unusual actions the client is allowed to
perform, in the same format as the tag set.
>>
: activate
The client is allowed to activate
itself – that is, focus its window and,
as the case may require, uncollapse it
and select a tag it resides on. This
flag must be set on a client if you wish
it able to activate itself from the
system tray.
<<
: floating <on | off | always | never>
Defines whether this client is likely to float when
attached to a new view. Ordinarilly, the value
changes automatically whenever the window is
moved between the floating and managed layers.
However, setting a value of _always_ or _never_
overrides this behavior. Additionally, dialogs,
menus, docks, and splash screens will always
float unless this value is set to _never_.
: fullscreen <on | off | toggle>
Sets the client's fullscreen state.
: group <group id>
The client's group ID, or 0 if not part of a group.
Clients tend to open with the same tags and in the
same columns as the last active member of their
group. Setting this property is only useful when
done via the rules file.
: kill
Close the client's window.
: pid
Read-only value of the PID of the program that
owns the window, if the value is available and
the process is on the same machine as wmii.
: slay
Forcibly kill the client's connection to the X
server, closing all of its windows. Kill the parent
process if the client's PID is available.
: tags <tags>
The client's tags. The same as the tags file.
: urgent <on | off | toggle>
Set or unset the client's urgent hint.
<<
: label
Set or read a client's label (title).
: props
Returns a clients class and label as:
<instance>:<class>:<label>.
: tags
Set or read a client's tags. Tags are separated by
**+**, **-**, or **^**. Tags beginning with **+** are
added, while those beginning with **-** are removed and
those beginning with **^** are toggled. If the tag
string written begins with **+**, **^**, or **-**, the
written tags are added to or removed from the client's
set, otherwise the set is overwritten.
:
== The /tag/ Hierarchy ==
Each directory under '/tag/' represents a view, containing
all of the clients with the given tag applied. The special
'sel' directory represents the currently selected tag.
: ctl
The 'ctl' file can be read to retrieve the name
of the tag the directory represents, or written with the
following commands:
>>
: select
Select a client:
select [left|right|up|down] +
select [<row number>|sel] [<frame number>] +
select client <client>
: send
Send a client somewhere:
>>
: send [<client>|sel] [up|down|left|right]
: send [<client>|sel] <area>
Send <client> to the _n_th <area>
: send [<client>|sel] toggle
Toggle <client> between the floating and managed layer.
<<
: swap
Swap a client with another. Same syntax as send.
: grow
Grow or shrink a client.
``` grow <frame> <direction> [<amount>]
: nudge
Nudge a client in a given direction.
``` grow <frame> <direction> [<amount>]
:
<<
Where the arguments are defined as follows:
>>
: area
Selects a column or the floating area.
``` area ::= <area_spec> | <screen_spec>:<area_spec>
When <screen_spec> is omitted and <area_spec> is not "sel",
0 is assumed. "sel" by itself represents the selected client no
matter which screen it is on.
``` area_spec ::= "~" | <number> | "sel"
Where "~" represents the floating area and <number> represents a column
index, starting at one.
``` screen_spec ::= <number>
Where <number> representes the 0-based Xinerama screen number.
: frame
Selects a client window.
``` frame ::= <area> <index> | <area> sel | client <window-id>
Where <index> represents the nth frame of <area> or <window-id> is
the X11 window id of the given client.
: amount
The amount to grow or nudge something.
``` amount ::= <number> | <number>px
If "px" is given, <number> is interperated as an exact pixel count.
Otherwise, it's interperated as a "reasonable" amount, which is
usually either the height of a window's title bar, or its sizing
increment (as defined by X11) in a given direction.
<<
: index
Read for a description of the contents of a tag.
:
== The /rbar/, /lbar/ Hierarchy ==
The files under '/rbar/' and '/lbar/' represent the
items of the bar at the bottom of the screen. Files under
'/lbar/' appear on the left side of the bar, while those
under '/rbar/' appear on the right, with the leftmost item
occupying all extra available space. The items are sorted
lexicographically.
The files may be read or written to obtain or alter the colors
and text of the bars. The format is similar to the various _ctl_
files and should be self explanitory.
= FILES =
: /tmp/ns.$USER.${DISPLAY%.0}/wmii
The wmii socket file which provides a 9P service.
: @GLOBALCONF@
Global action directory.
: @LOCALCONF@
User-specific action directory. Actions are first searched here.
:
= ENVIRONMENT =
: $HOME, $DISPLAY
See the section **FILES** above.
:
The following variables are set and exported within `wmii` and
thus can be used in actions:
: $WMII_ADDRESS
The address on which `wmii` is listening.
: $WMII_CONFPATH
The path that wmii searches for its configuration
scripts and actions.
: $NAMESPACE
The namespace directory to use if no address is provided.
:
= SEE ALSO =
wimenu(1), wmii9menu(1), witray(1), wmiir(1), wihack(1) +
@DOCDIR@/wmii.pdf
@DOCDIR@/FAQ
[1] http://www.suckless.org/wiki/wmii/tips/9p_tips +
[2] @DOCDIR@/wmii.pdf
|
Added man/wmii9menu.1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | .TH "WMII9MENU" 1 "Oct, 2009" "wmii-@VERSION@" .SH NAME .P wmii9menu \- The wmii menu program .SH SYNOPSIS .P wmii9menu \fI[\-a \fI<address>\fR]\fR \fI[\-i \fI<initial>\fR]\fR \fI<item>\fR\fI[:\fI<command>\fR]\fR... wmii9menu \-v .SH DESCRIPTION .P \fBwmii9menu\fR is \fBwmii\fR's standard clickable menu program. It's used extensively by \fBwmii\fR and related programs to display clickable menus, namely for window titlebars and bar items. The name, along with the code, derives from the 9menu program, which in turn derives its name from Plan 9's style of clickable menus. .SH ARGUMENTS .TP \-a The address at which to connect to \fBwmii\fR. .TP \-i \fI<initial>\fR .RS If \fI<initial>\fR is listed among the other items on the command line, it is selected at startup, and the menu is positioned so that the mouse pointer is centered on said item. .RE .P : .SH USAGE .P \fBwmii9menu\fR is invoked with a list of arguments, each of which is displayed as a menu item. The first \fI:\fR in the item name, and any text following it, is stripped. The menu is opened such that the mouse pointer is centered on the selected item. If a mouse button is depressed when the menu opens, then releasing it will confirm the selection. Otherwise, a mouse press will do the same. When a selection is made, \fBwmii9menu\fR prints the result. If the selected item initially contained a \fI:\fR, the text following it is printed. Otherwise, the item text itself is printed. .SH ENVIRONMENT .TP \fB$WMII_ADDRESS\fR The address at which to connect to wmii. .TP \fB$NAMESPACE\fR The namespace directory to use if no address is provided. .SH SEE ALSO .P wmii(1), wmiir(1), wimenu(1) .P \fI[1]\fR http://www.suckless.org/wiki/wmii/tips/9p_tips .\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net) .\" cmdline: txt2tags -o- wmii9menu.man1 |
Added man/wmii9menu.man1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
WMII9MENU
wmii-@VERSION@
Oct, 2009
%!includeconf: header.t2t
= NAME =
wmii9menu - The wmii menu program
= SYNOPSIS =
wmii9menu [-a <address>] [-i <initial>] <item>[:<command>]...
wmii9menu -v
= DESCRIPTION =
`wmii9menu` is `wmii`'s standard clickable menu program. It's used
extensively by `wmii` and related programs to display clickable
menus, namely for window titlebars and bar items. The name, along
with the code, derives from the 9menu program, which in turn derives
its name from Plan 9's style of clickable menus.
= ARGUMENTS =
: -a
The address at which to connect to `wmii`.
: -i <initial>
If <initial> is listed among the other items on the command
line, it is selected at startup, and the menu is positioned
so that the mouse pointer is centered on said item.
:
= USAGE =
`wmii9menu` is invoked with a list of arguments, each of which is
displayed as a menu item. The first _:_ in the item name, and any
text following it, is stripped. The menu is opened such that the
mouse pointer is centered on the selected item. If a mouse button is
depressed when the menu opens, then releasing it will confirm the
selection. Otherwise, a mouse press will do the same. When a
selection is made, `wmii9menu` prints the result. If the selected
item initially contained a _:_, the text following it is printed.
Otherwise, the item text itself is printed.
= ENVIRONMENT =
: $WMII_ADDRESS
The address at which to connect to wmii.
: $NAMESPACE
The namespace directory to use if no address is
provided.
:
= SEE ALSO =
wmii(1), wmiir(1), wimenu(1)
[1] http://www.suckless.org/wiki/wmii/tips/9p_tips
|
Added man/wmiir.1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
.TH "wmiir" 1 "Oct, 2009" "wmii-@VERSION@"
.SH NAME
.P
wmiir \- The wmii 9P filesystem client
.SH SYNOPSIS
.P
wmiir \fI[\-a \fI<address>\fR]\fR \fI[\-b]\fR {create | ls \fI[\-dlp]\fR | read | remove | write} \fI<file>\fR
.P
wmiir \fI[\-a \fI<address>\fR]\fR \fI[\-b]\fR xwrite \fI<file>\fR \fI<data>\fR ...
.P
wmiir \-v
.SH DESCRIPTION
.P
\fBwmiir\fR is a simple 9P filesystem client which ships with \fBwmii\fR, and connects
to its virtual filesystem by default. \fBwmiir\fR is most often used to query and
issue commands to \fBwmii\fR, both from the command line and from its \fBsh\fR\-based
configuration scripts.
.P
Since the default encoding of 9P filesystems is UTF\-8, \fBwmiir\fR
assumes that all data read and written is text data and
translates to or from your locale character encoding as
necessary. When working with non\-text data in a non\-UTF\-8
locale, the \fI\-b\fR flag should be specified to disable this
behavior.
.SH ARGUMENTS
.TP
\-a
The address at which to connect to \fBwmii\fR.
.TP
\-b
.RS
With the \fI\-b\fR flag, data that you intend to read or
write is treated as binary data.
.RE
.P
:
.SH COMMANDS
.P
The following commands deal with 9P filesystems.
.TP
create \fI<file>\fR
Creates a new file or directory in the filesystem. Permissions and
file type are inferred by \fBwmii\fR. The contents of the standard input
are written to the new file.
.TP
ls \fI[\-dlp]\fR \fI<path>\fR
Lists the contents of \fI<path>\fR.
Flags:
.RS 8
.TP
\-d
Don't list the contents of directories.
.TP
\-l
Long output. For each file, list its permissions, owner,
group, size (bytes), mtime, and name.
.TP
\-p
Print the full path to each file.
.RS -8
.TP
read \fI<file>\fR
Reads the entire contents of a file from the filesystem. Blocks until
interrupted or EOF is received.
Synonyms: \fBcat\fR
.TP
remove \fI<path>\fR
Removes \fI<path>\fR from the filesystem.
Synonyms: \fBrm\fR
.TP
write \fI<file>\fR
Writes the contents of the standard input to \fI<file>\fR.
.TP
xwrite \fI<file>\fR \fI<data>\fR ...
Writes each argument after \fI<file>\fR to the latter.
.P
Additionally, wmiir provides the following utility commands relevant
to scripting wmii:
.TP
namespace
.RS
Prints the current wmii namespace directory, usually
equivalent to /tmp/ns.\fB$USER\fR.\fB${DISPLAY\fR%.0\fB}\fR, but possibly
different depending on the value of \fB$NAMESPACE\fR and
\fB$WMII_NAMESPACE\fR.
.RE
.RS
Synonyms: \fBns\fR
.RE
.TP
setsid \fI[\-0 \fI<argv0>\fR]\fR \fI[\-f]\fR \fI<command>\fR
.RS
Executes the given command after setting the session id (see
setsid(2)). If \fI\-0\fR is given, the command is run with the
given value as argv\fI[0]\fR. For instance, to run sh as a login
shell, one might run
.RE
.nf
wmiir setsid -0 -sh sh
.fi
.RS
If \fI\-f\fR is given, wmiir will fork into the background before
executing the command.
.RE
.TP
proglist \fI[\-\-]\fR \fI<directory>\fR ...
.RS
Lists all executable commands in the given directories.
.RE
.SH ENVIRONMENT
.TP
\fB$WMII_ADDRESS\fR
The address at which to connect to wmii.
.TP
\fB$NAMESPACE\fR
The namespace directory to use if no address is
provided.
.SH SEE ALSO
.P
wmii(1), libixp\fI[2]\fR
.P
\fI[1]\fR http://www.suckless.org/wiki/wmii/tips/9p_tips
.P
\fI[2]\fR http://libs.suckless.org/libixp
.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
.\" cmdline: txt2tags -o- wmiir.man1
|
Added man/wmiir.man1.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
wmiir
wmii-@VERSION@
Oct, 2009
%!includeconf: header.t2t
= NAME =
wmiir - The wmii 9P filesystem client
= SYNOPSIS =
wmiir [-a <address>] [-b] {create | ls [-dlp] | read | remove | write} <file> +
wmiir [-a <address>] [-b] xwrite <file> <data> ... +
wmiir -v
= DESCRIPTION =
`wmiir` is a simple 9P filesystem client which ships with `wmii`, and connects
to its virtual filesystem by default. `wmiir` is most often used to query and
issue commands to `wmii`, both from the command line and from its `sh`-based
configuration scripts.
Since the default encoding of 9P filesystems is UTF-8, `wmiir`
assumes that all data read and written is text data and
translates to or from your locale character encoding as
necessary. When working with non-text data in a non-UTF-8
locale, the _-b_ flag should be specified to disable this
behavior.
= ARGUMENTS =
: -a
The address at which to connect to `wmii`.
: -b
With the _-b_ flag, data that you intend to read or
write is treated as binary data.
:
= COMMANDS =
The following commands deal with 9P filesystems.
: create <file>
Creates a new file or directory in the filesystem. Permissions and
file type are inferred by `wmii`. The contents of the standard input
are written to the new file.
: ls [-dlp] <path>
Lists the contents of <path>.
Flags:
>>
: -d
Don't list the contents of directories.
: -l
Long output. For each file, list its permissions, owner,
group, size (bytes), mtime, and name.
: -p
Print the full path to each file.
<<
: read <file>
Reads the entire contents of a file from the filesystem. Blocks until
interrupted or EOF is received.
Synonyms: `cat`
: remove <path>
Removes <path> from the filesystem.
Synonyms: `rm`
: write <file>
Writes the contents of the standard input to <file>.
: xwrite <file> <data> ...
Writes each argument after <file> to the latter.
:
Additionally, wmiir provides the following utility commands relevant
to scripting wmii:
: namespace
Prints the current wmii namespace directory, usually
equivalent to /tmp/ns.$USER.${DISPLAY%.0}, but possibly
different depending on the value of $NAMESPACE and
$WMII_NAMESPACE.
Synonyms: `ns`
: setsid [-0 <argv0>] [-f] <command>
Executes the given command after setting the session id (see
setsid(2)). If _-0_ is given, the command is run with the
given value as argv[0]. For instance, to run sh as a login
shell, one might run
``` wmiir setsid -0 -sh sh
If _-f_ is given, wmiir will fork into the background before
executing the command.
: proglist [--] <directory> ...
Lists all executable commands in the given directories.
= ENVIRONMENT =
: $WMII_ADDRESS
The address at which to connect to wmii.
: $NAMESPACE
The namespace directory to use if no address is
provided.
:
= SEE ALSO =
wmii(1), libixp[2]
[1] http://www.suckless.org/wiki/wmii/tips/9p_tips +
[2] http://libs.suckless.org/libixp
|
Added mk/common.mk.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | all: install: all simpleinstall uninstall: simpleuninstall DOCDIR = $(DOC) simpleinstall: for f in $(DOCS); do \ $(INSTALL) 0644 $$f $(DOCDIR) $$f; \ done for f in $(TEXT); do \ $(INSTALL) 0644 $$f $(DIR) $$f; \ done for f in $(BINARY); do \ $(INSTALL) -b 0644 $$f $(DIR) $$f; \ done for f in $(EXECS); do \ $(INSTALL) 0755 $$f $(DIR) $$f; \ done simpleuninstall: for f in $(DOCS); do \ $(UNINSTALL) $$f $(DOCDIR) $$f; \ done for f in $(TEXT); do \ $(UNINSTALL) $$f $(DIR) $$f; \ done for f in $(BINARY); do \ $(UNINSTALL) -b $$f $(DIR) $$f; \ done for f in $(EXECS); do \ $(UNINSTALL) -b $$f $(DIR) $$f; \ done cleandep: echo CLEANDEP rm .depend 2>/dev/null || true tags: files=; \ for f in $(OBJ); do \ [ -f "$$f.c" ] && files="$$files $$f.c"; \ done; \ echo CTAGS $$files $(TAGFILES); \ if [ -n "$$files" ]; then $(DEBUG) $(CTAGS) $$files $(TAGFILES); fi .PHONY: all options clean dist install uninstall depend cleandep tags .PHONY: simpleuninstall simpleinstall |
Added mk/dir.mk.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
MKSUBDIR = \
set -e; \
targ=$@; targ=$${targ\#d}; \
for i in $$dirs; do \
export $(SUBMAKE_EXPORT) BASE=$(BASE)$$i/; \
if [ ! -d $$i ]; then \
echo Skipping nonexistent directory: $$i 1>&2; \
else \
echo MAKE $$targ $$BASE; \
(cd $$i && $(MAKE) $$targ) || exit $?; \
fi; \
done
dall:
+dirs="$(DIRS)"; $(MKSUBDIR)
dclean:
+dirs="$(DIRS)"; $(MKSUBDIR)
dinstall:
+dirs="$(INSTDIRS)"; $(MKSUBDIR)
duninstall:
+dirs="$(INSTDIRS)"; $(MKSUBDIR)
ddepend:
+dirs="$(DIRS)"; $(MKSUBDIR)
dtags:
+dirs="$(DIRS)"; $(MKSUBDIR)
all: dall
clean: dclean
install: dinstall
uninstall: duninstall
depend: ddepend
tags: dtags
INSTDIRS = $(DIRS)
|
Added mk/gcc.mk.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | DEBUGCFLAGS = \ -g \ -O0 \ -fno-builtin \ -fno-inline \ -fno-omit-frame-pointer \ -fno-optimize-sibling-calls \ -fno-unroll-loops CFLAGS += \ -std=c99 \ -pedantic \ -pipe \ -fno-strict-aliasing \ -Wall \ -Wimplicit \ -Wmissing-prototypes \ -Wno-comment \ -Wno-missing-braces \ -Wno-parentheses \ -Wno-sign-compare \ -Wno-switch \ -Wpointer-arith \ -Wreturn-type \ -Wstrict-prototypes \ -Wtrigraphs MKDEP = cpp -M SOCFLAGS += -fPIC |
Added mk/hdr.mk.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
DIR =
DIRS =
DOC =
DOCDIR =
DOCS =
EXECS =
HFILES =
INCLUDES =
LIB =
LIBS =
OBJ =
OFILES =
OFILES_PIC =
PACKAGES =
PROG =
SO =
TAGFILES =
TARG =
TEXT =
FILTER = cat
EXCFLAGS = $(INCLUDES) -D_XOPEN_SOURCE=600
COMPILE_FLAGS = $(EXCFLAGS) $(CFLAGS)
COMPILE = $(SHELL) $(ROOT)/util/compile "$(CC)" "$(PACKAGES)" "$(COMPILE_FLAGS)"
COMPILEPIC = $(SHELL) $(ROOT)/util/compile "$(CC)" "$(PACKAGES)" "$(COMPILE_FLAGS) $(SOCFLAGS)"
LINK = $(SHELL) $(ROOT)/util/link "$(LD)" "$(PACKAGES)" "$(LIBS) $(LDFLAGS)"
LINKSO = $(SHELL) $(ROOT)/util/link "$(LD)" "$(PACKAGES)" "$(SOLDFLAGS) $(LIBS) $(SHARED)"
CLEANNAME=$(SHELL) $(ROOT)/util/cleanname
SOEXT=so
TAGFILES=
CTAGS=ctags --fields=+S --c-kinds=+px
PACKAGES =
# Try to find a sane shell. /bin/sh is a last resort, because it's
# usually bash on Linux, which means it's painfully slow.
SHELLSEARCH = for sh in /bin/dash /bin/ksh /bin/sh; do \
if test -x $$sh; then echo $$sh; exit; fi; done
BINSH:= $(shell $(SHELLSEARCH))
BINSH!= $(SHELLSEARCH)
SHELL := $(BINSH)
.SHELL: name=sh path=$(SHELL)
all:
include $(ROOT)/config.mk
sinclude $(ROOT)/config.local.mk
sinclude $(shell echo .)depend
.SILENT:
.SUFFIXES: .$(SOEXT) .1 .3 .awk .build .c .clean .depend .install .man1 .man3 .o .o_pic .out .pdf .py .rc .sh .uninstall
.c.depend:
echo MKDEP $<
$(DEBUG) eval "$(MKDEP) $(COMPILE_FLAGS)" $< | sed '1s|.*:|$(<:%.c=%.o):|' >>.depend
.sh.depend .rc.depend .1.depend .3.depend .awk.depend:
:
.c.o:
$(COMPILE) $@ $<
.c.o_pic:
$(COMPILEPIC) $@ $<
.o.out:
$(LINK) $@ $<
.c.out:
$(COMPILE) $(<:.c=.o) $<
$(LINK) $@ $(<:.c=.o)
.rc.out .awk.out .sh.out:
echo FILTER $(BASE)$<
[ -n "$(<:%.sh=)" ] || $(BINSH) -n $<
set -e; \
$(DEBUG) $(FILTER) $< >$@; \
$(DEBUG) chmod 0755 $@
.man1.1 .man3.3:
echo TXT2TAGS $(BASE)$<
$(DEBUG) txt2tags -o- $< >$@
DEBUG = _debug() { [ -n "$$noisycc" ] && echo >&2 $$@ || true; "$$@"; }; _debug
INSTALL= _install() { set -e; \
dashb=$$1; [ $$1 = -b ] && shift; \
d=$(DESTDIR)$$3; f=$$d/$$(basename $$4); \
if [ ! -d $$d ]; then echo MKDIR $$3; mkdir -p $$d; fi; \
echo INSTALL $$($(CLEANNAME) $(BASE)$$2); \
$(DEBUG) rm -f $$f; \
if [ "$$dashb" = -b ]; \
then $(DEBUG) cp -f $$2 $$f; \
else $(DEBUG) $(FILTER) <$$2 >$$f; \
fi; \
$(DEBUG) chmod $$1 $$f; \
}; _install
UNINSTALL= _uninstall() { set -e; \
echo UNINSTALL $$($(CLEANNAME) $(BASE)$$1); \
$(DEBUG) rm -f $(DESTDIR)$$2/$$(basename $$3); \
}; _uninstall
.out.install:
$(INSTALL) -b 0755 $< $(BIN) $*
.out.uninstall:
$(UNINSTALL) $< $(BIN) $*
.a.install .$(SOEXT).install:
$(INSTALL) -b 0644 $< $(LIBDIR) $<
.a.uninstall .$(SOEXT).uninstall:
$(UNINSTALL) $< $(LIBDIR) $<
.h.install:
$(INSTALL) 0644 $< $(INCLUDE) $<
.h.uninstall:
$(UNINSTALL) $< $(INCLUDE) $<
.pdf.install:
$(INSTALL) -b 0644 $< $(DOC) $<
.pdf.uninstall:
$(UNINSTALL) $< $(DOC) $<
INSTALMAN= _installman() { man=$${1\#\#*.}; $(INSTALL) 0644 $$1 $(MAN)/man$$man $$1; }; _installman
UNINSTALLMAN=_uninstallman() { man=$${1\#\#*.}; $(UNINSTALL) $$1 $(MAN)/man$$man $$1; }; _uninstallman
MANSECTIONS=1 2 3 4 5 6 7 8 9
$(MANSECTIONS:%=.%.install):
$(INSTALMAN) $<
$(MANSECTIONS:%=.%.uninstall):
$(UNINSTALLMAN) $<
.out.clean:
echo CLEAN $$($(CLEANNAME) $(BASE)$<)
rm -f $< || true 2>/dev/null
rm -f $*.o || true 2>/dev/null
.o.clean .o_pic.clean:
echo CLEAN $$($(CLEANNAME) $(BASE)$<)
rm -f $< || true 2>/dev/null
printinstall:
clean:
install: printinstall
depend: cleandep
include $(ROOT)/mk/common.mk
|
Added mk/lib.mk.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | PTARG = $(ROOT)/lib/$(TARG) LIB = $(PTARG).a OFILES = $(OBJ:=.o) all: $(HFILES) $(LIB) install: $(PTARG).install uninstall: $(PTARG).uninstall clean: libclean depend: $(OBJ:=.depend) libclean: for i in $(LIB) $(OFILES); do \ [ -e $$i ] && \ echo CLEAN $$($(CLEANNAME) $(BASE)$$i); \ rm -f $$i; \ done 2>/dev/null || true printinstall: echo 'Install directories:' echo ' Lib: $(LIBDIR)' $(LIB): $(OFILES) echo AR $$($(CLEANNAME) $(BASE)/$@) mkdir $(ROOT)/lib 2>/dev/null || true $(AR) $@ $(OFILES) SOMKSH=case "$(MAKESO)" in 1|[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) echo $(ROOT)/mk/so.mk;; *) echo /dev/null;; esac SOMK:=$(shell $(SOMKSH)) SOMK!=$(SOMKSH) include $(SOMK) |
Added mk/man.mk.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
targ = for k in $(MANPAGES); do echo $$k | sed 's/ .*//'; done
TARG:= $(shell $(targ))
TARG!= $(targ)
all: $(TARG)
install: $(TARG:.1=.install) $(TARG:.3=.install) maninstall
uninstall: $(TARG:.1=.uninstall) $(TARG:.3=.uninstall) manuninstall
.PHONY: maninstall manuninstall
MANLOOP = \
set -ef; \
for k in $(MANPAGES); do \
set -- $$k; \
real=$$1; shift; \
for targ; do \
_ $$real $(MAN)/man$${real\#\#*.}/$$targ; \
done; \
done
maninstall:
_() { echo LN $$1 $${2##*/}; ln -sf $$1 $(DESTDIR)$$2; }; $(MANLOOP)
manuninstall:
_() { echo RM $${2##*/}; rm -f $(DESTDIR)$$2; }; $(MANLOOP)
printinstall:
echo 'Install directories:'
echo ' Man: $(MAN)'
|
Added mk/many.mk.
> > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | PROGS = $(TARG:=.out) all: $(OFILES) $(PROGS) install: $(TARG:=.install) uninstall: $(TARG:=.uninstall) depend: $(OFILES:.o=.depend) $(TARG:=.depend) clean: manyclean printinstall: echo 'Install directories:' echo ' Bin: $(BIN)' manyclean: for i in $(TARG:=.o) $(TARG:=.out) $(OFILES); do \ [ -e $$i ] && \ echo CLEAN $$($(CLEANNAME) $(BASE)$$i); \ rm -f $$i; \ done 2>/dev/null || true |
Added mk/one.mk.
> > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | PROG = $(TARG).out OFILES = $(OBJ:=.o) all: $(PROG) install: $(TARG).install uninstall: $(TARG).uninstall clean: oneclean depend: $(OBJ:=.depend) printinstall: echo 'Install directories:' echo ' Bin: $(BIN)' oneclean: for i in $(PROG) $(OFILES); do \ [ -e $$i ] && \ echo CLEAN $$($(CLEANNAME) $(BASE)$$i); \ rm -f $$i; \ done 2>/dev/null || true $(OFILES): $(HFILES) $(PROG): $(OFILES) $(LIB) $(LINK) $@ $(OFILES) $(LIB) |
Added mk/python.mk.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# all: pybuild
install: $(PYMODULES:%=%.install)
clean: pyclean
.py.install:
echo PYTHON install $* $(PYPREFIX)
DESTDIR=$(DESTDIR); \
$(DEBUG) $(PYTHON) $< install -c --root=$${DESTDIR:-/} $(PYPREFIX)
pyclean:
echo CLEAN build/
rm -rf build
.PHONY: pybuild pyclean
|
Added mk/so.mk.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | SOPTARG = $(ROOT)/lib/$(TARG) SO = $(SOPTARG).$(SOEXT) SONAME = $(TARG).$(SOEXT) OFILES_PIC = $(OBJ:=.o_pic) all: $(HFILES) $(SO) install: $(SOPTARG).install uninstall: $(SOPTARG).uninstall clean: soclean depend: $(OBJ:=.depend) soclean: for i in $(SO) $(OFILES_PIC); do \ [ -e $$i ] && \ echo CLEAN $$($(CLEANNAME) $(BASE)$$i); \ rm -f $$i; \ done 2>/dev/null || true printsoinstall: echo 'Install directories:' echo ' Lib: $(LIBDIR)' printinstall: printsoinstall $(SO): $(OFILES_PIC) mkdir $(ROOT)/lib 2>/dev/null || true $(LINKSO) $@ $(OFILES_PIC) |
Added mk/wmii.mk.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
VERS = hg$$(hg identify -n)
VERS = $$(test -n "$$WMII_HGVERSION" && echo $$WMII_HGVERSION || \
echo -n "hg$$(hg id -n 2>/dev/null)")
WMII_HGVERSION = $(VERS)
WMII_HGVERSION:= $(shell echo $(VERS))
WMII_HGVERSION!= echo $(VERS)
VERSION = $(WMII_HGVERSION)
COPYRIGHT = ©2010 Kris Maglione
CONFDIR = wmii-hg
LOCALCONF = ~/.$(CONFDIR)
GLOBALCONF = $(ETC)/$(CONFDIR)
.MAKE.EXPORTED += WMII_HGVERSION
SUBMAKE_EXPORT = WMII_HGVERSION=$(WMII_HGVERSION)
LIBS9 = $(ROOT)/lib/libstuff.a $(ROOT)/lib/libregexp9.a $(ROOT)/lib/libbio.a $(ROOT)/lib/libfmt.a $(ROOT)/lib/libutf.a
CFLAGS += '-DVERSION=\"$(VERSION)\"' '-DCOPYRIGHT=\"$(COPYRIGHT)\"' \
'-DCONFDIR=\"$(CONFDIR)\"' '-DCONFPREFIX=\"$(ETC)\"' \
'-DLOCALCONF=\"$(LOCALCONF)\"' '-DGLOBALCONF=\"$(GLOBALCONF)\"' \
-DIXP_NEEDAPI=129
FILTER = sed "s|@ALTDOC@|$(DOC)/alternative_wmiircs|g; \
s|@BINSH@|$(BINSH)|g; \
s|@CONFDIR@|$(CONFDIR)|g; \
s|@CONFPREFIX@|$(ETC)|g; \
s|@DOCDIR@|$(DOC)|g; \
s|@EXAMPLES@|$(DOC)/examples|g; \
s|@GLOBALCONF@|$(GLOBALCONF)|g; \
s|@LIBDIR@|$(LIBDIR)|g; \
s|@LOCALCONF@|$(LOCALCONF)|g; \
s|@PYTHON@|$(PYTHON)|g; \
s|@TERMINAL@|$(TERMINAL)|g; \
s|@VERSION@|$(VERSION)|g; \
/^@@/d;"
|
Added rc/Makefile.
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | ROOT=.. include $(ROOT)/mk/hdr.mk include $(ROOT)/mk/wmii.mk BIN = $(GLOBALCONF) TARG = wmiirc \ welcome include $(ROOT)/mk/many.mk |
Added rc/sh.wmii.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
#!sh
# WMII Configuration
load std string regex expr echo
argv0 = $0
#mount -Aa {os dial unix!/tmp/ns.kris.:1/wmii >[1=0]} / || raise mount
#mount -Aa {styxmon {os rc -c 'dial $WMII_ADDRESS' >[1=0]}} / || raise mount
mount -Aa {os rc -c 'dial $WMII_ADDRESS' >[1=0]} / || raise mount
{`{read} && echo halt>/dev/sysctl}&
MODKEY=Mod1
UP=k
DOWN=j
LEFT=h
RIGHT=l
WMII_FONT=fixed
WMII_NORMCOLORS=('#222222' '#5FBF77' '#2A7F3F')
WMII_FOCUSCOLORS=('#ffffff' '#153F1F' '#2A7F3F')
WMII_BACKGROUND='#333333'
WMII_TERM=urxvt
fn wmiimenu {
(nf nb nil sf sb nil) := ($WMII_NORMCOLORS $WMII_FOCUSCOLORS)
os -d ${hostenv HOME} (
dmenu -b -fn $WMII_FONT
-nf $nf -nb $nb -sf $sf -sb $sb)
}
fn 9menu {
os -d ${hostenv HOME} (
wmii9menu -font ${hd ${split , $WMII_FONT}}
-^(nf nb br)^$WMII_NORMCOLORS
-^(sf sb br)^$WMII_FOCUSCOLORS $*)
}
# Column Rules
echo '/./ -> 60+40' >/colrules
# Tagging Rules
echo '
/Firefox/ -> www
/XMMS.*/ -> ~
/MPlayer.*/ -> ~
/.*/ -> sel
' >/tagrules
subfn seq {
result=${expr $* seq}
}
subfn hostenv {
arg := $"*
result="{os rc -c 'echo -n $'^$arg </dev/null}
}
subfn ftl {
result=${tl $*}
result=$"result
}
subfn lines {
ifs := "{echo}
arg := $*
result = `{$arg}
}
fn 'fn?' {
args := $*
~ ("{rescue '*' {} {whatis $args >[2]/dev/null}}
'load std; fn '*)
}
fn ifx {
(pred fn val args) := $*
if {$pred $val} {$fn $val $args}
}
fn dofn {
ifx 'fn?' {$*} $*
}
fn run_command {
os -b -d ${hostenv HOME} $* &
}
fn dprint {
arg := $*
or {~ $#debug 0} {~ $debug '' 0} { echo $arg }
}
subfn config_whatis {
result=${lines {os rc -c 'PATH=$WMII_CONFPATH which $*' $* </dev/null} $*}
}
# Status Bar Info
fn status {
echo ${re mg '[0-9]+\.[0-9]+' "{os uptime}} '|' `{date}
}
for(i in Key Event Action) {
'{fn $i { fn '$i'-$1 ${tl $*} }}'
}
# Events
Event Start {
if {~ $1 wmiirc} {
rm -f $progs_file
exit
}
}
Event Key {
dprint Key-$1
Key-$1 $1
}
Event CreateTag { echo $WMII_NORMCOLORS $* > /lbar/$"* }
Event DestroyTag { rm /lbar/$"* }
Event FocusTag { echo $WMII_FOCUSCOLORS $* > /lbar/$"* }
Event UnfocusTag { echo $WMII_NORMCOLORS $* > /lbar/$"* }
Event UrgentTag { echo '*'${ftl $*} > /lbar/${ftl $*} }
Event NotUrgentTag { echo ${tl $*} > /lbar/${ftl $*} }
Event LeftBarClick {
(button name) := $*
if {~ $button 1} { echo view $name >/ctl }
}
Event LeftBarMouseDown {
(button name) := $*
if {~ $button 3} { echo view "{9menu ${lines read_tags}} >/ctl & }
}
lastcmd=''
Event ClientMouseDown {
(client button) := $*
if {~ $button 3} {
lastcmd = `{9menu -initial $lastcmd Nop Delete Fullscreen}
if{~ $#lastcmd 0} {lastcmd=''}
cmp := {~ $lastcmd $*}
if {$cmp Nop} {
} {$cmp Delete} { echo kill >/client/$client/ctl
} {$cmp Fullscreen} { echo Fullscreen toggle >/client/$client/ctl
}
}
}
# Actions
Action quit { echo quit >>/ctl }
Action rehash {
flag x -
proglist ${hostenv PATH} >$progs_file
}
Action status {
flag x -
if {rm /rbar/status >[2]/dev/null} { sleep 1 }
echo $WMII_NORMCOLORS >/rbar/status
while {status >/rbar/status} { sleep 1 }
}
ifx {ftest -x $*} {run $*} $home/.wmii-3.5/sh.wmii.local
fn Key { ifx {! 'fn?' $*} {fn $*} Key-$1 ${tl $*} }
fn Action {
(action args) := $*
or {dofn Action-$action $args} {
ifx {! ~ $#* 0} {run_command $*} ${config_whatis $action} $args
}
}
# Key Bindings
Key $MODKEY-Control-t {
if { ~ `{wc -l /keys} 0 1} {
initkeys
echo grabmod $MODKEY >/ctl
} {
echo $MODKEY-Control-t >/keys
echo grabmod Mod3 >/ctl
}
}
Key $MODKEY-$LEFT { echo select left >/tag/sel/ctl }
Key $MODKEY-$RIGHT { echo select right >/tag/sel/ctl }
Key $MODKEY-$UP { echo select up >/tag/sel/ctl }
Key $MODKEY-$DOWN { echo select down >/tag/sel/ctl }
Key $MODKEY-Shift-$LEFT { echo send sel left >/tag/sel/ctl }
Key $MODKEY-Shift-$RIGHT { echo send sel right >/tag/sel/ctl }
Key $MODKEY-Shift-$DOWN { echo send sel down >/tag/sel/ctl }
Key $MODKEY-Shift-$UP { echo send sel up >/tag/sel/ctl }
Key $MODKEY-space { echo select toggle >/tag/sel/ctl }
Key $MODKEY-Shift-space { echo send sel toggle >/tag/sel/ctl }
Key $MODKEY-d { echo colmode sel default >/tag/sel/ctl }
Key $MODKEY-s { echo colmode sel stack >/tag/sel/ctl }
Key $MODKEY-m { echo colmode sel max >/tag/sel/ctl }
Key $MODKEY-f { echo Fullscreen toggle >/client/sel/ctl }
Key $MODKEY-Shift-c { echo kill >/client/sel/ctl }
Key $MODKEY-a { Action `{actionlist | wmiimenu} & }
Key $MODKEY-p { run_command rc -c "{wmiimenu <$progs_file} & }
Key $MODKEY-Return { run_command $WMII_TERM & }
Key $MODKEY-t { echo view `{read_tags | wmiimenu} >/ctl & }
Key $MODKEY-Shift-t {
sel := "{cat /client/sel/ctl}
read_tags | wmiimenu >/client/$sel/tags
}
Key $MODKEY-^${seq 0 9} { echo view ${tl ${splitr $1 -}} >/ctl }
Key Shift-$MODKEY-${seq 0 9} { echo ${tl ${splitr $1 -}} >/client/sel/tags}
# Functions
fn proglist {
os find ${split : $"*} -maxdepth 1 -type f </dev/null | sed 's,.*/,,' | sort | uniq
#for(d in /n/local^${split : $"*}) {
# fs filter {mode -d} $d
#} | sed 's,.*/,,' | sort | uniq
}
fn getfuns {
ls -p /env | sed -n 's/^fn-' ^ $1 ^ '-//p'
}
fn actionlist {
{ rescue '*' {} {
proglist ${hostenv WMII_CONFPATH}
}
getfuns Action
} | sort | uniq
}
fn initkeys {
getfuns Key >/keys
}
fn read_tags {
ls -p /tag | grep -v '^sel$'
}
# WM Configuration
{
echo grabmod $MODKEY
echo border 2
echo font $WMII_FONT
echo focuscolors $WMII_FOCUSCOLORS
echo normcolors $WMII_NORMCOLORS
} >/ctl
# Misc Setup
os xsetroot -solid $WMII_BACKGROUND </dev/null
dofn Local-Overrides
Action status &
progs_file=/tmp/proglist.${pid}
Action rehash &
# Tag Bar Setup
seltag=${lines sed 1q /tag/sel/ctl}
comm -13 ${pipe from {read_tags}} ${pipe from {ls -p /lbar/*}} |
getlines { rm /lbar/$line }
read_tags | getlines {
if {~ $line $seltag} {
echo $WMII_FOCUSCOLORS $line
} {
echo $WMII_NORMCOLORS $line
} >/lbar/$line
}
# Keygrab Setup
initkeys
echo Start wmiirc >/event
# Event Loop
getlines {
(event args) := ${split ' ' $line}
dprint Event-$event: $args
rescue '*' { dprint Exception: $exception } {
dofn Event-$event $args
} </dev/null
dprint loop
} </event
|
Added rc/welcome.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
#!/bin/sh
# display a welcome message that contains the wmii tutorial
xmessage -file - <<'EOF'
Welcome to wmii, the non-wimp environment of the Suckless Project.
This is a small step by step tutorial, intended to make you a
little bit familiar with wmii. For a more detailed walkthrough,
see @DOCDIR@/wmii.pdf.
From here on, keypresses will be described such that M-a refers to
pressing your modifier and a at the same time. The default modifier
key, hereafter $MODKEY, is the Windows(R) key, but it may also be Alt.
Let's go!
* Start two @TERMINAL@s by pressing M-Return twice.
* Switch between the three windows: M-j, M-k,
M*h, M-l
If you prefer to use the mouse, then just move the pointer to
the desired window.
* Try the other column modes: M-s for stack mode,
M*m for max mode Press M-d to return to default
mode.
* Create a new column with: M-Shift-l
This moves the client rightwards.
* Tag the selected client with another tag: M-Shift-2
IMPORTANT: before you do the next step, note that you
can select the current tag with M-1.
* Select the new tag: M-2
* Select the floating area: M-Space
* Open the programs menu: M-p
Type 'xclock' and press Enter.
* Move the xclock window: Hold $MODKEY, left-click on the
window and move the cursor around.
* Resize the xclock window: Hold $MODKEY, right-click the
window and move the cursor around.
* Kill the selected client (the xclock window) with: M-Shift-c
* Open the actions menu: M-a
Show the list of key bindings by selecting 'showkeys'
* We'll now have a look at the internal filesystem used by
wmii. Executing
wmiir ls /
in the shell of the terminal will list all the files in the
root directory.
Entries ending with / are directories.
If you are curious, you can now dig deeper into the
directory trees. For instance,
wmiir ls /rbar/
will show you the content of the right half of the bar.
We hope that these steps gave you an idea of how wmii works.
You can reread them at any time by pressing M-a and
selecting 'welcome'.
You should now take a look at the wmii(1) man page. A FAQ is
available at <http://wmii.suckless.org>.
Further documentation, including alternative configuration
possibilities, is provided in @DOCDIR@.
EOF
|
Added rc/wmiirc.sh.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
#!@BINSH@ -f
# Configure wmii
wmiiscript=wmiirc # For wmii.sh
. wmii.sh
# Configuration Variables
MODKEY=Mod4
UP=k
DOWN=j
LEFT=h
RIGHT=l
# Bars
noticetimeout=5
noticebar=/rbar/!notice
# Colors tuples: "<text> <background> <border>"
export WMII_NORMCOLORS='#000000 #c1c48b #81654f'
export WMII_FOCUSCOLORS='#000000 #81654f #000000'
export WMII_BACKGROUND='#333333'
export WMII_FONT='-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*'
set -- $(echo $WMII_NORMCOLORS $WMII_FOCUSCOLORS)
export WMII_TERM="@TERMINAL@"
# Ask about MODKEY on first run
if ! test -d "${WMII_CONFPATH%%:*}"; then
mkdir "${WMII_CONFPATH%%:*}"
res=$(wihack -type DIALOG xmessage -nearmouse -buttons Windows,Alt -print -fn $WMII_FONT \
"Welcome to wmii,$wi_newline$wi_newline" \
"Most of wmii's default key bindings make use of the$wi_newline" \
"Windows key, or equivalent. For keyboards lacking such$wi_newline" \
"a key, many users change this to the Alt key.$wi_newline$wi_newline" \
"Which would you prefer?")
[ "$res" = "Alt" ] && MODKEY=Mod1
echo "MODKEY=$MODKEY" >"${WMII_CONFPATH%%:*}/wmiirc_local"
chmod +x "${WMII_CONFPATH%%:*}/wmiirc_local"
fi
# Menu history
hist="${WMII_CONFPATH%%:*}/history"
histnum=5000
# Column Rules
wmiir write /colrules <<!
/gimp/ -> 17+83+41
/.*/ -> 62+38 # Golden Ratio
!
# Tagging Rules
wmiir write /rules <<!
# Apps with system tray icons like to their main windows
# Give them permission.
/^Pidgin:/ allow=+activate
# MPlayer and VLC don't float by default, but should.
/MPlayer|VLC/ floating=on
# ROX puts all of its windows in the same group, so they open
# with the same tags. Disable grouping for ROX Filer.
/^ROX-Filer:/ group=0
!
# Status Bar Info
status() {
echo -n label $(uptime | sed 's/.*://; s/, / /g') '|' $(date)
}
# Generic overridable startup details
startup() { witray & }
wi_runconf -s wmiirc_local
startup
echo colors $WMII_NORMCOLORS | wmiir create $noticebar
# Event processing
wi_events <<'!'
# Events
Event CreateTag
echo colors "$WMII_NORMCOLORS$wi_newline" label "$@" | wmiir create "/lbar/$@"
Event DestroyTag
wmiir remove "/lbar/$@"
Event FocusTag
wmiir xwrite "/lbar/$@" colors "$WMII_FOCUSCOLORS"
Event UnfocusTag
wmiir xwrite "/lbar/$@" colors "$WMII_NORMCOLORS"
Event UrgentTag
shift
wmiir xwrite "/lbar/$@" label "*$@"
Event NotUrgentTag
shift
wmiir xwrite "/lbar/$@" label "$@"
Event LeftBarClick LeftBarDND
shift
wmiir xwrite /ctl view "$@"
Event Unresponsive
{
client=$1; shift
msg="The following client is not responding. What would you like to do?$wi_newline"
resp=$(wihack -transient $client \
xmessage -nearmouse -buttons Kill,Wait -print \
-fn "${WMII_FONT%%,*}" "$msg $(wmiir read /client/sel/label)")
if [ "$resp" = Kill ]; then
wmiir xwrite /client/$client/ctl slay &
fi
}&
Event Notice
wmiir xwrite $noticebar label $wi_arg
kill $xpid 2>/dev/null # Let's hope this isn't reused...
{ sleep $noticetimeout; wmiir xwrite $noticebar label; }&
xpid = $!
# Menus
Menu Client-3-Delete
wmiir xwrite /client/$1/ctl kill
Menu Client-3-Kill
wmiir xwrite /client/$1/ctl slay
Menu Client-3-Fullscreen
wmiir xwrite /client/$1/ctl Fullscreen on
Event ClientMouseDown
wi_fnmenu Client $2 $1 &
Menu LBar-3-Delete
tag=$1; clients=$(wmiir read "/tag/$tag/index" | awk '/[^#]/{print $2}')
for c in $clients; do
if [ "$tag" = "$(wmiir read /client/$c/tags)" ]
then wmiir xwrite /client/$c/ctl kill
else wmiir xwrite /client/$c/ctl tags -$tag
fi
[ "$tag" = "$(wi_seltag)" ] &&
wmiir xwrite /ctl view $(wi_tags | wi_nexttag)
done
Event LeftBarMouseDown
wi_fnmenu LBar "$@" &
# Actions
Action showkeys
echo "$KeysHelp" | xmessage -file - -fn ${WMII_FONT%%,*}
Action quit
wmiir xwrite /ctl quit
Action exec
wmiir xwrite /ctl exec "$@"
Action rehash
wi_proglist $PATH >$progsfile
Action status
set +xv
if wmiir remove /rbar/status 2>/dev/null; then
sleep 2
fi
echo colors "$WMII_NORMCOLORS" | wmiir create /rbar/status
while status | wmiir write /rbar/status; do
sleep 1
done
# Key Bindings
KeyGroup Moving around
Key $MODKEY-$LEFT # Select the client to the left
wmiir xwrite /tag/sel/ctl select left
Key $MODKEY-$RIGHT # Select the client to the right
wmiir xwrite /tag/sel/ctl select right
Key $MODKEY-$UP # Select the client above
wmiir xwrite /tag/sel/ctl select up
Key $MODKEY-$DOWN # Select the client below
wmiir xwrite /tag/sel/ctl select down
Key $MODKEY-space # Toggle between floating and managed layers
wmiir xwrite /tag/sel/ctl select toggle
KeyGroup Moving through stacks
Key $MODKEY-Control-$UP # Select the stack above
wmiir xwrite /tag/sel/ctl select up stack
Key $MODKEY-Control-$DOWN # Select the stack below
wmiir xwrite /tag/sel/ctl select down stack
KeyGroup Moving clients around
Key $MODKEY-Shift-$LEFT # Move selected client to the left
wmiir xwrite /tag/sel/ctl send sel left
Key $MODKEY-Shift-$RIGHT # Move selected client to the right
wmiir xwrite /tag/sel/ctl send sel right
Key $MODKEY-Shift-$UP # Move selected client up
wmiir xwrite /tag/sel/ctl send sel up
Key $MODKEY-Shift-$DOWN # Move selected client down
wmiir xwrite /tag/sel/ctl send sel down
Key $MODKEY-Shift-space # Toggle selected client between floating and managed layers
wmiir xwrite /tag/sel/ctl send sel toggle
KeyGroup Client actions
Key $MODKEY-f # Toggle selected client's fullsceen state
wmiir xwrite /client/sel/ctl Fullscreen toggle
Key $MODKEY-Shift-c # Close client
wmiir xwrite /client/sel/ctl kill
KeyGroup Changing column modes
Key $MODKEY-d # Set column to default mode
wmiir xwrite /tag/sel/ctl colmode sel default-max
Key $MODKEY-s # Set column to stack mode
wmiir xwrite /tag/sel/ctl colmode sel stack-max
Key $MODKEY-m # Set column to max mode
wmiir xwrite /tag/sel/ctl colmode sel stack+max
KeyGroup Running programs
Key $MODKEY-a # Open wmii actions menu
action $(wi_actions | wimenu -h "${hist}.actions" -n $histnum) &
Key $MODKEY-p # Open program menu
eval wmiir setsid "$(wimenu -h "${hist}.progs" -n $histnum <$progsfile)" &
Key $MODKEY-Return # Launch a terminal
eval wmiir setsid $WMII_TERM &
KeyGroup Other
Key $MODKEY-Control-t # Toggle all other key bindings
case $(wmiir read /keys | wc -l | tr -d ' \t\n') in
0|1)
echo -n "$Keys" | wmiir write /keys
wmiir xwrite /ctl grabmod $MODKEY;;
*)
wmiir xwrite /keys $MODKEY-Control-t
wmiir xwrite /ctl grabmod Mod3;;
esac
KeyGroup Tag actions
Key $MODKEY-t # Change to another tag
wmiir xwrite /ctl view $(wi_tags | wimenu -h "${hist}.tags" -n 50) &
Key $MODKEY-Shift-t # Retag the selected client
# Assumes left-to-right order of evaluation
wmiir xwrite /client/$(wi_selclient)/ctl tags $(wi_tags | wimenu -h "${hist}.tags" -n 50) &
Key $MODKEY-n # Move to the next tag
wmiir xwrite /ctl view $(wi_tags | wi_nexttag)
Key $MODKEY-b # Move to the previous tag
wmiir xwrite /ctl view $(wi_tags | sort -r | wi_nexttag)
!
for i in 0 1 2 3 4 5 6 7 8 9; do
wi_events <<!
Key $MODKEY-$i # Move to the numbered view
wmiir xwrite /ctl view "$i"
Key $MODKEY-Shift-$i # Retag selected client with the numbered tag
wmiir xwrite /client/sel/ctl tags "$i"
!
done
wi_events -e
# WM Configuration
wmiir write /ctl <<!
font $WMII_FONT
focuscolors $WMII_FOCUSCOLORS
normcolors $WMII_NORMCOLORS
grabmod $MODKEY
border 1
!
xsetroot -solid "$WMII_BACKGROUND" &
# Misc
progsfile="$(wmiir namespace)/.proglist"
action status &
wi_proglist $PATH >$progsfile &
# Setup Tag Bar
IFS="$wi_newline"
wmiir rm $(wmiir ls -p /lbar) >/dev/null
seltag=$(wmiir read /tag/sel/ctl | sed 1q)
unset IFS
wi_tags | while read tag
do
if [ "$tag" = "$seltag" ]; then
echo colors "$WMII_FOCUSCOLORS"
echo label $tag
else
echo colors "$WMII_NORMCOLORS"
echo label $tag
fi | wmiir create "/lbar/$tag"
done
wi_eventloop
|
Added test/Makefile.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ROOT=.. include $(ROOT)/mk/hdr.mk TARG = grav OFILES = ../cmd/util.o \ ../cmd/wmii/map.o \ ../cmd/wmii/x11.o LDFLAGS += $(OFILES) -lfmt -lutf -lbio $(LIBX11) -lXext CFLAGS += $(INCX11) include $(ROOT)/mk/many.mk |
Added test/event.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#!/bin/rc
wm=''
if(~ $1 -d) {
wm = '&wm/wm wm/logon</dev/null'
shift
}
inferno '{$home/wmii/test/event.dis $*'$wm'}' $* &
inf = $apid
. 9.rc
fn sigint sigterm {exit}
fn sigexit {/bin/kill $apid}
while(! ~ `{read </dev/tty} q)
true
|
Added test/event.b.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
implement Event;
include "sys.m";
sys: Sys;
OREAD, OWRITE: import Sys;
print, sprint, read, open: import sys;
include "draw.m";
include "string.m";
str: String;
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
include "lists.m";
lists: Lists;
append, reverse: import lists;
include "regex.m";
regex: Regex;
Re: import regex;
include "sh.m";
sh: Sh;
Event: module
{
init: fn(nil: ref Draw->Context, argv: list of string);
};
line: chan of string;
suicide()
{
fd := open(sprint("/proc/%d/pgrp", sys->pctl(0, nil)), OWRITE);
sys->fprint(fd, "kill");
}
buflines(in, out: chan of string)
{
lines: list of string;
for(;;) {
if(lines == nil)
lines = <-in :: nil;
alt {
l := <-in =>
lines = append(lines, l);
out <-= hd lines =>
if(hd lines == nil)
suicide();
lines = tl lines;
}
}
}
readlines(c: chan of string, fd: ref sys->FD)
{
out := chan of string;
spawn buflines(out, c);
b := bufio->fopen(fd, OREAD);
while((s := b.gets('\n')) != nil)
out <-= s;
out <-= nil;
}
readfile(file: string): (string, int)
{
fd := open(file, OREAD);
if(fd == nil)
return ("", 0);
ret := "";
buf := array[512] of byte;
while((n := read(fd, buf, len buf)) > 0)
ret += string buf[:n];
return (ret, 1);
}
ishex(s: string): int
{
if(len s < 3 || s[0:2] != "0x")
return 0;
s = s[2:];
(nil, end) := str->toint(s, 16);
return end == nil;
}
init(draw: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
str = load String String->PATH;
bufio = load Bufio Bufio->PATH;
lists = load Lists "/dis/lib/lists.dis";
regex = load Regex Regex->PATH;
sh = load Sh Sh->PATH;
sys->pctl(sys->NEWPGRP, nil);
sh->system(draw, "mount -A {os rc -c 'exec dial $WMII_ADDRESS' >[1=0]} /mnt/wmii &");
line = chan of string;
spawn readlines(line, sys->fildes(0));
relist: list of ref (Re, int);
argv = tl argv;
for(; argv != nil; argv = tl argv) {
vflag := 0;
if(hd argv == "-v") {
argv = tl argv;
vflag = 1;
}
(re, err) := regex->compile(hd argv, 0);
if(err != nil)
raise sprint("bad regex %q: %s", hd argv, err);
relist = ref (re, vflag) :: relist;
}
relist = reverse(relist);
line: for(;;) {
lin := <-line;
if(lin == nil)
break;
l := str->unquoted(lin);
if(l == nil)
continue;
(evn, end) := str->toint(hd l, 10);
if(end == nil) {
for(rel := relist; rel != nil; rel = tl relist) {
(re, vflag) := *(hd rel);
match := regex->execute(re, lin);
if((match == nil) != vflag)
continue line;
}
print("%s", lin);
for(; l != nil; l = tl l) {
(k, v) := str->splitstrr(hd l, "=");
if(ishex(v)) {
(name, ok) := readfile(sprint("/mnt/wmii/client/%s/props", v));
if(ok)
print("%d %s%s\n", evn, k, name);
}
}
}else
print("%s", lin);
}
}
|
Added test/grav.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
#if 0
set -e
name=grav
root=..
obj=$root/cmd
lib=$root/lib
inc=$root/include
cc -I$inc -I/usr/local/include \
-o o.$name \
-Wall \
$name.c \
$obj/util.o \
$obj/wmii/map.o \
$obj/wmii/x11.o \
-L$lib -lfmt -lutf -lbio \
-L/usr/local/lib -lX11 -lXext \
exec o.$name
#endif
#include <fmt.h>
#include <stdarg.h>
#include <stdbool.h>
#include <unistd.h>
#include <stuff/util.h>
#include <stuff/x11.h>
char buffer[8196];
void debug() {}
static Window* win;
static char* gravity[] = {
[NorthEastGravity] = "NorthEastGravity",
[NorthWestGravity] = "NorthWestGravity",
[SouthEastGravity] = "SouthEastGravity",
[SouthWestGravity] = "SouthWestGravity",
[StaticGravity] = "StaticGravity",
};
static void
draw(Window *w) {
Rectangle r;
r = w->r;
r = rectsubpt(r, r.min);
fill(w, r, 0UL);
border(w, Rect(3, 3, 97, 97), 2, ~0UL);
border(w, Rect(8, 8, 92, 92), 2, ~0UL);
sync();
}
static void
setgravity(Window *w, long gravity) {
XSizeHints wmh;
wmh.flags = PWinGravity;
wmh.win_gravity = gravity;
XSetWMNormalHints(display, w->w, &wmh);
}
static void
config(Window *w, long grav, Point p) {
Rectangle r;
r = rectsetorigin(Rect(0, 0, 100, 100), p);
print("%s: %R\n", gravity[grav], r);
setgravity(w, grav);
w->r = ZR; /* Kludge. */
reshapewin(w, r);
draw(w);
sleep(1);
}
int
main(void) {
XSizeHints wmh;
WinAttr wa;
XEvent ev;
initdisplay();
/* Kludge the bar height. */
scr.rect.max.y -= 14;
wa.background_pixmap = ParentRelative;
wa.event_mask = ExposureMask|StructureNotifyMask;
win = createwindow(&scr.root,
Rect(0, 0, 100, 100), scr.depth, InputOutput,
&wa, CWEventMask | CWBackPixmap);
XSelectInput(display, win->w, ExposureMask);
wmh.flags = PMinSize|PMaxSize|USPosition;
wmh.min_width = wmh.max_width = 100;
wmh.min_height = wmh.max_height = 100;
XSetWMNormalHints(display, win->w, &wmh);
mapwin(win);
raisewin(win);
XMaskEvent(display, ExposureMask, &ev);
draw(win);
sleep(2);
config(win, StaticGravity, Pt(0, 0));
config(win, NorthWestGravity,
Pt(0,
0));
config(win, NorthEastGravity,
Pt(Dx(scr.rect) - 100,
0));
config(win, SouthEastGravity,
Pt(Dx(scr.rect) - 100,
Dy(scr.rect) - 100));
config(win, SouthWestGravity,
Pt(0,
Dy(scr.rect) - 100));
sleep(1);
return 0;
}
|
Added test/mkfile.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | default:V: all TARG=\ event.dis\ all:V: $TARG nuke:V: rm *.dis *.sbl %.dis: %.b limbo -gw $stem.b |
Added util/cleanname.
> > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#!/bin/sh -f
echo "$@" |
awk -F'/+' '{
delete a
n = 0
for(i = 1; i <= NF; i++) {
if($i == ".." && n > 0 && a[n] != "..")
n--
else if($i != "" && $i != ".")
a[++n] = $i
}
s = ""
for(i = 1; i <= n; i++)
s = s "/" a[i]
print substr(s, 2)
}'
|
Added util/compile.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
#!/bin/sh -f
CC=$1
PACKAGES=$2
CFLAGS=$3; shift 3
[ -n "$PACKAGES" ] && CFLAGS="$CFLAGS $(pkg-config --cflags $PACKAGES)"
outfile="$1"; shift
bin="$(echo $0 | sed 's,/[^/]*$,,')"
xtmp=/tmp/cc.$$.$USER.out
# Derived from Russ Cox's 9c in plan9port.
echo CC $($bin/cleanname ${BASE}$outfile)
[ -n "$noisycc" ] && echo $CC -o $outfile $CFLAGS $@
eval '$CC -o $outfile '"$CFLAGS"' $@ >$xtmp 2>&1'
status=$?
[ $status -eq 0 ] || echo $CC -o $outfile $CFLAGS $@ >&2
base=$(echo $BASE | sed 's/,/\\,/g')
re='\([^[:space:]/][^[:space:]]*\..:[0-9]\)'
undup() { # GCC is crap.
awk '
function shift() {
for(n=1; n<=3; n++)
if(2*n <= nl)
for(i=1; i<=n; i++) {
if(l[i] != l[i+n])
break;
if(i == n) {
for(i=1; i<=n; i++)
print l[i]
nl -= 2*n;
for(i=1; i<=nl; i++)
l[i] = l[i+2*n];
return;
}
}
if(nl == 0)
return
print l[1]
for(i=1; i<nl; i++)
l[i] = l[i+1]
nl--
}
BEGIN{
nl=0
maxl=6
}
tolower($0) ~ /: (error|note): .?each undeclared identifier|: error: for each function it appears|is dangerous, better use|is almost always misused|: in function |: at top level:|support .long long.|use of c99 long long|iso c forbids conversion|warning:.*warn_unused_result/ {
next
}
$1 == "warning:" {
t = $2 " " $1
sub(/^[^ ]+ [^ ]+ /, "")
$0 = t " " $0
}
{
sub(/\[/, ": [", $1)
if(nl == maxl)
shift()
l[++nl] = $0
}
END{
while(nl > 0)
shift();
}'
}
cat $xtmp | sed "s,^$re,$base&,g; s,\([[:space:]]\)$re,\1$base\2,g" |
sed 's/ .first use in this function.$//; s/\"\([^\"][^\"]*\)\", line \([0-9][0-9]*\)/\1:\2/g' |
undup >&2
rm -f $xtmp
exit $status
|
Added util/genchangelog.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#!/bin/sh
set -ef
ifs="$(echo)"
name=$1
vers=$2
dist=$3
desc="Upstream build"
auth="Kris Maglione <kris@suckless.org>"
date=$(date +'%a, %d %b %Y %T %z')
if hg root >/dev/null 2>&1; then
t() { hg log -r . --template "{$@}"; }
vers=$(t rev)
desc=$(t desc)
auth=$(t author)
date=$(t 'date|rfc822date')
fi
cat >debian/changelog.new <<!
$name ($vers) $dist; urgency=low
* $desc
-- $auth $date
$(cat debian/changelog)
!
mv debian/changelog.new debian/changelog
|
Added util/genconfig.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
#!/bin/sh -f
# What I wouldn't do for rc...
# Well... it's better than m4shgmake.
CONFIG="$ROOT/config.mk"
CONFSTR='# Generated by "make config"'
# ==================== The Messy Part ====================
#XXX Ignores lines ending in \
parseconfig() {
cat <<'!' | sed "s/CONFSTR/$CONFSTR/"
/^CONFSTR/ {exit}
/^( *#| )/ {next}
function fixup() {
sub(/ #.*/, "")
sub(/^ */, "")
gsub(/'/, "'\"'\"'")
sub(/[ ]*\+?=[ ]*/, "='")
sub(/[ ]*$/, "'")
var = $0
val = $0
sub(/\+?=.*/, "", var)
sub(/^[^=]+=/, "", val)
}
/\+=/ && !/^ / {
fixup()
if(!set[var]) {
print var"=''"
append[var]++
}
print var"=\"$" var " \"" val
print var"_orig=\"$" var "\""
next
}
/=/ && !/^ / {
fixup()
delete append[var]
set[var]++
print var"="val
print var"_orig=\"$" var "\""
}
END{
for(v in set)
print v "_append=''"
for(v in append)
print v "_append=true"
}
!
}
findinc() {
var="$1"; file="$2"; shift 2
for d in "$@"; do
if [ -d "$d" -a -f "$d/$file" ]; then
eval "$var=\"-I$d\""
break; fi; done
}
soext=.so
aext=.a
findlib() {
var="$1"; lib="$2"; shift 2
for d in "$@"; do
if [ -d "$d" -a -f "$d/$lib.so" -o -f "$d/lib$lib.a" ]; then
_libdir="$d"; _libname="$lib"
eval "$var=\"-L$d -l$lib\""
break; fi; done
}
expand() {
_expand="$@"; _expand_old=''
while [ "$_expand" != "$_expand_old" ]; do
_expand_old="$_expand"
eval "_expand=\"$_expand\""; done
echo -n "$_expand"
}
cfg() {
CFG="$CFG
$@"
}
equals() {
if [ -z "$append" ]; then
echo -n "=";
else
echo -n "+="; fi
}
prompt() {
var=$1; shift
eval "def=\$$var; orig=\$${var}_orig; append=\$${var}_append"
unset val
if [ -z "$def" -o -n "$force" ]; then
echo "$@"
echo -n "$var[$def]$(equals) "
read val
echo
fi
if [ -z "$val" ]; then
val="$def"; fi
if [ "$(expand $val)" != "$(expand "$orig")" ]; then
cfg "$var$(equals)$val"; fi
}
# The messy sed... Turns $(VAR) into ${VAR}, but not $$(VAR) into $${VAR}
eval "$(sed 's/\([^$]\)\$(\([A-Za-z_]*\))/\1${\2}/g' <"$CONFIG" | awk "`parseconfig`")"
CFG="$(sed -n "/^$CONFSTR/q; p" "$CONFIG"; echo "$CONFSTR")"
# ==================== The Fun Part ====================
cat <<!
Configuring for the wmii build.
You'll be prompted for a number of settings which wmii needs to build,
install, and run properly. In most cases, the defaults will be sufficient,
in which case, you may simply press return to accept them.
!
# Guess...
AWKPATH=$(which awk 2>/dev/null)
prompt AWKPATH "Full path to your system's 'awk' program"
prompt PLAN9 "Path of a Plan 9 Port or 9base installation"
force=1
prompt PREFIX Installation prefix
echo
echo "Compilation details (if you don't understand these, just leave the defaults)"
echo
prompt CC C object compiler
prompt LD 'Linker (this should normally not be "ld")'
set -- $CC
if $1 -v 2>&1 | grep 'gcc version' >/dev/null; then
echo -n You appear to be using gcc. Is this correct? '[yes] '
while :; do
read resp
case "$resp" in
[Yy][Ee][Ss]|'')
cfg 'include $(ROOT)/mk/gcc.mk'
break;;
[Nn][Oo])
cfg 'CFLAGS=""'
# Not perfect. Botches system cflags, but we
# need to ditch the gcc ones.
break;;
*)
echo -n 'Please answer yes or no: '
esac
done
echo
fi
prompt INCPATH Search path for include files
prompt LIBS Libraries to be linked with every executable
prompt CFLAGS Flags for the C compiler
prompt LDFLAGS Flags for the linker
case $(uname -s) in
[Dd]arwin) cfg 'STATIC=""';;
*) prompt STATIC Extra linker flags to produce a static executable;;
esac
unset force
# Make some guesses
# Extract the -L paths from ldflags.
ldlibs="$(awk 'BEGIN{
for(i=1; i <= ARGC; i++)
if(ARGV[i] ~ /-L/)
print ":" substr(ARGV[i], 3)
}' $LDFLAGS)"
# Turn include paths into ../lib paths.
inclibs="$(expand "$INCPATH"|sed 's,/include:,/lib:,g; s,/include$,/lib,')"
# Lace them all together, and expand them.
libs="$(expand "$LIBDIR:$ldlibs:$inclibs:/usr/local/lib:/opt/local/lib")"
LIBIXP=${LIBIXP%/libixp.a}
INCPATH="$INCPATH:/usr/local/include:/opt/local/include"
incpath="$(expand "$INCPATH")"
oifs="$IFS"; IFS=:
findinc INCX11 X11/Xlib.h $incpath \
/usr/X11R6/include /usr/x11/include /usr/x11/include /usr/X11/include \
/usr/openwin/include /opt/x11/include /opt/X11/include
findinc INCICONV iconv.h $incpath
findlib LIBX11 X11 $libs \
/usr/X11R6/lib /usr/X11/lib /usr/openwin/lib /usr/x11/lib \
/opt/X11 /opt/x11 /usr/local/lib /opt/local/lib
findlib LIBICONV iconv $libs
if [ -d "$ROOT/libixp" ]; then
_libdir="$ROOT/lib"; else
soext=.a findlib LIBIXP ixp "$ROOT/lib" $libs; fi
LIBIXP="$_libdir/libixp.a"
IFS="$oifs"
# Back to prompting
echo Library paths...
prompt INCX11 Compiler flags to find X11 includes
prompt LIBX11 Linker flags to link against libX11
# Find out if the system libc includes iconv...
# GNU systems tend to make /usr/lib/libc.so or /lib/libc.so
# linker scripts rather than libraries, so I can't parse them.
# As a kludge, I ask ldd what actual libc.so /bin/sh links to,
# which is pretty reliable. It's very unlikely that anyone will
# actually be prompted for this.
# I suppose the auto*hell way would be to just compile
# something against libc. Perhaps another day.
if nm -D $(ldd /bin/sh | awk '$1 ~ /^libc\.so/ {print $3}') |
awk -ve=1 '$2 == "T" && $3 == "iconv" {e=0; exit}; END {exit e}'
then
echo
echo "Your system's libc appears to include iconv."
echo
else
prompt LIBICONV Linker flags to link agains libiconv \
'(may be left blank if iconv is part of your system libc)'
fi
prompt INCICONV Compiler flags to find iconv.h
prompt LIBIXP Path to libixp.a
echo Writing config.mk
echo "$CFG
" >config.mk
echo Done.
|
Added util/link.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#!/bin/sh -f
LD=$1
PACKAGES=$2
LDFLAGS=$3; shift 3
[ -n "$PACKAGES" ] && LDFLAGS="$LDFLAGS $(pkg-config --libs $PACKAGES)"
outfile="$1"; shift
bin="$(echo $0 | sed 's,/[^/]*$,,')"
# Derived from Russ Cox's 9l in plan9port.
ofiles=""
args=""
for i
do
case "$i" in
*.[ao]|*.o_pic)
ofiles="$ofiles $i"
;;
*)
args="$args $i"
;;
esac
done
xtmp=/tmp/ld.$$.$USER.out
echo LD "$($bin/cleanname ${BASE}$outfile)"
[ -n "$noisycc" ] && echo $LD -o $outfile $ofiles $LDFLAGS $args
$LD -o $outfile $ofiles $LDFLAGS $args >$xtmp 2>&1
status=$?
[ $status -eq 0 ] || echo $LD -o $outfile $ofiles $LDFLAGS $args >&2
sed 's/.*: In function `[^:]*: *//' $xtmp | egrep . |
egrep -v 'is almost always misused|is dangerous, better use|in statically linked applications requires at runtime'
rm -f $xtmp
exit $status
|