mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
Compare commits
257 Commits
Author | SHA1 | Date | |
---|---|---|---|
3788d81061 | |||
1e186e8239 | |||
a0fffd3e5c | |||
f0e2766daf | |||
f093ef762b | |||
9e5019be7d | |||
a2d88b0daf | |||
44f50c24fa | |||
82aa1256be | |||
328b17ccc4 | |||
8a67302d7d | |||
c8b4c130c8 | |||
584c94b327 | |||
7189bb6973 | |||
2ef64e21a5 | |||
b0c0e7dcd1 | |||
d0dc23726e | |||
0a13fd2f0e | |||
f2852c2df7 | |||
7dbe152e4a | |||
38329f0180 | |||
60651000b3 | |||
52445999e7 | |||
2f9bf45389 | |||
4cd3f715e4 | |||
a55c5644da | |||
ecfd8e9e9c | |||
ed3505a828 | |||
ed386ddfca | |||
44db98e5a6 | |||
e332179504 | |||
aa321965ab | |||
92eaa06ec2 | |||
d3c1b6edd0 | |||
cad98a62a5 | |||
9f8222962e | |||
835dcd6d67 | |||
ef67c559a8 | |||
06e5d19944 | |||
299b1d7bdb | |||
aeb98e60cd | |||
6e101b6ac0 | |||
587249b101 | |||
6286e38ef4 | |||
2c10457877 | |||
914db9ed4e | |||
7a24165193 | |||
030e695e4f | |||
e81756d5cd | |||
d02617329b | |||
de04cac28e | |||
1977e017dc | |||
88c0337a16 | |||
aa1a3ec413 | |||
16e2481c1c | |||
a347b3e7b4 | |||
f6bc7350a8 | |||
ea80f07bcd | |||
b2afd1af6d | |||
d95947d4ec | |||
7667068437 | |||
0e4f2327d4 | |||
160b542a2c | |||
2fa9e47249 | |||
f4d442ab20 | |||
26bcfc3782 | |||
9b03c3a1d1 | |||
66c0827459 | |||
60bb553653 | |||
7e1d023311 | |||
3992bd39d4 | |||
7ee1280add | |||
645a57d439 | |||
419cb756c6 | |||
fcb055426f | |||
002ecec049 | |||
cc92893551 | |||
c35b5168b1 | |||
99d9090cf1 | |||
e0aa93c917 | |||
11f0385052 | |||
f16f550204 | |||
3953f3f2c4 | |||
1d0186aed2 | |||
aed37c553f | |||
c4f950bde1 | |||
4c0bde0811 | |||
8adea6a2dc | |||
547ffa7a7b | |||
9fbf31543f | |||
98e4a9522f | |||
90123e4fb0 | |||
395e23a155 | |||
71e1a503c1 | |||
4aa9b1b981 | |||
216e332c5a | |||
d770133e70 | |||
fb1647ac10 | |||
02d0a61cab | |||
d6dfefc9f2 | |||
bd5f899b6d | |||
bfcc3efe12 | |||
55e2f93e52 | |||
38e1b8f3e5 | |||
832968e8fc | |||
6f4bbeb452 | |||
9ce26cffc5 | |||
2fbf1e9ca4 | |||
3163735890 | |||
17ad17dd42 | |||
3826541804 | |||
0ecf669077 | |||
4afcd9e2a9 | |||
8c8df119ad | |||
e01ab240f1 | |||
b7a7a9accb | |||
477256bb94 | |||
2f7ac7e00f | |||
7f4b029091 | |||
0e6a158d64 | |||
085852e6e3 | |||
7897fb3749 | |||
aee08f6830 | |||
b063af8424 | |||
add6c35928 | |||
f280f05a58 | |||
c1135b1805 | |||
e80f258ae2 | |||
01d6ea5ad0 | |||
fcca903ae9 | |||
e6c7dd0122 | |||
48bbededc1 | |||
01564a57b5 | |||
8113ce276c | |||
e60f9ce838 | |||
6206fbbadd | |||
56bd6acf10 | |||
4a7800c93f | |||
70e8b215cb | |||
c176411512 | |||
5cf9c29319 | |||
8a56f238ad | |||
9a6ca9b5b0 | |||
36937a0776 | |||
d2477a37d0 | |||
bce622f31f | |||
4b378550c2 | |||
fe90a9555f | |||
ebec0fef90 | |||
0fc847fa59 | |||
aa1fedcb24 | |||
ca0b5b2d35 | |||
19c6b8c4ae | |||
5b23448144 | |||
27a1e0a6b2 | |||
416e7e84d6 | |||
b2348e0835 | |||
2d45eb5ca4 | |||
09b31687cc | |||
d451173cf0 | |||
28c87742f2 | |||
ea4fa1720c | |||
d8ec03694d | |||
086d8322e0 | |||
13817df1e4 | |||
258af8a3ca | |||
8ac0460f1d | |||
fa945d156f | |||
7d5d35e5ae | |||
98600ad5f6 | |||
6f3a7a6864 | |||
22772d3ac3 | |||
eb923b3290 | |||
f6cd7e7f68 | |||
cc95ee1376 | |||
019283c97e | |||
362441c5a9 | |||
fdbc711f9a | |||
badc3384a4 | |||
3883382c34 | |||
5afd1176b9 | |||
16a9b30291 | |||
5da903f3fe | |||
a04ac47812 | |||
f24c511a0c | |||
b6b530f8a6 | |||
bd1614b320 | |||
cf84eec999 | |||
40a9819253 | |||
52ee737276 | |||
14caa1fba8 | |||
1e77a1afde | |||
df98368137 | |||
8cea01f164 | |||
470bb2f659 | |||
584513de9b | |||
414b5a8015 | |||
0870a51223 | |||
dd59cbeea9 | |||
080766481c | |||
2fa5839b99 | |||
85f2f41176 | |||
cce6a90a15 | |||
180bfc250f | |||
96ea219340 | |||
e53a42a231 | |||
82ca6e13ca | |||
23d645f205 | |||
5e4ac2077d | |||
9220661ae0 | |||
613a192605 | |||
26c6cfbe1e | |||
9284c23771 | |||
048094e850 | |||
435ec8d0f6 | |||
6de731b9bb | |||
04033b664b | |||
853dd14386 | |||
6a687d3041 | |||
0dfefd4691 | |||
362cf6c254 | |||
19466b5625 | |||
9d484a49d0 | |||
fa64f930a9 | |||
75f54db90e | |||
bf51a3ff3a | |||
bcb4ea6641 | |||
e8f0be8586 | |||
2bcd9e985b | |||
d2f2e4cfb5 | |||
9c6fd9638e | |||
62082654b3 | |||
83ebf26cda | |||
ed83058f4e | |||
78bf6fbe4c | |||
b31036147d | |||
addead5005 | |||
7a9faaa20b | |||
6b2fa25aa8 | |||
26606c6963 | |||
efc8413b05 | |||
9310bb5572 | |||
bc38e036da | |||
1080ee8425 | |||
559a858893 | |||
7576d8c1da | |||
d5bff32302 | |||
1f8b4d44c7 | |||
714075935f | |||
27eaefb1d2 | |||
57425b2d42 | |||
0201b5bee4 | |||
fc43a0a3ab | |||
33384c0408 | |||
7ac99d1bf7 | |||
880f151185 | |||
d29a64ac86 |
@ -1,169 +1,18 @@
|
|||||||
FROM debian:stretch-slim
|
FROM nurdism/neko:dev
|
||||||
|
|
||||||
#
|
# Use the "remoteUser" property in devcontainer.json to use it. On Linux, the container
|
||||||
# cluster fuck of packages for neko, node, go and gstreamer
|
# user's GID/UIDs will be updated to match your local UID/GID (when using the dockerFile property).
|
||||||
RUN set -eux; apt-get update; apt-get install -y --no-install-recommends \
|
|
||||||
autoconf ca-certificates curl netbase wget \
|
|
||||||
bzr git mercurial openssh-client subversion procps cmake automake bzip2 dpkg-dev file g++ gcc \
|
|
||||||
libbz2-dev libc6-dev libcurl4-openssl-dev libdb-dev libevent-dev libffi-dev libgdbm-dev libglib2.0-dev libgmp-dev \
|
|
||||||
libjpeg-dev libkrb5-dev liblzma-dev libmagickcore-dev libmagickwand-dev libmaxminddb-dev libncurses5-dev libncursesw5-dev \
|
|
||||||
libpng-dev libpq-dev libreadline-dev libsqlite3-dev libssl-dev libtool libwebp-dev libxml2-dev libxslt-dev libyaml-dev \
|
|
||||||
make patch unzip xz-utils zlib1g-dev pkg-config \
|
|
||||||
build-essential perl python autopoint bison flex \
|
|
||||||
gettext openssl libopus-dev libvpx-dev libpulse-dev libx11-dev libxv-dev libxt-dev libxrandr-dev \
|
|
||||||
libxfixes-dev apt-utils x11vnc libxtst-dev dialog \
|
|
||||||
pulseaudio openbox chromium firefox-esr dbus-x11 xserver-xorg-video-dummy supervisor; \
|
|
||||||
if ! command -v gpg > /dev/null; then \
|
|
||||||
apt-get install -y --no-install-recommends gnupg dirmngr; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
#
|
|
||||||
# set up env for gst
|
|
||||||
ENV PATH=/gst/local/bin:$PATH
|
|
||||||
ENV LD_LIBRARY_PATH=/gst/local/lib:$LD_LIBRARY_PATH
|
|
||||||
ENV PKG_CONFIG_PATH=/gst/local/lib/pkgconfig:$PKG_CONFIG_PATH
|
|
||||||
|
|
||||||
#
|
|
||||||
# add node
|
|
||||||
ENV NODE_VERSION 12.14.1
|
|
||||||
RUN set -eux; \
|
|
||||||
ARCH= ; dpkgArch="$(dpkg --print-architecture)" \
|
|
||||||
;case "${dpkgArch##*-}" in \
|
|
||||||
amd64) ARCH='x64';; \
|
|
||||||
ppc64el) ARCH='ppc64le';; \
|
|
||||||
s390x) ARCH='s390x';; \
|
|
||||||
arm64) ARCH='arm64';; \
|
|
||||||
armhf) ARCH='armv7l';; \
|
|
||||||
i386) ARCH='x86';; \
|
|
||||||
*) echo "unsupported architecture"; exit 1 ;; \
|
|
||||||
esac;\
|
|
||||||
# gpg keys listed at https://github.com/nodejs/node#release-keys
|
|
||||||
for key in \
|
|
||||||
94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \
|
|
||||||
FD3A5288F042B6850C66B31F09FE44734EB7990E \
|
|
||||||
71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \
|
|
||||||
DD8F2338BAE7501E3DD5AC78C273792F7D83545D \
|
|
||||||
C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \
|
|
||||||
B9AE9905FFD7803F25714661B63B535A4C206CA9 \
|
|
||||||
77984A986EBC2AA786BC0F66B01FBB92821C587A \
|
|
||||||
8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 \
|
|
||||||
4ED778F539E3634C779C87C6D7062848A1AB005C \
|
|
||||||
A48C2BEE680E841632CD4E44F07496B3EB3C1762 \
|
|
||||||
B9E2F5981AA6E0CD28160D9FF13993A75599653C \
|
|
||||||
; do \
|
|
||||||
gpg --batch --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys "$key" || \
|
|
||||||
gpg --batch --keyserver hkp://ipv4.pool.sks-keyservers.net --recv-keys "$key" || \
|
|
||||||
gpg --batch --keyserver hkp://pgp.mit.edu:80 --recv-keys "$key"; \
|
|
||||||
done; \
|
|
||||||
curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH.tar.xz"; \
|
|
||||||
curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"; \
|
|
||||||
gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc; \
|
|
||||||
grep " node-v$NODE_VERSION-linux-$ARCH.tar.xz\$" SHASUMS256.txt | sha256sum -c - ; \
|
|
||||||
tar -xJf "node-v$NODE_VERSION-linux-$ARCH.tar.xz" -C /usr/local --strip-components=1 --no-same-owner; \
|
|
||||||
rm "node-v$NODE_VERSION-linux-$ARCH.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt; \
|
|
||||||
ln -s /usr/local/bin/node /usr/local/bin/nodejs
|
|
||||||
|
|
||||||
#
|
|
||||||
# add go
|
|
||||||
ENV GOLANG_VERSION 1.13.6
|
|
||||||
RUN set -eux; \
|
|
||||||
dpkgArch="$(dpkg --print-architecture)"; \
|
|
||||||
case "${dpkgArch##*-}" in \
|
|
||||||
amd64) goRelArch='linux-amd64'; goRelSha256='a1bc06deb070155c4f67c579f896a45eeda5a8fa54f35ba233304074c4abbbbd' ;; \
|
|
||||||
armhf) goRelArch='linux-armv6l'; goRelSha256='37a1a83e363dcf146a67fa839d170fd1afb13009585fdd493d0a3370fbe6f785' ;; \
|
|
||||||
arm64) goRelArch='linux-arm64'; goRelSha256='0a18125c4ed80f9c3045cf92384670907c4796b43ed63c4307210fe93e5bbca5' ;; \
|
|
||||||
i386) goRelArch='linux-386'; goRelSha256='27feb013106da784f09e560720aa41ab395c67f7eed4c4a0fce04bc6e3d01c7d' ;; \
|
|
||||||
ppc64el) goRelArch='linux-ppc64le'; goRelSha256='26a977a8af5dc50a562f0a57b58dded5fa3bacfe77722cf8a84ea54ca54728dd' ;; \
|
|
||||||
s390x) goRelArch='linux-s390x'; goRelSha256='5cd9900a1fa0f0cac657930b648381cad9b8c5e2bbc77caf86a6fb5cedad0017' ;; \
|
|
||||||
*) goRelArch='src'; goRelSha256='aae5be954bdc40bcf8006eb77e8d8a5dde412722bc8effcdaf9772620d06420c'; \
|
|
||||||
echo >&2; echo >&2 "warning: current architecture ($dpkgArch) does not have a corresponding Go binary release; will be building from source"; echo >&2 ;; \
|
|
||||||
esac; \
|
|
||||||
url="https://golang.org/dl/go${GOLANG_VERSION}.${goRelArch}.tar.gz"; \
|
|
||||||
wget -O go.tgz "$url"; \
|
|
||||||
echo "${goRelSha256} *go.tgz" | sha256sum -c - ; \
|
|
||||||
tar -C /usr/local -xzf go.tgz; \
|
|
||||||
rm go.tgz; \
|
|
||||||
if [ "$goRelArch" = 'src' ]; then \
|
|
||||||
echo >&2; \
|
|
||||||
echo >&2 'error: UNIMPLEMENTED'; \
|
|
||||||
echo >&2 'TODO install golang-any from jessie-backports for GOROOT_BOOTSTRAP (and uninstall after build)'; \
|
|
||||||
echo >&2; \
|
|
||||||
exit 1; \
|
|
||||||
fi; \
|
|
||||||
export PATH="/usr/local/go/bin:$PATH"; \
|
|
||||||
go version
|
|
||||||
|
|
||||||
ENV GOPATH /go
|
|
||||||
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
|
|
||||||
|
|
||||||
#
|
|
||||||
# install libclipboard
|
|
||||||
RUN set -eux; \
|
|
||||||
cd /tmp ; \
|
|
||||||
git clone https://github.com/jtanx/libclipboard ; \
|
|
||||||
cd libclipboard ; \
|
|
||||||
cmake . ; \
|
|
||||||
make -j4; \
|
|
||||||
make install; \
|
|
||||||
rm -rf /tmp/libclipboard
|
|
||||||
|
|
||||||
#
|
|
||||||
# install Go tools w/module support
|
|
||||||
RUN set -eux; \
|
|
||||||
mkdir -p /tmp/gotools; \
|
|
||||||
cd /tmp/gotools; \
|
|
||||||
GO111MODULE=on go get -v golang.org/x/tools/gopls@latest 2>&1; \
|
|
||||||
GO111MODULE=on go get -v \
|
|
||||||
honnef.co/go/tools/...@latest \
|
|
||||||
golang.org/x/tools/cmd/gorename@latest \
|
|
||||||
golang.org/x/tools/cmd/goimports@latest \
|
|
||||||
golang.org/x/tools/cmd/guru@latest \
|
|
||||||
golang.org/x/lint/golint@latest \
|
|
||||||
github.com/mdempsky/gocode@latest \
|
|
||||||
github.com/cweill/gotests/...@latest \
|
|
||||||
github.com/haya14busa/goplay/cmd/goplay@latest \
|
|
||||||
github.com/sqs/goreturns@latest \
|
|
||||||
github.com/josharian/impl@latest \
|
|
||||||
github.com/davidrjenni/reftools/cmd/fillstruct@latest \
|
|
||||||
github.com/uudashr/gopkgs/cmd/gopkgs@latest \
|
|
||||||
github.com/ramya-rao-a/go-outline@latest \
|
|
||||||
github.com/acroca/go-symbols@latest \
|
|
||||||
github.com/godoctor/godoctor@latest \
|
|
||||||
github.com/rogpeppe/godef@latest \
|
|
||||||
github.com/zmb3/gogetdoc@latest \
|
|
||||||
github.com/fatih/gomodifytags@latest \
|
|
||||||
github.com/mgechev/revive@latest \
|
|
||||||
github.com/go-delve/delve/cmd/dlv@latest 2>&1; \
|
|
||||||
#
|
|
||||||
# install Go tools w/o module support
|
|
||||||
go get -v github.com/alecthomas/gometalinter 2>&1; \
|
|
||||||
#
|
|
||||||
# install gocode-gomod
|
|
||||||
go get -x -d github.com/stamblerre/gocode 2>&1; \
|
|
||||||
go build -o gocode-gomod github.com/stamblerre/gocode; \
|
|
||||||
mv gocode-gomod $GOPATH/bin/; \
|
|
||||||
#
|
|
||||||
# install golangci-lint
|
|
||||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin 2>&1; \
|
|
||||||
mkdir -p "$GOPATH/src" "$GOPATH/bin" "$GOPATH/pkg/mod"; chmod -R 777 "$GOPATH"
|
|
||||||
#
|
|
||||||
# turn on go modules
|
|
||||||
ENV GO111MODULE=on
|
|
||||||
|
|
||||||
# the node image includes a non-root user with sudo access. Use the "remoteUser"
|
|
||||||
# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
|
|
||||||
# will be updated to match your local UID/GID (when using the dockerFile property).
|
|
||||||
# See https://aka.ms/vscode-remote/containers/non-root-user for details.
|
# See https://aka.ms/vscode-remote/containers/non-root-user for details.
|
||||||
ARG USERNAME=neko
|
ARG USERNAME=neko
|
||||||
ARG USER_UID=1000
|
ARG USER_UID=1000
|
||||||
ARG USER_GID=$USER_UID
|
ARG USER_GID=$USER_UID
|
||||||
|
|
||||||
#
|
#
|
||||||
# set to false to skip installing zsh and Oh My ZSH!
|
# Set to false to skip installing zsh and Oh My ZSH!
|
||||||
ARG INSTALL_ZSH="true"
|
ARG INSTALL_ZSH="true"
|
||||||
|
|
||||||
#
|
#
|
||||||
# location and expected SHA for common setup script - SHA generated on release
|
# Location and expected SHA for common setup script - SHA generated on release
|
||||||
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-debian.sh"
|
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-debian.sh"
|
||||||
ARG COMMON_SCRIPT_SHA="dev-mode"
|
ARG COMMON_SCRIPT_SHA="dev-mode"
|
||||||
|
|
||||||
@ -172,24 +21,24 @@ ARG COMMON_SCRIPT_SHA="dev-mode"
|
|||||||
ARG COMPOSE_VERSION=1.24.0
|
ARG COMPOSE_VERSION=1.24.0
|
||||||
|
|
||||||
#
|
#
|
||||||
# verify git, common tools / libs installed, add/modify non-root user, optionally install zsh
|
# Verify git, common tools / libs installed, add/modify non-root user, optionally install zsh
|
||||||
RUN set -eux; \
|
RUN set -eux; \
|
||||||
wget -q -O /tmp/common-setup.sh $COMMON_SCRIPT_SOURCE; \
|
wget -q -O /tmp/common-setup.sh $COMMON_SCRIPT_SOURCE; \
|
||||||
if [ "$COMMON_SCRIPT_SHA" != "dev-mode" ]; then echo "$COMMON_SCRIPT_SHA /tmp/common-setup.sh" | sha256sum -c - ; fi; \
|
if [ "$COMMON_SCRIPT_SHA" != "dev-mode" ]; then echo "$COMMON_SCRIPT_SHA /tmp/common-setup.sh" | sha256sum -c - ; fi; \
|
||||||
/bin/bash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID"; \
|
/bin/bash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID"; \
|
||||||
rm /tmp/common-setup.sh; \
|
rm /tmp/common-setup.sh; \
|
||||||
#
|
#
|
||||||
# install docker
|
# Install docker
|
||||||
apt-get install -y apt-transport-https gnupg-agent software-properties-common lsb-release; \
|
apt-get install -y apt-transport-https gnupg-agent software-properties-common lsb-release; \
|
||||||
curl -fsSL https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/gpg | (OUT=$(apt-key add - 2>&1) || echo $OUT); \
|
curl -fsSL https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/gpg | (OUT=$(apt-key add - 2>&1) || echo $OUT); \
|
||||||
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]') $(lsb_release -cs) stable"; \
|
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]') $(lsb_release -cs) stable"; \
|
||||||
apt-get update; apt-get install -y docker-ce-cli; \
|
apt-get update; apt-get install -y docker-ce-cli; \
|
||||||
#
|
#
|
||||||
# install docker compose
|
# Install docker compose
|
||||||
curl -sSL "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose; \
|
curl -sSL "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose; \
|
||||||
chmod +x /usr/local/bin/docker-compose; \
|
chmod +x /usr/local/bin/docker-compose; \
|
||||||
#
|
#
|
||||||
# set alternate global install location that both users have rights to access
|
# Set alternate global install location that both users have rights to access
|
||||||
mkdir -p /usr/local/share/npm-global; \
|
mkdir -p /usr/local/share/npm-global; \
|
||||||
chown ${USERNAME}:root /usr/local/share/npm-global; \
|
chown ${USERNAME}:root /usr/local/share/npm-global; \
|
||||||
npm config -g set prefix /usr/local/share/npm-global; \
|
npm config -g set prefix /usr/local/share/npm-global; \
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/.."
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/.."
|
||||||
|
|
||||||
build_gst() {
|
build_gst() {
|
||||||
if [ ! -d /gst ]; then
|
if [ ! -L /gst || ! -d /gst ]; then
|
||||||
|
sudo rm -rf /gst;
|
||||||
sudo mkdir -p /workspace/.build/gst
|
sudo mkdir -p /workspace/.build/gst
|
||||||
sudo ln -s /workspace/.build/gst /gst
|
sudo ln -s /workspace/.build/gst /gst
|
||||||
sudo chown -R neko /workspace/.build
|
sudo chown -R neko /workspace/.build
|
||||||
@ -41,47 +42,67 @@ build_gst() {
|
|||||||
|
|
||||||
build_base() {
|
build_base() {
|
||||||
set -eux; \
|
set -eux; \
|
||||||
cd $DIR/server; go get; ./build; \
|
cd $DIR/server; go get -v -t -d . ; ./build; \
|
||||||
cd $DIR/client; npm install; npm run build; \
|
cd $DIR/client; npm install; npm run build; \
|
||||||
cd $DIR; sudo docker build -f Dockerfile -t nurdism/neko:base . ;
|
cd $DIR; sudo docker build -f .docker/files/base/Dockerfile -t nurdism/neko:base . ;
|
||||||
}
|
}
|
||||||
|
|
||||||
build_firefox() {
|
build_latest() {
|
||||||
set -eux; \
|
set -eux; \
|
||||||
cd $DIR/.docker/files/firefox; \
|
cd $DIR; sudo docker build -f .docker/files/$1/Dockerfile -t nurdism/neko:latest . ;
|
||||||
sudo docker build -f Dockerfile -t nurdism/neko:firefox -t nurdism/neko:latest . ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
build_chromium() {
|
build_image() {
|
||||||
set -eux; \
|
set -eux; \
|
||||||
cd $DIR/.docker/files/chromium; \
|
cd $DIR; sudo docker build -f .docker/files/$1/Dockerfile -t nurdism/neko:$1 . ;
|
||||||
sudo docker build -f Dockerfile -t nurdism/neko:chromium . ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
build_docker() {
|
build() {
|
||||||
if [ ! -d /gst/local ]; then
|
if [ ! -d /gst/local ]; then
|
||||||
build_gst
|
build_gst
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set -eux; \
|
if [ $1 != "" ]; then
|
||||||
build_base; \
|
build_image $1
|
||||||
build_firefox; \
|
else
|
||||||
build_chromium; \
|
set -eux; \
|
||||||
sudo docker images nurdism/neko
|
build_image "deps"; \
|
||||||
|
build_image "base"; \
|
||||||
|
build_base; \
|
||||||
|
build_image "openbox"; \
|
||||||
|
build_image "xfce4"; \
|
||||||
|
build_image "jwm"; \
|
||||||
|
build_image "firefox"; \
|
||||||
|
build_image "chromium"; \
|
||||||
|
build_image "tor-browser";
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo docker images nurdism/neko
|
||||||
}
|
}
|
||||||
|
|
||||||
build_push() {
|
push() {
|
||||||
sudo docker push nurdism/neko:base
|
if [ $1 != "" ]; then
|
||||||
sudo docker push nurdism/neko:latest
|
sudo docker push nurdism/neko:$1
|
||||||
sudo docker push nurdism/neko:firefox
|
else
|
||||||
sudo docker push nurdism/neko:chromium
|
sudo docker push nurdism/neko:deps
|
||||||
|
sudo docker push nurdism/neko:base
|
||||||
|
sudo docker push nurdism/neko:openbox
|
||||||
|
sudo docker push nurdism/neko:xfce4
|
||||||
|
sudo docker push nurdism/neko:jwm
|
||||||
|
sudo docker push nurdism/neko:firefox
|
||||||
|
sudo docker push nurdism/neko:chromium
|
||||||
|
sudo docker push nurdism/neko:tor-browser
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
case $1 in
|
case $1 in
|
||||||
push) build_push ;;
|
images) build;;
|
||||||
docker) build_docker ;;
|
image) build $2 ;;
|
||||||
|
push) push $2 ;;
|
||||||
|
latest) build_latest ;;
|
||||||
|
base) build_image "base" ;;
|
||||||
|
deps) build_image "deps" ;;
|
||||||
|
dev) build_image "dev" ;;
|
||||||
gst) build_gst ;;
|
gst) build_gst ;;
|
||||||
*) build_docker ;;
|
*) build_docker ;;
|
||||||
esac
|
esac
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM debian:stretch-slim
|
FROM nurdism/neko:deps
|
||||||
|
|
||||||
#
|
#
|
||||||
# avoid warnings by switching to noninteractive
|
# avoid warnings by switching to noninteractive
|
||||||
@ -11,8 +11,7 @@ ARG USER_GID=$USER_UID
|
|||||||
#
|
#
|
||||||
# install neko dependencies
|
# install neko dependencies
|
||||||
RUN set -eux; apt-get update; \
|
RUN set -eux; apt-get update; \
|
||||||
apt-get install -y --no-install-recommends wget ca-certificates pulseaudio openbox dbus-x11 xserver-xorg-video-dummy supervisor; \
|
apt-get install -y --no-install-recommends wget ca-certificates supervisor; \
|
||||||
apt-get install -y --no-install-recommends libxcb1 libxrandr2 libxv1 libopus0 libvpx4; \
|
|
||||||
#
|
#
|
||||||
# create a non-root user
|
# create a non-root user
|
||||||
groupadd --gid $USER_GID $USERNAME; \
|
groupadd --gid $USER_GID $USERNAME; \
|
||||||
@ -36,41 +35,25 @@ RUN set -eux; apt-get update; \
|
|||||||
apt-get clean -y; \
|
apt-get clean -y; \
|
||||||
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||||
|
|
||||||
#
|
|
||||||
# add gst to env
|
|
||||||
ENV PATH=/gst/local/bin:$PATH
|
|
||||||
ENV LD_LIBRARY_PATH=/gst/local/lib:$LD_LIBRARY_PATH
|
|
||||||
ENV PKG_CONFIG_PATH=/gst/local/lib/pkgconfig:$PKG_CONFIG_PATH
|
|
||||||
|
|
||||||
#
|
|
||||||
# copy gst
|
|
||||||
COPY .build/gst/local /gst/local/
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# env
|
# env
|
||||||
ENV USER=$USERNAME
|
ENV USER=$USERNAME
|
||||||
ENV DISPLAY=:99.0
|
ENV DISPLAY=:99.0
|
||||||
|
ENV NEKO_PASSWORD=neko
|
||||||
|
ENV NEKO_PASSWORD_ADMIN=admin
|
||||||
|
ENV NEKO_BIND=:8080
|
||||||
|
|
||||||
#
|
#
|
||||||
# copy configuation files
|
# neko config
|
||||||
COPY .docker/files/dbus /usr/bin/dbus
|
COPY .docker/files/base/supervisord.conf /etc/neko/supervisord.conf
|
||||||
COPY .docker/files/openbox.xml /etc/neko/openbox.xml
|
COPY .docker/files/base/xorg.conf /etc/neko/xorg.conf
|
||||||
COPY .docker/files/neko/supervisord.conf /etc/neko/supervisord/neko.conf
|
COPY .docker/files/base/neko.conf /etc/neko/supervisord/neko.conf
|
||||||
COPY .docker/files/supervisord.conf /etc/neko/supervisord.conf
|
|
||||||
COPY .docker/files/xorg.conf /etc/neko/xorg.conf
|
|
||||||
COPY .docker/files/default.pa /etc/pulse/default.pa
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# neko files
|
# neko dist
|
||||||
COPY client/dist/ /var/www
|
COPY client/dist/ /var/www
|
||||||
COPY server/bin/neko /usr/bin/neko
|
COPY server/bin/neko /usr/bin/neko
|
||||||
|
|
||||||
#
|
|
||||||
# neko env
|
|
||||||
ENV NEKO_PASSWORD=neko
|
|
||||||
ENV NEKO_ADMIN=admin
|
|
||||||
ENV NEKO_BIND=:8080
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# run neko
|
# run neko
|
||||||
CMD ["/usr/bin/supervisord", "-c", "/etc/neko/supervisord.conf"]
|
CMD ["/usr/bin/supervisord", "-c", "/etc/neko/supervisord.conf"]
|
@ -8,7 +8,4 @@ user=%(ENV_USER)s
|
|||||||
stdout_logfile=/var/log/neko/neko.log
|
stdout_logfile=/var/log/neko/neko.log
|
||||||
stdout_logfile_maxbytes=100MB
|
stdout_logfile_maxbytes=100MB
|
||||||
stdout_logfile_backups=10
|
stdout_logfile_backups=10
|
||||||
redirect_stderr=true
|
redirect_stderr=true
|
||||||
stderr_logfile=/var/log/neko/neko.err.log
|
|
||||||
stderr_logfile_maxbytes=100MB
|
|
||||||
stderr_logfile_backups=10
|
|
42
.docker/files/base/supervisord.conf
Normal file
42
.docker/files/base/supervisord.conf
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
pidfile=/var/run/supervisord.pid
|
||||||
|
logfile=/dev/null
|
||||||
|
logfile_maxbytes=0
|
||||||
|
loglevel=debug
|
||||||
|
|
||||||
|
[include]
|
||||||
|
files=/etc/neko/supervisord/*.conf
|
||||||
|
|
||||||
|
[program:dbus]
|
||||||
|
environment=HOME="/root",USER="root"
|
||||||
|
command=/usr/bin/dbus
|
||||||
|
autorestart=true
|
||||||
|
priority=100
|
||||||
|
user=root
|
||||||
|
stdout_logfile=/var/log/neko/dbus.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
||||||
|
|
||||||
|
[program:x-server]
|
||||||
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s"
|
||||||
|
command=/usr/bin/X -config /etc/neko/xorg.conf %(ENV_DISPLAY)s
|
||||||
|
autorestart=true
|
||||||
|
priority=300
|
||||||
|
user=%(ENV_USER)s
|
||||||
|
stdout_logfile=/var/log/neko/xorg.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
||||||
|
|
||||||
|
[program:pulseaudio]
|
||||||
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
|
command=/usr/bin/pulseaudio --disallow-module-loading -vvvv --disallow-exit --exit-idle-time=-1
|
||||||
|
autorestart=true
|
||||||
|
priority=300
|
||||||
|
user=%(ENV_USER)s
|
||||||
|
stdout_logfile=/var/log/neko/pulseaudio.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
90
.docker/files/base/xorg.conf
Normal file
90
.docker/files/base/xorg.conf
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# This xorg configuration file is meant to be used by xpra
|
||||||
|
# to start a dummy X11 server.
|
||||||
|
# For details, please see:
|
||||||
|
# https://xpra.org/trac/wiki/Xdummy
|
||||||
|
|
||||||
|
Section "ServerFlags"
|
||||||
|
Option "DontVTSwitch" "true"
|
||||||
|
Option "AllowMouseOpenFail" "true"
|
||||||
|
Option "PciForceNone" "true"
|
||||||
|
Option "AutoEnableDevices" "false"
|
||||||
|
Option "AutoAddDevices" "false"
|
||||||
|
EndSection
|
||||||
|
|
||||||
|
Section "InputDevice"
|
||||||
|
Identifier "dummy_mouse"
|
||||||
|
Option "CorePointer" "true"
|
||||||
|
Driver "void"
|
||||||
|
EndSection
|
||||||
|
|
||||||
|
Section "InputDevice"
|
||||||
|
Identifier "dummy_keyboard"
|
||||||
|
Option "CoreKeyboard" "true"
|
||||||
|
Driver "void"
|
||||||
|
EndSection
|
||||||
|
|
||||||
|
Section "Device"
|
||||||
|
Identifier "dummy_videocard"
|
||||||
|
Driver "dummy"
|
||||||
|
Option "ConstantDPI" "true"
|
||||||
|
#VideoRam 4096000
|
||||||
|
#VideoRam 256000
|
||||||
|
VideoRam 192000
|
||||||
|
EndSection
|
||||||
|
|
||||||
|
Section "Monitor"
|
||||||
|
Identifier "dummy_monitor"
|
||||||
|
HorizSync 5.0 - 1000.0
|
||||||
|
VertRefresh 5.0 - 200.0
|
||||||
|
#This can be used to get a specific DPI, but only for the default resolution:
|
||||||
|
#DisplaySize 508 317
|
||||||
|
#NOTE: the highest modes will not work without increasing the VideoRam
|
||||||
|
# for the dummy video card.
|
||||||
|
# https://arachnoid.com/modelines/
|
||||||
|
|
||||||
|
# 1280x720 @ 30.00 Hz (GTF) hsync: 21.99 kHz; pclk: 33.78 MHz
|
||||||
|
Modeline "1280x720_30.00" 33.78 1280 1288 1408 1536 720 721 724 733 -HSync +Vsync
|
||||||
|
|
||||||
|
# 1280x720 @ 60.00 Hz (GTF) hsync: 44.76 kHz; pclk: 74.48 MHz
|
||||||
|
Modeline "1280x720_60.00" 74.48 1280 1336 1472 1664 720 721 724 746 -HSync +Vsync
|
||||||
|
# 1152x648 @ 60.00 Hz (GTF) hsync: 40.26 kHz; pclk: 59.91 MHz
|
||||||
|
Modeline "1152x648_60.00" 59.91 1152 1200 1320 1488 648 649 652 671 -HSync +Vsync
|
||||||
|
# 1024x576 @ 60.00 Hz (GTF) hsync: 35.82 kHz; pclk: 47.00 MHz
|
||||||
|
Modeline "1024x576_60.00" 47.00 1024 1064 1168 1312 576 577 580 597 -HSync +Vsync
|
||||||
|
# 960x720 @ 60.00 Hz (GTF) hsync: 44.76 kHz; pclk: 55.86 MHz
|
||||||
|
Modeline "960x720_60.00" 55.86 960 1008 1104 1248 720 721 724 746 -HSync +Vsync
|
||||||
|
# 800x600 @ 60.00 Hz (GTF) hsync: 37.32 kHz; pclk: 38.22 MHz
|
||||||
|
Modeline "800x600_60.00" 38.22 800 832 912 1024 600 601 604 622 -HSync +Vsync
|
||||||
|
|
||||||
|
# 1920x1080 @ 60.00 Hz (GTF) hsync: 67.08 kHz; pclk: 172.80 MHz
|
||||||
|
Modeline "1920x1080_60.00" 172.80 1920 2040 2248 2576 1080 1081 1084 1118 -HSync +Vsync
|
||||||
|
# 1920x1080 @ 30.00 Hz (GTF) hsync: 32.97 kHz; pclk: 80.18 MHz
|
||||||
|
Modeline "1920x1080_30.00" 80.18 1920 1984 2176 2432 1080 1081 1084 1099 -HSync +Vsync
|
||||||
|
# 1152x648 @ 30.00 Hz (GTF) hsync: 19.80 kHz; pclk: 26.93 MHz
|
||||||
|
Modeline "1152x648_30.00" 26.93 1152 1144 1256 1360 648 649 652 660 -HSync +Vsync
|
||||||
|
# 1024x576 @ 30.00 Hz (GTF) hsync: 17.61 kHz; pclk: 20.85 MHz
|
||||||
|
Modeline "1024x576_30.00" 20.85 1024 1008 1104 1184 576 577 580 587 -HSync +Vsync
|
||||||
|
# 960x720 @ 30.00 Hz (GTF) hsync: 21.99 kHz; pclk: 25.33 MHz
|
||||||
|
Modeline "960x720_30.00" 25.33 960 960 1056 1152 720 721 724 733 -HSync +Vsync
|
||||||
|
# 800x600 @ 30.00 Hz (GTF) hsync: 18.33 kHz; pclk: 17.01 MHz
|
||||||
|
Modeline "800x600_30.00" 17.01 800 792 864 928 600 601 604 611 -HSync +Vsync
|
||||||
|
EndSection
|
||||||
|
|
||||||
|
Section "Screen"
|
||||||
|
Identifier "dummy_screen"
|
||||||
|
Device "dummy_videocard"
|
||||||
|
Monitor "dummy_monitor"
|
||||||
|
DefaultDepth 24
|
||||||
|
SubSectionSub "Display"
|
||||||
|
Viewport 0 0
|
||||||
|
Depth 24
|
||||||
|
Modes "1280x720_30.00" "1920x1080_60.00" "1280x720_60.00" "1152x648_60.00" "1024x576_60.00" "960x720_60.00" "800x600_60.00" "1920x1080_30.00" "1152x648_30.00" "1024x576_30.00" "960x720_30.00" "800x600_30.00"
|
||||||
|
EndSubSection
|
||||||
|
EndSection
|
||||||
|
|
||||||
|
Section "ServerLayout"
|
||||||
|
Identifier "dummy_layout"
|
||||||
|
Screen "dummy_screen"
|
||||||
|
InputDevice "dummy_mouse"
|
||||||
|
InputDevice "dummy_keyboard"
|
||||||
|
EndSection
|
@ -1,4 +1,4 @@
|
|||||||
FROM nurdism/neko:base
|
FROM nurdism/neko:openbox
|
||||||
|
|
||||||
#
|
#
|
||||||
# install neko chromium
|
# install neko chromium
|
||||||
@ -19,6 +19,7 @@ RUN set -eux; apt-get update; \
|
|||||||
|
|
||||||
#
|
#
|
||||||
# copy configuation files
|
# copy configuation files
|
||||||
COPY supervisord.conf /etc/neko/supervisord/chromium.conf
|
COPY .docker/files/chromium/supervisord.conf /etc/neko/supervisord/chromium.conf
|
||||||
COPY preferences.json /usr/share/chromium/master_preferences
|
COPY .docker/files/chromium/preferences.json /usr/share/chromium/master_preferences
|
||||||
COPY policies.json /etc/chromium/policies/managed/policies.json
|
COPY .docker/files/chromium/policies.json /etc/chromium/policies/managed/policies.json
|
||||||
|
COPY .docker/files/chromium/openbox.xml /etc/neko/openbox.xml
|
@ -13,12 +13,6 @@
|
|||||||
|
|
||||||
<applications>
|
<applications>
|
||||||
<!-- Match all windows and remove their decorations (obxprop | grep "^_OB_APP") -->
|
<!-- Match all windows and remove their decorations (obxprop | grep "^_OB_APP") -->
|
||||||
<application class="Firefox*" name="Navigator">
|
|
||||||
<decor>no</decor>
|
|
||||||
<maximized>true</maximized>
|
|
||||||
<focus>yes</focus>
|
|
||||||
<layer>normal</layer>
|
|
||||||
</application>
|
|
||||||
<application class="Chromium*" name="chromium-browser">
|
<application class="Chromium*" name="chromium-browser">
|
||||||
<decor>no</decor>
|
<decor>no</decor>
|
||||||
<maximized>true</maximized>
|
<maximized>true</maximized>
|
||||||
@ -144,7 +138,7 @@
|
|||||||
|
|
||||||
use obconf if you want to change these without having to log out
|
use obconf if you want to change these without having to log out
|
||||||
and back in -->
|
and back in -->
|
||||||
<number>4</number>
|
<number>1</number>
|
||||||
<firstdesk>1</firstdesk>
|
<firstdesk>1</firstdesk>
|
||||||
<names>
|
<names>
|
||||||
<!-- set names up here if you want to, like this:
|
<!-- set names up here if you want to, like this:
|
@ -2,7 +2,7 @@
|
|||||||
# https://peter.sh/experiments/chromium-command-line-switches/ --no-sandbox
|
# https://peter.sh/experiments/chromium-command-line-switches/ --no-sandbox
|
||||||
[program:chromium]
|
[program:chromium]
|
||||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
command=/usr/lib/chromium/chromium --window-position=0,0 --display=%(ENV_DISPLAY)s --start-maximized --bwsi --test-type --force-dark-mode --disable-file-system --disable-gpu --disable-software-rasterizer --disable-dev-shm-usage
|
command=/usr/lib/chromium/chromium --window-position=0,0 --display=%(ENV_DISPLAY)s --start-maximized --bwsi --test-type --force-dark-mode --disable-file-system --disable-gpu --disable-software-rasterizer --disable-dev-shm-usage %(ENV_START_URL)s
|
||||||
autorestart=true
|
autorestart=true
|
||||||
priority=800
|
priority=800
|
||||||
user=%(ENV_USER)s
|
user=%(ENV_USER)s
|
||||||
@ -10,6 +10,3 @@ stdout_logfile=/var/log/neko/chromium.log
|
|||||||
stdout_logfile_maxbytes=100MB
|
stdout_logfile_maxbytes=100MB
|
||||||
stdout_logfile_backups=10
|
stdout_logfile_backups=10
|
||||||
redirect_stderr=true
|
redirect_stderr=true
|
||||||
stderr_logfile=/var/log/neko/chromium.err.log
|
|
||||||
stderr_logfile_maxbytes=100MB
|
|
||||||
stderr_logfile_backups=10
|
|
23
.docker/files/deps/Dockerfile
Normal file
23
.docker/files/deps/Dockerfile
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
FROM debian:stretch-slim
|
||||||
|
|
||||||
|
#
|
||||||
|
# install neko dependencies
|
||||||
|
RUN set -eux; apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends pulseaudio dbus-x11 xserver-xorg-video-dummy; \
|
||||||
|
apt-get install -y --no-install-recommends libcairo2 libxcb1 libxrandr2 libxv1 libopus0 libvpx4; \
|
||||||
|
#
|
||||||
|
# clean up
|
||||||
|
apt-get clean -y; \
|
||||||
|
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||||
|
|
||||||
|
#
|
||||||
|
# add gst to env
|
||||||
|
ENV PATH=/gst/local/bin:$PATH
|
||||||
|
ENV LD_LIBRARY_PATH=/gst/local/lib:$LD_LIBRARY_PATH
|
||||||
|
ENV PKG_CONFIG_PATH=/gst/local/lib/pkgconfig:$PKG_CONFIG_PATH
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy gst
|
||||||
|
COPY .build/gst/local /gst/local/
|
||||||
|
COPY .docker/files/deps/dbus /usr/bin/dbus
|
||||||
|
COPY .docker/files/deps/default.pa /etc/pulse/default.pa
|
191
.docker/files/dev/Dockerfile
Normal file
191
.docker/files/dev/Dockerfile
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
FROM debian:stretch-slim
|
||||||
|
|
||||||
|
#
|
||||||
|
# cluster fuck of packages for neko, node, go and gstreamer
|
||||||
|
RUN set -eux; apt-get update; apt-get install -y --no-install-recommends \
|
||||||
|
apt-transport-https gnupg-agent software-properties-common lsb-release \
|
||||||
|
autoconf ca-certificates curl netbase wget gnupg dirmngr libatomic1 \
|
||||||
|
libghc-zlib-dev libexpat1-dev \
|
||||||
|
bzr mercurial openssh-client subversion procps cmake automake bzip2 dpkg-dev file g++ gcc \
|
||||||
|
libbz2-dev libc6-dev libcurl4-openssl-dev libdb-dev libevent-dev libffi-dev libgdbm-dev libglib2.0-dev libgmp-dev \
|
||||||
|
libjpeg-dev libkrb5-dev liblzma-dev libmagickcore-dev libmagickwand-dev libmaxminddb-dev libncurses5-dev libncursesw5-dev \
|
||||||
|
libpng-dev libpq-dev libreadline-dev libsqlite3-dev libssl-dev libtool libwebp-dev libxml2-dev libxslt-dev libyaml-dev \
|
||||||
|
make patch unzip xz-utils zlib1g-dev pkg-config \
|
||||||
|
build-essential perl python autopoint bison flex \
|
||||||
|
gettext openssl libopus-dev libvpx-dev libpulse-dev libx11-dev libxv-dev libxt-dev libxrandr-dev \
|
||||||
|
libxfixes-dev apt-utils x11vnc libxtst-dev dialog \
|
||||||
|
pulseaudio openbox chromium firefox-esr dbus-x11 xserver-xorg-video-dummy supervisor;
|
||||||
|
|
||||||
|
#
|
||||||
|
# add git
|
||||||
|
ENV GIT_VERSION 2.21.0
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
cd /tmp/; \
|
||||||
|
wget https://github.com/git/git/archive/v$GIT_VERSION.zip -O latestgit.zip; \
|
||||||
|
unzip latestgit.zip; \
|
||||||
|
cd git-$GIT_VERSION; \
|
||||||
|
make prefix=/usr/local all; \
|
||||||
|
make prefix=/usr/local install; \
|
||||||
|
rm -rf /tmp/latestgit.zip /tmp/git-$GIT_VERSION;
|
||||||
|
|
||||||
|
#
|
||||||
|
# install libclipboard
|
||||||
|
RUN set -eux; \
|
||||||
|
cd /tmp; \
|
||||||
|
git clone https://github.com/jtanx/libclipboard; \
|
||||||
|
cd libclipboard; \
|
||||||
|
cmake . ; \
|
||||||
|
make -j4; \
|
||||||
|
make install; \
|
||||||
|
rm -rf /tmp/libclipboard;
|
||||||
|
|
||||||
|
#
|
||||||
|
# set up env for gst
|
||||||
|
ENV PATH=/gst/local/bin:$PATH
|
||||||
|
ENV LD_LIBRARY_PATH=/gst/local/lib:$LD_LIBRARY_PATH
|
||||||
|
ENV PKG_CONFIG_PATH=/gst/local/lib/pkgconfig:$PKG_CONFIG_PATH
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy gst
|
||||||
|
COPY .build/gst/local /gst/local/
|
||||||
|
|
||||||
|
#
|
||||||
|
# add node
|
||||||
|
ENV NODE_VERSION 12.16.2
|
||||||
|
RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" \
|
||||||
|
&& case "${dpkgArch##*-}" in \
|
||||||
|
amd64) ARCH='x64';; \
|
||||||
|
ppc64el) ARCH='ppc64le';; \
|
||||||
|
s390x) ARCH='s390x';; \
|
||||||
|
arm64) ARCH='arm64';; \
|
||||||
|
armhf) ARCH='armv7l';; \
|
||||||
|
i386) ARCH='x86';; \
|
||||||
|
*) echo "unsupported architecture"; exit 1 ;; \
|
||||||
|
esac \
|
||||||
|
&& set -ex \
|
||||||
|
&& for key in \
|
||||||
|
94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \
|
||||||
|
FD3A5288F042B6850C66B31F09FE44734EB7990E \
|
||||||
|
71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \
|
||||||
|
DD8F2338BAE7501E3DD5AC78C273792F7D83545D \
|
||||||
|
C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \
|
||||||
|
B9AE9905FFD7803F25714661B63B535A4C206CA9 \
|
||||||
|
77984A986EBC2AA786BC0F66B01FBB92821C587A \
|
||||||
|
8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 \
|
||||||
|
4ED778F539E3634C779C87C6D7062848A1AB005C \
|
||||||
|
A48C2BEE680E841632CD4E44F07496B3EB3C1762 \
|
||||||
|
B9E2F5981AA6E0CD28160D9FF13993A75599653C \
|
||||||
|
; do \
|
||||||
|
gpg --batch --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys "$key" || \
|
||||||
|
gpg --batch --keyserver hkp://ipv4.pool.sks-keyservers.net --recv-keys "$key" || \
|
||||||
|
gpg --batch --keyserver hkp://pgp.mit.edu:80 --recv-keys "$key" ; \
|
||||||
|
done \
|
||||||
|
&& curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH.tar.xz" \
|
||||||
|
&& curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
|
||||||
|
&& gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
|
||||||
|
&& grep " node-v$NODE_VERSION-linux-$ARCH.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
|
||||||
|
&& tar -xJf "node-v$NODE_VERSION-linux-$ARCH.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \
|
||||||
|
&& rm "node-v$NODE_VERSION-linux-$ARCH.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
|
||||||
|
&& apt-mark auto '.*' > /dev/null \
|
||||||
|
&& find /usr/local -type f -executable -exec ldd '{}' ';' \
|
||||||
|
| awk '/=>/ { print $(NF-1) }' \
|
||||||
|
| sort -u \
|
||||||
|
| xargs -r dpkg-query --search \
|
||||||
|
| cut -d: -f1 \
|
||||||
|
| sort -u \
|
||||||
|
| xargs -r apt-mark manual \
|
||||||
|
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs \
|
||||||
|
# smoke tests
|
||||||
|
&& node --version \
|
||||||
|
&& npm --version
|
||||||
|
|
||||||
|
#
|
||||||
|
# add golang
|
||||||
|
ENV GOLANG_VERSION 1.14.2
|
||||||
|
RUN set -eux; \
|
||||||
|
dpkgArch="$(dpkg --print-architecture)"; \
|
||||||
|
case "${dpkgArch##*-}" in \
|
||||||
|
amd64) goRelArch='linux-amd64'; goRelSha256='6272d6e940ecb71ea5636ddb5fab3933e087c1356173c61f4a803895e947ebb3' ;; \
|
||||||
|
armhf) goRelArch='linux-armv6l'; goRelSha256='eb4550ba741506c2a4057ea4d3a5ad7ed5a887de67c7232f1e4795464361c83c' ;; \
|
||||||
|
arm64) goRelArch='linux-arm64'; goRelSha256='bb6d22fe5806352c3d0826676654e09b6e41eb1af52e8d506d3fa85adf7f8d88' ;; \
|
||||||
|
i386) goRelArch='linux-386'; goRelSha256='cab5f51e6ffb616c6ee963c3d0650ca4e3c4108307c44f2baf233fcb8ff098f6' ;; \
|
||||||
|
ppc64el) goRelArch='linux-ppc64le'; goRelSha256='48c22268c81ced9084a43bbe2c1596d3e636b5560b30a32434a7f15e561de160' ;; \
|
||||||
|
s390x) goRelArch='linux-s390x'; goRelSha256='501cc919648c9d85b901963303c5061ea6814c80f0d35fda9e62980d3ff58cf4' ;; \
|
||||||
|
*) goRelArch='src'; goRelSha256='98de84e69726a66da7b4e58eac41b99cbe274d7e8906eeb8a5b7eb0aadee7f7c'; \
|
||||||
|
echo >&2; echo >&2 "warning: current architecture ($dpkgArch) does not have a corresponding Go binary release; will be building from source"; echo >&2 ;; \
|
||||||
|
esac; \
|
||||||
|
url="https://golang.org/dl/go${GOLANG_VERSION}.${goRelArch}.tar.gz"; \
|
||||||
|
wget -O go.tgz "$url"; \
|
||||||
|
echo "${goRelSha256} *go.tgz" | sha256sum -c -; \
|
||||||
|
tar -C /usr/local -xzf go.tgz; \
|
||||||
|
rm go.tgz; \
|
||||||
|
if [ "$goRelArch" = 'src' ]; then \
|
||||||
|
echo >&2; \
|
||||||
|
echo >&2 'error: UNIMPLEMENTED'; \
|
||||||
|
echo >&2 'TODO install golang-any from jessie-backports for GOROOT_BOOTSTRAP (and uninstall after build)'; \
|
||||||
|
echo >&2; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
export PATH="/usr/local/go/bin:$PATH"; \
|
||||||
|
go version
|
||||||
|
|
||||||
|
ENV GOPATH /go
|
||||||
|
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
|
||||||
|
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
|
||||||
|
|
||||||
|
#
|
||||||
|
# install Go tools w/module support
|
||||||
|
RUN mkdir -p /tmp/gotools \
|
||||||
|
&& cd /tmp/gotools \
|
||||||
|
&& GOPATH=/tmp/gotools GO111MODULE=on go get -v golang.org/x/tools/gopls@latest 2>&1 \
|
||||||
|
&& GOPATH=/tmp/gotools GO111MODULE=on go get -v \
|
||||||
|
honnef.co/go/tools/...@latest \
|
||||||
|
golang.org/x/tools/cmd/gorename@latest \
|
||||||
|
golang.org/x/tools/cmd/goimports@latest \
|
||||||
|
golang.org/x/tools/cmd/guru@latest \
|
||||||
|
golang.org/x/lint/golint@latest \
|
||||||
|
github.com/mdempsky/gocode@latest \
|
||||||
|
github.com/cweill/gotests/...@latest \
|
||||||
|
github.com/haya14busa/goplay/cmd/goplay@latest \
|
||||||
|
github.com/sqs/goreturns@latest \
|
||||||
|
github.com/josharian/impl@latest \
|
||||||
|
github.com/davidrjenni/reftools/cmd/fillstruct@latest \
|
||||||
|
github.com/uudashr/gopkgs/v2/cmd/gopkgs@latest \
|
||||||
|
github.com/ramya-rao-a/go-outline@latest \
|
||||||
|
github.com/acroca/go-symbols@latest \
|
||||||
|
github.com/godoctor/godoctor@latest \
|
||||||
|
github.com/rogpeppe/godef@latest \
|
||||||
|
github.com/zmb3/gogetdoc@latest \
|
||||||
|
github.com/fatih/gomodifytags@latest \
|
||||||
|
github.com/mgechev/revive@latest \
|
||||||
|
github.com/go-delve/delve/cmd/dlv@latest 2>&1 \
|
||||||
|
#
|
||||||
|
# build Go tools w/o module support
|
||||||
|
&& GOPATH=/tmp/gotools go get -v github.com/alecthomas/gometalinter 2>&1 \
|
||||||
|
#
|
||||||
|
# build gocode-gomod
|
||||||
|
&& GOPATH=/tmp/gotools go get -x -d github.com/stamblerre/gocode 2>&1 \
|
||||||
|
&& GOPATH=/tmp/gotools go build -o gocode-gomod github.com/stamblerre/gocode \
|
||||||
|
#
|
||||||
|
# install Go tools
|
||||||
|
&& mv /tmp/gotools/bin/* /usr/local/bin/ \
|
||||||
|
&& mv gocode-gomod /usr/local/bin/ \
|
||||||
|
#
|
||||||
|
# install golangci-lint
|
||||||
|
&& curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b /usr/local/bin 2>&1 \
|
||||||
|
#
|
||||||
|
# setup paths
|
||||||
|
&& mkdir -p "$GOPATH/src" "$GOPATH/bin" "$GOPATH/pkg/mod" \
|
||||||
|
&& chmod -R 777 "$GOPATH"
|
||||||
|
|
||||||
|
#
|
||||||
|
# turn on go modules
|
||||||
|
ENV GO111MODULE=on
|
||||||
|
|
||||||
|
#
|
||||||
|
# install docker
|
||||||
|
RUN set -eux; \
|
||||||
|
curl -fsSL https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/gpg | (OUT=$(apt-key add - 2>&1) || echo $OUT); \
|
||||||
|
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/$(lsb_release -is | tr '[:upper:]' '[:lower:]') $(lsb_release -cs) stable"; \
|
||||||
|
apt-get update; apt-get install -y docker-ce-cli;
|
@ -1,4 +1,4 @@
|
|||||||
FROM nurdism/neko:base
|
FROM nurdism/neko:openbox
|
||||||
|
|
||||||
#
|
#
|
||||||
# install firefox-esr
|
# install firefox-esr
|
||||||
@ -16,7 +16,8 @@ RUN set -eux; apt-get update; \
|
|||||||
|
|
||||||
#
|
#
|
||||||
# copy configuation files
|
# copy configuation files
|
||||||
COPY supervisord.conf /etc/neko/supervisord/firefox.conf
|
COPY .docker/files/firefox/supervisord.conf /etc/neko/supervisord/firefox.conf
|
||||||
COPY neko.js /usr/lib/firefox-esr/mozilla.cfg
|
COPY .docker/files/firefox/neko.js /usr/lib/firefox-esr/mozilla.cfg
|
||||||
COPY autoconfig.js /usr/lib/firefox-esr/defaults/pref/autoconfig.js
|
COPY .docker/files/firefox/autoconfig.js /usr/lib/firefox-esr/defaults/pref/autoconfig.js
|
||||||
COPY policies.json /usr/lib/firefox-esr/distribution/policies.json
|
COPY .docker/files/firefox/policies.json /usr/lib/firefox-esr/distribution/policies.json
|
||||||
|
COPY .docker/files/firefox/openbox.xml /etc/neko/openbox.xml
|
||||||
|
763
.docker/files/firefox/openbox.xml
Normal file
763
.docker/files/firefox/openbox.xml
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!-- Default openbox config but all window decorations are moved
|
||||||
|
thereby making it harder to accidentally close the virtual browser -->
|
||||||
|
|
||||||
|
<openbox_config xmlns="http://openbox.org/3.4/rc"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
|
||||||
|
<resistance>
|
||||||
|
<strength>10</strength>
|
||||||
|
<screen_edge_strength>20</screen_edge_strength>
|
||||||
|
</resistance>
|
||||||
|
|
||||||
|
<applications>
|
||||||
|
<!-- Match all windows and remove their decorations (obxprop | grep "^_OB_APP") -->
|
||||||
|
<application class="Firefox*" name="Navigator">
|
||||||
|
<decor>no</decor>
|
||||||
|
<maximized>true</maximized>
|
||||||
|
<focus>yes</focus>
|
||||||
|
<layer>normal</layer>
|
||||||
|
</application>
|
||||||
|
</applications>
|
||||||
|
|
||||||
|
<focus>
|
||||||
|
<focusNew>yes</focusNew>
|
||||||
|
<!-- always try to focus new windows when they appear. other rules do
|
||||||
|
apply -->
|
||||||
|
<followMouse>no</followMouse>
|
||||||
|
<!-- move focus to a window when you move the mouse into it -->
|
||||||
|
<focusLast>yes</focusLast>
|
||||||
|
<!-- focus the last used window when changing desktops, instead of the one
|
||||||
|
under the mouse pointer. when followMouse is enabled -->
|
||||||
|
<underMouse>no</underMouse>
|
||||||
|
<!-- move focus under the mouse, even when the mouse is not moving -->
|
||||||
|
<focusDelay>200</focusDelay>
|
||||||
|
<!-- when followMouse is enabled, the mouse must be inside the window for
|
||||||
|
this many milliseconds (1000 = 1 sec) before moving focus to it -->
|
||||||
|
<raiseOnFocus>no</raiseOnFocus>
|
||||||
|
<!-- when followMouse is enabled, and a window is given focus by moving the
|
||||||
|
mouse into it, also raise the window -->
|
||||||
|
</focus>
|
||||||
|
|
||||||
|
<placement>
|
||||||
|
<policy>Smart</policy>
|
||||||
|
<!-- 'Smart' or 'UnderMouse' -->
|
||||||
|
<center>yes</center>
|
||||||
|
<!-- whether to place windows in the center of the free area found or
|
||||||
|
the top left corner -->
|
||||||
|
<monitor>Primary</monitor>
|
||||||
|
<!-- with Smart placement on a multi-monitor system, try to place new windows
|
||||||
|
on: 'Any' - any monitor, 'Mouse' - where the mouse is, 'Active' - where
|
||||||
|
the active window is, 'Primary' - only on the primary monitor -->
|
||||||
|
<primaryMonitor>1</primaryMonitor>
|
||||||
|
<!-- The monitor where Openbox should place popup dialogs such as the
|
||||||
|
focus cycling popup, or the desktop switch popup. It can be an index
|
||||||
|
from 1, specifying a particular monitor. Or it can be one of the
|
||||||
|
following: 'Mouse' - where the mouse is, or
|
||||||
|
'Active' - where the active window is -->
|
||||||
|
</placement>
|
||||||
|
|
||||||
|
<theme>
|
||||||
|
<name>Clearlooks</name>
|
||||||
|
<titleLayout>NLIMC</titleLayout>
|
||||||
|
<!--
|
||||||
|
available characters are NDSLIMC, each can occur at most once.
|
||||||
|
N: window icon
|
||||||
|
L: window label (AKA title).
|
||||||
|
I: iconify
|
||||||
|
M: maximize
|
||||||
|
C: close
|
||||||
|
S: shade (roll up/down)
|
||||||
|
D: omnipresent (on all desktops).
|
||||||
|
-->
|
||||||
|
<keepBorder>yes</keepBorder>
|
||||||
|
<animateIconify>yes</animateIconify>
|
||||||
|
<font place="ActiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuHeader">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuItem">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="ActiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
</theme>
|
||||||
|
|
||||||
|
<desktops>
|
||||||
|
<!-- this stuff is only used at startup, pagers allow you to change them
|
||||||
|
during a session
|
||||||
|
|
||||||
|
these are default values to use when other ones are not already set
|
||||||
|
by other applications, or saved in your session
|
||||||
|
|
||||||
|
use obconf if you want to change these without having to log out
|
||||||
|
and back in -->
|
||||||
|
<number>1</number>
|
||||||
|
<firstdesk>1</firstdesk>
|
||||||
|
<names>
|
||||||
|
<!-- set names up here if you want to, like this:
|
||||||
|
<name>desktop 1</name>
|
||||||
|
<name>desktop 2</name>
|
||||||
|
-->
|
||||||
|
</names>
|
||||||
|
<popupTime>875</popupTime>
|
||||||
|
<!-- The number of milliseconds to show the popup for when switching
|
||||||
|
desktops. Set this to 0 to disable the popup. -->
|
||||||
|
</desktops>
|
||||||
|
|
||||||
|
<resize>
|
||||||
|
<drawContents>yes</drawContents>
|
||||||
|
<popupShow>Nonpixel</popupShow>
|
||||||
|
<!-- 'Always', 'Never', or 'Nonpixel' (xterms and such) -->
|
||||||
|
<popupPosition>Center</popupPosition>
|
||||||
|
<!-- 'Center', 'Top', or 'Fixed' -->
|
||||||
|
<popupFixedPosition>
|
||||||
|
<!-- these are used if popupPosition is set to 'Fixed' -->
|
||||||
|
|
||||||
|
<x>10</x>
|
||||||
|
<!-- positive number for distance from left edge, negative number for
|
||||||
|
distance from right edge, or 'Center' -->
|
||||||
|
<y>10</y>
|
||||||
|
<!-- positive number for distance from top edge, negative number for
|
||||||
|
distance from bottom edge, or 'Center' -->
|
||||||
|
</popupFixedPosition>
|
||||||
|
</resize>
|
||||||
|
|
||||||
|
<!-- You can reserve a portion of your screen where windows will not cover when
|
||||||
|
they are maximized, or when they are initially placed.
|
||||||
|
Many programs reserve space automatically, but you can use this in other
|
||||||
|
cases. -->
|
||||||
|
<margins>
|
||||||
|
<top>0</top>
|
||||||
|
<bottom>0</bottom>
|
||||||
|
<left>0</left>
|
||||||
|
<right>0</right>
|
||||||
|
</margins>
|
||||||
|
|
||||||
|
<dock>
|
||||||
|
<position>TopLeft</position>
|
||||||
|
<!-- (Top|Bottom)(Left|Right|)|Top|Bottom|Left|Right|Floating -->
|
||||||
|
<floatingX>0</floatingX>
|
||||||
|
<floatingY>0</floatingY>
|
||||||
|
<noStrut>no</noStrut>
|
||||||
|
<stacking>Above</stacking>
|
||||||
|
<!-- 'Above', 'Normal', or 'Below' -->
|
||||||
|
<direction>Vertical</direction>
|
||||||
|
<!-- 'Vertical' or 'Horizontal' -->
|
||||||
|
<autoHide>no</autoHide>
|
||||||
|
<hideDelay>300</hideDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<showDelay>300</showDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<moveButton>Middle</moveButton>
|
||||||
|
<!-- 'Left', 'Middle', 'Right' -->
|
||||||
|
</dock>
|
||||||
|
|
||||||
|
<keyboard>
|
||||||
|
<chainQuitKey>C-g</chainQuitKey>
|
||||||
|
|
||||||
|
<!-- Keybindings for desktop switching -->
|
||||||
|
<keybind key="C-A-Left">
|
||||||
|
<action name="GoToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Right">
|
||||||
|
<action name="GoToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Up">
|
||||||
|
<action name="GoToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Down">
|
||||||
|
<action name="GoToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Left">
|
||||||
|
<action name="SendToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Right">
|
||||||
|
<action name="SendToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Up">
|
||||||
|
<action name="SendToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Down">
|
||||||
|
<action name="SendToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F1">
|
||||||
|
<action name="GoToDesktop"><to>1</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F2">
|
||||||
|
<action name="GoToDesktop"><to>2</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F3">
|
||||||
|
<action name="GoToDesktop"><to>3</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F4">
|
||||||
|
<action name="GoToDesktop"><to>4</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-d">
|
||||||
|
<action name="ToggleShowDesktop"/>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for windows -->
|
||||||
|
<keybind key="A-F4">
|
||||||
|
<action name="Close"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-Escape">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-space">
|
||||||
|
<!--action name="ShowMenu"><menu>client-menu</menu></action-->
|
||||||
|
</keybind>
|
||||||
|
<!-- Take a screenshot of the current window with scrot when Alt+Print are pressed -->
|
||||||
|
<keybind key="A-Print">
|
||||||
|
<action name="Execute"><command>scrot -s</command></action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching -->
|
||||||
|
<keybind key="A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-S-Tab">
|
||||||
|
<action name="PreviousWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<panels>yes</panels><desktop>yes</desktop>
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching with the arrow keys -->
|
||||||
|
<keybind key="W-S-Right">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>right</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Left">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>left</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Up">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>up</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Down">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>down</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for running applications -->
|
||||||
|
<keybind key="W-e">
|
||||||
|
<action name="Execute">
|
||||||
|
<startupnotify>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
<name>Konqueror</name>
|
||||||
|
</startupnotify>
|
||||||
|
<command>kfmclient openProfile filemanagement</command>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<!-- Launch scrot when Print is pressed -->
|
||||||
|
<keybind key="Print">
|
||||||
|
<action name="Execute"><command>scrot</command></action>
|
||||||
|
</keybind>
|
||||||
|
</keyboard>
|
||||||
|
|
||||||
|
<mouse>
|
||||||
|
<dragThreshold>1</dragThreshold>
|
||||||
|
<!-- number of pixels the mouse must move before a drag begins -->
|
||||||
|
<doubleClickTime>500</doubleClickTime>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<screenEdgeWarpTime>400</screenEdgeWarpTime>
|
||||||
|
<!-- Time before changing desktops when the pointer touches the edge of the
|
||||||
|
screen while moving a window, in milliseconds (1000 = 1 second).
|
||||||
|
Set this to 0 to disable warping -->
|
||||||
|
<screenEdgeWarpMouse>false</screenEdgeWarpMouse>
|
||||||
|
<!-- Set this to TRUE to move the mouse pointer across the desktop when
|
||||||
|
switching due to hitting the edge of the screen -->
|
||||||
|
|
||||||
|
<context name="Frame">
|
||||||
|
<mousebind button="A-Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Click">
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Right" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Up" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Down" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="DoubleClick">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>no</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Shade"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
<action name="Lower"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>yes</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar Top Right Bottom Left TLCorner TRCorner BRCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<!--mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Top">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>top</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Left">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>left</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Right">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>right</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Bottom">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>bottom</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<!--mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="TRCorner BRCorner TLCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Client">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Icon">
|
||||||
|
<!--mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="AllDesktops">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleOmnipresent"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Shade">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleShade"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Iconify">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Iconify"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Maximize">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>vertical</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>horizontal</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Close">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Close"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Desktop">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Root">
|
||||||
|
<!-- Menus -->
|
||||||
|
<!--mousebind button="Middle" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>client-list-combined-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>root-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="MoveResize">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
</mouse>
|
||||||
|
|
||||||
|
<menu>
|
||||||
|
<!-- You can specify more than one menu file in here and they are all loaded,
|
||||||
|
just don't make menu ids clash or, well, it'll be kind of pointless -->
|
||||||
|
|
||||||
|
<!-- default menu file (or custom one in $HOME/.config/openbox/) -->
|
||||||
|
<!-- system menu files on Debian systems -->
|
||||||
|
<!--file>/var/lib/openbox/debian-menu.xml</file-->
|
||||||
|
<file>menu.xml</file>
|
||||||
|
<hideDelay>200</hideDelay>
|
||||||
|
<!-- if a press-release lasts longer than this setting (in milliseconds), the
|
||||||
|
menu is hidden again -->
|
||||||
|
<middle>no</middle>
|
||||||
|
<!-- center submenus vertically about the parent entry -->
|
||||||
|
<submenuShowDelay>100</submenuShowDelay>
|
||||||
|
<!-- time to delay before showing a submenu after hovering over the parent
|
||||||
|
entry.
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be shown until it is clicked on -->
|
||||||
|
<submenuHideDelay>400</submenuHideDelay>
|
||||||
|
<!-- time to delay before hiding a submenu when selecting another
|
||||||
|
entry in parent menu
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be hidden until a different submenu is opened -->
|
||||||
|
<showIcons>yes</showIcons>
|
||||||
|
<!-- controls if icons appear in the client-list-(combined-)menu -->
|
||||||
|
<manageDesktops>yes</manageDesktops>
|
||||||
|
<!-- show the manage desktops section in the client-list-(combined-)menu -->
|
||||||
|
</menu>
|
||||||
|
|
||||||
|
<applications>
|
||||||
|
<!--
|
||||||
|
# this is an example with comments through out. use these to make your
|
||||||
|
# own rules, but without the comments of course.
|
||||||
|
# you may use one or more of the name/class/role/title/type rules to specify
|
||||||
|
# windows to match
|
||||||
|
|
||||||
|
<application name="the window's _OB_APP_NAME property (see obxprop)"
|
||||||
|
class="the window's _OB_APP_CLASS property (see obxprop)"
|
||||||
|
groupname="the window's _OB_APP_GROUP_NAME property (see obxprop)"
|
||||||
|
groupclass="the window's _OB_APP_GROUP_CLASS property (see obxprop)"
|
||||||
|
role="the window's _OB_APP_ROLE property (see obxprop)"
|
||||||
|
title="the window's _OB_APP_TITLE property (see obxprop)"
|
||||||
|
type="the window's _OB_APP_TYPE property (see obxprob)..
|
||||||
|
(if unspecified, then it is 'dialog' for child windows)">
|
||||||
|
# you may set only one of name/class/role/title/type, or you may use more
|
||||||
|
# than one together to restrict your matches.
|
||||||
|
|
||||||
|
# the name, class, role, and title use simple wildcard matching such as those
|
||||||
|
# used by a shell. you can use * to match any characters and ? to match
|
||||||
|
# any single character.
|
||||||
|
|
||||||
|
# the type is one of: normal, dialog, splash, utility, menu, toolbar, dock,
|
||||||
|
# or desktop
|
||||||
|
|
||||||
|
# when multiple rules match a window, they will all be applied, in the
|
||||||
|
# order that they appear in this list
|
||||||
|
|
||||||
|
|
||||||
|
# each rule element can be left out or set to 'default' to specify to not
|
||||||
|
# change that attribute of the window
|
||||||
|
|
||||||
|
<decor>yes</decor>
|
||||||
|
# enable or disable window decorations
|
||||||
|
|
||||||
|
<shade>no</shade>
|
||||||
|
# make the window shaded when it appears, or not
|
||||||
|
|
||||||
|
<position force="no">
|
||||||
|
# the position is only used if both an x and y coordinate are provided
|
||||||
|
# (and not set to 'default')
|
||||||
|
# when force is "yes", then the window will be placed here even if it
|
||||||
|
# says you want it placed elsewhere. this is to override buggy
|
||||||
|
# applications who refuse to behave
|
||||||
|
<x>center</x>
|
||||||
|
# a number like 50, or 'center' to center on screen. use a negative number
|
||||||
|
# to start from the right (or bottom for <y>), ie -50 is 50 pixels from
|
||||||
|
# the right edge (or bottom). use 'default' to specify using value
|
||||||
|
# provided by the application, or chosen by openbox, instead.
|
||||||
|
<y>200</y>
|
||||||
|
<monitor>1</monitor>
|
||||||
|
# specifies the monitor in a xinerama setup.
|
||||||
|
# 1 is the first head, or 'mouse' for wherever the mouse is
|
||||||
|
</position>
|
||||||
|
|
||||||
|
<size>
|
||||||
|
# the size to make the window.
|
||||||
|
<width>20</width>
|
||||||
|
# a number like 20, or 'default' to use the size given by the application.
|
||||||
|
# you can use fractions such as 1/2 or percentages such as 75% in which
|
||||||
|
# case the value is relative to the size of the monitor that the window
|
||||||
|
# appears on.
|
||||||
|
<height>30%</height>
|
||||||
|
</size>
|
||||||
|
|
||||||
|
<focus>yes</focus>
|
||||||
|
# if the window should try be given focus when it appears. if this is set
|
||||||
|
# to yes it doesn't guarantee the window will be given focus. some
|
||||||
|
# restrictions may apply, but Openbox will try to
|
||||||
|
|
||||||
|
<desktop>1</desktop>
|
||||||
|
# 1 is the first desktop, 'all' for all desktops
|
||||||
|
|
||||||
|
<layer>normal</layer>
|
||||||
|
# 'above', 'normal', or 'below'
|
||||||
|
|
||||||
|
<iconic>no</iconic>
|
||||||
|
# make the window iconified when it appears, or not
|
||||||
|
|
||||||
|
<skip_pager>no</skip_pager>
|
||||||
|
# asks to not be shown in pagers
|
||||||
|
|
||||||
|
<skip_taskbar>no</skip_taskbar>
|
||||||
|
# asks to not be shown in taskbars. window cycling actions will also
|
||||||
|
# skip past such windows
|
||||||
|
|
||||||
|
<fullscreen>yes</fullscreen>
|
||||||
|
# make the window in fullscreen mode when it appears
|
||||||
|
|
||||||
|
<maximized>true</maximized>
|
||||||
|
# 'Horizontal', 'Vertical' or boolean (yes/no)
|
||||||
|
</application>
|
||||||
|
|
||||||
|
# end of the example
|
||||||
|
-->
|
||||||
|
</applications>
|
||||||
|
|
||||||
|
</openbox_config>
|
@ -8,7 +8,4 @@ user=%(ENV_USER)s
|
|||||||
stdout_logfile=/var/log/neko/firefox-esr.log
|
stdout_logfile=/var/log/neko/firefox-esr.log
|
||||||
stdout_logfile_maxbytes=100MB
|
stdout_logfile_maxbytes=100MB
|
||||||
stdout_logfile_backups=10
|
stdout_logfile_backups=10
|
||||||
redirect_stderr=true
|
redirect_stderr=true
|
||||||
stderr_logfile=/var/log/neko/firefox-esr.err.log
|
|
||||||
stderr_logfile_maxbytes=100MB
|
|
||||||
stderr_logfile_backups=10
|
|
11
.docker/files/jwm/Dockerfile
Normal file
11
.docker/files/jwm/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
FROM nurdism/neko:base
|
||||||
|
|
||||||
|
#
|
||||||
|
# install jwm
|
||||||
|
RUN set -eux; apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends jwm;
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy jwm conf and supervisord conf
|
||||||
|
COPY .docker/files/jwm/supervisord.conf /etc/neko/supervisord/jwm.conf
|
||||||
|
COPY .docker/files/jwm/conf.xml /etc/neko/jwm.xml
|
10
.docker/files/jwm/supervisord.conf
Normal file
10
.docker/files/jwm/supervisord.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[program:jwm]
|
||||||
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
|
command=/usr/bin/jwm -f /etc/neko/jwm.xml -display %(ENV_DISPLAY)s
|
||||||
|
autorestart=true
|
||||||
|
priority=300
|
||||||
|
user=%(ENV_USER)s
|
||||||
|
stdout_logfile=/var/log/neko/jwm.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
11
.docker/files/openbox/Dockerfile
Normal file
11
.docker/files/openbox/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
FROM nurdism/neko:base
|
||||||
|
|
||||||
|
#
|
||||||
|
# install openbox
|
||||||
|
RUN set -eux; apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends openbox;
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy openbox conf and supervisord conf
|
||||||
|
COPY .docker/files/openbox/supervisord.conf /etc/neko/supervisord/openbox.conf
|
||||||
|
COPY .docker/files/openbox/conf.xml /etc/neko/openbox.xml
|
753
.docker/files/openbox/conf.xml
Normal file
753
.docker/files/openbox/conf.xml
Normal file
@ -0,0 +1,753 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!-- Default openbox config but all window decorations are moved
|
||||||
|
thereby making it harder to accidentally close the virtual browser -->
|
||||||
|
|
||||||
|
<openbox_config xmlns="http://openbox.org/3.4/rc"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
|
||||||
|
<resistance>
|
||||||
|
<strength>10</strength>
|
||||||
|
<screen_edge_strength>20</screen_edge_strength>
|
||||||
|
</resistance>
|
||||||
|
|
||||||
|
<focus>
|
||||||
|
<focusNew>yes</focusNew>
|
||||||
|
<!-- always try to focus new windows when they appear. other rules do
|
||||||
|
apply -->
|
||||||
|
<followMouse>no</followMouse>
|
||||||
|
<!-- move focus to a window when you move the mouse into it -->
|
||||||
|
<focusLast>yes</focusLast>
|
||||||
|
<!-- focus the last used window when changing desktops, instead of the one
|
||||||
|
under the mouse pointer. when followMouse is enabled -->
|
||||||
|
<underMouse>no</underMouse>
|
||||||
|
<!-- move focus under the mouse, even when the mouse is not moving -->
|
||||||
|
<focusDelay>200</focusDelay>
|
||||||
|
<!-- when followMouse is enabled, the mouse must be inside the window for
|
||||||
|
this many milliseconds (1000 = 1 sec) before moving focus to it -->
|
||||||
|
<raiseOnFocus>no</raiseOnFocus>
|
||||||
|
<!-- when followMouse is enabled, and a window is given focus by moving the
|
||||||
|
mouse into it, also raise the window -->
|
||||||
|
</focus>
|
||||||
|
|
||||||
|
<placement>
|
||||||
|
<policy>Smart</policy>
|
||||||
|
<!-- 'Smart' or 'UnderMouse' -->
|
||||||
|
<center>yes</center>
|
||||||
|
<!-- whether to place windows in the center of the free area found or
|
||||||
|
the top left corner -->
|
||||||
|
<monitor>Primary</monitor>
|
||||||
|
<!-- with Smart placement on a multi-monitor system, try to place new windows
|
||||||
|
on: 'Any' - any monitor, 'Mouse' - where the mouse is, 'Active' - where
|
||||||
|
the active window is, 'Primary' - only on the primary monitor -->
|
||||||
|
<primaryMonitor>1</primaryMonitor>
|
||||||
|
<!-- The monitor where Openbox should place popup dialogs such as the
|
||||||
|
focus cycling popup, or the desktop switch popup. It can be an index
|
||||||
|
from 1, specifying a particular monitor. Or it can be one of the
|
||||||
|
following: 'Mouse' - where the mouse is, or
|
||||||
|
'Active' - where the active window is -->
|
||||||
|
</placement>
|
||||||
|
|
||||||
|
<theme>
|
||||||
|
<name>Clearlooks</name>
|
||||||
|
<titleLayout>NLIMC</titleLayout>
|
||||||
|
<!--
|
||||||
|
available characters are NDSLIMC, each can occur at most once.
|
||||||
|
N: window icon
|
||||||
|
L: window label (AKA title).
|
||||||
|
I: iconify
|
||||||
|
M: maximize
|
||||||
|
C: close
|
||||||
|
S: shade (roll up/down)
|
||||||
|
D: omnipresent (on all desktops).
|
||||||
|
-->
|
||||||
|
<keepBorder>yes</keepBorder>
|
||||||
|
<animateIconify>yes</animateIconify>
|
||||||
|
<font place="ActiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuHeader">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuItem">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="ActiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
</theme>
|
||||||
|
|
||||||
|
<desktops>
|
||||||
|
<!-- this stuff is only used at startup, pagers allow you to change them
|
||||||
|
during a session
|
||||||
|
|
||||||
|
these are default values to use when other ones are not already set
|
||||||
|
by other applications, or saved in your session
|
||||||
|
|
||||||
|
use obconf if you want to change these without having to log out
|
||||||
|
and back in -->
|
||||||
|
<number>10</number>
|
||||||
|
<firstdesk>1</firstdesk>
|
||||||
|
<names>
|
||||||
|
<!-- set names up here if you want to, like this:
|
||||||
|
<name>desktop 1</name>
|
||||||
|
<name>desktop 2</name>
|
||||||
|
-->
|
||||||
|
</names>
|
||||||
|
<popupTime>875</popupTime>
|
||||||
|
<!-- The number of milliseconds to show the popup for when switching
|
||||||
|
desktops. Set this to 0 to disable the popup. -->
|
||||||
|
</desktops>
|
||||||
|
|
||||||
|
<resize>
|
||||||
|
<drawContents>yes</drawContents>
|
||||||
|
<popupShow>Nonpixel</popupShow>
|
||||||
|
<!-- 'Always', 'Never', or 'Nonpixel' (xterms and such) -->
|
||||||
|
<popupPosition>Center</popupPosition>
|
||||||
|
<!-- 'Center', 'Top', or 'Fixed' -->
|
||||||
|
<popupFixedPosition>
|
||||||
|
<!-- these are used if popupPosition is set to 'Fixed' -->
|
||||||
|
|
||||||
|
<x>10</x>
|
||||||
|
<!-- positive number for distance from left edge, negative number for
|
||||||
|
distance from right edge, or 'Center' -->
|
||||||
|
<y>10</y>
|
||||||
|
<!-- positive number for distance from top edge, negative number for
|
||||||
|
distance from bottom edge, or 'Center' -->
|
||||||
|
</popupFixedPosition>
|
||||||
|
</resize>
|
||||||
|
|
||||||
|
<!-- You can reserve a portion of your screen where windows will not cover when
|
||||||
|
they are maximized, or when they are initially placed.
|
||||||
|
Many programs reserve space automatically, but you can use this in other
|
||||||
|
cases. -->
|
||||||
|
<margins>
|
||||||
|
<top>0</top>
|
||||||
|
<bottom>0</bottom>
|
||||||
|
<left>0</left>
|
||||||
|
<right>0</right>
|
||||||
|
</margins>
|
||||||
|
|
||||||
|
<dock>
|
||||||
|
<position>TopLeft</position>
|
||||||
|
<!-- (Top|Bottom)(Left|Right|)|Top|Bottom|Left|Right|Floating -->
|
||||||
|
<floatingX>0</floatingX>
|
||||||
|
<floatingY>0</floatingY>
|
||||||
|
<noStrut>no</noStrut>
|
||||||
|
<stacking>Above</stacking>
|
||||||
|
<!-- 'Above', 'Normal', or 'Below' -->
|
||||||
|
<direction>Vertical</direction>
|
||||||
|
<!-- 'Vertical' or 'Horizontal' -->
|
||||||
|
<autoHide>no</autoHide>
|
||||||
|
<hideDelay>300</hideDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<showDelay>300</showDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<moveButton>Middle</moveButton>
|
||||||
|
<!-- 'Left', 'Middle', 'Right' -->
|
||||||
|
</dock>
|
||||||
|
|
||||||
|
<keyboard>
|
||||||
|
<chainQuitKey>C-g</chainQuitKey>
|
||||||
|
|
||||||
|
<!-- Keybindings for desktop switching -->
|
||||||
|
<keybind key="C-A-Left">
|
||||||
|
<action name="GoToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Right">
|
||||||
|
<action name="GoToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Up">
|
||||||
|
<action name="GoToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Down">
|
||||||
|
<action name="GoToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Left">
|
||||||
|
<action name="SendToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Right">
|
||||||
|
<action name="SendToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Up">
|
||||||
|
<action name="SendToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Down">
|
||||||
|
<action name="SendToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F1">
|
||||||
|
<action name="GoToDesktop"><to>1</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F2">
|
||||||
|
<action name="GoToDesktop"><to>2</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F3">
|
||||||
|
<action name="GoToDesktop"><to>3</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F4">
|
||||||
|
<action name="GoToDesktop"><to>4</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-d">
|
||||||
|
<action name="ToggleShowDesktop"/>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for windows -->
|
||||||
|
<keybind key="A-F4">
|
||||||
|
<action name="Close"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-Escape">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-space">
|
||||||
|
<!--action name="ShowMenu"><menu>client-menu</menu></action-->
|
||||||
|
</keybind>
|
||||||
|
<!-- Take a screenshot of the current window with scrot when Alt+Print are pressed -->
|
||||||
|
<keybind key="A-Print">
|
||||||
|
<action name="Execute"><command>scrot -s</command></action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching -->
|
||||||
|
<keybind key="A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-S-Tab">
|
||||||
|
<action name="PreviousWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<panels>yes</panels><desktop>yes</desktop>
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching with the arrow keys -->
|
||||||
|
<keybind key="W-S-Right">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>right</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Left">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>left</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Up">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>up</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Down">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>down</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for running applications -->
|
||||||
|
<keybind key="W-e">
|
||||||
|
<action name="Execute">
|
||||||
|
<startupnotify>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
<name>Konqueror</name>
|
||||||
|
</startupnotify>
|
||||||
|
<command>kfmclient openProfile filemanagement</command>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<!-- Launch scrot when Print is pressed -->
|
||||||
|
<keybind key="Print">
|
||||||
|
<action name="Execute"><command>scrot</command></action>
|
||||||
|
</keybind>
|
||||||
|
</keyboard>
|
||||||
|
|
||||||
|
<mouse>
|
||||||
|
<dragThreshold>1</dragThreshold>
|
||||||
|
<!-- number of pixels the mouse must move before a drag begins -->
|
||||||
|
<doubleClickTime>500</doubleClickTime>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<screenEdgeWarpTime>400</screenEdgeWarpTime>
|
||||||
|
<!-- Time before changing desktops when the pointer touches the edge of the
|
||||||
|
screen while moving a window, in milliseconds (1000 = 1 second).
|
||||||
|
Set this to 0 to disable warping -->
|
||||||
|
<screenEdgeWarpMouse>false</screenEdgeWarpMouse>
|
||||||
|
<!-- Set this to TRUE to move the mouse pointer across the desktop when
|
||||||
|
switching due to hitting the edge of the screen -->
|
||||||
|
|
||||||
|
<context name="Frame">
|
||||||
|
<mousebind button="A-Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Click">
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Right" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Up" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Down" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="DoubleClick">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>no</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Shade"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
<action name="Lower"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>yes</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar Top Right Bottom Left TLCorner TRCorner BRCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Top">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>top</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Left">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>left</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Right">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>right</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Bottom">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>bottom</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="TRCorner BRCorner TLCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Client">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Icon">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="AllDesktops">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleOmnipresent"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Shade">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleShade"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Iconify">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Iconify"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Maximize">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>vertical</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>horizontal</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Close">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Close"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Desktop">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Root">
|
||||||
|
<!-- Menus -->
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>client-list-combined-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>root-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="MoveResize">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
</mouse>
|
||||||
|
|
||||||
|
<menu>
|
||||||
|
<!-- You can specify more than one menu file in here and they are all loaded,
|
||||||
|
just don't make menu ids clash or, well, it'll be kind of pointless -->
|
||||||
|
|
||||||
|
<!-- default menu file (or custom one in $HOME/.config/openbox/) -->
|
||||||
|
<!-- system menu files on Debian systems -->
|
||||||
|
<!--file>/var/lib/openbox/debian-menu.xml</file-->
|
||||||
|
<file>menu.xml</file>
|
||||||
|
<hideDelay>200</hideDelay>
|
||||||
|
<!-- if a press-release lasts longer than this setting (in milliseconds), the
|
||||||
|
menu is hidden again -->
|
||||||
|
<middle>no</middle>
|
||||||
|
<!-- center submenus vertically about the parent entry -->
|
||||||
|
<submenuShowDelay>100</submenuShowDelay>
|
||||||
|
<!-- time to delay before showing a submenu after hovering over the parent
|
||||||
|
entry.
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be shown until it is clicked on -->
|
||||||
|
<submenuHideDelay>400</submenuHideDelay>
|
||||||
|
<!-- time to delay before hiding a submenu when selecting another
|
||||||
|
entry in parent menu
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be hidden until a different submenu is opened -->
|
||||||
|
<showIcons>yes</showIcons>
|
||||||
|
<!-- controls if icons appear in the client-list-(combined-)menu -->
|
||||||
|
<manageDesktops>yes</manageDesktops>
|
||||||
|
<!-- show the manage desktops section in the client-list-(combined-)menu -->
|
||||||
|
</menu>
|
||||||
|
|
||||||
|
<applications>
|
||||||
|
<!--
|
||||||
|
# this is an example with comments through out. use these to make your
|
||||||
|
# own rules, but without the comments of course.
|
||||||
|
# you may use one or more of the name/class/role/title/type rules to specify
|
||||||
|
# windows to match
|
||||||
|
|
||||||
|
<application name="the window's _OB_APP_NAME property (see obxprop)"
|
||||||
|
class="the window's _OB_APP_CLASS property (see obxprop)"
|
||||||
|
groupname="the window's _OB_APP_GROUP_NAME property (see obxprop)"
|
||||||
|
groupclass="the window's _OB_APP_GROUP_CLASS property (see obxprop)"
|
||||||
|
role="the window's _OB_APP_ROLE property (see obxprop)"
|
||||||
|
title="the window's _OB_APP_TITLE property (see obxprop)"
|
||||||
|
type="the window's _OB_APP_TYPE property (see obxprob)..
|
||||||
|
(if unspecified, then it is 'dialog' for child windows)">
|
||||||
|
# you may set only one of name/class/role/title/type, or you may use more
|
||||||
|
# than one together to restrict your matches.
|
||||||
|
|
||||||
|
# the name, class, role, and title use simple wildcard matching such as those
|
||||||
|
# used by a shell. you can use * to match any characters and ? to match
|
||||||
|
# any single character.
|
||||||
|
|
||||||
|
# the type is one of: normal, dialog, splash, utility, menu, toolbar, dock,
|
||||||
|
# or desktop
|
||||||
|
|
||||||
|
# when multiple rules match a window, they will all be applied, in the
|
||||||
|
# order that they appear in this list
|
||||||
|
|
||||||
|
|
||||||
|
# each rule element can be left out or set to 'default' to specify to not
|
||||||
|
# change that attribute of the window
|
||||||
|
|
||||||
|
<decor>yes</decor>
|
||||||
|
# enable or disable window decorations
|
||||||
|
|
||||||
|
<shade>no</shade>
|
||||||
|
# make the window shaded when it appears, or not
|
||||||
|
|
||||||
|
<position force="no">
|
||||||
|
# the position is only used if both an x and y coordinate are provided
|
||||||
|
# (and not set to 'default')
|
||||||
|
# when force is "yes", then the window will be placed here even if it
|
||||||
|
# says you want it placed elsewhere. this is to override buggy
|
||||||
|
# applications who refuse to behave
|
||||||
|
<x>center</x>
|
||||||
|
# a number like 50, or 'center' to center on screen. use a negative number
|
||||||
|
# to start from the right (or bottom for <y>), ie -50 is 50 pixels from
|
||||||
|
# the right edge (or bottom). use 'default' to specify using value
|
||||||
|
# provided by the application, or chosen by openbox, instead.
|
||||||
|
<y>200</y>
|
||||||
|
<monitor>1</monitor>
|
||||||
|
# specifies the monitor in a xinerama setup.
|
||||||
|
# 1 is the first head, or 'mouse' for wherever the mouse is
|
||||||
|
</position>
|
||||||
|
|
||||||
|
<size>
|
||||||
|
# the size to make the window.
|
||||||
|
<width>20</width>
|
||||||
|
# a number like 20, or 'default' to use the size given by the application.
|
||||||
|
# you can use fractions such as 1/2 or percentages such as 75% in which
|
||||||
|
# case the value is relative to the size of the monitor that the window
|
||||||
|
# appears on.
|
||||||
|
<height>30%</height>
|
||||||
|
</size>
|
||||||
|
|
||||||
|
<focus>yes</focus>
|
||||||
|
# if the window should try be given focus when it appears. if this is set
|
||||||
|
# to yes it doesn't guarantee the window will be given focus. some
|
||||||
|
# restrictions may apply, but Openbox will try to
|
||||||
|
|
||||||
|
<desktop>1</desktop>
|
||||||
|
# 1 is the first desktop, 'all' for all desktops
|
||||||
|
|
||||||
|
<layer>normal</layer>
|
||||||
|
# 'above', 'normal', or 'below'
|
||||||
|
|
||||||
|
<iconic>no</iconic>
|
||||||
|
# make the window iconified when it appears, or not
|
||||||
|
|
||||||
|
<skip_pager>no</skip_pager>
|
||||||
|
# asks to not be shown in pagers
|
||||||
|
|
||||||
|
<skip_taskbar>no</skip_taskbar>
|
||||||
|
# asks to not be shown in taskbars. window cycling actions will also
|
||||||
|
# skip past such windows
|
||||||
|
|
||||||
|
<fullscreen>yes</fullscreen>
|
||||||
|
# make the window in fullscreen mode when it appears
|
||||||
|
|
||||||
|
<maximized>true</maximized>
|
||||||
|
# 'Horizontal', 'Vertical' or boolean (yes/no)
|
||||||
|
</application>
|
||||||
|
|
||||||
|
# end of the example
|
||||||
|
-->
|
||||||
|
</applications>
|
||||||
|
|
||||||
|
</openbox_config>
|
10
.docker/files/openbox/supervisord.conf
Normal file
10
.docker/files/openbox/supervisord.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[program:openbox]
|
||||||
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
|
command=/usr/bin/openbox --config-file /etc/neko/openbox.xml
|
||||||
|
autorestart=true
|
||||||
|
priority=300
|
||||||
|
user=%(ENV_USER)s
|
||||||
|
stdout_logfile=/var/log/neko/openbox.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
15
.docker/files/popcorn/Dockerfile
Normal file
15
.docker/files/popcorn/Dockerfile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
FROM nurdism/neko:openbox
|
||||||
|
|
||||||
|
#
|
||||||
|
# install popcorn time
|
||||||
|
RUN set -eux; apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends ; \
|
||||||
|
#
|
||||||
|
# clean up
|
||||||
|
apt-get clean -y; \
|
||||||
|
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy configuation files
|
||||||
|
COPY .docker/files/popcorn/supervisord.conf /etc/neko/supervisord/popcorn.conf
|
||||||
|
COPY .docker/files/popcorn/openbox.xml /etc/neko/openbox.xml
|
763
.docker/files/popcorn/openbox.xml
Normal file
763
.docker/files/popcorn/openbox.xml
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!-- Default openbox config but all window decorations are moved
|
||||||
|
thereby making it harder to accidentally close the virtual browser -->
|
||||||
|
|
||||||
|
<openbox_config xmlns="http://openbox.org/3.4/rc"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
|
||||||
|
<resistance>
|
||||||
|
<strength>10</strength>
|
||||||
|
<screen_edge_strength>20</screen_edge_strength>
|
||||||
|
</resistance>
|
||||||
|
|
||||||
|
<applications>
|
||||||
|
<!-- Match all windows and remove their decorations (obxprop | grep "^_OB_APP") -->
|
||||||
|
<application class="Firefox*" name="Navigator">
|
||||||
|
<decor>no</decor>
|
||||||
|
<maximized>true</maximized>
|
||||||
|
<focus>yes</focus>
|
||||||
|
<layer>normal</layer>
|
||||||
|
</application>
|
||||||
|
</applications>
|
||||||
|
|
||||||
|
<focus>
|
||||||
|
<focusNew>yes</focusNew>
|
||||||
|
<!-- always try to focus new windows when they appear. other rules do
|
||||||
|
apply -->
|
||||||
|
<followMouse>no</followMouse>
|
||||||
|
<!-- move focus to a window when you move the mouse into it -->
|
||||||
|
<focusLast>yes</focusLast>
|
||||||
|
<!-- focus the last used window when changing desktops, instead of the one
|
||||||
|
under the mouse pointer. when followMouse is enabled -->
|
||||||
|
<underMouse>no</underMouse>
|
||||||
|
<!-- move focus under the mouse, even when the mouse is not moving -->
|
||||||
|
<focusDelay>200</focusDelay>
|
||||||
|
<!-- when followMouse is enabled, the mouse must be inside the window for
|
||||||
|
this many milliseconds (1000 = 1 sec) before moving focus to it -->
|
||||||
|
<raiseOnFocus>no</raiseOnFocus>
|
||||||
|
<!-- when followMouse is enabled, and a window is given focus by moving the
|
||||||
|
mouse into it, also raise the window -->
|
||||||
|
</focus>
|
||||||
|
|
||||||
|
<placement>
|
||||||
|
<policy>Smart</policy>
|
||||||
|
<!-- 'Smart' or 'UnderMouse' -->
|
||||||
|
<center>yes</center>
|
||||||
|
<!-- whether to place windows in the center of the free area found or
|
||||||
|
the top left corner -->
|
||||||
|
<monitor>Primary</monitor>
|
||||||
|
<!-- with Smart placement on a multi-monitor system, try to place new windows
|
||||||
|
on: 'Any' - any monitor, 'Mouse' - where the mouse is, 'Active' - where
|
||||||
|
the active window is, 'Primary' - only on the primary monitor -->
|
||||||
|
<primaryMonitor>1</primaryMonitor>
|
||||||
|
<!-- The monitor where Openbox should place popup dialogs such as the
|
||||||
|
focus cycling popup, or the desktop switch popup. It can be an index
|
||||||
|
from 1, specifying a particular monitor. Or it can be one of the
|
||||||
|
following: 'Mouse' - where the mouse is, or
|
||||||
|
'Active' - where the active window is -->
|
||||||
|
</placement>
|
||||||
|
|
||||||
|
<theme>
|
||||||
|
<name>Clearlooks</name>
|
||||||
|
<titleLayout>NLIMC</titleLayout>
|
||||||
|
<!--
|
||||||
|
available characters are NDSLIMC, each can occur at most once.
|
||||||
|
N: window icon
|
||||||
|
L: window label (AKA title).
|
||||||
|
I: iconify
|
||||||
|
M: maximize
|
||||||
|
C: close
|
||||||
|
S: shade (roll up/down)
|
||||||
|
D: omnipresent (on all desktops).
|
||||||
|
-->
|
||||||
|
<keepBorder>yes</keepBorder>
|
||||||
|
<animateIconify>yes</animateIconify>
|
||||||
|
<font place="ActiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuHeader">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuItem">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="ActiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
</theme>
|
||||||
|
|
||||||
|
<desktops>
|
||||||
|
<!-- this stuff is only used at startup, pagers allow you to change them
|
||||||
|
during a session
|
||||||
|
|
||||||
|
these are default values to use when other ones are not already set
|
||||||
|
by other applications, or saved in your session
|
||||||
|
|
||||||
|
use obconf if you want to change these without having to log out
|
||||||
|
and back in -->
|
||||||
|
<number>1</number>
|
||||||
|
<firstdesk>1</firstdesk>
|
||||||
|
<names>
|
||||||
|
<!-- set names up here if you want to, like this:
|
||||||
|
<name>desktop 1</name>
|
||||||
|
<name>desktop 2</name>
|
||||||
|
-->
|
||||||
|
</names>
|
||||||
|
<popupTime>875</popupTime>
|
||||||
|
<!-- The number of milliseconds to show the popup for when switching
|
||||||
|
desktops. Set this to 0 to disable the popup. -->
|
||||||
|
</desktops>
|
||||||
|
|
||||||
|
<resize>
|
||||||
|
<drawContents>yes</drawContents>
|
||||||
|
<popupShow>Nonpixel</popupShow>
|
||||||
|
<!-- 'Always', 'Never', or 'Nonpixel' (xterms and such) -->
|
||||||
|
<popupPosition>Center</popupPosition>
|
||||||
|
<!-- 'Center', 'Top', or 'Fixed' -->
|
||||||
|
<popupFixedPosition>
|
||||||
|
<!-- these are used if popupPosition is set to 'Fixed' -->
|
||||||
|
|
||||||
|
<x>10</x>
|
||||||
|
<!-- positive number for distance from left edge, negative number for
|
||||||
|
distance from right edge, or 'Center' -->
|
||||||
|
<y>10</y>
|
||||||
|
<!-- positive number for distance from top edge, negative number for
|
||||||
|
distance from bottom edge, or 'Center' -->
|
||||||
|
</popupFixedPosition>
|
||||||
|
</resize>
|
||||||
|
|
||||||
|
<!-- You can reserve a portion of your screen where windows will not cover when
|
||||||
|
they are maximized, or when they are initially placed.
|
||||||
|
Many programs reserve space automatically, but you can use this in other
|
||||||
|
cases. -->
|
||||||
|
<margins>
|
||||||
|
<top>0</top>
|
||||||
|
<bottom>0</bottom>
|
||||||
|
<left>0</left>
|
||||||
|
<right>0</right>
|
||||||
|
</margins>
|
||||||
|
|
||||||
|
<dock>
|
||||||
|
<position>TopLeft</position>
|
||||||
|
<!-- (Top|Bottom)(Left|Right|)|Top|Bottom|Left|Right|Floating -->
|
||||||
|
<floatingX>0</floatingX>
|
||||||
|
<floatingY>0</floatingY>
|
||||||
|
<noStrut>no</noStrut>
|
||||||
|
<stacking>Above</stacking>
|
||||||
|
<!-- 'Above', 'Normal', or 'Below' -->
|
||||||
|
<direction>Vertical</direction>
|
||||||
|
<!-- 'Vertical' or 'Horizontal' -->
|
||||||
|
<autoHide>no</autoHide>
|
||||||
|
<hideDelay>300</hideDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<showDelay>300</showDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<moveButton>Middle</moveButton>
|
||||||
|
<!-- 'Left', 'Middle', 'Right' -->
|
||||||
|
</dock>
|
||||||
|
|
||||||
|
<keyboard>
|
||||||
|
<chainQuitKey>C-g</chainQuitKey>
|
||||||
|
|
||||||
|
<!-- Keybindings for desktop switching -->
|
||||||
|
<keybind key="C-A-Left">
|
||||||
|
<action name="GoToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Right">
|
||||||
|
<action name="GoToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Up">
|
||||||
|
<action name="GoToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Down">
|
||||||
|
<action name="GoToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Left">
|
||||||
|
<action name="SendToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Right">
|
||||||
|
<action name="SendToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Up">
|
||||||
|
<action name="SendToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Down">
|
||||||
|
<action name="SendToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F1">
|
||||||
|
<action name="GoToDesktop"><to>1</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F2">
|
||||||
|
<action name="GoToDesktop"><to>2</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F3">
|
||||||
|
<action name="GoToDesktop"><to>3</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F4">
|
||||||
|
<action name="GoToDesktop"><to>4</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-d">
|
||||||
|
<action name="ToggleShowDesktop"/>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for windows -->
|
||||||
|
<keybind key="A-F4">
|
||||||
|
<action name="Close"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-Escape">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-space">
|
||||||
|
<!--action name="ShowMenu"><menu>client-menu</menu></action-->
|
||||||
|
</keybind>
|
||||||
|
<!-- Take a screenshot of the current window with scrot when Alt+Print are pressed -->
|
||||||
|
<keybind key="A-Print">
|
||||||
|
<action name="Execute"><command>scrot -s</command></action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching -->
|
||||||
|
<keybind key="A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-S-Tab">
|
||||||
|
<action name="PreviousWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<panels>yes</panels><desktop>yes</desktop>
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching with the arrow keys -->
|
||||||
|
<keybind key="W-S-Right">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>right</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Left">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>left</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Up">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>up</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Down">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>down</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for running applications -->
|
||||||
|
<keybind key="W-e">
|
||||||
|
<action name="Execute">
|
||||||
|
<startupnotify>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
<name>Konqueror</name>
|
||||||
|
</startupnotify>
|
||||||
|
<command>kfmclient openProfile filemanagement</command>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<!-- Launch scrot when Print is pressed -->
|
||||||
|
<keybind key="Print">
|
||||||
|
<action name="Execute"><command>scrot</command></action>
|
||||||
|
</keybind>
|
||||||
|
</keyboard>
|
||||||
|
|
||||||
|
<mouse>
|
||||||
|
<dragThreshold>1</dragThreshold>
|
||||||
|
<!-- number of pixels the mouse must move before a drag begins -->
|
||||||
|
<doubleClickTime>500</doubleClickTime>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<screenEdgeWarpTime>400</screenEdgeWarpTime>
|
||||||
|
<!-- Time before changing desktops when the pointer touches the edge of the
|
||||||
|
screen while moving a window, in milliseconds (1000 = 1 second).
|
||||||
|
Set this to 0 to disable warping -->
|
||||||
|
<screenEdgeWarpMouse>false</screenEdgeWarpMouse>
|
||||||
|
<!-- Set this to TRUE to move the mouse pointer across the desktop when
|
||||||
|
switching due to hitting the edge of the screen -->
|
||||||
|
|
||||||
|
<context name="Frame">
|
||||||
|
<mousebind button="A-Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Click">
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Right" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Up" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Down" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="DoubleClick">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>no</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Shade"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
<action name="Lower"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>yes</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar Top Right Bottom Left TLCorner TRCorner BRCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<!--mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Top">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>top</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Left">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>left</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Right">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>right</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Bottom">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>bottom</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<!--mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="TRCorner BRCorner TLCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Client">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Icon">
|
||||||
|
<!--mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="AllDesktops">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleOmnipresent"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Shade">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleShade"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Iconify">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Iconify"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Maximize">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>vertical</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>horizontal</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Close">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Close"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Desktop">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Root">
|
||||||
|
<!-- Menus -->
|
||||||
|
<!--mousebind button="Middle" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>client-list-combined-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>root-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="MoveResize">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
</mouse>
|
||||||
|
|
||||||
|
<menu>
|
||||||
|
<!-- You can specify more than one menu file in here and they are all loaded,
|
||||||
|
just don't make menu ids clash or, well, it'll be kind of pointless -->
|
||||||
|
|
||||||
|
<!-- default menu file (or custom one in $HOME/.config/openbox/) -->
|
||||||
|
<!-- system menu files on Debian systems -->
|
||||||
|
<!--file>/var/lib/openbox/debian-menu.xml</file-->
|
||||||
|
<file>menu.xml</file>
|
||||||
|
<hideDelay>200</hideDelay>
|
||||||
|
<!-- if a press-release lasts longer than this setting (in milliseconds), the
|
||||||
|
menu is hidden again -->
|
||||||
|
<middle>no</middle>
|
||||||
|
<!-- center submenus vertically about the parent entry -->
|
||||||
|
<submenuShowDelay>100</submenuShowDelay>
|
||||||
|
<!-- time to delay before showing a submenu after hovering over the parent
|
||||||
|
entry.
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be shown until it is clicked on -->
|
||||||
|
<submenuHideDelay>400</submenuHideDelay>
|
||||||
|
<!-- time to delay before hiding a submenu when selecting another
|
||||||
|
entry in parent menu
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be hidden until a different submenu is opened -->
|
||||||
|
<showIcons>yes</showIcons>
|
||||||
|
<!-- controls if icons appear in the client-list-(combined-)menu -->
|
||||||
|
<manageDesktops>yes</manageDesktops>
|
||||||
|
<!-- show the manage desktops section in the client-list-(combined-)menu -->
|
||||||
|
</menu>
|
||||||
|
|
||||||
|
<applications>
|
||||||
|
<!--
|
||||||
|
# this is an example with comments through out. use these to make your
|
||||||
|
# own rules, but without the comments of course.
|
||||||
|
# you may use one or more of the name/class/role/title/type rules to specify
|
||||||
|
# windows to match
|
||||||
|
|
||||||
|
<application name="the window's _OB_APP_NAME property (see obxprop)"
|
||||||
|
class="the window's _OB_APP_CLASS property (see obxprop)"
|
||||||
|
groupname="the window's _OB_APP_GROUP_NAME property (see obxprop)"
|
||||||
|
groupclass="the window's _OB_APP_GROUP_CLASS property (see obxprop)"
|
||||||
|
role="the window's _OB_APP_ROLE property (see obxprop)"
|
||||||
|
title="the window's _OB_APP_TITLE property (see obxprop)"
|
||||||
|
type="the window's _OB_APP_TYPE property (see obxprob)..
|
||||||
|
(if unspecified, then it is 'dialog' for child windows)">
|
||||||
|
# you may set only one of name/class/role/title/type, or you may use more
|
||||||
|
# than one together to restrict your matches.
|
||||||
|
|
||||||
|
# the name, class, role, and title use simple wildcard matching such as those
|
||||||
|
# used by a shell. you can use * to match any characters and ? to match
|
||||||
|
# any single character.
|
||||||
|
|
||||||
|
# the type is one of: normal, dialog, splash, utility, menu, toolbar, dock,
|
||||||
|
# or desktop
|
||||||
|
|
||||||
|
# when multiple rules match a window, they will all be applied, in the
|
||||||
|
# order that they appear in this list
|
||||||
|
|
||||||
|
|
||||||
|
# each rule element can be left out or set to 'default' to specify to not
|
||||||
|
# change that attribute of the window
|
||||||
|
|
||||||
|
<decor>yes</decor>
|
||||||
|
# enable or disable window decorations
|
||||||
|
|
||||||
|
<shade>no</shade>
|
||||||
|
# make the window shaded when it appears, or not
|
||||||
|
|
||||||
|
<position force="no">
|
||||||
|
# the position is only used if both an x and y coordinate are provided
|
||||||
|
# (and not set to 'default')
|
||||||
|
# when force is "yes", then the window will be placed here even if it
|
||||||
|
# says you want it placed elsewhere. this is to override buggy
|
||||||
|
# applications who refuse to behave
|
||||||
|
<x>center</x>
|
||||||
|
# a number like 50, or 'center' to center on screen. use a negative number
|
||||||
|
# to start from the right (or bottom for <y>), ie -50 is 50 pixels from
|
||||||
|
# the right edge (or bottom). use 'default' to specify using value
|
||||||
|
# provided by the application, or chosen by openbox, instead.
|
||||||
|
<y>200</y>
|
||||||
|
<monitor>1</monitor>
|
||||||
|
# specifies the monitor in a xinerama setup.
|
||||||
|
# 1 is the first head, or 'mouse' for wherever the mouse is
|
||||||
|
</position>
|
||||||
|
|
||||||
|
<size>
|
||||||
|
# the size to make the window.
|
||||||
|
<width>20</width>
|
||||||
|
# a number like 20, or 'default' to use the size given by the application.
|
||||||
|
# you can use fractions such as 1/2 or percentages such as 75% in which
|
||||||
|
# case the value is relative to the size of the monitor that the window
|
||||||
|
# appears on.
|
||||||
|
<height>30%</height>
|
||||||
|
</size>
|
||||||
|
|
||||||
|
<focus>yes</focus>
|
||||||
|
# if the window should try be given focus when it appears. if this is set
|
||||||
|
# to yes it doesn't guarantee the window will be given focus. some
|
||||||
|
# restrictions may apply, but Openbox will try to
|
||||||
|
|
||||||
|
<desktop>1</desktop>
|
||||||
|
# 1 is the first desktop, 'all' for all desktops
|
||||||
|
|
||||||
|
<layer>normal</layer>
|
||||||
|
# 'above', 'normal', or 'below'
|
||||||
|
|
||||||
|
<iconic>no</iconic>
|
||||||
|
# make the window iconified when it appears, or not
|
||||||
|
|
||||||
|
<skip_pager>no</skip_pager>
|
||||||
|
# asks to not be shown in pagers
|
||||||
|
|
||||||
|
<skip_taskbar>no</skip_taskbar>
|
||||||
|
# asks to not be shown in taskbars. window cycling actions will also
|
||||||
|
# skip past such windows
|
||||||
|
|
||||||
|
<fullscreen>yes</fullscreen>
|
||||||
|
# make the window in fullscreen mode when it appears
|
||||||
|
|
||||||
|
<maximized>true</maximized>
|
||||||
|
# 'Horizontal', 'Vertical' or boolean (yes/no)
|
||||||
|
</application>
|
||||||
|
|
||||||
|
# end of the example
|
||||||
|
-->
|
||||||
|
</applications>
|
||||||
|
|
||||||
|
</openbox_config>
|
11
.docker/files/popcorn/supervisord.conf
Normal file
11
.docker/files/popcorn/supervisord.conf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
[program:popcorn]
|
||||||
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
|
command=
|
||||||
|
autorestart=true
|
||||||
|
priority=800
|
||||||
|
user=%(ENV_USER)s
|
||||||
|
stdout_logfile=/var/log/neko/popcorn.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
28
.docker/files/tor-browser/Dockerfile
Normal file
28
.docker/files/tor-browser/Dockerfile
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
FROM nurdism/neko:openbox
|
||||||
|
|
||||||
|
#
|
||||||
|
# install dependencies
|
||||||
|
RUN set -eux; apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends curl xz-utils file libgtk-3-0 libdbus-glib-1-2; \
|
||||||
|
#
|
||||||
|
# clean up
|
||||||
|
apt-get clean -y; \
|
||||||
|
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||||
|
|
||||||
|
WORKDIR /home/neko
|
||||||
|
USER neko
|
||||||
|
|
||||||
|
#
|
||||||
|
# download TOR browser
|
||||||
|
RUN DOWNLOAD_URI="$(curl -s -N https://www.torproject.org/download/ | grep -Po -m 1 '(?=(dist/torbrowser)).*(?<=.tar.xz)')"; \
|
||||||
|
echo "Downloading $DOWNLOAD_URI"; \
|
||||||
|
curl -sSL -o tor.tar.xz "https://www.torproject.org/$DOWNLOAD_URI"; \
|
||||||
|
tar -xvJf tor.tar.xz; \
|
||||||
|
rm -f tor.tar.xz*;
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy configuation file
|
||||||
|
COPY .docker/files/tor-browser/supervisord.conf /etc/neko/supervisord/tor-browser.conf
|
||||||
|
COPY .docker/files/tor-browser/openbox.xml /etc/neko/openbox.xml
|
763
.docker/files/tor-browser/openbox.xml
Normal file
763
.docker/files/tor-browser/openbox.xml
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!-- Default openbox config but all window decorations are moved
|
||||||
|
thereby making it harder to accidentally close the virtual browser -->
|
||||||
|
|
||||||
|
<openbox_config xmlns="http://openbox.org/3.4/rc"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
|
||||||
|
<resistance>
|
||||||
|
<strength>10</strength>
|
||||||
|
<screen_edge_strength>20</screen_edge_strength>
|
||||||
|
</resistance>
|
||||||
|
|
||||||
|
<applications>
|
||||||
|
<!-- Match all windows and remove their decorations (obxprop | grep "^_OB_APP") -->
|
||||||
|
<application class="Tor*" name="Navigator">
|
||||||
|
<decor>no</decor>
|
||||||
|
<maximized>true</maximized>
|
||||||
|
<focus>yes</focus>
|
||||||
|
<layer>normal</layer>
|
||||||
|
</application>
|
||||||
|
</applications>
|
||||||
|
|
||||||
|
<focus>
|
||||||
|
<focusNew>yes</focusNew>
|
||||||
|
<!-- always try to focus new windows when they appear. other rules do
|
||||||
|
apply -->
|
||||||
|
<followMouse>no</followMouse>
|
||||||
|
<!-- move focus to a window when you move the mouse into it -->
|
||||||
|
<focusLast>yes</focusLast>
|
||||||
|
<!-- focus the last used window when changing desktops, instead of the one
|
||||||
|
under the mouse pointer. when followMouse is enabled -->
|
||||||
|
<underMouse>no</underMouse>
|
||||||
|
<!-- move focus under the mouse, even when the mouse is not moving -->
|
||||||
|
<focusDelay>200</focusDelay>
|
||||||
|
<!-- when followMouse is enabled, the mouse must be inside the window for
|
||||||
|
this many milliseconds (1000 = 1 sec) before moving focus to it -->
|
||||||
|
<raiseOnFocus>no</raiseOnFocus>
|
||||||
|
<!-- when followMouse is enabled, and a window is given focus by moving the
|
||||||
|
mouse into it, also raise the window -->
|
||||||
|
</focus>
|
||||||
|
|
||||||
|
<placement>
|
||||||
|
<policy>Smart</policy>
|
||||||
|
<!-- 'Smart' or 'UnderMouse' -->
|
||||||
|
<center>yes</center>
|
||||||
|
<!-- whether to place windows in the center of the free area found or
|
||||||
|
the top left corner -->
|
||||||
|
<monitor>Primary</monitor>
|
||||||
|
<!-- with Smart placement on a multi-monitor system, try to place new windows
|
||||||
|
on: 'Any' - any monitor, 'Mouse' - where the mouse is, 'Active' - where
|
||||||
|
the active window is, 'Primary' - only on the primary monitor -->
|
||||||
|
<primaryMonitor>1</primaryMonitor>
|
||||||
|
<!-- The monitor where Openbox should place popup dialogs such as the
|
||||||
|
focus cycling popup, or the desktop switch popup. It can be an index
|
||||||
|
from 1, specifying a particular monitor. Or it can be one of the
|
||||||
|
following: 'Mouse' - where the mouse is, or
|
||||||
|
'Active' - where the active window is -->
|
||||||
|
</placement>
|
||||||
|
|
||||||
|
<theme>
|
||||||
|
<name>Clearlooks</name>
|
||||||
|
<titleLayout>NLIMC</titleLayout>
|
||||||
|
<!--
|
||||||
|
available characters are NDSLIMC, each can occur at most once.
|
||||||
|
N: window icon
|
||||||
|
L: window label (AKA title).
|
||||||
|
I: iconify
|
||||||
|
M: maximize
|
||||||
|
C: close
|
||||||
|
S: shade (roll up/down)
|
||||||
|
D: omnipresent (on all desktops).
|
||||||
|
-->
|
||||||
|
<keepBorder>yes</keepBorder>
|
||||||
|
<animateIconify>yes</animateIconify>
|
||||||
|
<font place="ActiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuHeader">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuItem">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="ActiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
</theme>
|
||||||
|
|
||||||
|
<desktops>
|
||||||
|
<!-- this stuff is only used at startup, pagers allow you to change them
|
||||||
|
during a session
|
||||||
|
|
||||||
|
these are default values to use when other ones are not already set
|
||||||
|
by other applications, or saved in your session
|
||||||
|
|
||||||
|
use obconf if you want to change these without having to log out
|
||||||
|
and back in -->
|
||||||
|
<number>1</number>
|
||||||
|
<firstdesk>1</firstdesk>
|
||||||
|
<names>
|
||||||
|
<!-- set names up here if you want to, like this:
|
||||||
|
<name>desktop 1</name>
|
||||||
|
<name>desktop 2</name>
|
||||||
|
-->
|
||||||
|
</names>
|
||||||
|
<popupTime>875</popupTime>
|
||||||
|
<!-- The number of milliseconds to show the popup for when switching
|
||||||
|
desktops. Set this to 0 to disable the popup. -->
|
||||||
|
</desktops>
|
||||||
|
|
||||||
|
<resize>
|
||||||
|
<drawContents>yes</drawContents>
|
||||||
|
<popupShow>Nonpixel</popupShow>
|
||||||
|
<!-- 'Always', 'Never', or 'Nonpixel' (xterms and such) -->
|
||||||
|
<popupPosition>Center</popupPosition>
|
||||||
|
<!-- 'Center', 'Top', or 'Fixed' -->
|
||||||
|
<popupFixedPosition>
|
||||||
|
<!-- these are used if popupPosition is set to 'Fixed' -->
|
||||||
|
|
||||||
|
<x>10</x>
|
||||||
|
<!-- positive number for distance from left edge, negative number for
|
||||||
|
distance from right edge, or 'Center' -->
|
||||||
|
<y>10</y>
|
||||||
|
<!-- positive number for distance from top edge, negative number for
|
||||||
|
distance from bottom edge, or 'Center' -->
|
||||||
|
</popupFixedPosition>
|
||||||
|
</resize>
|
||||||
|
|
||||||
|
<!-- You can reserve a portion of your screen where windows will not cover when
|
||||||
|
they are maximized, or when they are initially placed.
|
||||||
|
Many programs reserve space automatically, but you can use this in other
|
||||||
|
cases. -->
|
||||||
|
<margins>
|
||||||
|
<top>0</top>
|
||||||
|
<bottom>0</bottom>
|
||||||
|
<left>0</left>
|
||||||
|
<right>0</right>
|
||||||
|
</margins>
|
||||||
|
|
||||||
|
<dock>
|
||||||
|
<position>TopLeft</position>
|
||||||
|
<!-- (Top|Bottom)(Left|Right|)|Top|Bottom|Left|Right|Floating -->
|
||||||
|
<floatingX>0</floatingX>
|
||||||
|
<floatingY>0</floatingY>
|
||||||
|
<noStrut>no</noStrut>
|
||||||
|
<stacking>Above</stacking>
|
||||||
|
<!-- 'Above', 'Normal', or 'Below' -->
|
||||||
|
<direction>Vertical</direction>
|
||||||
|
<!-- 'Vertical' or 'Horizontal' -->
|
||||||
|
<autoHide>no</autoHide>
|
||||||
|
<hideDelay>300</hideDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<showDelay>300</showDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<moveButton>Middle</moveButton>
|
||||||
|
<!-- 'Left', 'Middle', 'Right' -->
|
||||||
|
</dock>
|
||||||
|
|
||||||
|
<keyboard>
|
||||||
|
<chainQuitKey>C-g</chainQuitKey>
|
||||||
|
|
||||||
|
<!-- Keybindings for desktop switching -->
|
||||||
|
<keybind key="C-A-Left">
|
||||||
|
<action name="GoToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Right">
|
||||||
|
<action name="GoToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Up">
|
||||||
|
<action name="GoToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Down">
|
||||||
|
<action name="GoToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Left">
|
||||||
|
<action name="SendToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Right">
|
||||||
|
<action name="SendToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Up">
|
||||||
|
<action name="SendToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Down">
|
||||||
|
<action name="SendToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F1">
|
||||||
|
<action name="GoToDesktop"><to>1</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F2">
|
||||||
|
<action name="GoToDesktop"><to>2</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F3">
|
||||||
|
<action name="GoToDesktop"><to>3</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F4">
|
||||||
|
<action name="GoToDesktop"><to>4</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-d">
|
||||||
|
<action name="ToggleShowDesktop"/>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for windows -->
|
||||||
|
<keybind key="A-F4">
|
||||||
|
<action name="Close"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-Escape">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-space">
|
||||||
|
<!--action name="ShowMenu"><menu>client-menu</menu></action-->
|
||||||
|
</keybind>
|
||||||
|
<!-- Take a screenshot of the current window with scrot when Alt+Print are pressed -->
|
||||||
|
<keybind key="A-Print">
|
||||||
|
<action name="Execute"><command>scrot -s</command></action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching -->
|
||||||
|
<keybind key="A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-S-Tab">
|
||||||
|
<action name="PreviousWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<panels>yes</panels><desktop>yes</desktop>
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching with the arrow keys -->
|
||||||
|
<keybind key="W-S-Right">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>right</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Left">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>left</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Up">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>up</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Down">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>down</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for running applications -->
|
||||||
|
<keybind key="W-e">
|
||||||
|
<action name="Execute">
|
||||||
|
<startupnotify>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
<name>Konqueror</name>
|
||||||
|
</startupnotify>
|
||||||
|
<command>kfmclient openProfile filemanagement</command>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<!-- Launch scrot when Print is pressed -->
|
||||||
|
<keybind key="Print">
|
||||||
|
<action name="Execute"><command>scrot</command></action>
|
||||||
|
</keybind>
|
||||||
|
</keyboard>
|
||||||
|
|
||||||
|
<mouse>
|
||||||
|
<dragThreshold>1</dragThreshold>
|
||||||
|
<!-- number of pixels the mouse must move before a drag begins -->
|
||||||
|
<doubleClickTime>500</doubleClickTime>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<screenEdgeWarpTime>400</screenEdgeWarpTime>
|
||||||
|
<!-- Time before changing desktops when the pointer touches the edge of the
|
||||||
|
screen while moving a window, in milliseconds (1000 = 1 second).
|
||||||
|
Set this to 0 to disable warping -->
|
||||||
|
<screenEdgeWarpMouse>false</screenEdgeWarpMouse>
|
||||||
|
<!-- Set this to TRUE to move the mouse pointer across the desktop when
|
||||||
|
switching due to hitting the edge of the screen -->
|
||||||
|
|
||||||
|
<context name="Frame">
|
||||||
|
<mousebind button="A-Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Click">
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Right" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Up" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Down" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="DoubleClick">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>no</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Shade"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
<action name="Lower"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>yes</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar Top Right Bottom Left TLCorner TRCorner BRCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<!--mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Top">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>top</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Left">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>left</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Right">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>right</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Bottom">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>bottom</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<!--mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="TRCorner BRCorner TLCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Client">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Icon">
|
||||||
|
<!--mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="AllDesktops">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleOmnipresent"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Shade">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleShade"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Iconify">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Iconify"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Maximize">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>vertical</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>horizontal</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Close">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Close"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Desktop">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Root">
|
||||||
|
<!-- Menus -->
|
||||||
|
<!--mousebind button="Middle" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>client-list-combined-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>root-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="MoveResize">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
</mouse>
|
||||||
|
|
||||||
|
<menu>
|
||||||
|
<!-- You can specify more than one menu file in here and they are all loaded,
|
||||||
|
just don't make menu ids clash or, well, it'll be kind of pointless -->
|
||||||
|
|
||||||
|
<!-- default menu file (or custom one in $HOME/.config/openbox/) -->
|
||||||
|
<!-- system menu files on Debian systems -->
|
||||||
|
<!--file>/var/lib/openbox/debian-menu.xml</file-->
|
||||||
|
<file>menu.xml</file>
|
||||||
|
<hideDelay>200</hideDelay>
|
||||||
|
<!-- if a press-release lasts longer than this setting (in milliseconds), the
|
||||||
|
menu is hidden again -->
|
||||||
|
<middle>no</middle>
|
||||||
|
<!-- center submenus vertically about the parent entry -->
|
||||||
|
<submenuShowDelay>100</submenuShowDelay>
|
||||||
|
<!-- time to delay before showing a submenu after hovering over the parent
|
||||||
|
entry.
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be shown until it is clicked on -->
|
||||||
|
<submenuHideDelay>400</submenuHideDelay>
|
||||||
|
<!-- time to delay before hiding a submenu when selecting another
|
||||||
|
entry in parent menu
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be hidden until a different submenu is opened -->
|
||||||
|
<showIcons>yes</showIcons>
|
||||||
|
<!-- controls if icons appear in the client-list-(combined-)menu -->
|
||||||
|
<manageDesktops>yes</manageDesktops>
|
||||||
|
<!-- show the manage desktops section in the client-list-(combined-)menu -->
|
||||||
|
</menu>
|
||||||
|
|
||||||
|
<applications>
|
||||||
|
<!--
|
||||||
|
# this is an example with comments through out. use these to make your
|
||||||
|
# own rules, but without the comments of course.
|
||||||
|
# you may use one or more of the name/class/role/title/type rules to specify
|
||||||
|
# windows to match
|
||||||
|
|
||||||
|
<application name="the window's _OB_APP_NAME property (see obxprop)"
|
||||||
|
class="the window's _OB_APP_CLASS property (see obxprop)"
|
||||||
|
groupname="the window's _OB_APP_GROUP_NAME property (see obxprop)"
|
||||||
|
groupclass="the window's _OB_APP_GROUP_CLASS property (see obxprop)"
|
||||||
|
role="the window's _OB_APP_ROLE property (see obxprop)"
|
||||||
|
title="the window's _OB_APP_TITLE property (see obxprop)"
|
||||||
|
type="the window's _OB_APP_TYPE property (see obxprob)..
|
||||||
|
(if unspecified, then it is 'dialog' for child windows)">
|
||||||
|
# you may set only one of name/class/role/title/type, or you may use more
|
||||||
|
# than one together to restrict your matches.
|
||||||
|
|
||||||
|
# the name, class, role, and title use simple wildcard matching such as those
|
||||||
|
# used by a shell. you can use * to match any characters and ? to match
|
||||||
|
# any single character.
|
||||||
|
|
||||||
|
# the type is one of: normal, dialog, splash, utility, menu, toolbar, dock,
|
||||||
|
# or desktop
|
||||||
|
|
||||||
|
# when multiple rules match a window, they will all be applied, in the
|
||||||
|
# order that they appear in this list
|
||||||
|
|
||||||
|
|
||||||
|
# each rule element can be left out or set to 'default' to specify to not
|
||||||
|
# change that attribute of the window
|
||||||
|
|
||||||
|
<decor>yes</decor>
|
||||||
|
# enable or disable window decorations
|
||||||
|
|
||||||
|
<shade>no</shade>
|
||||||
|
# make the window shaded when it appears, or not
|
||||||
|
|
||||||
|
<position force="no">
|
||||||
|
# the position is only used if both an x and y coordinate are provided
|
||||||
|
# (and not set to 'default')
|
||||||
|
# when force is "yes", then the window will be placed here even if it
|
||||||
|
# says you want it placed elsewhere. this is to override buggy
|
||||||
|
# applications who refuse to behave
|
||||||
|
<x>center</x>
|
||||||
|
# a number like 50, or 'center' to center on screen. use a negative number
|
||||||
|
# to start from the right (or bottom for <y>), ie -50 is 50 pixels from
|
||||||
|
# the right edge (or bottom). use 'default' to specify using value
|
||||||
|
# provided by the application, or chosen by openbox, instead.
|
||||||
|
<y>200</y>
|
||||||
|
<monitor>1</monitor>
|
||||||
|
# specifies the monitor in a xinerama setup.
|
||||||
|
# 1 is the first head, or 'mouse' for wherever the mouse is
|
||||||
|
</position>
|
||||||
|
|
||||||
|
<size>
|
||||||
|
# the size to make the window.
|
||||||
|
<width>20</width>
|
||||||
|
# a number like 20, or 'default' to use the size given by the application.
|
||||||
|
# you can use fractions such as 1/2 or percentages such as 75% in which
|
||||||
|
# case the value is relative to the size of the monitor that the window
|
||||||
|
# appears on.
|
||||||
|
<height>30%</height>
|
||||||
|
</size>
|
||||||
|
|
||||||
|
<focus>yes</focus>
|
||||||
|
# if the window should try be given focus when it appears. if this is set
|
||||||
|
# to yes it doesn't guarantee the window will be given focus. some
|
||||||
|
# restrictions may apply, but Openbox will try to
|
||||||
|
|
||||||
|
<desktop>1</desktop>
|
||||||
|
# 1 is the first desktop, 'all' for all desktops
|
||||||
|
|
||||||
|
<layer>normal</layer>
|
||||||
|
# 'above', 'normal', or 'below'
|
||||||
|
|
||||||
|
<iconic>no</iconic>
|
||||||
|
# make the window iconified when it appears, or not
|
||||||
|
|
||||||
|
<skip_pager>no</skip_pager>
|
||||||
|
# asks to not be shown in pagers
|
||||||
|
|
||||||
|
<skip_taskbar>no</skip_taskbar>
|
||||||
|
# asks to not be shown in taskbars. window cycling actions will also
|
||||||
|
# skip past such windows
|
||||||
|
|
||||||
|
<fullscreen>yes</fullscreen>
|
||||||
|
# make the window in fullscreen mode when it appears
|
||||||
|
|
||||||
|
<maximized>true</maximized>
|
||||||
|
# 'Horizontal', 'Vertical' or boolean (yes/no)
|
||||||
|
</application>
|
||||||
|
|
||||||
|
# end of the example
|
||||||
|
-->
|
||||||
|
</applications>
|
||||||
|
|
||||||
|
</openbox_config>
|
13
.docker/files/tor-browser/supervisord.conf
Normal file
13
.docker/files/tor-browser/supervisord.conf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[program:tor-browser]
|
||||||
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
|
command=/home/neko/tor-browser_en-US/Browser/start-tor-browser --display=%(ENV_DISPLAY)s --setDefaultBrowser --window-size 1280,720
|
||||||
|
autorestart=true
|
||||||
|
priority=800
|
||||||
|
user=%(ENV_USER)s
|
||||||
|
stdout_logfile=/var/log/neko/tor-browser.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
||||||
|
stderr_logfile=/var/log/neko/tor-browser.err.log
|
||||||
|
stderr_logfile_maxbytes=100MB
|
||||||
|
stderr_logfile_backups=10
|
11
.docker/files/xfce4/Dockerfile
Normal file
11
.docker/files/xfce4/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
FROM nurdism/neko:base
|
||||||
|
|
||||||
|
#
|
||||||
|
# install xfce4
|
||||||
|
RUN set -eux; apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends xfce4;
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy xfce4 conf and supervisord conf
|
||||||
|
COPY .docker/files/xfce4/supervisord.conf /etc/neko/openbox.xml
|
||||||
|
# COPY .docker/files/xfce4/xfconf /etc/neko/xfconf
|
10
.docker/files/xfce4/supervisord.conf
Normal file
10
.docker/files/xfce4/supervisord.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[program:xfce4]
|
||||||
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
|
command=/usr/bin/xfce4-session
|
||||||
|
autorestart=true
|
||||||
|
priority=300
|
||||||
|
user=%(ENV_USER)s
|
||||||
|
stdout_logfile=/var/log/neko/xfce4.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
16
.examples/local/docker-compose.yaml
Normal file
16
.examples/local/docker-compose.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
version: "2.0"
|
||||||
|
services:
|
||||||
|
neko:
|
||||||
|
image: nurdism/neko:firefox
|
||||||
|
restart: always
|
||||||
|
shm_size: "1gb"
|
||||||
|
ports:
|
||||||
|
- "80:8080"
|
||||||
|
- "59000-59100:59000-59100/udp"
|
||||||
|
environment:
|
||||||
|
DISPLAY: :99.0
|
||||||
|
NEKO_PASSWORD: neko
|
||||||
|
NEKO_PASSWORD_ADMIN: admin
|
||||||
|
NEKO_BIND: :8080
|
||||||
|
NEKO_EPR: 59000-59100
|
||||||
|
NEKO_NAT1TO1: 192.168.0.X
|
0
.examples/simple/README.md
Normal file
0
.examples/simple/README.md
Normal file
@ -10,5 +10,6 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
DISPLAY: :99.0
|
DISPLAY: :99.0
|
||||||
NEKO_PASSWORD: neko
|
NEKO_PASSWORD: neko
|
||||||
NEKO_ADMIN: admin
|
NEKO_PASSWORD_ADMIN: admin
|
||||||
NEKO_BIND: :8080
|
NEKO_BIND: :8080
|
||||||
|
NEKO_EPR: 59000-59100
|
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@ -1 +0,0 @@
|
|||||||
patreon: nurdism
|
|
42
.github/ISSUE_TEMPLATE/bug_report.md
vendored
42
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,42 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve
|
|
||||||
title: "[BUG]"
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
Steps to reproduce the behavior:
|
|
||||||
1. Go to '...'
|
|
||||||
2. Click on '....'
|
|
||||||
3. Scroll down to '....'
|
|
||||||
4. See error
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Screenshots**
|
|
||||||
If applicable, add screenshots to help explain your problem.
|
|
||||||
|
|
||||||
**Desktop (please complete the following information):**
|
|
||||||
- OS: [e.g. iOS]
|
|
||||||
- Browser [e.g. chrome, safari]
|
|
||||||
- Version [e.g. 22]
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
||||||
|
|
||||||
**Client Log:**
|
|
||||||
```
|
|
||||||
client log here....
|
|
||||||
```
|
|
||||||
|
|
||||||
**Server Log:**
|
|
||||||
```
|
|
||||||
server log here....
|
|
||||||
```
|
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for this project
|
|
||||||
title: "[FEATURE]"
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you want to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context or screenshots about the feature request here.
|
|
122
.m1k1o/base/Dockerfile
Normal file
122
.m1k1o/base/Dockerfile
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#
|
||||||
|
# STAGE 1: SERVER
|
||||||
|
#
|
||||||
|
FROM golang:1.15-buster as server
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
#
|
||||||
|
# install dependencies
|
||||||
|
RUN set -eux; apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends git cmake make libx11-dev libxrandr-dev libxtst-dev \
|
||||||
|
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly; \
|
||||||
|
#
|
||||||
|
# install libclipboard
|
||||||
|
set -eux; \
|
||||||
|
cd /tmp; \
|
||||||
|
git clone https://github.com/jtanx/libclipboard; \
|
||||||
|
cd libclipboard; \
|
||||||
|
cmake .; \
|
||||||
|
make -j4; \
|
||||||
|
make install; \
|
||||||
|
rm -rf /tmp/libclipboard; \
|
||||||
|
#
|
||||||
|
# clean up
|
||||||
|
apt-get clean -y; \
|
||||||
|
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||||
|
|
||||||
|
#
|
||||||
|
# build server
|
||||||
|
COPY server/ .
|
||||||
|
RUN go get -v -t -d . && go build -o bin/neko -i cmd/neko/main.go
|
||||||
|
|
||||||
|
#
|
||||||
|
# STAGE 2: CLIENT
|
||||||
|
#
|
||||||
|
FROM node:12-buster-slim as client
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
#
|
||||||
|
# install dependencies
|
||||||
|
COPY client/package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
#
|
||||||
|
# build client
|
||||||
|
COPY client/ .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
#
|
||||||
|
# STAGE 3: RUNTIME
|
||||||
|
#
|
||||||
|
FROM debian:buster-slim
|
||||||
|
|
||||||
|
#
|
||||||
|
# avoid warnings by switching to noninteractive
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
#
|
||||||
|
# set custom user
|
||||||
|
ARG USERNAME=neko
|
||||||
|
ARG USER_UID=1000
|
||||||
|
ARG USER_GID=$USER_UID
|
||||||
|
|
||||||
|
#
|
||||||
|
# install dependencies
|
||||||
|
RUN set -eux; apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends wget ca-certificates supervisor; \
|
||||||
|
apt-get install -y --no-install-recommends pulseaudio dbus-x11 xserver-xorg-video-dummy; \
|
||||||
|
apt-get install -y --no-install-recommends libcairo2 libxcb1 libxrandr2 libxv1 libopus0 libvpx5; \
|
||||||
|
#
|
||||||
|
# gst
|
||||||
|
apt-get install -y --no-install-recommends libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
|
||||||
|
gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-pulseaudio; \
|
||||||
|
#
|
||||||
|
# create a non-root user
|
||||||
|
groupadd --gid $USER_GID $USERNAME; \
|
||||||
|
useradd --uid $USER_UID --gid $USERNAME --shell /bin/bash --create-home $USERNAME; \
|
||||||
|
adduser $USERNAME audio; \
|
||||||
|
adduser $USERNAME video; \
|
||||||
|
adduser $USERNAME pulse; \
|
||||||
|
#
|
||||||
|
# setup pulseaudio
|
||||||
|
mkdir -p /home/$USERNAME/.config/pulse/; \
|
||||||
|
echo "default-server=unix:/tmp/pulseaudio.socket" > /home/$USERNAME/.config/pulse/client.conf; \
|
||||||
|
#
|
||||||
|
# workaround for an X11 problem: http://blog.tigerteufel.de/?p=476
|
||||||
|
mkdir /tmp/.X11-unix; \
|
||||||
|
chmod 1777 /tmp/.X11-unix; \
|
||||||
|
chown $USERNAME /tmp/.X11-unix/; \
|
||||||
|
#
|
||||||
|
# make directories for neko
|
||||||
|
mkdir -p /etc/neko /var/www /var/log/neko; \
|
||||||
|
chmod 1777 /var/log/neko; \
|
||||||
|
chown $USERNAME /var/log/neko/; \
|
||||||
|
chown -R $USERNAME:$USERNAME /home/$USERNAME; \
|
||||||
|
#
|
||||||
|
# clean up
|
||||||
|
apt-get clean -y; \
|
||||||
|
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy config files
|
||||||
|
COPY .m1k1o/base/dbus /usr/bin/dbus
|
||||||
|
COPY .m1k1o/base/default.pa /etc/pulse/default.pa
|
||||||
|
COPY .m1k1o/base/supervisord.conf /etc/neko/supervisord.conf
|
||||||
|
COPY .m1k1o/base/xorg.conf /etc/neko/xorg.conf
|
||||||
|
|
||||||
|
#
|
||||||
|
# set default envs
|
||||||
|
ENV USER=$USERNAME
|
||||||
|
ENV DISPLAY=:99.0
|
||||||
|
ENV NEKO_PASSWORD=neko
|
||||||
|
ENV NEKO_PASSWORD_ADMIN=admin
|
||||||
|
ENV NEKO_BIND=:8080
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy static files from previous stages
|
||||||
|
COPY --from=server /src/bin/neko /usr/bin/neko
|
||||||
|
COPY --from=client /src/dist/ /var/www
|
||||||
|
|
||||||
|
#
|
||||||
|
# run neko
|
||||||
|
CMD ["/usr/bin/supervisord", "-c", "/etc/neko/supervisord.conf"]
|
11
.m1k1o/base/dbus
Executable file
11
.m1k1o/base/dbus
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ ! -d /var/run/dbus ]; then
|
||||||
|
mkdir -p /var/run/dbus
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f /var/run/dbus/pid ]; then
|
||||||
|
rm -f /var/run/dbus/pid
|
||||||
|
fi
|
||||||
|
|
||||||
|
/usr/bin/dbus-daemon --nofork --print-pid --config-file=/usr/share/dbus-1/system.conf
|
7
.m1k1o/base/default.pa
Normal file
7
.m1k1o/base/default.pa
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/pulseaudio -nF
|
||||||
|
|
||||||
|
# Allow pulse audio to be accessed via TCP (from localhost only), to allow other users to access the virtual devices
|
||||||
|
load-module module-native-protocol-unix socket=/tmp/pulseaudio.socket auth-anonymous=1
|
||||||
|
|
||||||
|
### Make sure we always have a sink around, even if it is a null sink.
|
||||||
|
load-module module-always-sink
|
@ -41,13 +41,13 @@ stdout_logfile_maxbytes=100MB
|
|||||||
stdout_logfile_backups=10
|
stdout_logfile_backups=10
|
||||||
redirect_stderr=true
|
redirect_stderr=true
|
||||||
|
|
||||||
[program:openbox]
|
[program:neko]
|
||||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
command=/usr/bin/openbox --config-file /etc/neko/openbox.xml
|
command=/usr/bin/neko serve --static "/var/www"
|
||||||
autorestart=true
|
autorestart=true
|
||||||
priority=300
|
priority=800
|
||||||
user=%(ENV_USER)s
|
user=%(ENV_USER)s
|
||||||
stdout_logfile=/var/log/neko/openbox.log
|
stdout_logfile=/var/log/neko/neko.log
|
||||||
stdout_logfile_maxbytes=100MB
|
stdout_logfile_maxbytes=100MB
|
||||||
stdout_logfile_backups=10
|
stdout_logfile_backups=10
|
||||||
redirect_stderr=true
|
redirect_stderr=true
|
@ -85,4 +85,4 @@ Section "ServerLayout"
|
|||||||
Screen "dummy_screen"
|
Screen "dummy_screen"
|
||||||
InputDevice "dummy_mouse"
|
InputDevice "dummy_mouse"
|
||||||
InputDevice "dummy_keyboard"
|
InputDevice "dummy_keyboard"
|
||||||
EndSection
|
EndSection
|
35
.m1k1o/build
Executable file
35
.m1k1o/build
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
BASE=../
|
||||||
|
|
||||||
|
build_client() {
|
||||||
|
docker build -t neko-dev-client -f base/Dockerfile --target client "$BASE"
|
||||||
|
docker run --rm -v "$BASE"/client/dist:/tmp/dist neko-dev-client sh -c "rm -rf /tmp/dist/*; cp -r /src/dist/* /tmp/dist"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_server() {
|
||||||
|
docker build -t neko-dev-server -f base/Dockerfile --target server "$BASE"
|
||||||
|
docker run --rm -v "$BASE"/server/bin:/tmp/bin neko-dev-server sh -c "rm -rf /tmp/bin/neko; cp /src/bin/neko /tmp/bin"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_base() {
|
||||||
|
docker build -t m1k1o/neko:base -f base/Dockerfile "$BASE"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_firefox() {
|
||||||
|
docker build -t m1k1o/neko:firefox -f firefox/Dockerfile firefox/
|
||||||
|
}
|
||||||
|
|
||||||
|
build_chromium() {
|
||||||
|
docker build -t m1k1o/neko:chromium -f chromium/Dockerfile chromium/
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
client) build_client;;
|
||||||
|
serve) build_server;;
|
||||||
|
base) build_base;;
|
||||||
|
firefox) build_firefox;;
|
||||||
|
chromium) build_chromium;;
|
||||||
|
*) echo "Unknown $1";;
|
||||||
|
esac
|
32
.m1k1o/chromium/Dockerfile
Normal file
32
.m1k1o/chromium/Dockerfile
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
FROM m1k1o/neko:base
|
||||||
|
|
||||||
|
ARG SRC_URL="https://github.com/macchrome/linchrome/releases/download/v87.0.4280.88-r812852-portable-ungoogled-Lin64/ungoogled-chromium_87.0.4280.88_1.vaapi_linux.tar.xz"
|
||||||
|
|
||||||
|
#
|
||||||
|
# install custom chromium build from woolyss with support for hevc/x265
|
||||||
|
RUN set -eux; apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends libatk1.0-0 libatk-bridge2.0-0 libatomic1 \
|
||||||
|
libcups2 libgtk-3-0 libnss3 libpci3 libxcomposite1 libxss1 openbox xz-utils; \
|
||||||
|
wget -O - /tmp/chromium.tar.xz "${SRC_URL}" | tar -xJf- -C /tmp; \
|
||||||
|
mv /tmp/ungoogled-chromium_* /usr/lib/chromium; \
|
||||||
|
#
|
||||||
|
# make required changes for sandbox mode
|
||||||
|
mv /usr/lib/chromium/chrome_sandbox /usr/lib/chromium/chrome-sandbox; \
|
||||||
|
chown root:root /usr/lib/chromium/chrome-sandbox; \
|
||||||
|
chmod 4755 /usr/lib/chromium/chrome-sandbox; \
|
||||||
|
#
|
||||||
|
# clean up
|
||||||
|
apt-get --purge autoremove -y xz-utils; \
|
||||||
|
apt-get clean -y; \
|
||||||
|
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy configuation files
|
||||||
|
COPY supervisord.conf /etc/neko/supervisord/chromium.conf
|
||||||
|
COPY preferences.json /usr/lib/chromium/master_preferences
|
||||||
|
COPY policies.json /etc/chromium/policies/managed/policies.json
|
||||||
|
COPY openbox.xml /etc/neko/openbox.xml
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy extensions and policy files
|
||||||
|
COPY extensions /usr/share/chromium/extensions
|
BIN
.m1k1o/chromium/extensions/cjpalhdlnbpafiamejdnhcphjbkeiagm.crx
Normal file
BIN
.m1k1o/chromium/extensions/cjpalhdlnbpafiamejdnhcphjbkeiagm.crx
Normal file
Binary file not shown.
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"external_crx": "/usr/share/chromium/extensions/cjpalhdlnbpafiamejdnhcphjbkeiagm.crx",
|
||||||
|
"external_version": "1.30.6"
|
||||||
|
}
|
BIN
.m1k1o/chromium/extensions/fjoaledfpmneenckfbpdfhkmimnjocfa.crx
Normal file
BIN
.m1k1o/chromium/extensions/fjoaledfpmneenckfbpdfhkmimnjocfa.crx
Normal file
Binary file not shown.
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"external_crx": "/usr/share/chromium/extensions/fjoaledfpmneenckfbpdfhkmimnjocfa.crx",
|
||||||
|
"external_version": "2.21.0"
|
||||||
|
}
|
763
.m1k1o/chromium/openbox.xml
Normal file
763
.m1k1o/chromium/openbox.xml
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!-- Default openbox config but all window decorations are moved
|
||||||
|
thereby making it harder to accidentally close the virtual browser -->
|
||||||
|
|
||||||
|
<openbox_config xmlns="http://openbox.org/3.4/rc"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
|
||||||
|
<resistance>
|
||||||
|
<strength>10</strength>
|
||||||
|
<screen_edge_strength>20</screen_edge_strength>
|
||||||
|
</resistance>
|
||||||
|
|
||||||
|
<applications>
|
||||||
|
<!-- Match all windows and remove their decorations (obxprop | grep "^_OB_APP") -->
|
||||||
|
<application class="Chromium*" name="chromium-devel">
|
||||||
|
<decor>no</decor>
|
||||||
|
<maximized>true</maximized>
|
||||||
|
<focus>yes</focus>
|
||||||
|
<layer>normal</layer>
|
||||||
|
</application>
|
||||||
|
</applications>
|
||||||
|
|
||||||
|
<focus>
|
||||||
|
<focusNew>yes</focusNew>
|
||||||
|
<!-- always try to focus new windows when they appear. other rules do
|
||||||
|
apply -->
|
||||||
|
<followMouse>no</followMouse>
|
||||||
|
<!-- move focus to a window when you move the mouse into it -->
|
||||||
|
<focusLast>yes</focusLast>
|
||||||
|
<!-- focus the last used window when changing desktops, instead of the one
|
||||||
|
under the mouse pointer. when followMouse is enabled -->
|
||||||
|
<underMouse>no</underMouse>
|
||||||
|
<!-- move focus under the mouse, even when the mouse is not moving -->
|
||||||
|
<focusDelay>200</focusDelay>
|
||||||
|
<!-- when followMouse is enabled, the mouse must be inside the window for
|
||||||
|
this many milliseconds (1000 = 1 sec) before moving focus to it -->
|
||||||
|
<raiseOnFocus>no</raiseOnFocus>
|
||||||
|
<!-- when followMouse is enabled, and a window is given focus by moving the
|
||||||
|
mouse into it, also raise the window -->
|
||||||
|
</focus>
|
||||||
|
|
||||||
|
<placement>
|
||||||
|
<policy>Smart</policy>
|
||||||
|
<!-- 'Smart' or 'UnderMouse' -->
|
||||||
|
<center>yes</center>
|
||||||
|
<!-- whether to place windows in the center of the free area found or
|
||||||
|
the top left corner -->
|
||||||
|
<monitor>Primary</monitor>
|
||||||
|
<!-- with Smart placement on a multi-monitor system, try to place new windows
|
||||||
|
on: 'Any' - any monitor, 'Mouse' - where the mouse is, 'Active' - where
|
||||||
|
the active window is, 'Primary' - only on the primary monitor -->
|
||||||
|
<primaryMonitor>1</primaryMonitor>
|
||||||
|
<!-- The monitor where Openbox should place popup dialogs such as the
|
||||||
|
focus cycling popup, or the desktop switch popup. It can be an index
|
||||||
|
from 1, specifying a particular monitor. Or it can be one of the
|
||||||
|
following: 'Mouse' - where the mouse is, or
|
||||||
|
'Active' - where the active window is -->
|
||||||
|
</placement>
|
||||||
|
|
||||||
|
<theme>
|
||||||
|
<name>Clearlooks</name>
|
||||||
|
<titleLayout>NLIMC</titleLayout>
|
||||||
|
<!--
|
||||||
|
available characters are NDSLIMC, each can occur at most once.
|
||||||
|
N: window icon
|
||||||
|
L: window label (AKA title).
|
||||||
|
I: iconify
|
||||||
|
M: maximize
|
||||||
|
C: close
|
||||||
|
S: shade (roll up/down)
|
||||||
|
D: omnipresent (on all desktops).
|
||||||
|
-->
|
||||||
|
<keepBorder>yes</keepBorder>
|
||||||
|
<animateIconify>yes</animateIconify>
|
||||||
|
<font place="ActiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuHeader">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuItem">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="ActiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
</theme>
|
||||||
|
|
||||||
|
<desktops>
|
||||||
|
<!-- this stuff is only used at startup, pagers allow you to change them
|
||||||
|
during a session
|
||||||
|
|
||||||
|
these are default values to use when other ones are not already set
|
||||||
|
by other applications, or saved in your session
|
||||||
|
|
||||||
|
use obconf if you want to change these without having to log out
|
||||||
|
and back in -->
|
||||||
|
<number>1</number>
|
||||||
|
<firstdesk>1</firstdesk>
|
||||||
|
<names>
|
||||||
|
<!-- set names up here if you want to, like this:
|
||||||
|
<name>desktop 1</name>
|
||||||
|
<name>desktop 2</name>
|
||||||
|
-->
|
||||||
|
</names>
|
||||||
|
<popupTime>875</popupTime>
|
||||||
|
<!-- The number of milliseconds to show the popup for when switching
|
||||||
|
desktops. Set this to 0 to disable the popup. -->
|
||||||
|
</desktops>
|
||||||
|
|
||||||
|
<resize>
|
||||||
|
<drawContents>yes</drawContents>
|
||||||
|
<popupShow>Nonpixel</popupShow>
|
||||||
|
<!-- 'Always', 'Never', or 'Nonpixel' (xterms and such) -->
|
||||||
|
<popupPosition>Center</popupPosition>
|
||||||
|
<!-- 'Center', 'Top', or 'Fixed' -->
|
||||||
|
<popupFixedPosition>
|
||||||
|
<!-- these are used if popupPosition is set to 'Fixed' -->
|
||||||
|
|
||||||
|
<x>10</x>
|
||||||
|
<!-- positive number for distance from left edge, negative number for
|
||||||
|
distance from right edge, or 'Center' -->
|
||||||
|
<y>10</y>
|
||||||
|
<!-- positive number for distance from top edge, negative number for
|
||||||
|
distance from bottom edge, or 'Center' -->
|
||||||
|
</popupFixedPosition>
|
||||||
|
</resize>
|
||||||
|
|
||||||
|
<!-- You can reserve a portion of your screen where windows will not cover when
|
||||||
|
they are maximized, or when they are initially placed.
|
||||||
|
Many programs reserve space automatically, but you can use this in other
|
||||||
|
cases. -->
|
||||||
|
<margins>
|
||||||
|
<top>0</top>
|
||||||
|
<bottom>0</bottom>
|
||||||
|
<left>0</left>
|
||||||
|
<right>0</right>
|
||||||
|
</margins>
|
||||||
|
|
||||||
|
<dock>
|
||||||
|
<position>TopLeft</position>
|
||||||
|
<!-- (Top|Bottom)(Left|Right|)|Top|Bottom|Left|Right|Floating -->
|
||||||
|
<floatingX>0</floatingX>
|
||||||
|
<floatingY>0</floatingY>
|
||||||
|
<noStrut>no</noStrut>
|
||||||
|
<stacking>Above</stacking>
|
||||||
|
<!-- 'Above', 'Normal', or 'Below' -->
|
||||||
|
<direction>Vertical</direction>
|
||||||
|
<!-- 'Vertical' or 'Horizontal' -->
|
||||||
|
<autoHide>no</autoHide>
|
||||||
|
<hideDelay>300</hideDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<showDelay>300</showDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<moveButton>Middle</moveButton>
|
||||||
|
<!-- 'Left', 'Middle', 'Right' -->
|
||||||
|
</dock>
|
||||||
|
|
||||||
|
<keyboard>
|
||||||
|
<chainQuitKey>C-g</chainQuitKey>
|
||||||
|
|
||||||
|
<!-- Keybindings for desktop switching -->
|
||||||
|
<keybind key="C-A-Left">
|
||||||
|
<action name="GoToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Right">
|
||||||
|
<action name="GoToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Up">
|
||||||
|
<action name="GoToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Down">
|
||||||
|
<action name="GoToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Left">
|
||||||
|
<action name="SendToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Right">
|
||||||
|
<action name="SendToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Up">
|
||||||
|
<action name="SendToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Down">
|
||||||
|
<action name="SendToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F1">
|
||||||
|
<action name="GoToDesktop"><to>1</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F2">
|
||||||
|
<action name="GoToDesktop"><to>2</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F3">
|
||||||
|
<action name="GoToDesktop"><to>3</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F4">
|
||||||
|
<action name="GoToDesktop"><to>4</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-d">
|
||||||
|
<action name="ToggleShowDesktop"/>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for windows -->
|
||||||
|
<keybind key="A-F4">
|
||||||
|
<action name="Close"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-Escape">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-space">
|
||||||
|
<!--action name="ShowMenu"><menu>client-menu</menu></action-->
|
||||||
|
</keybind>
|
||||||
|
<!-- Take a screenshot of the current window with scrot when Alt+Print are pressed -->
|
||||||
|
<keybind key="A-Print">
|
||||||
|
<action name="Execute"><command>scrot -s</command></action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching -->
|
||||||
|
<keybind key="A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-S-Tab">
|
||||||
|
<action name="PreviousWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<panels>yes</panels><desktop>yes</desktop>
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching with the arrow keys -->
|
||||||
|
<keybind key="W-S-Right">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>right</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Left">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>left</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Up">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>up</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Down">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>down</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for running applications -->
|
||||||
|
<keybind key="W-e">
|
||||||
|
<action name="Execute">
|
||||||
|
<startupnotify>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
<name>Konqueror</name>
|
||||||
|
</startupnotify>
|
||||||
|
<command>kfmclient openProfile filemanagement</command>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<!-- Launch scrot when Print is pressed -->
|
||||||
|
<keybind key="Print">
|
||||||
|
<action name="Execute"><command>scrot</command></action>
|
||||||
|
</keybind>
|
||||||
|
</keyboard>
|
||||||
|
|
||||||
|
<mouse>
|
||||||
|
<dragThreshold>1</dragThreshold>
|
||||||
|
<!-- number of pixels the mouse must move before a drag begins -->
|
||||||
|
<doubleClickTime>500</doubleClickTime>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<screenEdgeWarpTime>400</screenEdgeWarpTime>
|
||||||
|
<!-- Time before changing desktops when the pointer touches the edge of the
|
||||||
|
screen while moving a window, in milliseconds (1000 = 1 second).
|
||||||
|
Set this to 0 to disable warping -->
|
||||||
|
<screenEdgeWarpMouse>false</screenEdgeWarpMouse>
|
||||||
|
<!-- Set this to TRUE to move the mouse pointer across the desktop when
|
||||||
|
switching due to hitting the edge of the screen -->
|
||||||
|
|
||||||
|
<context name="Frame">
|
||||||
|
<mousebind button="A-Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Click">
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Right" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Up" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Down" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="DoubleClick">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>no</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Shade"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
<action name="Lower"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>yes</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar Top Right Bottom Left TLCorner TRCorner BRCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<!--mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Top">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>top</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Left">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>left</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Right">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>right</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Bottom">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>bottom</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<!--mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="TRCorner BRCorner TLCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Client">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Icon">
|
||||||
|
<!--mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="AllDesktops">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleOmnipresent"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Shade">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleShade"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Iconify">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Iconify"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Maximize">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>vertical</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>horizontal</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Close">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Close"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Desktop">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Root">
|
||||||
|
<!-- Menus -->
|
||||||
|
<!--mousebind button="Middle" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>client-list-combined-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>root-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="MoveResize">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
</mouse>
|
||||||
|
|
||||||
|
<menu>
|
||||||
|
<!-- You can specify more than one menu file in here and they are all loaded,
|
||||||
|
just don't make menu ids clash or, well, it'll be kind of pointless -->
|
||||||
|
|
||||||
|
<!-- default menu file (or custom one in $HOME/.config/openbox/) -->
|
||||||
|
<!-- system menu files on Debian systems -->
|
||||||
|
<!--file>/var/lib/openbox/debian-menu.xml</file-->
|
||||||
|
<file>menu.xml</file>
|
||||||
|
<hideDelay>200</hideDelay>
|
||||||
|
<!-- if a press-release lasts longer than this setting (in milliseconds), the
|
||||||
|
menu is hidden again -->
|
||||||
|
<middle>no</middle>
|
||||||
|
<!-- center submenus vertically about the parent entry -->
|
||||||
|
<submenuShowDelay>100</submenuShowDelay>
|
||||||
|
<!-- time to delay before showing a submenu after hovering over the parent
|
||||||
|
entry.
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be shown until it is clicked on -->
|
||||||
|
<submenuHideDelay>400</submenuHideDelay>
|
||||||
|
<!-- time to delay before hiding a submenu when selecting another
|
||||||
|
entry in parent menu
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be hidden until a different submenu is opened -->
|
||||||
|
<showIcons>yes</showIcons>
|
||||||
|
<!-- controls if icons appear in the client-list-(combined-)menu -->
|
||||||
|
<manageDesktops>yes</manageDesktops>
|
||||||
|
<!-- show the manage desktops section in the client-list-(combined-)menu -->
|
||||||
|
</menu>
|
||||||
|
|
||||||
|
<applications>
|
||||||
|
<!--
|
||||||
|
# this is an example with comments through out. use these to make your
|
||||||
|
# own rules, but without the comments of course.
|
||||||
|
# you may use one or more of the name/class/role/title/type rules to specify
|
||||||
|
# windows to match
|
||||||
|
|
||||||
|
<application name="the window's _OB_APP_NAME property (see obxprop)"
|
||||||
|
class="the window's _OB_APP_CLASS property (see obxprop)"
|
||||||
|
groupname="the window's _OB_APP_GROUP_NAME property (see obxprop)"
|
||||||
|
groupclass="the window's _OB_APP_GROUP_CLASS property (see obxprop)"
|
||||||
|
role="the window's _OB_APP_ROLE property (see obxprop)"
|
||||||
|
title="the window's _OB_APP_TITLE property (see obxprop)"
|
||||||
|
type="the window's _OB_APP_TYPE property (see obxprob)..
|
||||||
|
(if unspecified, then it is 'dialog' for child windows)">
|
||||||
|
# you may set only one of name/class/role/title/type, or you may use more
|
||||||
|
# than one together to restrict your matches.
|
||||||
|
|
||||||
|
# the name, class, role, and title use simple wildcard matching such as those
|
||||||
|
# used by a shell. you can use * to match any characters and ? to match
|
||||||
|
# any single character.
|
||||||
|
|
||||||
|
# the type is one of: normal, dialog, splash, utility, menu, toolbar, dock,
|
||||||
|
# or desktop
|
||||||
|
|
||||||
|
# when multiple rules match a window, they will all be applied, in the
|
||||||
|
# order that they appear in this list
|
||||||
|
|
||||||
|
|
||||||
|
# each rule element can be left out or set to 'default' to specify to not
|
||||||
|
# change that attribute of the window
|
||||||
|
|
||||||
|
<decor>yes</decor>
|
||||||
|
# enable or disable window decorations
|
||||||
|
|
||||||
|
<shade>no</shade>
|
||||||
|
# make the window shaded when it appears, or not
|
||||||
|
|
||||||
|
<position force="no">
|
||||||
|
# the position is only used if both an x and y coordinate are provided
|
||||||
|
# (and not set to 'default')
|
||||||
|
# when force is "yes", then the window will be placed here even if it
|
||||||
|
# says you want it placed elsewhere. this is to override buggy
|
||||||
|
# applications who refuse to behave
|
||||||
|
<x>center</x>
|
||||||
|
# a number like 50, or 'center' to center on screen. use a negative number
|
||||||
|
# to start from the right (or bottom for <y>), ie -50 is 50 pixels from
|
||||||
|
# the right edge (or bottom). use 'default' to specify using value
|
||||||
|
# provided by the application, or chosen by openbox, instead.
|
||||||
|
<y>200</y>
|
||||||
|
<monitor>1</monitor>
|
||||||
|
# specifies the monitor in a xinerama setup.
|
||||||
|
# 1 is the first head, or 'mouse' for wherever the mouse is
|
||||||
|
</position>
|
||||||
|
|
||||||
|
<size>
|
||||||
|
# the size to make the window.
|
||||||
|
<width>20</width>
|
||||||
|
# a number like 20, or 'default' to use the size given by the application.
|
||||||
|
# you can use fractions such as 1/2 or percentages such as 75% in which
|
||||||
|
# case the value is relative to the size of the monitor that the window
|
||||||
|
# appears on.
|
||||||
|
<height>30%</height>
|
||||||
|
</size>
|
||||||
|
|
||||||
|
<focus>yes</focus>
|
||||||
|
# if the window should try be given focus when it appears. if this is set
|
||||||
|
# to yes it doesn't guarantee the window will be given focus. some
|
||||||
|
# restrictions may apply, but Openbox will try to
|
||||||
|
|
||||||
|
<desktop>1</desktop>
|
||||||
|
# 1 is the first desktop, 'all' for all desktops
|
||||||
|
|
||||||
|
<layer>normal</layer>
|
||||||
|
# 'above', 'normal', or 'below'
|
||||||
|
|
||||||
|
<iconic>no</iconic>
|
||||||
|
# make the window iconified when it appears, or not
|
||||||
|
|
||||||
|
<skip_pager>no</skip_pager>
|
||||||
|
# asks to not be shown in pagers
|
||||||
|
|
||||||
|
<skip_taskbar>no</skip_taskbar>
|
||||||
|
# asks to not be shown in taskbars. window cycling actions will also
|
||||||
|
# skip past such windows
|
||||||
|
|
||||||
|
<fullscreen>yes</fullscreen>
|
||||||
|
# make the window in fullscreen mode when it appears
|
||||||
|
|
||||||
|
<maximized>true</maximized>
|
||||||
|
# 'Horizontal', 'Vertical' or boolean (yes/no)
|
||||||
|
</application>
|
||||||
|
|
||||||
|
# end of the example
|
||||||
|
-->
|
||||||
|
</applications>
|
||||||
|
|
||||||
|
</openbox_config>
|
34
.m1k1o/chromium/policies.json
Normal file
34
.m1k1o/chromium/policies.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"HomepageLocation": "",
|
||||||
|
"AutoFillEnabled": false,
|
||||||
|
"AutofillAddressEnabled": false,
|
||||||
|
"AutofillCreditCardEnabled": false,
|
||||||
|
"BrowserSignin": 0,
|
||||||
|
"DefaultNotificationsSetting": 2,
|
||||||
|
"DeveloperToolsAvailability": 2,
|
||||||
|
"EditBookmarksEnabled": false,
|
||||||
|
"FullscreenAllowed": true,
|
||||||
|
"IncognitoModeAvailability": 1,
|
||||||
|
"SyncDisabled": true,
|
||||||
|
"AutoplayAllowed": true,
|
||||||
|
"BrowserAddPersonEnabled": false,
|
||||||
|
"BrowserGuestModeEnabled": false,
|
||||||
|
"DefaultPopupsSetting": 2,
|
||||||
|
"DownloadRestrictions": 3,
|
||||||
|
"VideoCaptureAllowed": true,
|
||||||
|
"AllowFileSelectionDialogs": false,
|
||||||
|
"PromptForDownloadLocation": false,
|
||||||
|
"BookmarkBarEnabled": false,
|
||||||
|
"PasswordManagerEnabled": false,
|
||||||
|
"URLBlacklist": [
|
||||||
|
"file://*",
|
||||||
|
"chrome://policy"
|
||||||
|
],
|
||||||
|
"ExtensionInstallWhitelist": [
|
||||||
|
"cjpalhdlnbpafiamejdnhcphjbkeiagm",
|
||||||
|
"fjoaledfpmneenckfbpdfhkmimnjocfa"
|
||||||
|
],
|
||||||
|
"ExtensionInstallBlacklist": [
|
||||||
|
"*"
|
||||||
|
]
|
||||||
|
}
|
110
.m1k1o/chromium/preferences.json
Normal file
110
.m1k1o/chromium/preferences.json
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
{
|
||||||
|
"homepage": "http://www.google.com",
|
||||||
|
"homepage_is_newtabpage": false,
|
||||||
|
"first_run_tabs": [
|
||||||
|
"https://www.google.com/_/chrome/newtab?ie=UTF-8"
|
||||||
|
],
|
||||||
|
"custom_links": {
|
||||||
|
"initialized": true,
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"title": "YouTube",
|
||||||
|
"url": "https://www.youtube.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Netflix",
|
||||||
|
"url": "https://netflix.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Hulu",
|
||||||
|
"url": "https://www.hulu.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "9Anime",
|
||||||
|
"url": "https://9anime.to/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Crunchy Roll",
|
||||||
|
"url": "https://www.crunchyroll.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Funimation",
|
||||||
|
"url": "https://www.funimation.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Disney+",
|
||||||
|
"url": "https://www.disneyplus.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "HBO Now",
|
||||||
|
"url": "https://play.hbonow.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Amazon Video",
|
||||||
|
"url": "https://www.amazon.com/Amazon-Video/b?node=2858778011"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "VRV",
|
||||||
|
"url": "https://vrv.co/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Twitch",
|
||||||
|
"url": "https://www.twitch.tv/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Mixer",
|
||||||
|
"url": "https://mixer.com/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"browser": {
|
||||||
|
"custom_chrome_frame": false,
|
||||||
|
"show_home_button": true,
|
||||||
|
"window_placement": {
|
||||||
|
"maximized": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bookmark_bar": {
|
||||||
|
"show_on_all_tabs": false
|
||||||
|
},
|
||||||
|
"sync_promo": {
|
||||||
|
"show_on_first_run_allowed": false
|
||||||
|
},
|
||||||
|
"distribution": {
|
||||||
|
"import_bookmarks_from_file": "bookmarks.html",
|
||||||
|
"import_bookmarks": true,
|
||||||
|
"import_history": true,
|
||||||
|
"import_home_page": true,
|
||||||
|
"import_search_engine": true,
|
||||||
|
"ping_delay": 60,
|
||||||
|
"do_not_create_desktop_shortcut": true,
|
||||||
|
"do_not_create_quick_launch_shortcut": true,
|
||||||
|
"do_not_create_taskbar_shortcut": true,
|
||||||
|
"do_not_launch_chrome": true,
|
||||||
|
"do_not_register_for_update_launch": true,
|
||||||
|
"make_chrome_default": true,
|
||||||
|
"make_chrome_default_for_user": true,
|
||||||
|
"system_level": false,
|
||||||
|
"verbose_logging": false
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"avatar_index": 19,
|
||||||
|
"default_content_setting_values": {
|
||||||
|
"clipboard": 2,
|
||||||
|
"cookies": 4,
|
||||||
|
"geolocation": 2,
|
||||||
|
"media_stream_camera": 2,
|
||||||
|
"media_stream_mic": 2,
|
||||||
|
"midi_sysex": 2,
|
||||||
|
"payment_handler": 2,
|
||||||
|
"usb_guard": 2
|
||||||
|
},
|
||||||
|
"name": "neko",
|
||||||
|
"using_default_avatar": false,
|
||||||
|
"using_default_name": false,
|
||||||
|
"using_gaia_avatar": false
|
||||||
|
},
|
||||||
|
"signin": {
|
||||||
|
"allowed": false
|
||||||
|
}
|
||||||
|
}
|
21
.m1k1o/chromium/supervisord.conf
Normal file
21
.m1k1o/chromium/supervisord.conf
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[program:chromium]
|
||||||
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
|
command=/usr/lib/chromium/chrome-wrapper --window-position=0,0 --display=%(ENV_DISPLAY)s --start-maximized --bwsi --test-type --force-dark-mode --disable-file-system --disable-gpu --disable-software-rasterizer --disable-dev-shm-usage
|
||||||
|
autorestart=true
|
||||||
|
priority=800
|
||||||
|
user=%(ENV_USER)s
|
||||||
|
stdout_logfile=/var/log/neko/chromium.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
||||||
|
|
||||||
|
[program:openbox]
|
||||||
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
|
command=/usr/bin/openbox --config-file /etc/neko/openbox.xml
|
||||||
|
autorestart=true
|
||||||
|
priority=300
|
||||||
|
user=%(ENV_USER)s
|
||||||
|
stdout_logfile=/var/log/neko/openbox.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
22
.m1k1o/firefox/Dockerfile
Normal file
22
.m1k1o/firefox/Dockerfile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
FROM m1k1o/neko:base
|
||||||
|
|
||||||
|
#
|
||||||
|
# install firefox-esr
|
||||||
|
RUN set -eux; apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends openbox firefox-esr; \
|
||||||
|
#
|
||||||
|
# install extensions
|
||||||
|
mkdir -p /usr/lib/firefox-esr/distribution/extensions; \
|
||||||
|
wget -O '/usr/lib/firefox-esr/distribution/extensions/uBlock0@raymondhill.net.xpi' https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi; \
|
||||||
|
#
|
||||||
|
# clean up
|
||||||
|
apt-get clean -y; \
|
||||||
|
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
||||||
|
|
||||||
|
#
|
||||||
|
# copy configuation files
|
||||||
|
COPY supervisord.conf /etc/neko/supervisord/firefox.conf
|
||||||
|
COPY neko.js /usr/lib/firefox-esr/mozilla.cfg
|
||||||
|
COPY autoconfig.js /usr/lib/firefox-esr/defaults/pref/autoconfig.js
|
||||||
|
COPY policies.json /usr/lib/firefox-esr/distribution/policies.json
|
||||||
|
COPY openbox.xml /etc/neko/openbox.xml
|
2
.m1k1o/firefox/autoconfig.js
Normal file
2
.m1k1o/firefox/autoconfig.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pref("general.config.obscure_value", 0);
|
||||||
|
pref("general.config.filename", "mozilla.cfg");
|
35
.m1k1o/firefox/neko.js
Normal file
35
.m1k1o/firefox/neko.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// firefox config for neko
|
||||||
|
lockPref("browser.tabs.closeWindowWithLastTab", false);
|
||||||
|
lockPref("app.update.auto", false);
|
||||||
|
lockPref("app.update.enabled", false);
|
||||||
|
lockPref("app.update.silent", true);
|
||||||
|
lockPref("browser.cache.disk.capacity", 1000);
|
||||||
|
lockPref("browser.download.useDownloadDir", false);
|
||||||
|
lockPref("browser.rights.3.shown", true);
|
||||||
|
lockPref("browser.search.update", false);
|
||||||
|
lockPref("browser.shell.checkDefaultBrowser", false);
|
||||||
|
lockPref("extensions.update.enabled", false);
|
||||||
|
lockPref("plugin.default_plugin_disabled", false);
|
||||||
|
lockPref("plugin.scan.plid.all", true);
|
||||||
|
lockPref("plugins.hide_infobar_for_missing_plugin", true);
|
||||||
|
lockPref("profile.allow_automigration", false);
|
||||||
|
lockPref("signon.prefillForms", false);
|
||||||
|
lockPref("signon.rememberSignons", false);
|
||||||
|
lockPref("xpinstall.enabled", false);
|
||||||
|
lockPref("xpinstall.whitelist.required", true);
|
||||||
|
lockPref("browser.download.manager.retention", 0);
|
||||||
|
lockPref("browser.download.folderList", 2);
|
||||||
|
lockPref("browser.download.forbid_open_with", true);
|
||||||
|
lockPref("browser.safebrowsing.downloads.enabled", false);
|
||||||
|
lockPref("browser.safebrowsing.downloads.remote.enabled", false);
|
||||||
|
lockPref("browser.helperApps.alwaysAsk.force", false);
|
||||||
|
lockPref("browser.helperApps.neverAsk.saveToDisk", "application/zip,application/octet-stream,image/jpeg,application/vnd.ms-outlook,text/html,application/pdf");
|
||||||
|
lockPref("browser.helperApps.neverAsk.openFile", "application/zip,application/octet-stream,image/jpeg,application/vnd.ms-outlook,text/html,application/pdf");
|
||||||
|
lockPref("browser.newtabpage.activity-stream.default.sites", "https://ipleak.net/,https://www.youtube.com/,https://www.google.com/");
|
||||||
|
// dark mode
|
||||||
|
lockPref("reader.color_scheme", "dark");
|
||||||
|
lockPref("devtools.theme", "dark");
|
||||||
|
lockPref("ui.systemUsesDarkTheme", 1);
|
||||||
|
lockPref("lightweightThemes.usedThemes","[]");
|
||||||
|
lockPref("lightweightThemes.selectedThemeID", "firefox-compact-dark@mozilla.org");
|
||||||
|
lockPref("browser.in-content.dark-mode", true);
|
763
.m1k1o/firefox/openbox.xml
Normal file
763
.m1k1o/firefox/openbox.xml
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!-- Default openbox config but all window decorations are moved
|
||||||
|
thereby making it harder to accidentally close the virtual browser -->
|
||||||
|
|
||||||
|
<openbox_config xmlns="http://openbox.org/3.4/rc"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
|
||||||
|
<resistance>
|
||||||
|
<strength>10</strength>
|
||||||
|
<screen_edge_strength>20</screen_edge_strength>
|
||||||
|
</resistance>
|
||||||
|
|
||||||
|
<applications>
|
||||||
|
<!-- Match all windows and remove their decorations (obxprop | grep "^_OB_APP") -->
|
||||||
|
<application class="Firefox*" name="Navigator">
|
||||||
|
<decor>no</decor>
|
||||||
|
<maximized>true</maximized>
|
||||||
|
<focus>yes</focus>
|
||||||
|
<layer>normal</layer>
|
||||||
|
</application>
|
||||||
|
</applications>
|
||||||
|
|
||||||
|
<focus>
|
||||||
|
<focusNew>yes</focusNew>
|
||||||
|
<!-- always try to focus new windows when they appear. other rules do
|
||||||
|
apply -->
|
||||||
|
<followMouse>no</followMouse>
|
||||||
|
<!-- move focus to a window when you move the mouse into it -->
|
||||||
|
<focusLast>yes</focusLast>
|
||||||
|
<!-- focus the last used window when changing desktops, instead of the one
|
||||||
|
under the mouse pointer. when followMouse is enabled -->
|
||||||
|
<underMouse>no</underMouse>
|
||||||
|
<!-- move focus under the mouse, even when the mouse is not moving -->
|
||||||
|
<focusDelay>200</focusDelay>
|
||||||
|
<!-- when followMouse is enabled, the mouse must be inside the window for
|
||||||
|
this many milliseconds (1000 = 1 sec) before moving focus to it -->
|
||||||
|
<raiseOnFocus>no</raiseOnFocus>
|
||||||
|
<!-- when followMouse is enabled, and a window is given focus by moving the
|
||||||
|
mouse into it, also raise the window -->
|
||||||
|
</focus>
|
||||||
|
|
||||||
|
<placement>
|
||||||
|
<policy>Smart</policy>
|
||||||
|
<!-- 'Smart' or 'UnderMouse' -->
|
||||||
|
<center>yes</center>
|
||||||
|
<!-- whether to place windows in the center of the free area found or
|
||||||
|
the top left corner -->
|
||||||
|
<monitor>Primary</monitor>
|
||||||
|
<!-- with Smart placement on a multi-monitor system, try to place new windows
|
||||||
|
on: 'Any' - any monitor, 'Mouse' - where the mouse is, 'Active' - where
|
||||||
|
the active window is, 'Primary' - only on the primary monitor -->
|
||||||
|
<primaryMonitor>1</primaryMonitor>
|
||||||
|
<!-- The monitor where Openbox should place popup dialogs such as the
|
||||||
|
focus cycling popup, or the desktop switch popup. It can be an index
|
||||||
|
from 1, specifying a particular monitor. Or it can be one of the
|
||||||
|
following: 'Mouse' - where the mouse is, or
|
||||||
|
'Active' - where the active window is -->
|
||||||
|
</placement>
|
||||||
|
|
||||||
|
<theme>
|
||||||
|
<name>Clearlooks</name>
|
||||||
|
<titleLayout>NLIMC</titleLayout>
|
||||||
|
<!--
|
||||||
|
available characters are NDSLIMC, each can occur at most once.
|
||||||
|
N: window icon
|
||||||
|
L: window label (AKA title).
|
||||||
|
I: iconify
|
||||||
|
M: maximize
|
||||||
|
C: close
|
||||||
|
S: shade (roll up/down)
|
||||||
|
D: omnipresent (on all desktops).
|
||||||
|
-->
|
||||||
|
<keepBorder>yes</keepBorder>
|
||||||
|
<animateIconify>yes</animateIconify>
|
||||||
|
<font place="ActiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveWindow">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>8</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuHeader">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="MenuItem">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>normal</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="ActiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
<font place="InactiveOnScreenDisplay">
|
||||||
|
<name>sans</name>
|
||||||
|
<size>9</size>
|
||||||
|
<!-- font size in points -->
|
||||||
|
<weight>bold</weight>
|
||||||
|
<!-- 'bold' or 'normal' -->
|
||||||
|
<slant>normal</slant>
|
||||||
|
<!-- 'italic' or 'normal' -->
|
||||||
|
</font>
|
||||||
|
</theme>
|
||||||
|
|
||||||
|
<desktops>
|
||||||
|
<!-- this stuff is only used at startup, pagers allow you to change them
|
||||||
|
during a session
|
||||||
|
|
||||||
|
these are default values to use when other ones are not already set
|
||||||
|
by other applications, or saved in your session
|
||||||
|
|
||||||
|
use obconf if you want to change these without having to log out
|
||||||
|
and back in -->
|
||||||
|
<number>1</number>
|
||||||
|
<firstdesk>1</firstdesk>
|
||||||
|
<names>
|
||||||
|
<!-- set names up here if you want to, like this:
|
||||||
|
<name>desktop 1</name>
|
||||||
|
<name>desktop 2</name>
|
||||||
|
-->
|
||||||
|
</names>
|
||||||
|
<popupTime>875</popupTime>
|
||||||
|
<!-- The number of milliseconds to show the popup for when switching
|
||||||
|
desktops. Set this to 0 to disable the popup. -->
|
||||||
|
</desktops>
|
||||||
|
|
||||||
|
<resize>
|
||||||
|
<drawContents>yes</drawContents>
|
||||||
|
<popupShow>Nonpixel</popupShow>
|
||||||
|
<!-- 'Always', 'Never', or 'Nonpixel' (xterms and such) -->
|
||||||
|
<popupPosition>Center</popupPosition>
|
||||||
|
<!-- 'Center', 'Top', or 'Fixed' -->
|
||||||
|
<popupFixedPosition>
|
||||||
|
<!-- these are used if popupPosition is set to 'Fixed' -->
|
||||||
|
|
||||||
|
<x>10</x>
|
||||||
|
<!-- positive number for distance from left edge, negative number for
|
||||||
|
distance from right edge, or 'Center' -->
|
||||||
|
<y>10</y>
|
||||||
|
<!-- positive number for distance from top edge, negative number for
|
||||||
|
distance from bottom edge, or 'Center' -->
|
||||||
|
</popupFixedPosition>
|
||||||
|
</resize>
|
||||||
|
|
||||||
|
<!-- You can reserve a portion of your screen where windows will not cover when
|
||||||
|
they are maximized, or when they are initially placed.
|
||||||
|
Many programs reserve space automatically, but you can use this in other
|
||||||
|
cases. -->
|
||||||
|
<margins>
|
||||||
|
<top>0</top>
|
||||||
|
<bottom>0</bottom>
|
||||||
|
<left>0</left>
|
||||||
|
<right>0</right>
|
||||||
|
</margins>
|
||||||
|
|
||||||
|
<dock>
|
||||||
|
<position>TopLeft</position>
|
||||||
|
<!-- (Top|Bottom)(Left|Right|)|Top|Bottom|Left|Right|Floating -->
|
||||||
|
<floatingX>0</floatingX>
|
||||||
|
<floatingY>0</floatingY>
|
||||||
|
<noStrut>no</noStrut>
|
||||||
|
<stacking>Above</stacking>
|
||||||
|
<!-- 'Above', 'Normal', or 'Below' -->
|
||||||
|
<direction>Vertical</direction>
|
||||||
|
<!-- 'Vertical' or 'Horizontal' -->
|
||||||
|
<autoHide>no</autoHide>
|
||||||
|
<hideDelay>300</hideDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<showDelay>300</showDelay>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<moveButton>Middle</moveButton>
|
||||||
|
<!-- 'Left', 'Middle', 'Right' -->
|
||||||
|
</dock>
|
||||||
|
|
||||||
|
<keyboard>
|
||||||
|
<chainQuitKey>C-g</chainQuitKey>
|
||||||
|
|
||||||
|
<!-- Keybindings for desktop switching -->
|
||||||
|
<keybind key="C-A-Left">
|
||||||
|
<action name="GoToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Right">
|
||||||
|
<action name="GoToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Up">
|
||||||
|
<action name="GoToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Down">
|
||||||
|
<action name="GoToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Left">
|
||||||
|
<action name="SendToDesktop"><to>left</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Right">
|
||||||
|
<action name="SendToDesktop"><to>right</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Up">
|
||||||
|
<action name="SendToDesktop"><to>up</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="S-A-Down">
|
||||||
|
<action name="SendToDesktop"><to>down</to><wrap>no</wrap></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F1">
|
||||||
|
<action name="GoToDesktop"><to>1</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F2">
|
||||||
|
<action name="GoToDesktop"><to>2</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F3">
|
||||||
|
<action name="GoToDesktop"><to>3</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-F4">
|
||||||
|
<action name="GoToDesktop"><to>4</to></action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-d">
|
||||||
|
<action name="ToggleShowDesktop"/>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for windows -->
|
||||||
|
<keybind key="A-F4">
|
||||||
|
<action name="Close"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-Escape">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-space">
|
||||||
|
<!--action name="ShowMenu"><menu>client-menu</menu></action-->
|
||||||
|
</keybind>
|
||||||
|
<!-- Take a screenshot of the current window with scrot when Alt+Print are pressed -->
|
||||||
|
<keybind key="A-Print">
|
||||||
|
<action name="Execute"><command>scrot -s</command></action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching -->
|
||||||
|
<keybind key="A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="A-S-Tab">
|
||||||
|
<action name="PreviousWindow">
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="C-A-Tab">
|
||||||
|
<action name="NextWindow">
|
||||||
|
<panels>yes</panels><desktop>yes</desktop>
|
||||||
|
<finalactions>
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</finalactions>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for window switching with the arrow keys -->
|
||||||
|
<keybind key="W-S-Right">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>right</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Left">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>left</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Up">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>up</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<keybind key="W-S-Down">
|
||||||
|
<action name="DirectionalCycleWindows">
|
||||||
|
<direction>down</direction>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
|
||||||
|
<!-- Keybindings for running applications -->
|
||||||
|
<keybind key="W-e">
|
||||||
|
<action name="Execute">
|
||||||
|
<startupnotify>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
<name>Konqueror</name>
|
||||||
|
</startupnotify>
|
||||||
|
<command>kfmclient openProfile filemanagement</command>
|
||||||
|
</action>
|
||||||
|
</keybind>
|
||||||
|
<!-- Launch scrot when Print is pressed -->
|
||||||
|
<keybind key="Print">
|
||||||
|
<action name="Execute"><command>scrot</command></action>
|
||||||
|
</keybind>
|
||||||
|
</keyboard>
|
||||||
|
|
||||||
|
<mouse>
|
||||||
|
<dragThreshold>1</dragThreshold>
|
||||||
|
<!-- number of pixels the mouse must move before a drag begins -->
|
||||||
|
<doubleClickTime>500</doubleClickTime>
|
||||||
|
<!-- in milliseconds (1000 = 1 second) -->
|
||||||
|
<screenEdgeWarpTime>400</screenEdgeWarpTime>
|
||||||
|
<!-- Time before changing desktops when the pointer touches the edge of the
|
||||||
|
screen while moving a window, in milliseconds (1000 = 1 second).
|
||||||
|
Set this to 0 to disable warping -->
|
||||||
|
<screenEdgeWarpMouse>false</screenEdgeWarpMouse>
|
||||||
|
<!-- Set this to TRUE to move the mouse pointer across the desktop when
|
||||||
|
switching due to hitting the edge of the screen -->
|
||||||
|
|
||||||
|
<context name="Frame">
|
||||||
|
<mousebind button="A-Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Click">
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Right" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Up" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-S-Down" action="Click">
|
||||||
|
<action name="SendToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Move"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="DoubleClick">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>no</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Shade"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
<action name="Lower"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="if">
|
||||||
|
<shaded>yes</shaded>
|
||||||
|
<then>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</then>
|
||||||
|
</action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Titlebar Top Right Bottom Left TLCorner TRCorner BRCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Lower"/>
|
||||||
|
<action name="FocusToBottom"/>
|
||||||
|
<action name="Unfocus"/>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<!--mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Top">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>top</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Left">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>left</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Right">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>right</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Bottom">
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"><edge>bottom</edge></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<!--mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="TRCorner BRCorner TLCorner BLCorner">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Drag">
|
||||||
|
<action name="Resize"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Client">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Icon">
|
||||||
|
<!--mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="ShowMenu"><menu>client-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="AllDesktops">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleOmnipresent"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Shade">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleShade"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Iconify">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Iconify"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Maximize">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="ToggleMaximize"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Middle" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>vertical</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Click">
|
||||||
|
<action name="ToggleMaximize"><direction>horizontal</direction></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Close">
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
<action name="Unshade"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Left" action="Click">
|
||||||
|
<action name="Close"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Desktop">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="C-A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
|
||||||
|
<mousebind button="Left" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="Focus"/>
|
||||||
|
<action name="Raise"/>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="Root">
|
||||||
|
<!-- Menus -->
|
||||||
|
<!--mousebind button="Middle" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>client-list-combined-menu</menu></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Right" action="Press">
|
||||||
|
<action name="ShowMenu"><menu>root-menu</menu></action>
|
||||||
|
</mousebind-->
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context name="MoveResize">
|
||||||
|
<mousebind button="Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Up" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>previous</to></action>
|
||||||
|
</mousebind>
|
||||||
|
<mousebind button="A-Down" action="Click">
|
||||||
|
<action name="GoToDesktop"><to>next</to></action>
|
||||||
|
</mousebind>
|
||||||
|
</context>
|
||||||
|
</mouse>
|
||||||
|
|
||||||
|
<menu>
|
||||||
|
<!-- You can specify more than one menu file in here and they are all loaded,
|
||||||
|
just don't make menu ids clash or, well, it'll be kind of pointless -->
|
||||||
|
|
||||||
|
<!-- default menu file (or custom one in $HOME/.config/openbox/) -->
|
||||||
|
<!-- system menu files on Debian systems -->
|
||||||
|
<!--file>/var/lib/openbox/debian-menu.xml</file-->
|
||||||
|
<file>menu.xml</file>
|
||||||
|
<hideDelay>200</hideDelay>
|
||||||
|
<!-- if a press-release lasts longer than this setting (in milliseconds), the
|
||||||
|
menu is hidden again -->
|
||||||
|
<middle>no</middle>
|
||||||
|
<!-- center submenus vertically about the parent entry -->
|
||||||
|
<submenuShowDelay>100</submenuShowDelay>
|
||||||
|
<!-- time to delay before showing a submenu after hovering over the parent
|
||||||
|
entry.
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be shown until it is clicked on -->
|
||||||
|
<submenuHideDelay>400</submenuHideDelay>
|
||||||
|
<!-- time to delay before hiding a submenu when selecting another
|
||||||
|
entry in parent menu
|
||||||
|
if this is a negative value, then the delay is infinite and the
|
||||||
|
submenu will not be hidden until a different submenu is opened -->
|
||||||
|
<showIcons>yes</showIcons>
|
||||||
|
<!-- controls if icons appear in the client-list-(combined-)menu -->
|
||||||
|
<manageDesktops>yes</manageDesktops>
|
||||||
|
<!-- show the manage desktops section in the client-list-(combined-)menu -->
|
||||||
|
</menu>
|
||||||
|
|
||||||
|
<applications>
|
||||||
|
<!--
|
||||||
|
# this is an example with comments through out. use these to make your
|
||||||
|
# own rules, but without the comments of course.
|
||||||
|
# you may use one or more of the name/class/role/title/type rules to specify
|
||||||
|
# windows to match
|
||||||
|
|
||||||
|
<application name="the window's _OB_APP_NAME property (see obxprop)"
|
||||||
|
class="the window's _OB_APP_CLASS property (see obxprop)"
|
||||||
|
groupname="the window's _OB_APP_GROUP_NAME property (see obxprop)"
|
||||||
|
groupclass="the window's _OB_APP_GROUP_CLASS property (see obxprop)"
|
||||||
|
role="the window's _OB_APP_ROLE property (see obxprop)"
|
||||||
|
title="the window's _OB_APP_TITLE property (see obxprop)"
|
||||||
|
type="the window's _OB_APP_TYPE property (see obxprob)..
|
||||||
|
(if unspecified, then it is 'dialog' for child windows)">
|
||||||
|
# you may set only one of name/class/role/title/type, or you may use more
|
||||||
|
# than one together to restrict your matches.
|
||||||
|
|
||||||
|
# the name, class, role, and title use simple wildcard matching such as those
|
||||||
|
# used by a shell. you can use * to match any characters and ? to match
|
||||||
|
# any single character.
|
||||||
|
|
||||||
|
# the type is one of: normal, dialog, splash, utility, menu, toolbar, dock,
|
||||||
|
# or desktop
|
||||||
|
|
||||||
|
# when multiple rules match a window, they will all be applied, in the
|
||||||
|
# order that they appear in this list
|
||||||
|
|
||||||
|
|
||||||
|
# each rule element can be left out or set to 'default' to specify to not
|
||||||
|
# change that attribute of the window
|
||||||
|
|
||||||
|
<decor>yes</decor>
|
||||||
|
# enable or disable window decorations
|
||||||
|
|
||||||
|
<shade>no</shade>
|
||||||
|
# make the window shaded when it appears, or not
|
||||||
|
|
||||||
|
<position force="no">
|
||||||
|
# the position is only used if both an x and y coordinate are provided
|
||||||
|
# (and not set to 'default')
|
||||||
|
# when force is "yes", then the window will be placed here even if it
|
||||||
|
# says you want it placed elsewhere. this is to override buggy
|
||||||
|
# applications who refuse to behave
|
||||||
|
<x>center</x>
|
||||||
|
# a number like 50, or 'center' to center on screen. use a negative number
|
||||||
|
# to start from the right (or bottom for <y>), ie -50 is 50 pixels from
|
||||||
|
# the right edge (or bottom). use 'default' to specify using value
|
||||||
|
# provided by the application, or chosen by openbox, instead.
|
||||||
|
<y>200</y>
|
||||||
|
<monitor>1</monitor>
|
||||||
|
# specifies the monitor in a xinerama setup.
|
||||||
|
# 1 is the first head, or 'mouse' for wherever the mouse is
|
||||||
|
</position>
|
||||||
|
|
||||||
|
<size>
|
||||||
|
# the size to make the window.
|
||||||
|
<width>20</width>
|
||||||
|
# a number like 20, or 'default' to use the size given by the application.
|
||||||
|
# you can use fractions such as 1/2 or percentages such as 75% in which
|
||||||
|
# case the value is relative to the size of the monitor that the window
|
||||||
|
# appears on.
|
||||||
|
<height>30%</height>
|
||||||
|
</size>
|
||||||
|
|
||||||
|
<focus>yes</focus>
|
||||||
|
# if the window should try be given focus when it appears. if this is set
|
||||||
|
# to yes it doesn't guarantee the window will be given focus. some
|
||||||
|
# restrictions may apply, but Openbox will try to
|
||||||
|
|
||||||
|
<desktop>1</desktop>
|
||||||
|
# 1 is the first desktop, 'all' for all desktops
|
||||||
|
|
||||||
|
<layer>normal</layer>
|
||||||
|
# 'above', 'normal', or 'below'
|
||||||
|
|
||||||
|
<iconic>no</iconic>
|
||||||
|
# make the window iconified when it appears, or not
|
||||||
|
|
||||||
|
<skip_pager>no</skip_pager>
|
||||||
|
# asks to not be shown in pagers
|
||||||
|
|
||||||
|
<skip_taskbar>no</skip_taskbar>
|
||||||
|
# asks to not be shown in taskbars. window cycling actions will also
|
||||||
|
# skip past such windows
|
||||||
|
|
||||||
|
<fullscreen>yes</fullscreen>
|
||||||
|
# make the window in fullscreen mode when it appears
|
||||||
|
|
||||||
|
<maximized>true</maximized>
|
||||||
|
# 'Horizontal', 'Vertical' or boolean (yes/no)
|
||||||
|
</application>
|
||||||
|
|
||||||
|
# end of the example
|
||||||
|
-->
|
||||||
|
</applications>
|
||||||
|
|
||||||
|
</openbox_config>
|
125
.m1k1o/firefox/policies.json
Normal file
125
.m1k1o/firefox/policies.json
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
{
|
||||||
|
"policies": {
|
||||||
|
"BlockAboutAddons": false,
|
||||||
|
"BlockAboutConfig": true,
|
||||||
|
"BlockAboutProfiles": true,
|
||||||
|
"BlockAboutSupport": true,
|
||||||
|
"Bookmarks": [
|
||||||
|
{
|
||||||
|
"Title": "IPLeak",
|
||||||
|
"URL": "https://ipleak.net/",
|
||||||
|
"Favicon": "https://ipleak.net/favicon.ico",
|
||||||
|
"Folder": "Pages",
|
||||||
|
"Placement": "toolbar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Title": "YouTube",
|
||||||
|
"URL": "https://www.youtube.com/",
|
||||||
|
"Favicon": "https://www.youtube.com/favicon.ico",
|
||||||
|
"Folder": "Pages",
|
||||||
|
"Placement": "toolbar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Title": "Google",
|
||||||
|
"URL": "https://www.google.com/",
|
||||||
|
"Favicon": "https://www.google.com/favicon.ico",
|
||||||
|
"Folder": "Pages",
|
||||||
|
"Placement": "toolbar"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"CaptivePortal": false,
|
||||||
|
"DisableAppUpdate": true,
|
||||||
|
"DisableBuiltinPDFViewer": true,
|
||||||
|
"DisableDeveloperTools": false,
|
||||||
|
"DisableFeedbackCommands": true,
|
||||||
|
"DisableFirefoxAccounts": true,
|
||||||
|
"DisableFirefoxScreenshots": true,
|
||||||
|
"DisableFirefoxStudies": true,
|
||||||
|
"DisableForgetButton": true,
|
||||||
|
"DisableMasterPasswordCreation": true,
|
||||||
|
"DisablePocket": true,
|
||||||
|
"DisablePrivateBrowsing": true,
|
||||||
|
"DisableProfileImport": true,
|
||||||
|
"DisableProfileRefresh": true,
|
||||||
|
"DisableSafeMode": true,
|
||||||
|
"DisableSetDesktopBackground": true,
|
||||||
|
"DisableSystemAddonUpdate": true,
|
||||||
|
"DisableTelemetry": true,
|
||||||
|
"DisplayBookmarksToolbar": false,
|
||||||
|
"DontCheckDefaultBrowser": true,
|
||||||
|
"EnableTrackingProtection": {
|
||||||
|
"Cryptomining": true,
|
||||||
|
"Fingerprinting": true,
|
||||||
|
"Value": true
|
||||||
|
},
|
||||||
|
"ExtensionSettings": {
|
||||||
|
"*": {
|
||||||
|
"installation_mode": "blocked"
|
||||||
|
},
|
||||||
|
"uBlock0@raymondhill.net": {
|
||||||
|
"install_url": "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi",
|
||||||
|
"installation_mode": "force_installed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ExtensionUpdate": false,
|
||||||
|
"FirefoxHome": {
|
||||||
|
"Highlights": false,
|
||||||
|
"Pocket": false,
|
||||||
|
"Search": true,
|
||||||
|
"Snippets": false,
|
||||||
|
"TopSites": true
|
||||||
|
},
|
||||||
|
"FlashPlugin": {},
|
||||||
|
"HardwareAcceleration": false,
|
||||||
|
"Homepage": {
|
||||||
|
"Additional": [],
|
||||||
|
"StartPage": "none"
|
||||||
|
},
|
||||||
|
"NewTabPage": true,
|
||||||
|
"NoDefaultBookmarks": true,
|
||||||
|
"OfferToSaveLogins": false,
|
||||||
|
"OfferToSaveLoginsDefault": false,
|
||||||
|
"OverrideFirstRunPage": "",
|
||||||
|
"OverridePostUpdatePage": "",
|
||||||
|
"PasswordManagerEnabled": false,
|
||||||
|
"Permissions": {
|
||||||
|
"Camera": {
|
||||||
|
"BlockNewRequests": true
|
||||||
|
},
|
||||||
|
"Location": {
|
||||||
|
"BlockNewRequests": true
|
||||||
|
},
|
||||||
|
"Microphone": {
|
||||||
|
"BlockNewRequests": true
|
||||||
|
},
|
||||||
|
"Notifications": {
|
||||||
|
"BlockNewRequests": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Preferences": {
|
||||||
|
"browser.tabs.warnOnClose": false,
|
||||||
|
"browser.urlbar.suggest.bookmark": false,
|
||||||
|
"browser.urlbar.suggest.history": false,
|
||||||
|
"browser.urlbar.suggest.openpage": false,
|
||||||
|
"datareporting.policy.dataSubmissionPolicyBypassNotification": true,
|
||||||
|
"dom.disable_window_flip": true,
|
||||||
|
"dom.disable_window_move_resize": true,
|
||||||
|
"dom.event.contextmenu.enabled": false,
|
||||||
|
"extensions.getAddons.showPane": false,
|
||||||
|
"places.history.enabled": false,
|
||||||
|
"privacy.file_unique_origin": true,
|
||||||
|
"ui.key.menuAccessKeyFocuses": false
|
||||||
|
},
|
||||||
|
"PromptForDownloadLocation": false,
|
||||||
|
"SanitizeOnShutdown": {
|
||||||
|
"Cache": true,
|
||||||
|
"Cookies": true,
|
||||||
|
"Downloads": true,
|
||||||
|
"FormData": true,
|
||||||
|
"History": true,
|
||||||
|
"OfflineApps": true,
|
||||||
|
"Sessions": true,
|
||||||
|
"SiteSettings": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
.m1k1o/firefox/supervisord.conf
Normal file
21
.m1k1o/firefox/supervisord.conf
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[program:firefox-esr]
|
||||||
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
|
command=/usr/lib/firefox-esr/firefox-esr --display=%(ENV_DISPLAY)s -setDefaultBrowser -width 1280 -height 720
|
||||||
|
autorestart=true
|
||||||
|
priority=800
|
||||||
|
user=%(ENV_USER)s
|
||||||
|
stdout_logfile=/var/log/neko/firefox-esr.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
||||||
|
|
||||||
|
[program:openbox]
|
||||||
|
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||||
|
command=/usr/bin/openbox --config-file /etc/neko/openbox.xml
|
||||||
|
autorestart=true
|
||||||
|
priority=300
|
||||||
|
user=%(ENV_USER)s
|
||||||
|
stdout_logfile=/var/log/neko/openbox.log
|
||||||
|
stdout_logfile_maxbytes=100MB
|
||||||
|
stdout_logfile_backups=10
|
||||||
|
redirect_stderr=true
|
143
README.md
143
README.md
@ -1,39 +1,120 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://n.eko.moe/#/" ><img src="https://raw.githubusercontent.com/nurdism/neko/master/docs/_media/logo.png" width="450" height="auto"/></a>
|
<a href="https://n.eko.moe/#/" ><img src="https://raw.githubusercontent.com/nurdism/neko/master/docs/_media/logo.png" width="450" height="auto"/></a>
|
||||||
<br/>
|
<p align="center">
|
||||||
<br/>
|
<img src="https://img.shields.io/github/v/release/nurdism/neko" alt="release">
|
||||||
<img src="https://i.imgur.com/ZSzbQr7.gif" width="650" height="auto"/>
|
<img src="https://img.shields.io/github/license/nurdism/neko" alt="license">
|
||||||
<br/>
|
<img src="https://img.shields.io/docker/pulls/nurdism/neko" alt="pulls">
|
||||||
<br/>
|
<img src="https://img.shields.io/github/issues/nurdism/neko" alt="issues">
|
||||||
|
<a href="https://discord.gg/3U6hWpC" ><img src="https://discordapp.com/api/guilds/665851821906067466/widget.png" alt="Chat on discord"><a/>
|
||||||
|
<a href="https://github.com/nurdism/neko/actions" ><img src="https://github.com/nurdism/neko/workflows/deploy/badge.svg" alt="build"><a/>
|
||||||
|
</p>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<img src="https://i.imgur.com/ZSzbQr7.gif" width="650" height="auto"/>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
# n.eko
|
# n.eko (m1k1o fork)
|
||||||
This app uses Web RTC to stream a desktop inside of a docker container, I made this because [rabb.it](https://en.wikipedia.org/wiki/Rabb.it) went under and my internet can't handle streaming and discord keeps crashing when my friend attempts to. I just want to watch anime with my friends ლ(ಠ益ಠლ) so I started digging throughout the internet and found a few *kinda* clones, but none of them had the virtual browser, then I found [Turtus](https://github.com/Khauri/Turtus) and I was able to figure out the rest. This is by no means a fully featured clone of rabbit, it hs only *one* room. It's stateless, so no saved user names or passwords.
|
This app uses Web RTC to stream a desktop inside of a docker container. This is fork of https://github.com/nurdism/neko.
|
||||||
|
|
||||||
## Features
|
## Differences to original repository.
|
||||||
* Text Chat (With basic markdown support, discord flavor)
|
|
||||||
* Admin users (Kick, Ban & Force Give/Release Controls)
|
|
||||||
* Clipboard synchronization (on [supported browsers](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText))
|
|
||||||
* Emote overlay
|
|
||||||
* Ignore user (chat and emotes)
|
|
||||||
* Persistent settings
|
|
||||||
|
|
||||||
## Why n.eko?
|
### New Features
|
||||||
I like cats 🐱 (`Neko` is the Japanese word for cat), I'm a weeb/nerd
|
- Clipboard button with text area - for browsers, that don't support clipboard syncing or for HTTP.
|
||||||
|
- Keyboard modifier state synchronization (Num Lock, Caps Lock, Scroll Lock) for each hosting.
|
||||||
|
- Added chromium ungoogled (with h265 support) an kept up to date by @whalehub.
|
||||||
|
- Added Picture in Picture button (only for watching screen, controlling not possible).
|
||||||
|
- Added RTMP broadcast. Enables broadcasting neko screen to local RTMP server, YouTube or Twitch.
|
||||||
|
- Stereo sound (works properly only in Firefox host).
|
||||||
|
|
||||||
***But why the cat butt?*** Because cats are *assholes*, but you love them anyways.
|
### Bugs
|
||||||
|
- Fixed minor gst pipeline bug.
|
||||||
|
- Locked screen only for users, admins can still join.
|
||||||
|
|
||||||
## Documentation
|
### Misc
|
||||||
|
- Custom docker workflow.
|
||||||
|
- Based on debian buster instead of stretch.
|
||||||
|
- Custom avatars without any 3rd party depenency.
|
||||||
|
- Ignore duplicate notify bars.
|
||||||
|
- No pointer events for notify bars.
|
||||||
|
- Disable debug mode by default.
|
||||||
|
|
||||||
* [Getting Started](https://n.eko.moe/#/getting-started)
|
# Getting started & FAQ
|
||||||
* [Quick Start](https://n.eko.moe/#/quick-start)
|
|
||||||
* [Configuration](https://n.eko.moe/#/configuration)
|
Use following docker images:
|
||||||
* [Development](https://n.eko.moe/#/development)
|
- `m1k1o/neko:latest` - for Firefox.
|
||||||
* [Client](https://n.eko.moe/#/client)
|
- `m1k1o/neko:chromium` - for Chromium Ungoogled (needs `--cap-add=SYS_ADMIN`).
|
||||||
* [Server](https://n.eko.moe/#/server)
|
- `m1k1o/neko:base` - for custom base.
|
||||||
* [Docker](https://n.eko.moe/#/docker)
|
|
||||||
* [Non Goals](https://n.eko.moe/#/non-goals)
|
Networking:
|
||||||
* [Contributing](https://n.eko.moe/#/contributing)
|
- If you want to use n.eko in **external** network, you can omit `NEKO_NAT1TO1`. It will automatically get your Public IP.
|
||||||
* [Change logs](https://n.eko.moe/#/change-logs/)
|
- If you want to use n.eko in **internal** network, set `NEKO_NAT1TO1` to your local IP address (e.g. `NEKO_NAT1TO1: 192.168.1.20`)-
|
||||||
* [Technologies](https://n.eko.moe/#/technologies)
|
|
||||||
* [Glossary](https://n.eko.moe/#/glossary)
|
Why so many ports?
|
||||||
|
- WebRTC needs UDP ports for each channel it creates towards users.
|
||||||
|
- Every user will need 2 UDP ports (for getting audio/video and sending mouse positions).
|
||||||
|
- You can freely limit number of UDP ports. But you can't map them to diferent ports.
|
||||||
|
- This **WONT** work: `32000-32100:52000-52100/udp`
|
||||||
|
- You can change API port (8080).
|
||||||
|
- This **WILL** work: `3000:8080`
|
||||||
|
|
||||||
|
Behind reverse proxy?
|
||||||
|
- Nginx configuration: https://github.com/nurdism/neko/issues/111#issuecomment-742656957
|
||||||
|
- Apache configuration: https://github.com/nurdism/neko/blob/cad98a62a5bd7f1daf2c11980631bb14ba81a1f6/docs/apache-proxypass-config.md#example-apache-config
|
||||||
|
- Traefik configuration: https://github.com/m1k1o/neko-vpn/blob/a1b934515dcf597992a515d61d307c2450a11002/docker-compose.yml#L38-L43
|
||||||
|
|
||||||
|
Want to use VPN for your neko browsing?
|
||||||
|
- Check this out: https://github.com/m1k1o/neko-vpn
|
||||||
|
|
||||||
|
Accounts:
|
||||||
|
- There are no accounts, display name (a.k.a. username) can be freely chosen. Only paword needs to match. Depeding on which password matches, visitor gets its privilege:
|
||||||
|
- Anyone, who enters with `NEKO_PASSWORD` will be **user**.
|
||||||
|
- Anyone, who enters with `NEKO_PASSWORD_ADMIN` will be **admin**.
|
||||||
|
|
||||||
|
Screen size
|
||||||
|
- Only admins can change screen size.
|
||||||
|
- You can set default screen size, but this size **MUST** be one from list, that your server supports.
|
||||||
|
- You will get this list in frontend, where you can choose from.
|
||||||
|
|
||||||
|
## Firefox
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.4"
|
||||||
|
services:
|
||||||
|
neko:
|
||||||
|
image: "m1k1o/neko:latest"
|
||||||
|
restart: "unless-stopped"
|
||||||
|
shm_size: "2gb"
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
- "52000-52100:52000-52100/udp"
|
||||||
|
environment:
|
||||||
|
NEKO_SCREEN: '1920x1080@30'
|
||||||
|
NEKO_PASSWORD: neko
|
||||||
|
NEKO_PASSWORD_ADMIN: admin
|
||||||
|
NEKO_EPR: 52000-52100
|
||||||
|
NEKO_NAT1TO1: <your-IP>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Chromium Ungoogled
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.4"
|
||||||
|
services:
|
||||||
|
neko:
|
||||||
|
image: "m1k1o/neko:chromium"
|
||||||
|
restart: "unless-stopped"
|
||||||
|
shm_size: "2gb"
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
- "52000-52100:52000-52100/udp"
|
||||||
|
cap_add:
|
||||||
|
- SYS_ADMIN
|
||||||
|
environment:
|
||||||
|
NEKO_SCREEN: '1920x1080@30'
|
||||||
|
NEKO_PASSWORD: neko
|
||||||
|
NEKO_PASSWORD_ADMIN: admin
|
||||||
|
NEKO_EPR: 52000-52100
|
||||||
|
NEKO_NAT1TO1: <your-IP>
|
||||||
|
```
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "neko-client",
|
"name": "neko-client",
|
||||||
"version": "0.1.0",
|
"version": "2.0.0",
|
||||||
"description": "Client for neko streaming server",
|
"description": "Client for neko streaming server",
|
||||||
"license": "Apache License 2.0",
|
"license": "Apache License 2.0",
|
||||||
"author": "Nurdism <https://github.com/nurdism>",
|
"author": "Nurdism <https://github.com/nurdism>",
|
||||||
@ -19,46 +19,49 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^5.12.0",
|
"@fortawesome/fontawesome-free": "^5.14.0",
|
||||||
"animejs": "^3.1.0",
|
"animejs": "^3.2.0",
|
||||||
"axios": "^0.19.1",
|
"axios": "^0.19.1",
|
||||||
"date-fns": "^2.9.0",
|
"date-fns": "^2.16.1",
|
||||||
"emoji-datasource": "^5.0.1",
|
"emoji-datasource": "^5.0.1",
|
||||||
"emojilib": "^2.4.0",
|
"emojilib": "^2.4.0",
|
||||||
"eventemitter3": "^4.0.0",
|
"eventemitter3": "^4.0.7",
|
||||||
"resize-observer-polyfill": "^1.5.1",
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
"simple-markdown": "^0.7.2",
|
"simple-markdown": "^0.7.2",
|
||||||
"sweetalert2": "^9.6.1",
|
"sweetalert2": "^9.17.2",
|
||||||
"typed-vuex": "^0.1.15",
|
"typed-vuex": "^0.1.21",
|
||||||
"v-tooltip": "^2.0.3",
|
"v-tooltip": "^2.0.3",
|
||||||
"vue": "^2.6.10",
|
"vue": "^2.6.12",
|
||||||
"vue-class-component": "^7.0.2",
|
"vue-class-component": "^7.2.6",
|
||||||
"vue-clickaway": "^2.2.2",
|
"vue-clickaway": "^2.2.2",
|
||||||
"vue-context": "^5.0.0",
|
"vue-context": "^5.2.0",
|
||||||
|
"vue-i18n": "^8.21.1",
|
||||||
"vue-notification": "^1.3.20",
|
"vue-notification": "^1.3.20",
|
||||||
"vue-property-decorator": "^8.3.0",
|
"vue-property-decorator": "^8.5.1",
|
||||||
"vuex": "^3.1.2"
|
"vuex": "^3.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/animejs": "^3.1.0",
|
"@types/animejs": "^3.1.2",
|
||||||
"@types/node": "^13.7.0",
|
"@types/node": "^13.13.21",
|
||||||
"@types/vue": "^2.0.0",
|
"@types/vue": "^2.0.0",
|
||||||
"@types/vue-clickaway": "^2.2.0",
|
"@types/vue-clickaway": "^2.2.0",
|
||||||
"@vue/cli-plugin-babel": "^4.1.0",
|
"@typescript-eslint/eslint-plugin": "^2.34.0",
|
||||||
"@vue/cli-plugin-eslint": "^4.1.0",
|
"@typescript-eslint/parser": "^2.34.0",
|
||||||
"@vue/cli-plugin-typescript": "^4.1.0",
|
"@vue/cli-plugin-babel": "^4.5.6",
|
||||||
"@vue/cli-plugin-vuex": "^4.1.0",
|
"@vue/cli-plugin-eslint": "^4.5.6",
|
||||||
"@vue/cli-service": "^4.1.0",
|
"@vue/cli-plugin-typescript": "^4.5.6",
|
||||||
"@vue/eslint-config-prettier": "^5.0.0",
|
"@vue/cli-plugin-vuex": "^4.5.6",
|
||||||
"@vue/eslint-config-typescript": "^4.0.0",
|
"@vue/cli-service": "^4.5.6",
|
||||||
"eslint": "^5.16.0",
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
"eslint-plugin-prettier": "^3.1.1",
|
"@vue/eslint-config-typescript": "^5.1.0",
|
||||||
"eslint-plugin-vue": "^5.0.0",
|
"eslint": "^6.8.0",
|
||||||
"node-sass": "^4.12.0",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"prettier": "^1.19.1",
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"node-sass": "^4.14.1",
|
||||||
|
"prettier": "^2.1.2",
|
||||||
"sass-loader": "^8.0.0",
|
"sass-loader": "^8.0.0",
|
||||||
"ts-node": "^8.6.2",
|
"ts-node": "^8.10.2",
|
||||||
"typescript": "~3.5.3",
|
"typescript": "^3.9.7",
|
||||||
"vue-template-compiler": "^2.6.10"
|
"vue-template-compiler": "^2.6.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
<strong>We're sorry but test doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
<strong>We're sorry but n.eko doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
</noscript>
|
</noscript>
|
||||||
<div id="neko"></div>
|
<div id="neko"></div>
|
||||||
</body>
|
</body>
|
||||||
|
1
client/public/keyboard_layouts.json
Normal file
1
client/public/keyboard_layouts.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"af":"Afghani","al":"Albanian","et":"Amharic","ma":"Arabic (Morocco)","sy":"Arabic (Syria)","am":"Armenian","az":"Azerbaijani","ml":"Bambara","bd":"Bangla","by":"Belarusian","be":"Belgian","dz":"Berber (Algeria, Latin characters)","ba":"Bosnian","bg":"Bulgarian","mm":"Burmese","hr":"Croatian","cz":"Czech","dk":"Danish","mv":"Dhivehi","nl":"Dutch","bt":"Dzongkha","au":"English (Australian)","cm":"English (Cameroon)","gh":"English (Ghana)","ng":"English (Nigeria)","za":"English (South Africa)","us":"English (US)","gb":"English (UK)","ee":"Estonian","fo":"Faroese","ph":"Filipino","fi":"Finnish","fr":"French","ca":"French (Canada)","cd":"French (Democratic Republic of the Congo)","gn":"French (Guinea)","tg":"French (Togo)","ge":"Georgian","de":"German","at":"German (Austria)","ch":"German (Switzerland)","gr":"Greek","il":"Hebrew","hu":"Hungarian","cn":"Chinese","is":"Icelandic","in":"Indian","id":"Indonesian (Jawi)","iq":"Iraqi","ie":"Irish","it":"Italian","jp":"Japanese","kz":"Kazakh","kh":"Khmer (Cambodia)","kr":"Korean","kg":"Kyrgyz","la":"Lao","lv":"Latvian","lt":"Lithuanian","mk":"Macedonian","my":"Malay (Jawi)","mt":"Maltese","md":"Moldavian","mn":"Mongolian","me":"Montenegrin","np":"Nepali","no":"Norwegian","ir":"Persian","pl":"Polish","pt":"Portuguese","br":"Portuguese (Brazil)","ro":"Romanian","ru":"Russian","rs":"Serbian","lk":"Sinhala (phonetic)","sk":"Slovak","si":"Slovenian","es":"Spanish","ke":"Swahili (Kenya)","tz":"Swahili (Tanzania)","se":"Swedish","tw":"Taiwanese","tj":"Tajik","th":"Thai","bw":"Tswana","tr":"Turkish","tm":"Turkmen","ua":"Ukrainian","pk":"Urdu (Pakistan)","uz":"Uzbek","vn":"Vietnamese","sn":"Wolof"}
|
@ -29,7 +29,7 @@
|
|||||||
<neko-side v-if="side" />
|
<neko-side v-if="side" />
|
||||||
<neko-connect v-if="!connected" />
|
<neko-connect v-if="!connected" />
|
||||||
<neko-about v-if="about" />
|
<neko-about v-if="about" />
|
||||||
<notifications group="neko" position="top left" style="top: 50px;" />
|
<notifications group="neko" position="top left" :ignoreDuplicates="true" style="top: 50px;pointer-events: none" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -148,18 +148,18 @@
|
|||||||
this.loading = true
|
this.loading = true
|
||||||
this.$http
|
this.$http
|
||||||
.get<string>('https://raw.githubusercontent.com/nurdism/neko/master/docs/README.md')
|
.get<string>('https://raw.githubusercontent.com/nurdism/neko/master/docs/README.md')
|
||||||
.then(res => {
|
.then((res) => {
|
||||||
return this.$http.post('https://api.github.com/markdown', {
|
return this.$http.post('https://api.github.com/markdown', {
|
||||||
text: res.data,
|
text: res.data,
|
||||||
mode: 'gfm',
|
mode: 'gfm',
|
||||||
context: 'github/gollum',
|
context: 'github/gollum',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then((res) => {
|
||||||
this.$accessor.client.setAbout(res.data)
|
this.$accessor.client.setAbout(res.data)
|
||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
.catch(err => console.error(err))
|
.catch((err) => console.error(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
52
client/src/components/avatar.vue
Normal file
52
client/src/components/avatar.vue
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<!--
|
||||||
|
<img :src="`https://ui-avatars.com/api/?name=${seed}&size=${size}`" />
|
||||||
|
-->
|
||||||
|
<div class="avatar" :style="{
|
||||||
|
width: size + 'px',
|
||||||
|
height: size + 'px',
|
||||||
|
lineHeight: size + 'px',
|
||||||
|
fontSize: (size/2) + 'px',
|
||||||
|
backgroundColor: Background(seed),
|
||||||
|
}">
|
||||||
|
{{ seed.substring(0, 2).toUpperCase() }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.avatar {
|
||||||
|
user-select: none;
|
||||||
|
text-align: center;
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
display: inline-block;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Vue, Component, Prop } from 'vue-property-decorator'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
name: 'neko-avatar',
|
||||||
|
})
|
||||||
|
export default class extends Vue {
|
||||||
|
@Prop(String) readonly seed: string | undefined;
|
||||||
|
@Prop(Number) readonly size: number | undefined;
|
||||||
|
|
||||||
|
Background(seed: string) {
|
||||||
|
let a = 0, b = 0, c = 0;
|
||||||
|
for(let i = 0; i < seed.length; i++) {
|
||||||
|
a += seed.charCodeAt(i) * 3;
|
||||||
|
b += seed.charCodeAt(i) * 5;
|
||||||
|
c += seed.charCodeAt(i) * 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = Math.floor(128 + (a % 128));
|
||||||
|
let y = Math.floor(128 + (b % 128));
|
||||||
|
let z = Math.floor(128 + (c % 128));
|
||||||
|
return "rgb(" + x + "," + y + "," + z + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -4,11 +4,11 @@
|
|||||||
<template v-for="(message, index) in history">
|
<template v-for="(message, index) in history">
|
||||||
<li :key="index" class="message" v-if="message.type === 'text'">
|
<li :key="index" class="message" v-if="message.type === 'text'">
|
||||||
<div class="author" @contextmenu.stop.prevent="onContext($event, { member: member(message.id) })">
|
<div class="author" @contextmenu.stop.prevent="onContext($event, { member: member(message.id) })">
|
||||||
<img :src="`https://api.adorable.io/avatars/40/${member(message.id).username}.png`" />
|
<neko-avatar class="avatar" :seed="member(message.id).displayname" :size="40" />
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="content-head">
|
<div class="content-head">
|
||||||
<span>{{ member(message.id).username }}</span>
|
<span>{{ member(message.id).displayname }}</span>
|
||||||
<span class="timestamp">{{ timestamp(message.created) }}</span>
|
<span class="timestamp">{{ timestamp(message.created) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<neko-markdown class="content-body" :source="message.content" />
|
<neko-markdown class="content-body" :source="message.content" />
|
||||||
@ -24,8 +24,8 @@
|
|||||||
boundariesElement: 'body',
|
boundariesElement: 'body',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<strong v-if="message.id === id">You</strong>
|
<strong v-if="message.id === id">{{ $t('you') }}</strong>
|
||||||
<strong v-else>{{ member(message.id).username }}</strong>
|
<strong v-else>{{ member(message.id).displayname }}</strong>
|
||||||
{{ message.content }}
|
{{ message.content }}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@ -35,7 +35,7 @@
|
|||||||
<div v-if="!muted" class="chat-send">
|
<div v-if="!muted" class="chat-send">
|
||||||
<div class="accent" />
|
<div class="accent" />
|
||||||
<div class="text-container">
|
<div class="text-container">
|
||||||
<textarea ref="input" placeholder="Send a message" @keydown="onKeyDown" v-model="content" />
|
<textarea ref="input" :placeholder="$t('send_a_message')" @keydown="onKeyDown" v-model="content" />
|
||||||
<neko-emoji v-if="emoji" @picked="onEmojiPicked" @done="emoji = false" />
|
<neko-emoji v-if="emoji" @picked="onEmojiPicked" @done="emoji = false" />
|
||||||
<i class="emoji-menu fas fa-laugh" @click.stop.prevent="onEmoji"></i>
|
<i class="emoji-menu fas fa-laugh" @click.stop.prevent="onEmoji"></i>
|
||||||
</div>
|
</div>
|
||||||
@ -106,7 +106,7 @@
|
|||||||
background: $style-primary;
|
background: $style-primary;
|
||||||
margin: 0px 10px 10px 0px;
|
margin: 0px 10px 10px 0px;
|
||||||
|
|
||||||
img {
|
.avatar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,6 +329,7 @@
|
|||||||
import Markdown from './markdown'
|
import Markdown from './markdown'
|
||||||
import Content from './context.vue'
|
import Content from './context.vue'
|
||||||
import Emoji from './emoji.vue'
|
import Emoji from './emoji.vue'
|
||||||
|
import Avatar from './avatar.vue'
|
||||||
|
|
||||||
const length = 512 // max length of message
|
const length = 512 // max length of message
|
||||||
|
|
||||||
@ -338,6 +339,7 @@
|
|||||||
'neko-markdown': Markdown,
|
'neko-markdown': Markdown,
|
||||||
'neko-context': Content,
|
'neko-context': Content,
|
||||||
'neko-emoji': Emoji,
|
'neko-emoji': Emoji,
|
||||||
|
'neko-avatar': Avatar,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class extends Vue {
|
export default class extends Vue {
|
||||||
|
82
client/src/components/clipboard.vue
Normal file
82
client/src/components/clipboard.vue
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="clipboard"
|
||||||
|
v-if="opened"
|
||||||
|
@click="$event.stopPropagation()"
|
||||||
|
>
|
||||||
|
<textarea
|
||||||
|
ref="textarea"
|
||||||
|
v-model="clipboard"
|
||||||
|
@focus="$event.target.select()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.clipboard {
|
||||||
|
background-color: $background-primary;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
display: block;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
right: 10px;
|
||||||
|
|
||||||
|
&, textarea {
|
||||||
|
max-width: 320px;
|
||||||
|
width: 100%;
|
||||||
|
max-height: 120px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
border: 0;
|
||||||
|
color: $text-normal;
|
||||||
|
background: none;
|
||||||
|
|
||||||
|
&::selection {
|
||||||
|
background: $text-normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Ref, Vue } from 'vue-property-decorator'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
name: 'neko-clipboard',
|
||||||
|
})
|
||||||
|
export default class extends Vue {
|
||||||
|
@Ref('textarea') readonly _textarea!: HTMLTextAreaElement
|
||||||
|
|
||||||
|
private opened: boolean = false
|
||||||
|
private typing: any = null
|
||||||
|
|
||||||
|
get clipboard() {
|
||||||
|
return this.$accessor.remote.clipboard
|
||||||
|
}
|
||||||
|
|
||||||
|
set clipboard(data: string) {
|
||||||
|
this.$accessor.remote.setClipboard(data)
|
||||||
|
|
||||||
|
if (this.typing) {
|
||||||
|
clearTimeout(this.typing)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.typing = setTimeout(() => this.$accessor.remote.sendClipboard(this.clipboard), 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
open() {
|
||||||
|
this.opened = true
|
||||||
|
document.body.addEventListener('click', this.close)
|
||||||
|
setTimeout(() => this._textarea.focus(), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.opened = false
|
||||||
|
document.body.removeEventListener('click', this.close)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -6,11 +6,11 @@
|
|||||||
<span><b>n</b>.eko</span>
|
<span><b>n</b>.eko</span>
|
||||||
</div>
|
</div>
|
||||||
<form class="message" v-if="!connecting" @submit.stop.prevent="connect">
|
<form class="message" v-if="!connecting" @submit.stop.prevent="connect">
|
||||||
<span>Please Login</span>
|
<span>{{ $t('connect.title') }}</span>
|
||||||
<input type="text" placeholder="Username" v-model="username" />
|
<input type="text" :placeholder="$t('connect.displayname')" v-model="displayname" />
|
||||||
<input type="password" placeholder="Password" v-model="password" />
|
<input type="password" :placeholder="$t('connect.password')" v-model="password" />
|
||||||
<button type="submit" @click.stop.prevent="login">
|
<button type="submit" @click.stop.prevent="login">
|
||||||
Connect
|
{{ $t('connect.connect') }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<div class="loader" v-if="connecting">
|
<div class="loader" v-if="connecting">
|
||||||
@ -150,12 +150,12 @@
|
|||||||
|
|
||||||
@Component({ name: 'neko-connect' })
|
@Component({ name: 'neko-connect' })
|
||||||
export default class extends Vue {
|
export default class extends Vue {
|
||||||
private username = ''
|
private displayname = ''
|
||||||
private password = ''
|
private password = ''
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.$accessor.username !== '' && this.$accessor.password !== '') {
|
if (this.$accessor.displayname !== '' && this.$accessor.password !== '') {
|
||||||
this.$accessor.login({ username: this.$accessor.username, password: this.$accessor.password })
|
this.$accessor.login({ displayname: this.$accessor.displayname, password: this.$accessor.password })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +164,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
login() {
|
login() {
|
||||||
this.$accessor.login({ username: this.username, password: this.password })
|
this.$accessor.login({ displayname: this.displayname, password: this.password })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -3,44 +3,46 @@
|
|||||||
<template slot-scope="child" v-if="child.data">
|
<template slot-scope="child" v-if="child.data">
|
||||||
<li class="header">
|
<li class="header">
|
||||||
<div class="user">
|
<div class="user">
|
||||||
<img :src="`https://api.adorable.io/avatars/25/${child.data.member.username}.png`" />
|
<neko-avatar class="avatar" :seed="child.data.member.displayname" :size="25" />
|
||||||
<strong>{{ child.data.member.username }}</strong>
|
<strong>{{ child.data.member.displayname }}</strong>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li class="seperator" />
|
<li class="seperator" />
|
||||||
<li>
|
<li>
|
||||||
<span @click="ignore(child.data.member)" v-if="!child.data.member.ignored">Ignore</span>
|
<span @click="ignore(child.data.member)" v-if="!child.data.member.ignored">{{ $t('context.ignore') }}</span>
|
||||||
<span @click="unignore(child.data.member)" v-else>Unignore</span>
|
<span @click="unignore(child.data.member)" v-else>{{ $t('context.unignore') }}</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<template v-if="admin">
|
<template v-if="admin">
|
||||||
<li>
|
<li>
|
||||||
<span @click="mute(child.data.member)" v-if="!child.data.member.muted">Mute</span>
|
<span @click="mute(child.data.member)" v-if="!child.data.member.muted">{{ $t('context.mute') }}</span>
|
||||||
<span @click="unmute(child.data.member)" v-else>Unmute</span>
|
<span @click="unmute(child.data.member)" v-else>{{ $t('context.unmute') }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="child.data.member.id === host">
|
<li v-if="child.data.member.id === host">
|
||||||
<span @click="adminRelease(child.data.member)">Force Release Controls</span>
|
<span @click="adminRelease(child.data.member)">{{ $t('context.release') }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="child.data.member.id === host">
|
<li v-if="child.data.member.id === host">
|
||||||
<span @click="adminControl(child.data.member)">Force Take Controls</span>
|
<span @click="adminControl(child.data.member)">{{ $t('context.take') }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span v-if="child.data.member.id !== host" @click="adminGive(child.data.member)">Give Controls</span>
|
<span v-if="child.data.member.id !== host" @click="adminGive(child.data.member)">{{
|
||||||
|
$t('context.give')
|
||||||
|
}}</span>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<li v-if="hosting">
|
<li v-if="hosting">
|
||||||
<span @click="give(child.data.member)">Give Controls</span>
|
<span @click="give(child.data.member)">{{ $t('context.give') }}</span>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-if="admin">
|
<template v-if="admin && !child.data.member.admin">
|
||||||
<li class="seperator" />
|
<li class="seperator" />
|
||||||
<li>
|
<li>
|
||||||
<span @click="kick(child.data.member)" style="color: #f04747">Kick</span>
|
<span @click="kick(child.data.member)" style="color: #f04747;">{{ $t('context.kick') }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span @click="ban(child.data.member)" style="color: #f04747">Ban IP</span>
|
<span @click="ban(child.data.member)" style="color: #f04747;">{{ $t('context.ban') }}</span>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
@ -78,7 +80,7 @@
|
|||||||
align-content: center;
|
align-content: center;
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
|
|
||||||
img {
|
.avatar {
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@ -135,11 +137,13 @@
|
|||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { VueContext } from 'vue-context'
|
import { VueContext } from 'vue-context'
|
||||||
|
import Avatar from './avatar.vue'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
name: 'neko-context',
|
name: 'neko-context',
|
||||||
components: {
|
components: {
|
||||||
'vue-context': VueContext,
|
'vue-context': VueContext,
|
||||||
|
'neko-avatar': Avatar,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class extends Vue {
|
export default class extends Vue {
|
||||||
@ -163,11 +167,12 @@
|
|||||||
|
|
||||||
kick(member: Member) {
|
kick(member: Member) {
|
||||||
this.$swal({
|
this.$swal({
|
||||||
title: `Kick ${member.username}?`,
|
title: this.$t('context.confirm.kick_title', { name: member.displayname }) as string,
|
||||||
text: `Are you sure you want to kick ${member.username}?`,
|
text: this.$t('context.confirm.kick_text', { name: member.displayname }) as string,
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonText: 'Yes',
|
confirmButtonText: this.$t('context.confirm.button_yes') as string,
|
||||||
|
cancelButtonText: this.$t('context.confirm.button_cancel') as string,
|
||||||
}).then(({ value }) => {
|
}).then(({ value }) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
this.$accessor.user.kick(member)
|
this.$accessor.user.kick(member)
|
||||||
@ -177,11 +182,12 @@
|
|||||||
|
|
||||||
ban(member: Member) {
|
ban(member: Member) {
|
||||||
this.$swal({
|
this.$swal({
|
||||||
title: `Ban ${member.username}?`,
|
title: this.$t('context.confirm.ban_title', { name: member.displayname }) as string,
|
||||||
text: `Are you sure you want to ban ${member.username}? You will need to restart the server to undo this.`,
|
text: this.$t('context.confirm.ban_text', { name: member.displayname }) as string,
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonText: 'Yes',
|
confirmButtonText: this.$t('context.confirm.button_yes') as string,
|
||||||
|
cancelButtonText: this.$t('context.confirm.button_cancel') as string,
|
||||||
}).then(({ value }) => {
|
}).then(({ value }) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
this.$accessor.user.ban(member)
|
this.$accessor.user.ban(member)
|
||||||
@ -191,11 +197,12 @@
|
|||||||
|
|
||||||
mute(member: Member) {
|
mute(member: Member) {
|
||||||
this.$swal({
|
this.$swal({
|
||||||
title: `Mute ${member.username}?`,
|
title: this.$t('context.confirm.mute_title', { name: member.displayname }) as string,
|
||||||
text: `Are you sure you want to mute ${member.username}?`,
|
text: this.$t('context.confirm.mute_text', { name: member.displayname }) as string,
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonText: 'Yes',
|
confirmButtonText: this.$t('context.confirm.button_yes') as string,
|
||||||
|
cancelButtonText: this.$t('context.confirm.button_cancel') as string,
|
||||||
}).then(({ value }) => {
|
}).then(({ value }) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
this.$accessor.user.mute(member)
|
this.$accessor.user.mute(member)
|
||||||
@ -205,11 +212,12 @@
|
|||||||
|
|
||||||
unmute(member: Member) {
|
unmute(member: Member) {
|
||||||
this.$swal({
|
this.$swal({
|
||||||
title: `Unmute ${member.username}?`,
|
title: this.$t('context.confirm.unmute_title', { name: member.displayname }) as string,
|
||||||
text: `Are you sure you want to unmute ${member.username}?`,
|
text: this.$t('context.confirm.unmute_text', { name: member.displayname }) as string,
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
confirmButtonText: 'Yes',
|
confirmButtonText: this.$t('context.confirm.button_yes') as string,
|
||||||
|
cancelButtonText: this.$t('context.confirm.button_cancel') as string,
|
||||||
}).then(({ value }) => {
|
}).then(({ value }) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
this.$accessor.user.unmute(member)
|
this.$accessor.user.unmute(member)
|
||||||
|
@ -9,9 +9,31 @@
|
|||||||
'fa-keyboard',
|
'fa-keyboard',
|
||||||
'request',
|
'request',
|
||||||
]"
|
]"
|
||||||
|
v-tooltip="{
|
||||||
|
content: !hosted || hosting ? (hosting ? $t('controls.release') : $t('controls.request')) : '',
|
||||||
|
placement: 'top',
|
||||||
|
offset: 5,
|
||||||
|
boundariesElement: 'body',
|
||||||
|
delay: { show: 300, hide: 100 },
|
||||||
|
}"
|
||||||
@click.stop.prevent="toggleControl"
|
@click.stop.prevent="toggleControl"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<label
|
||||||
|
class="switch"
|
||||||
|
v-tooltip="{
|
||||||
|
content: hosting ? (locked ? $t('controls.unlock') : $t('controls.lock')) : '',
|
||||||
|
placement: 'top',
|
||||||
|
offset: 5,
|
||||||
|
boundariesElement: 'body',
|
||||||
|
delay: { show: 300, hide: 100 },
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<input type="checkbox" v-model="locked" :disabled="!hosting" />
|
||||||
|
<span />
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<i
|
<i
|
||||||
:class="[{ disabled: !playable }, playing ? 'fa-pause-circle' : 'fa-play-circle', 'fas', 'play']"
|
:class="[{ disabled: !playable }, playing ? 'fa-pause-circle' : 'fa-play-circle', 'fas', 'play']"
|
||||||
@ -43,7 +65,7 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
i {
|
i {
|
||||||
padding: 0 10px;
|
padding: 0 5px;
|
||||||
|
|
||||||
&.faded {
|
&.faded {
|
||||||
color: rgba($color: $text-normal, $alpha: 0.4);
|
color: rgba($color: $text-normal, $alpha: 0.4);
|
||||||
@ -66,7 +88,7 @@
|
|||||||
input[type='range'] {
|
input[type='range'] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
width: 200px;
|
width: 150px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
|
|
||||||
@ -105,6 +127,69 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
margin: 0 5px;
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 42px;
|
||||||
|
height: 24px;
|
||||||
|
|
||||||
|
input[type='checkbox'] {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: $background-secondary;
|
||||||
|
transition: 0.2s;
|
||||||
|
border-radius: 34px;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
color: $background-tertiary;
|
||||||
|
font-weight: 900;
|
||||||
|
font-family: 'Font Awesome 5 Free';
|
||||||
|
content: '\f3c1';
|
||||||
|
font-size: 8px;
|
||||||
|
line-height: 18px;
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
left: 3px;
|
||||||
|
bottom: 3px;
|
||||||
|
background-color: white;
|
||||||
|
transition: 0.3s;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='checkbox'] {
|
||||||
|
&:checked + span {
|
||||||
|
background-color: $style-primary;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: '\f023';
|
||||||
|
transform: translateX(18px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled + span {
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
background-color: rgba($color: $text-normal, $alpha: 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -149,6 +234,14 @@
|
|||||||
return this.$accessor.video.playable
|
return this.$accessor.video.playable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get locked() {
|
||||||
|
return this.$accessor.remote.locked && this.$accessor.remote.hosting
|
||||||
|
}
|
||||||
|
|
||||||
|
set locked(locked: boolean) {
|
||||||
|
this.$accessor.remote.setLocked(locked)
|
||||||
|
}
|
||||||
|
|
||||||
toggleControl() {
|
toggleControl() {
|
||||||
if (!this.playable) {
|
if (!this.playable) {
|
||||||
return
|
return
|
||||||
|
@ -329,7 +329,7 @@
|
|||||||
for (const emoji of this.list) {
|
for (const emoji of this.list) {
|
||||||
if (
|
if (
|
||||||
emoji.includes(this.search) || typeof this.keywords[emoji] !== 'undefined'
|
emoji.includes(this.search) || typeof this.keywords[emoji] !== 'undefined'
|
||||||
? this.keywords[emoji].some(keyword => keyword.includes(this.search))
|
? this.keywords[emoji].some((keyword) => keyword.includes(this.search))
|
||||||
: false
|
: false
|
||||||
) {
|
) {
|
||||||
filtered.push(emoji)
|
filtered.push(emoji)
|
||||||
|
@ -150,7 +150,7 @@
|
|||||||
'cold',
|
'cold',
|
||||||
'blush',
|
'blush',
|
||||||
'sad',
|
'sad',
|
||||||
].filter(v => !this.recent.includes(v))
|
].filter((v) => !this.recent.includes(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
get muted() {
|
get muted() {
|
||||||
|
@ -9,6 +9,19 @@
|
|||||||
<i
|
<i
|
||||||
:class="[{ disabled: !admin }, { 'fa-lock-open': !locked }, { 'fa-lock': locked }, 'fas', 'lock']"
|
:class="[{ disabled: !admin }, { 'fa-lock-open': !locked }, { 'fa-lock': locked }, 'fas', 'lock']"
|
||||||
@click="toggleLock"
|
@click="toggleLock"
|
||||||
|
v-tooltip="{
|
||||||
|
content: admin
|
||||||
|
? locked
|
||||||
|
? $t('room.unlock')
|
||||||
|
: $t('room.lock')
|
||||||
|
: locked
|
||||||
|
? $t('room.unlocked')
|
||||||
|
: $t('room.locked'),
|
||||||
|
placement: 'bottom',
|
||||||
|
offset: 5,
|
||||||
|
boundariesElement: 'body',
|
||||||
|
delay: { show: 300, hide: 100 },
|
||||||
|
}"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@ -106,9 +119,9 @@
|
|||||||
toggleLock() {
|
toggleLock() {
|
||||||
if (this.admin) {
|
if (this.admin) {
|
||||||
if (this.locked) {
|
if (this.locked) {
|
||||||
this.$accessor.remote.unlock()
|
this.$accessor.unlock()
|
||||||
} else {
|
} else {
|
||||||
this.$accessor.remote.lock()
|
this.$accessor.lock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ function htmlTag(
|
|||||||
if (attributes.class && state.cssModuleNames) {
|
if (attributes.class && state.cssModuleNames) {
|
||||||
attributes.class = attributes.class
|
attributes.class = attributes.class
|
||||||
.split(' ')
|
.split(' ')
|
||||||
.map(cl => state.cssModuleNames[cl] || cl)
|
.map((cl) => state.cssModuleNames[cl] || cl)
|
||||||
.join(' ')
|
.join(' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ const rules: MarkdownRules = {
|
|||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
...text,
|
...text,
|
||||||
match: source => /^[\s\S]+?(?=[^0-9A-Za-z\s\u00c0-\uffff-]|\n\n|\n|\w+:\S|$)/.exec(source),
|
match: (source) => /^[\s\S]+?(?=[^0-9A-Za-z\s\u00c0-\uffff-]|\n\n|\n|\w+:\S|$)/.exec(source),
|
||||||
html(node, output, state) {
|
html(node, output, state) {
|
||||||
if (state.escapeHTML) {
|
if (state.escapeHTML) {
|
||||||
return md.sanitizeText(node.content)
|
return md.sanitizeText(node.content)
|
||||||
@ -214,7 +214,7 @@ const rules: MarkdownRules = {
|
|||||||
},
|
},
|
||||||
emoji: {
|
emoji: {
|
||||||
order: md.defaultRules.strong.order,
|
order: md.defaultRules.strong.order,
|
||||||
match: source => /^:([a-zA-z_-]*):/.exec(source),
|
match: (source) => /^:([a-zA-z_-]*):/.exec(source),
|
||||||
parse(capture) {
|
parse(capture) {
|
||||||
return {
|
return {
|
||||||
id: capture[1],
|
id: capture[1],
|
||||||
@ -235,7 +235,7 @@ const rules: MarkdownRules = {
|
|||||||
},
|
},
|
||||||
emoticon: {
|
emoticon: {
|
||||||
order: md.defaultRules.text.order,
|
order: md.defaultRules.text.order,
|
||||||
match: source => /^(¯\\_\(ツ\)_\/¯)/.exec(source),
|
match: (source) => /^(¯\\_\(ツ\)_\/¯)/.exec(source),
|
||||||
parse(capture) {
|
parse(capture) {
|
||||||
return {
|
return {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
@ -248,7 +248,7 @@ const rules: MarkdownRules = {
|
|||||||
},
|
},
|
||||||
spoiler: {
|
spoiler: {
|
||||||
order: 0,
|
order: 0,
|
||||||
match: source => /^\|\|([\s\S]+?)\|\|/.exec(source),
|
match: (source) => /^\|\|([\s\S]+?)\|\|/.exec(source),
|
||||||
parse(capture, parse, state) {
|
parse(capture, parse, state) {
|
||||||
return {
|
return {
|
||||||
content: parse(capture[1], state),
|
content: parse(capture[1], state),
|
||||||
|
@ -4,20 +4,20 @@
|
|||||||
<ul class="members-list">
|
<ul class="members-list">
|
||||||
<li v-if="member">
|
<li v-if="member">
|
||||||
<div :class="[{ host: member.id === host }, 'self', 'member']">
|
<div :class="[{ host: member.id === host }, 'self', 'member']">
|
||||||
<img :src="`https://api.adorable.io/avatars/50/${member.username}.png`" />
|
<neko-avatar class="avatar" :seed="member.displayname" :size="50" />
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<template v-for="(member, index) in members">
|
<template v-for="(member, index) in members">
|
||||||
<li
|
<li
|
||||||
v-if="member.id !== id && member.connected"
|
v-if="member.id !== id && member.connected"
|
||||||
:key="index"
|
:key="index"
|
||||||
v-tooltip="{ content: member.username, placement: 'bottom', offset: -15, boundariesElement: 'body' }"
|
v-tooltip="{ content: member.displayname, placement: 'bottom', offset: -15, boundariesElement: 'body' }"
|
||||||
>
|
>
|
||||||
<div :class="[{ host: member.id === host, admin: member.admin }, 'member']">
|
<div
|
||||||
<img
|
:class="[{ host: member.id === host, admin: member.admin }, 'member']"
|
||||||
:src="`https://api.adorable.io/avatars/50/${member.username}.png`"
|
@contextmenu.stop.prevent="onContext($event, { member })"
|
||||||
@contextmenu.stop.prevent="onContext($event, { member })"
|
>
|
||||||
/>
|
<neko-avatar class="avatar" :seed="member.displayname" :size="50" />
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
@ -130,7 +130,7 @@
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
.avatar {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -161,11 +161,13 @@
|
|||||||
import { Member } from '~/neko/types'
|
import { Member } from '~/neko/types'
|
||||||
|
|
||||||
import Content from './context.vue'
|
import Content from './context.vue'
|
||||||
|
import Avatar from './avatar.vue'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
name: 'neko-members',
|
name: 'neko-members',
|
||||||
components: {
|
components: {
|
||||||
'neko-context': Content,
|
'neko-context': Content,
|
||||||
|
'neko-avatar': Avatar,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class extends Vue {
|
export default class extends Vue {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<i
|
<i
|
||||||
class="fas fa-shield-alt"
|
class="fas fa-shield-alt"
|
||||||
v-tooltip="{
|
v-tooltip="{
|
||||||
content: 'You are logged in as an admin',
|
content: $t('admin_loggedin'),
|
||||||
placement: 'right',
|
placement: 'right',
|
||||||
offset: 5,
|
offset: 5,
|
||||||
boundariesElement: 'body',
|
boundariesElement: 'body',
|
||||||
|
@ -2,41 +2,63 @@
|
|||||||
<div class="settings">
|
<div class="settings">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<span>Scroll Sensitivity</span>
|
<span>{{ $t('setting.scroll') }}</span>
|
||||||
<label class="slider">
|
<label class="slider">
|
||||||
<input type="range" min="5" max="100" v-model="scroll" />
|
<input type="range" min="1" max="100" v-model="scroll" />
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span>Invert Scroll</span>
|
<span>{{ $t('setting.scroll_invert') }}</span>
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
<input type="checkbox" v-model="scroll_invert" />
|
<input type="checkbox" v-model="scroll_invert" />
|
||||||
<span />
|
<span />
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span>Autoplay Video</span>
|
<span>{{ $t('setting.autoplay') }}</span>
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
<input type="checkbox" v-model="autoplay" />
|
<input type="checkbox" v-model="autoplay" />
|
||||||
<span />
|
<span />
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span>Ignore Emotes</span>
|
<span>{{ $t('setting.ignore_emotes') }}</span>
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
<input type="checkbox" v-model="ignore_emotes" />
|
<input type="checkbox" v-model="ignore_emotes" />
|
||||||
<span />
|
<span />
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span>Play Chat Sound</span>
|
<span>{{ $t('setting.chat_sound') }}</span>
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
<input type="checkbox" v-model="chat_sound" />
|
<input type="checkbox" v-model="chat_sound" />
|
||||||
<span />
|
<span />
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<span>{{ $t('setting.keyboard_layout') }}</span>
|
||||||
|
<label class="select">
|
||||||
|
<select v-model="keyboard_layout">
|
||||||
|
<option v-for="(name, code) in keyboard_layouts_list" :key="code" :value="code">{{ name }}</option>
|
||||||
|
</select>
|
||||||
|
<span />
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
<template v-if="admin">
|
||||||
|
<li>
|
||||||
|
<span>{{ $t('setting.broadcast_is_active') }}</span>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" v-model="broadcast_is_active" />
|
||||||
|
<span />
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span>{{ $t('setting.broadcast_url') }}</span>
|
||||||
|
<input v-model="broadcast_url" :disabled="broadcast_is_active" class="input">
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
<li v-if="connected">
|
<li v-if="connected">
|
||||||
<button @click.stop.prevent="logout">Logout</button>
|
<button @click.stop.prevent="logout">{{ $t('logout') }}</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -108,7 +130,7 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-color: $background-tertiary;
|
background-color: $background-tertiary;
|
||||||
transition: 0.4s;
|
transition: 0.2s;
|
||||||
border-radius: 34px;
|
border-radius: 34px;
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
@ -182,6 +204,68 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.select {
|
||||||
|
max-width: 120px;
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
select:hover {
|
||||||
|
border: 1px solid $background-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
height: 30px;
|
||||||
|
text-align: right;
|
||||||
|
padding: 0 5px 0 10px;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 30px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 12px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: white;
|
||||||
|
background-color: $background-tertiary;
|
||||||
|
font-weight: lighter;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
option {
|
||||||
|
font-weight: normal;
|
||||||
|
color: $text-normal;
|
||||||
|
background-color: $background-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
display: block;
|
||||||
|
height: 30px;
|
||||||
|
text-align: right;
|
||||||
|
padding: 0 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
line-height: 30px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: white;
|
||||||
|
background-color: $background-tertiary;
|
||||||
|
font-weight: lighter;
|
||||||
|
user-select: auto;
|
||||||
|
|
||||||
|
&::selection {
|
||||||
|
background: $text-normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,6 +276,12 @@
|
|||||||
|
|
||||||
@Component({ name: 'neko-settings' })
|
@Component({ name: 'neko-settings' })
|
||||||
export default class extends Vue {
|
export default class extends Vue {
|
||||||
|
private broadcast_url: string = '';
|
||||||
|
|
||||||
|
get admin() {
|
||||||
|
return this.$accessor.user.admin
|
||||||
|
}
|
||||||
|
|
||||||
get connected() {
|
get connected() {
|
||||||
return this.$accessor.connected
|
return this.$accessor.connected
|
||||||
}
|
}
|
||||||
@ -236,6 +326,40 @@
|
|||||||
this.$accessor.settings.setSound(value)
|
this.$accessor.settings.setSound(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get keyboard_layouts_list() {
|
||||||
|
return this.$accessor.settings.keyboard_layouts_list
|
||||||
|
}
|
||||||
|
|
||||||
|
get keyboard_layout() {
|
||||||
|
return this.$accessor.settings.keyboard_layout
|
||||||
|
}
|
||||||
|
|
||||||
|
get broadcast_is_active() {
|
||||||
|
return this.$accessor.settings.broadcast_is_active
|
||||||
|
}
|
||||||
|
|
||||||
|
set broadcast_is_active(value: boolean) {
|
||||||
|
if (value) {
|
||||||
|
this.$accessor.settings.broadcastCreate(this.broadcast_url)
|
||||||
|
} else {
|
||||||
|
this.$accessor.settings.broadcastDestroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get broadcast_url_remote() {
|
||||||
|
return this.$accessor.settings.broadcast_url
|
||||||
|
}
|
||||||
|
|
||||||
|
@Watch('broadcast_url_remote', { immediate: true })
|
||||||
|
onBroadcastUrlChange() {
|
||||||
|
this.broadcast_url = this.broadcast_url_remote
|
||||||
|
}
|
||||||
|
|
||||||
|
set keyboard_layout(value: string) {
|
||||||
|
this.$accessor.settings.setKeyboardLayout(value)
|
||||||
|
this.$accessor.remote.changeKeyboard()
|
||||||
|
}
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
this.$accessor.logout()
|
this.$accessor.logout()
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li :class="{ active: tab === 'chat' }" @click.stop.prevent="change('chat')">
|
<li :class="{ active: tab === 'chat' }" @click.stop.prevent="change('chat')">
|
||||||
<i class="fas fa-comment-alt" />
|
<i class="fas fa-comment-alt" />
|
||||||
<span>Chat</span>
|
<span>{{ $t('side.chat') }}</span>
|
||||||
</li>
|
</li>
|
||||||
<li :class="{ active: tab === 'settings' }" @click.stop.prevent="change('settings')">
|
<li :class="{ active: tab === 'settings' }" @click.stop.prevent="change('settings')">
|
||||||
<i class="fas fa-sliders-h" />
|
<i class="fas fa-sliders-h" />
|
||||||
<span>Settings</span>
|
<span>{{ $t('side.settings') }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<span><b>n</b>.eko</span>
|
<span><b>n</b>.eko</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="message">
|
<div class="message">
|
||||||
<span>this browser does not support webrtc</span>
|
<span>{{ $t('unsupported') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,19 +20,34 @@
|
|||||||
@mouseup.stop.prevent="onMouseUp"
|
@mouseup.stop.prevent="onMouseUp"
|
||||||
@mouseenter.stop.prevent="onMouseEnter"
|
@mouseenter.stop.prevent="onMouseEnter"
|
||||||
@mouseleave.stop.prevent="onMouseLeave"
|
@mouseleave.stop.prevent="onMouseLeave"
|
||||||
@keydown.stop.prevent="onKeyDown"
|
|
||||||
@keyup.stop.prevent="onKeyUp"
|
|
||||||
/>
|
/>
|
||||||
<div v-if="!playing" class="player-overlay">
|
<div v-if="!playing" class="player-overlay">
|
||||||
<i @click.stop.prevent="toggle" v-if="playable" class="fas fa-play-circle" />
|
<i @click.stop.prevent="toggle" v-if="playable" class="fas fa-play-circle" />
|
||||||
</div>
|
</div>
|
||||||
<div ref="aspect" class="player-aspect" />
|
<div ref="aspect" class="player-aspect" />
|
||||||
</div>
|
</div>
|
||||||
<ul v-if="!fullscreen" class="video-menu">
|
<ul v-if="!fullscreen" class="video-menu top">
|
||||||
<li><i @click.stop.prevent="requestFullscreen" class="fas fa-expand"></i></li>
|
<li><i @click.stop.prevent="requestFullscreen" class="fas fa-expand"></i></li>
|
||||||
<li v-if="admin"><i @click.stop.prevent="onResolution" class="fas fa-desktop"></i></li>
|
<li v-if="admin"><i @click.stop.prevent="onResolution" class="fas fa-desktop"></i></li>
|
||||||
|
<li class="request-control">
|
||||||
|
<i
|
||||||
|
:class="[hosted && !hosting ? 'disabled' : '', !hosted && !hosting ? 'faded' : '', 'fas', 'fa-keyboard']"
|
||||||
|
@click.stop.prevent="toggleControl"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<neko-resolution ref="resolution" />
|
<ul v-if="!fullscreen" class="video-menu bottom">
|
||||||
|
<li v-if="hosting && !clipboard_available"><i @click.stop.prevent="onClipboard" class="fas fa-clipboard"></i></li>
|
||||||
|
<li>
|
||||||
|
<i
|
||||||
|
@click.stop.prevent="requestPictureInPicture"
|
||||||
|
v-tooltip="{ content: 'Picture-in-Picture', placement: 'left', offset: 5, boundariesElement: 'body' }"
|
||||||
|
class="fas fa-external-link-alt"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<neko-resolution ref="resolution" v-if="admin" />
|
||||||
|
<neko-clipboard ref="clipboard" v-if="hosting && !clipboard_available" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -51,7 +66,14 @@
|
|||||||
.video-menu {
|
.video-menu {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
top: 15px;
|
|
||||||
|
&.top {
|
||||||
|
top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bottom {
|
||||||
|
bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
margin: 0 0 10px 0;
|
margin: 0 0 10px 0;
|
||||||
@ -66,6 +88,28 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
color: rgba($color: #fff, $alpha: 0.6);
|
color: rgba($color: #fff, $alpha: 0.6);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.faded {
|
||||||
|
color: rgba($color: $text-normal, $alpha: 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
color: rgba($color: $style-error, $alpha: 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.request-control {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
&.request-control {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,12 +185,16 @@
|
|||||||
|
|
||||||
import Emote from './emote.vue'
|
import Emote from './emote.vue'
|
||||||
import Resolution from './resolution.vue'
|
import Resolution from './resolution.vue'
|
||||||
|
import Clipboard from './clipboard.vue'
|
||||||
|
|
||||||
|
import GuacamoleKeyboard from '~/utils/guacamole-keyboard.ts'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
name: 'neko-video',
|
name: 'neko-video',
|
||||||
components: {
|
components: {
|
||||||
'neko-emote': Emote,
|
'neko-emote': Emote,
|
||||||
'neko-resolution': Resolution,
|
'neko-resolution': Resolution,
|
||||||
|
'neko-clipboard': Clipboard,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class extends Vue {
|
export default class extends Vue {
|
||||||
@ -157,7 +205,9 @@
|
|||||||
@Ref('player') readonly _player!: HTMLElement
|
@Ref('player') readonly _player!: HTMLElement
|
||||||
@Ref('video') readonly _video!: HTMLVideoElement
|
@Ref('video') readonly _video!: HTMLVideoElement
|
||||||
@Ref('resolution') readonly _resolution!: any
|
@Ref('resolution') readonly _resolution!: any
|
||||||
|
@Ref('clipboard') readonly _clipboard!: any
|
||||||
|
|
||||||
|
private keyboard = GuacamoleKeyboard()
|
||||||
private observer = new ResizeObserver(this.onResise.bind(this))
|
private observer = new ResizeObserver(this.onResise.bind(this))
|
||||||
private focused = false
|
private focused = false
|
||||||
private fullscreen = false
|
private fullscreen = false
|
||||||
@ -178,6 +228,10 @@
|
|||||||
return this.$accessor.remote.hosting
|
return this.$accessor.remote.hosting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get hosted() {
|
||||||
|
return this.$accessor.remote.hosted
|
||||||
|
}
|
||||||
|
|
||||||
get volume() {
|
get volume() {
|
||||||
return this.$accessor.video.volume
|
return this.$accessor.video.volume
|
||||||
}
|
}
|
||||||
@ -206,6 +260,10 @@
|
|||||||
return this.$accessor.settings.autoplay
|
return this.$accessor.settings.autoplay
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get locked() {
|
||||||
|
return this.$accessor.remote.locked
|
||||||
|
}
|
||||||
|
|
||||||
get scroll() {
|
get scroll() {
|
||||||
return this.$accessor.settings.scroll
|
return this.$accessor.settings.scroll
|
||||||
}
|
}
|
||||||
@ -214,6 +272,10 @@
|
|||||||
return this.$accessor.settings.scroll_invert
|
return this.$accessor.settings.scroll_invert
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get clipboard_available() {
|
||||||
|
return 'clipboard' in navigator
|
||||||
|
}
|
||||||
|
|
||||||
get clipboard() {
|
get clipboard() {
|
||||||
return this.$accessor.remote.clipboard
|
return this.$accessor.remote.clipboard
|
||||||
}
|
}
|
||||||
@ -240,8 +302,6 @@
|
|||||||
|
|
||||||
@Watch('width')
|
@Watch('width')
|
||||||
onWidthChanged(width: number) {
|
onWidthChanged(width: number) {
|
||||||
const { videoWidth, videoHeight } = this._video
|
|
||||||
console.log({ videoWidth, videoHeight })
|
|
||||||
this.onResise()
|
this.onResise()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +349,7 @@
|
|||||||
|
|
||||||
@Watch('clipboard')
|
@Watch('clipboard')
|
||||||
onClipboardChanged(clipboard: string) {
|
onClipboardChanged(clipboard: string) {
|
||||||
if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
|
if (this.clipboard_available && typeof navigator.clipboard.writeText === 'function') {
|
||||||
navigator.clipboard.writeText(clipboard).catch(console.error)
|
navigator.clipboard.writeText(clipboard).catch(console.error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,6 +370,11 @@
|
|||||||
this._video.addEventListener('canplaythrough', () => {
|
this._video.addEventListener('canplaythrough', () => {
|
||||||
this.$accessor.video.setPlayable(true)
|
this.$accessor.video.setPlayable(true)
|
||||||
if (this.autoplay) {
|
if (this.autoplay) {
|
||||||
|
if (!document.hasFocus() || !this.$accessor.active) {
|
||||||
|
this.$accessor.video.setMuted(true)
|
||||||
|
this._video.muted = true
|
||||||
|
}
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$accessor.video.play()
|
this.$accessor.video.play()
|
||||||
})
|
})
|
||||||
@ -320,18 +385,37 @@
|
|||||||
this.$accessor.video.setPlayable(false)
|
this.$accessor.video.setPlayable(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
this._video.addEventListener('error', event => {
|
this._video.addEventListener('error', (event) => {
|
||||||
console.error(event.error)
|
this.$log.error(event.error)
|
||||||
this.$accessor.video.setPlayable(false)
|
this.$accessor.video.setPlayable(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
document.addEventListener('focusin', this.onFocus.bind(this))
|
document.addEventListener('focusin', this.onFocus.bind(this))
|
||||||
|
|
||||||
|
/* Initialize Guacamole Keyboard */
|
||||||
|
this.keyboard.onkeydown = (key: number) => {
|
||||||
|
if (!this.focused || !this.hosting || this.locked) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$client.sendData('keydown', { key })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
this.keyboard.onkeyup = (key: number) => {
|
||||||
|
if (!this.focused || !this.hosting || this.locked) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$client.sendData('keyup', { key })
|
||||||
|
}
|
||||||
|
this.keyboard.listenTo(this._overlay)
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.observer.disconnect()
|
this.observer.disconnect()
|
||||||
this.$accessor.video.setPlayable(false)
|
this.$accessor.video.setPlayable(false)
|
||||||
document.removeEventListener('focusin', this.onFocus.bind(this))
|
document.removeEventListener('focusin', this.onFocus.bind(this))
|
||||||
|
/* Guacamole Keyboard does not provide destroy functions */
|
||||||
}
|
}
|
||||||
|
|
||||||
play() {
|
play() {
|
||||||
@ -339,12 +423,16 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this._video
|
try {
|
||||||
.play()
|
this._video
|
||||||
.then(() => {
|
.play()
|
||||||
this.onResise()
|
.then(() => {
|
||||||
})
|
this.onResise()
|
||||||
.catch(err => console.log(err))
|
})
|
||||||
|
.catch((err) => this.$log.error)
|
||||||
|
} catch (err) {
|
||||||
|
this.$log.error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pause() {
|
pause() {
|
||||||
@ -367,25 +455,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleControl() {
|
||||||
|
if (!this.playable) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$accessor.remote.toggle()
|
||||||
|
}
|
||||||
|
|
||||||
requestFullscreen() {
|
requestFullscreen() {
|
||||||
this._player.requestFullscreen()
|
this._player.requestFullscreen()
|
||||||
this.onResise()
|
this.onResise()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestPictureInPicture() {
|
||||||
|
//@ts-ignore
|
||||||
|
this._video.requestPictureInPicture()
|
||||||
|
this.onResise()
|
||||||
|
}
|
||||||
|
|
||||||
onFocus() {
|
onFocus() {
|
||||||
if (!document.hasFocus()) {
|
if (!document.hasFocus() || !this.$accessor.active) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hosting && navigator.clipboard && typeof navigator.clipboard.readText === 'function') {
|
if (this.hosting && this.clipboard_available && typeof navigator.clipboard.readText === 'function') {
|
||||||
navigator.clipboard
|
navigator.clipboard
|
||||||
.readText()
|
.readText()
|
||||||
.then(text => {
|
.then((text) => {
|
||||||
if (this.clipboard !== text) {
|
if (this.clipboard !== text) {
|
||||||
|
this.$accessor.remote.setClipboard(text)
|
||||||
this.$accessor.remote.sendClipboard(text)
|
this.$accessor.remote.sendClipboard(text)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(console.error)
|
.catch(this.$log.error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +502,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onWheel(e: WheelEvent) {
|
onWheel(e: WheelEvent) {
|
||||||
if (!this.hosting) {
|
if (!this.hosting || this.locked) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.onMousePos(e)
|
this.onMousePos(e)
|
||||||
@ -419,52 +522,56 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMouseDown(e: MouseEvent) {
|
onMouseDown(e: MouseEvent) {
|
||||||
if (!this.hosting) {
|
if (!this.hosting || this.locked) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.onMousePos(e)
|
this.onMousePos(e)
|
||||||
this.$client.sendData('mousedown', { key: e.button })
|
this.$client.sendData('mousedown', { key: e.button + 1 })
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseUp(e: MouseEvent) {
|
onMouseUp(e: MouseEvent) {
|
||||||
if (!this.hosting) {
|
if (!this.hosting || this.locked) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.onMousePos(e)
|
this.onMousePos(e)
|
||||||
this.$client.sendData('mouseup', { key: e.button })
|
this.$client.sendData('mouseup', { key: e.button + 1 })
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove(e: MouseEvent) {
|
onMouseMove(e: MouseEvent) {
|
||||||
if (!this.hosting) {
|
if (!this.hosting || this.locked) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onMousePos(e)
|
this.onMousePos(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseEnter(e: MouseEvent) {
|
onMouseEnter(e: MouseEvent) {
|
||||||
|
if(this.hosting) {
|
||||||
|
this.$accessor.remote.syncKeyboardModifierState({
|
||||||
|
capsLock: e.getModifierState("CapsLock"),
|
||||||
|
numLock: e.getModifierState("NumLock"),
|
||||||
|
scrollLock: e.getModifierState("ScrollLock"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
this._overlay.focus()
|
this._overlay.focus()
|
||||||
this.onFocus()
|
this.onFocus()
|
||||||
this.focused = true
|
this.focused = true
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseLeave(e: MouseEvent) {
|
onMouseLeave(e: MouseEvent) {
|
||||||
|
if(this.hosting) {
|
||||||
|
this.$accessor.remote.setKeyboardModifierState({
|
||||||
|
capsLock: e.getModifierState("CapsLock"),
|
||||||
|
numLock: e.getModifierState("NumLock"),
|
||||||
|
scrollLock: e.getModifierState("ScrollLock"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.keyboard.reset()
|
||||||
this.focused = false
|
this.focused = false
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown(e: KeyboardEvent) {
|
|
||||||
if (!this.focused || !this.hosting) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.$client.sendData('keydown', { key: e.keyCode })
|
|
||||||
}
|
|
||||||
|
|
||||||
onKeyUp(e: KeyboardEvent) {
|
|
||||||
if (!this.focused || !this.hosting) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.$client.sendData('keyup', { key: e.keyCode })
|
|
||||||
}
|
|
||||||
|
|
||||||
onResise() {
|
onResise() {
|
||||||
let height = 0
|
let height = 0
|
||||||
if (!this.fullscreen) {
|
if (!this.fullscreen) {
|
||||||
@ -484,5 +591,9 @@
|
|||||||
onResolution(event: MouseEvent) {
|
onResolution(event: MouseEvent) {
|
||||||
this._resolution.open(event)
|
this._resolution.open(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onClipboard(event: MouseEvent) {
|
||||||
|
this._clipboard.open(event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
95
client/src/locale/en-us.ts
Normal file
95
client/src/locale/en-us.ts
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
export const logout = 'logout'
|
||||||
|
export const unsupported = 'this browser does not support webrtc'
|
||||||
|
export const admin_loggedin = 'You are logged in as an admin'
|
||||||
|
export const you = 'You'
|
||||||
|
export const send_a_message = 'Send a message'
|
||||||
|
|
||||||
|
export const side = {
|
||||||
|
chat: 'Chat',
|
||||||
|
settings: 'Settings',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const connect = {
|
||||||
|
title: 'Please Login',
|
||||||
|
displayname: 'Display Name',
|
||||||
|
password: 'Password',
|
||||||
|
connect: 'Connect',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const context = {
|
||||||
|
ignore: 'Ignore',
|
||||||
|
unignore: 'Unignore',
|
||||||
|
mute: 'Mute',
|
||||||
|
unmute: 'Unmute',
|
||||||
|
release: 'Force Release Controls',
|
||||||
|
take: 'Force Take Controls',
|
||||||
|
give: 'Give Controls',
|
||||||
|
kick: 'Kick',
|
||||||
|
ban: 'Ban IP',
|
||||||
|
confirm: {
|
||||||
|
kick_title: 'Kick {name}?',
|
||||||
|
kick_text: 'Are you sure you want to kick {name}?',
|
||||||
|
ban_title: 'Ban {name}?',
|
||||||
|
ban_text: 'Are you sure you want to ban {name}? You will need to restart the server to undo this.',
|
||||||
|
mute_title: 'Mute {name}?',
|
||||||
|
mute_text: 'Are you sure you want to mute {name}?',
|
||||||
|
unmute_title: 'Unmute {name}?',
|
||||||
|
unmute_text: 'Are you sure you want to unmute {name}?',
|
||||||
|
button_yes: 'Yes',
|
||||||
|
button_cancel: 'Cancel',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const controls = {
|
||||||
|
release: 'Release Controls',
|
||||||
|
request: 'Request Controls',
|
||||||
|
lock: 'Lock Controls',
|
||||||
|
unlock: 'Unlock Controls',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const room = {
|
||||||
|
lock: 'Lock Room (for users)',
|
||||||
|
unlock: 'Unlock Room (for users)',
|
||||||
|
locked: 'Room Locked (for users)',
|
||||||
|
unlocked: 'Room Unlocked (for users)',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setting = {
|
||||||
|
scroll: 'Scroll Sensitivity',
|
||||||
|
scroll_invert: 'Invert Scroll',
|
||||||
|
autoplay: 'Autoplay Video',
|
||||||
|
ignore_emotes: 'Ignore Emotes',
|
||||||
|
chat_sound: 'Play Chat Sound',
|
||||||
|
keyboard_layout: 'Keyboard Layout',
|
||||||
|
broadcast_is_active: 'Broadcast Enabled',
|
||||||
|
broadcast_url: 'RTMP url',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const connection = {
|
||||||
|
logged_out: 'You have been logged out!',
|
||||||
|
connected: 'Successfully connected',
|
||||||
|
disconnected: 'You have been disconnected',
|
||||||
|
button_confirm: 'Ok',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const notifications = {
|
||||||
|
connected: '{name} connected',
|
||||||
|
disconnected: '{name} disconnected',
|
||||||
|
controls_taken: '{name} took the controls',
|
||||||
|
controls_taken_force: 'force took the controls',
|
||||||
|
controls_taken_steal: 'took the controls from {name}',
|
||||||
|
controls_released: '{name} released the controls',
|
||||||
|
controls_released_force: 'force released the controls',
|
||||||
|
controls_released_steal: 'released the controls from {name}',
|
||||||
|
controls_given: 'gave the controls to {name}',
|
||||||
|
controls_has: '{name} has the controls',
|
||||||
|
controls_has_alt: 'But I let them know you wanted it',
|
||||||
|
controls_requesting: '{name} is requesting the controls',
|
||||||
|
resolution: 'changed the resolution to {width}x{height}@{rate}',
|
||||||
|
banned: 'banned {name}',
|
||||||
|
kicked: 'kicked {name}',
|
||||||
|
muted: 'muted {name}',
|
||||||
|
unmuted: 'unmuted {name}',
|
||||||
|
room_locked: 'locked the room',
|
||||||
|
room_unlocked: 'unlocked the room',
|
||||||
|
}
|
5
client/src/locale/index.ts
Normal file
5
client/src/locale/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import * as en from './en-us'
|
||||||
|
|
||||||
|
export const messages = {
|
||||||
|
en,
|
||||||
|
}
|
@ -10,6 +10,7 @@ import Axios from './plugins/axios'
|
|||||||
import Swal from './plugins/swal'
|
import Swal from './plugins/swal'
|
||||||
import Anime from './plugins/anime'
|
import Anime from './plugins/anime'
|
||||||
|
|
||||||
|
import { i18n } from './plugins/i18n'
|
||||||
import store from './store'
|
import store from './store'
|
||||||
import app from './app.vue'
|
import app from './app.vue'
|
||||||
|
|
||||||
@ -24,9 +25,19 @@ Vue.use(Anime)
|
|||||||
Vue.use(Client)
|
Vue.use(Client)
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
|
i18n,
|
||||||
store,
|
store,
|
||||||
render: h => h(app),
|
render: (h) => h(app),
|
||||||
created() {
|
created() {
|
||||||
|
const click = () => {
|
||||||
|
this.$accessor.setActive()
|
||||||
|
if (this.$accessor.settings.autoplay && this.$accessor.video.playing) {
|
||||||
|
this.$accessor.video.setMuted(false)
|
||||||
|
}
|
||||||
|
window.removeEventListener('click', click, false)
|
||||||
|
}
|
||||||
|
window.addEventListener('click', click, false)
|
||||||
|
|
||||||
this.$client.init(this)
|
this.$client.init(this)
|
||||||
this.$accessor.initialise()
|
this.$accessor.initialise()
|
||||||
},
|
},
|
||||||
|
@ -2,15 +2,7 @@ import EventEmitter from 'eventemitter3'
|
|||||||
import { OPCODE } from './data'
|
import { OPCODE } from './data'
|
||||||
import { EVENT, WebSocketEvents } from './events'
|
import { EVENT, WebSocketEvents } from './events'
|
||||||
|
|
||||||
import {
|
import { WebSocketMessages, WebSocketPayloads, SignalProvidePayload } from './messages'
|
||||||
WebSocketMessages,
|
|
||||||
WebSocketPayloads,
|
|
||||||
IdentityPayload,
|
|
||||||
SignalPayload,
|
|
||||||
MemberListPayload,
|
|
||||||
MemberPayload,
|
|
||||||
ControlPayload,
|
|
||||||
} from './messages'
|
|
||||||
|
|
||||||
export interface BaseEvents {
|
export interface BaseEvents {
|
||||||
info: (...message: any[]) => void
|
info: (...message: any[]) => void
|
||||||
@ -24,8 +16,13 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
protected _peer?: RTCPeerConnection
|
protected _peer?: RTCPeerConnection
|
||||||
protected _channel?: RTCDataChannel
|
protected _channel?: RTCDataChannel
|
||||||
protected _timeout?: NodeJS.Timeout
|
protected _timeout?: NodeJS.Timeout
|
||||||
protected _username?: string
|
protected _displayname?: string
|
||||||
protected _state: RTCIceConnectionState = 'disconnected'
|
protected _state: RTCIceConnectionState = 'disconnected'
|
||||||
|
protected _id = ''
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this._id
|
||||||
|
}
|
||||||
|
|
||||||
get supported() {
|
get supported() {
|
||||||
return typeof RTCPeerConnection !== 'undefined' && typeof RTCPeerConnection.prototype.addTransceiver !== 'undefined'
|
return typeof RTCPeerConnection !== 'undefined' && typeof RTCPeerConnection.prototype.addTransceiver !== 'undefined'
|
||||||
@ -43,7 +40,7 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
return this.peerConnected && this.socketOpen
|
return this.peerConnected && this.socketOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
public connect(url: string, password: string, username: string) {
|
public connect(url: string, password: string, displayname: string) {
|
||||||
if (this.socketOpen) {
|
if (this.socketOpen) {
|
||||||
this.emit('warn', `attempting to create websocket while connection open`)
|
this.emit('warn', `attempting to create websocket while connection open`)
|
||||||
return
|
return
|
||||||
@ -54,11 +51,11 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (username === '') {
|
if (displayname === '') {
|
||||||
throw new Error('Must add a username') // TODO: Better handleing
|
throw new Error('Must add a displayname') // TODO: Better handling
|
||||||
}
|
}
|
||||||
|
|
||||||
this._username = username
|
this._displayname = displayname
|
||||||
this[EVENT.CONNECTING]()
|
this[EVENT.CONNECTING]()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -93,13 +90,15 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._state = 'disconnected'
|
this._state = 'disconnected'
|
||||||
|
this._displayname = undefined
|
||||||
|
this._id = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendData(event: 'wheel' | 'mousemove', data: { x: number; y: number }): void
|
public sendData(event: 'wheel' | 'mousemove', data: { x: number; y: number }): void
|
||||||
public sendData(event: 'mousedown' | 'mouseup' | 'keydown' | 'keyup', data: { key: number }): void
|
public sendData(event: 'mousedown' | 'mouseup' | 'keydown' | 'keyup', data: { key: number }): void
|
||||||
public sendData(event: string, data: any) {
|
public sendData(event: string, data: any) {
|
||||||
if (!this.connected) {
|
if (!this.connected) {
|
||||||
this.emit('warn', `attemping to send data while dissconneted`)
|
this.emit('warn', `attempting to send data while disconnected`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,19 +123,19 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
break
|
break
|
||||||
case 'keydown':
|
case 'keydown':
|
||||||
case 'mousedown':
|
case 'mousedown':
|
||||||
buffer = new ArrayBuffer(5)
|
buffer = new ArrayBuffer(11)
|
||||||
payload = new DataView(buffer)
|
payload = new DataView(buffer)
|
||||||
payload.setUint8(0, OPCODE.KEY_DOWN)
|
payload.setUint8(0, OPCODE.KEY_DOWN)
|
||||||
payload.setUint16(1, 1, true)
|
payload.setUint16(1, 8, true)
|
||||||
payload.setUint16(3, data.key, true)
|
payload.setBigUint64(3, BigInt(data.key), true)
|
||||||
break
|
break
|
||||||
case 'keyup':
|
case 'keyup':
|
||||||
case 'mouseup':
|
case 'mouseup':
|
||||||
buffer = new ArrayBuffer(5)
|
buffer = new ArrayBuffer(11)
|
||||||
payload = new DataView(buffer)
|
payload = new DataView(buffer)
|
||||||
payload.setUint8(0, OPCODE.KEY_UP)
|
payload.setUint8(0, OPCODE.KEY_UP)
|
||||||
payload.setUint16(1, 1, true)
|
payload.setUint16(1, 8, true)
|
||||||
payload.setUint16(3, data.key, true)
|
payload.setBigUint64(3, BigInt(data.key), true)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
this.emit('warn', `unknown data event: ${event}`)
|
this.emit('warn', `unknown data event: ${event}`)
|
||||||
@ -150,14 +149,14 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
|
|
||||||
public sendMessage(event: WebSocketEvents, payload?: WebSocketPayloads) {
|
public sendMessage(event: WebSocketEvents, payload?: WebSocketPayloads) {
|
||||||
if (!this.connected) {
|
if (!this.connected) {
|
||||||
this.emit('warn', `attemping to send message while dissconneted`)
|
this.emit('warn', `attempting to send message while disconnected`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.emit('debug', `sending event '${event}' ${payload ? `with payload: ` : ''}`, payload)
|
this.emit('debug', `sending event '${event}' ${payload ? `with payload: ` : ''}`, payload)
|
||||||
this._ws!.send(JSON.stringify({ event, ...payload }))
|
this._ws!.send(JSON.stringify({ event, ...payload }))
|
||||||
}
|
}
|
||||||
|
|
||||||
public createPeer() {
|
public createPeer(sdp: string, lite: boolean, servers: string[]) {
|
||||||
this.emit('debug', `creating peer`)
|
this.emit('debug', `creating peer`)
|
||||||
if (!this.socketOpen) {
|
if (!this.socketOpen) {
|
||||||
this.emit(
|
this.emit(
|
||||||
@ -174,23 +173,24 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._peer = new RTCPeerConnection()
|
this._peer = new RTCPeerConnection()
|
||||||
|
if (lite !== true) {
|
||||||
|
this._peer = new RTCPeerConnection({
|
||||||
|
iceServers: [{ urls: servers }],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
this._peer.onicecandidate = event => {
|
this._peer.onconnectionstatechange = event => {
|
||||||
if (event.candidate === null && this._peer!.localDescription) {
|
this.emit('debug', `peer connection state changed`, this._peer ? this._peer.connectionState : undefined)
|
||||||
this.emit('debug', `sending event '${EVENT.SIGNAL.PROVIDE}' with payload`, this._peer!.localDescription.sdp)
|
}
|
||||||
this._ws!.send(
|
|
||||||
JSON.stringify({
|
this._peer.onsignalingstatechange = event => {
|
||||||
event: EVENT.SIGNAL.PROVIDE,
|
this.emit('debug', `peer signaling state changed`, this._peer ? this._peer.signalingState : undefined)
|
||||||
sdp: this._peer!.localDescription.sdp,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._peer.oniceconnectionstatechange = event => {
|
this._peer.oniceconnectionstatechange = event => {
|
||||||
this._state = this._peer!.iceConnectionState
|
this._state = this._peer!.iceConnectionState
|
||||||
|
|
||||||
this.emit('debug', `peer ice connection state chagned: ${this._peer!.iceConnectionState}`)
|
this.emit('debug', `peer ice connection state changed: ${this._peer!.iceConnectionState}`)
|
||||||
|
|
||||||
switch (this._state) {
|
switch (this._state) {
|
||||||
case 'checking':
|
case 'checking':
|
||||||
@ -219,41 +219,40 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
this._channel.onmessage = this.onData.bind(this)
|
this._channel.onmessage = this.onData.bind(this)
|
||||||
this._channel.onclose = this.onDisconnected.bind(this, new Error('peer data channel closed'))
|
this._channel.onclose = this.onDisconnected.bind(this, new Error('peer data channel closed'))
|
||||||
|
|
||||||
|
this._peer.setRemoteDescription({ type: 'offer', sdp })
|
||||||
this._peer
|
this._peer
|
||||||
.createOffer()
|
.createAnswer()
|
||||||
.then(d => this._peer!.setLocalDescription(d))
|
.then(d => {
|
||||||
|
this._peer!.setLocalDescription(d)
|
||||||
|
this._ws!.send(
|
||||||
|
JSON.stringify({
|
||||||
|
event: EVENT.SIGNAL.ANSWER,
|
||||||
|
sdp: d.sdp,
|
||||||
|
displayname: this._displayname,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
.catch(err => this.emit('error', err))
|
.catch(err => this.emit('error', err))
|
||||||
}
|
}
|
||||||
|
|
||||||
private setRemoteDescription(payload: SignalPayload) {
|
|
||||||
if (this.peerConnected) {
|
|
||||||
this.emit('warn', `attempting to set remote description while peer connected`, payload)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this._peer!.setRemoteDescription({ type: 'answer', sdp: payload.sdp })
|
|
||||||
}
|
|
||||||
|
|
||||||
private onMessage(e: MessageEvent) {
|
private onMessage(e: MessageEvent) {
|
||||||
const { event, ...payload } = JSON.parse(e.data) as WebSocketMessages
|
const { event, ...payload } = JSON.parse(e.data) as WebSocketMessages
|
||||||
|
|
||||||
this.emit('debug', `received websocket event ${event} ${payload ? `with payload: ` : ''}`, payload)
|
this.emit('debug', `received websocket event ${event} ${payload ? `with payload: ` : ''}`, payload)
|
||||||
|
|
||||||
switch (event) {
|
if (event === EVENT.SIGNAL.PROVIDE) {
|
||||||
case EVENT.IDENTITY.PROVIDE:
|
const { sdp, lite, ice, id } = payload as SignalProvidePayload
|
||||||
this[EVENT.IDENTITY.PROVIDE](payload as IdentityPayload)
|
this._id = id
|
||||||
this.createPeer()
|
this.createPeer(sdp, lite, ice)
|
||||||
break
|
return
|
||||||
case EVENT.SIGNAL.ANSWER:
|
}
|
||||||
this.setRemoteDescription(payload as SignalPayload)
|
|
||||||
break
|
// @ts-ignore
|
||||||
default:
|
if (typeof this[event] === 'function') {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (typeof this[event] === 'function') {
|
this[event](payload)
|
||||||
// @ts-ignore
|
} else {
|
||||||
this[event](payload)
|
this[EVENT.MESSAGE](event, payload)
|
||||||
} else {
|
|
||||||
this[EVENT.MESSAGE](event, payload)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,20 +284,12 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('debug', `sending event '${EVENT.IDENTITY.DETAILS}' with payload`, { username: this._username })
|
|
||||||
this._ws!.send(
|
|
||||||
JSON.stringify({
|
|
||||||
event: EVENT.IDENTITY.DETAILS,
|
|
||||||
username: this._username,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
this.emit('debug', `connected`)
|
this.emit('debug', `connected`)
|
||||||
this[EVENT.CONNECTED]()
|
this[EVENT.CONNECTED]()
|
||||||
}
|
}
|
||||||
|
|
||||||
private onTimeout() {
|
private onTimeout() {
|
||||||
this.emit('debug', `connection timedout`)
|
this.emit('debug', `connection timeout`)
|
||||||
if (this._timeout) {
|
if (this._timeout) {
|
||||||
clearTimeout(this._timeout)
|
clearTimeout(this._timeout)
|
||||||
}
|
}
|
||||||
@ -320,5 +311,4 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
|||||||
protected abstract [EVENT.DISCONNECTED](reason?: Error): void
|
protected abstract [EVENT.DISCONNECTED](reason?: Error): void
|
||||||
protected abstract [EVENT.TRACK](event: RTCTrackEvent): void
|
protected abstract [EVENT.TRACK](event: RTCTrackEvent): void
|
||||||
protected abstract [EVENT.DATA](data: any): void
|
protected abstract [EVENT.DATA](data: any): void
|
||||||
protected abstract [EVENT.IDENTITY.PROVIDE](payload: IdentityPayload): void
|
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,6 @@ export const EVENT = {
|
|||||||
ANSWER: 'signal/answer',
|
ANSWER: 'signal/answer',
|
||||||
PROVIDE: 'signal/provide',
|
PROVIDE: 'signal/provide',
|
||||||
},
|
},
|
||||||
IDENTITY: {
|
|
||||||
PROVIDE: 'identity/provide',
|
|
||||||
DETAILS: 'identity/details',
|
|
||||||
},
|
|
||||||
MEMBER: {
|
MEMBER: {
|
||||||
LIST: 'member/list',
|
LIST: 'member/list',
|
||||||
CONNECTED: 'member/connected',
|
CONNECTED: 'member/connected',
|
||||||
@ -31,6 +27,7 @@ export const EVENT = {
|
|||||||
REQUESTING: 'control/requesting',
|
REQUESTING: 'control/requesting',
|
||||||
CLIPBOARD: 'control/clipboard',
|
CLIPBOARD: 'control/clipboard',
|
||||||
GIVE: 'control/give',
|
GIVE: 'control/give',
|
||||||
|
KEYBOARD: 'control/keyboard',
|
||||||
},
|
},
|
||||||
CHAT: {
|
CHAT: {
|
||||||
MESSAGE: 'chat/message',
|
MESSAGE: 'chat/message',
|
||||||
@ -41,6 +38,11 @@ export const EVENT = {
|
|||||||
RESOLUTION: 'screen/resolution',
|
RESOLUTION: 'screen/resolution',
|
||||||
SET: 'screen/set',
|
SET: 'screen/set',
|
||||||
},
|
},
|
||||||
|
BROADCAST: {
|
||||||
|
STATUS: "broadcast/status",
|
||||||
|
CREATE: "broadcast/create",
|
||||||
|
DESTROY: "broadcast/destroy",
|
||||||
|
},
|
||||||
ADMIN: {
|
ADMIN: {
|
||||||
BAN: 'admin/ban',
|
BAN: 'admin/ban',
|
||||||
KICK: 'admin/kick',
|
KICK: 'admin/kick',
|
||||||
@ -59,11 +61,11 @@ export type Events = typeof EVENT
|
|||||||
export type WebSocketEvents =
|
export type WebSocketEvents =
|
||||||
| SystemEvents
|
| SystemEvents
|
||||||
| ControlEvents
|
| ControlEvents
|
||||||
| IdentityEvents
|
|
||||||
| MemberEvents
|
| MemberEvents
|
||||||
| SignalEvents
|
| SignalEvents
|
||||||
| ChatEvents
|
| ChatEvents
|
||||||
| ScreenEvents
|
| ScreenEvents
|
||||||
|
| BroadcastEvents
|
||||||
| AdminEvents
|
| AdminEvents
|
||||||
|
|
||||||
export type ControlEvents =
|
export type ControlEvents =
|
||||||
@ -72,14 +74,19 @@ export type ControlEvents =
|
|||||||
| typeof EVENT.CONTROL.REQUEST
|
| typeof EVENT.CONTROL.REQUEST
|
||||||
| typeof EVENT.CONTROL.GIVE
|
| typeof EVENT.CONTROL.GIVE
|
||||||
| typeof EVENT.CONTROL.CLIPBOARD
|
| typeof EVENT.CONTROL.CLIPBOARD
|
||||||
|
| typeof EVENT.CONTROL.KEYBOARD
|
||||||
|
|
||||||
export type SystemEvents = typeof EVENT.SYSTEM.DISCONNECT
|
export type SystemEvents = typeof EVENT.SYSTEM.DISCONNECT
|
||||||
export type IdentityEvents = typeof EVENT.IDENTITY.PROVIDE | typeof EVENT.IDENTITY.DETAILS
|
|
||||||
export type MemberEvents = typeof EVENT.MEMBER.LIST | typeof EVENT.MEMBER.CONNECTED | typeof EVENT.MEMBER.DISCONNECTED
|
export type MemberEvents = typeof EVENT.MEMBER.LIST | typeof EVENT.MEMBER.CONNECTED | typeof EVENT.MEMBER.DISCONNECTED
|
||||||
export type SignalEvents = typeof EVENT.SIGNAL.ANSWER | typeof EVENT.SIGNAL.PROVIDE
|
export type SignalEvents = typeof EVENT.SIGNAL.ANSWER | typeof EVENT.SIGNAL.PROVIDE
|
||||||
export type ChatEvents = typeof EVENT.CHAT.MESSAGE | typeof EVENT.CHAT.EMOTE
|
export type ChatEvents = typeof EVENT.CHAT.MESSAGE | typeof EVENT.CHAT.EMOTE
|
||||||
export type ScreenEvents = typeof EVENT.SCREEN.CONFIGURATIONS | typeof EVENT.SCREEN.RESOLUTION | typeof EVENT.SCREEN.SET
|
export type ScreenEvents = typeof EVENT.SCREEN.CONFIGURATIONS | typeof EVENT.SCREEN.RESOLUTION | typeof EVENT.SCREEN.SET
|
||||||
|
|
||||||
|
export type BroadcastEvents =
|
||||||
|
| typeof EVENT.BROADCAST.STATUS
|
||||||
|
| typeof EVENT.BROADCAST.CREATE
|
||||||
|
| typeof EVENT.BROADCAST.DESTROY
|
||||||
|
|
||||||
export type AdminEvents =
|
export type AdminEvents =
|
||||||
| typeof EVENT.ADMIN.BAN
|
| typeof EVENT.ADMIN.BAN
|
||||||
| typeof EVENT.ADMIN.KICK
|
| typeof EVENT.ADMIN.KICK
|
||||||
|
@ -7,7 +7,7 @@ import { accessor } from '~/store'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
DisconnectPayload,
|
DisconnectPayload,
|
||||||
IdentityPayload,
|
SignalProvidePayload,
|
||||||
MemberListPayload,
|
MemberListPayload,
|
||||||
MemberDisconnectPayload,
|
MemberDisconnectPayload,
|
||||||
MemberPayload,
|
MemberPayload,
|
||||||
@ -18,6 +18,7 @@ import {
|
|||||||
ControlClipboardPayload,
|
ControlClipboardPayload,
|
||||||
ScreenConfigurationsPayload,
|
ScreenConfigurationsPayload,
|
||||||
ScreenResolutionPayload,
|
ScreenResolutionPayload,
|
||||||
|
BroadcastStatusPayload,
|
||||||
AdminPayload,
|
AdminPayload,
|
||||||
AdminTargetPayload,
|
AdminTargetPayload,
|
||||||
} from './messages'
|
} from './messages'
|
||||||
@ -28,10 +29,6 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
private $vue!: Vue
|
private $vue!: Vue
|
||||||
private $accessor!: typeof accessor
|
private $accessor!: typeof accessor
|
||||||
|
|
||||||
private get id() {
|
|
||||||
return this.$accessor.user.id
|
|
||||||
}
|
|
||||||
|
|
||||||
init(vue: Vue) {
|
init(vue: Vue) {
|
||||||
this.$vue = vue
|
this.$vue = vue
|
||||||
this.$accessor = vue.$accessor
|
this.$accessor = vue.$accessor
|
||||||
@ -45,22 +42,22 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
this.$accessor.chat.reset()
|
this.$accessor.chat.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
login(password: string, username: string) {
|
login(password: string, displayname: string) {
|
||||||
const url =
|
const url =
|
||||||
process.env.NODE_ENV === 'development'
|
process.env.NODE_ENV === 'development'
|
||||||
? `ws://${location.host.split(':')[0]}:${process.env.VUE_APP_SERVER_PORT}/`
|
? `ws://${location.host.split(':')[0]}:${process.env.VUE_APP_SERVER_PORT}/`
|
||||||
: `${/https/gi.test(location.protocol) ? 'wss' : 'ws'}://${location.host}/`
|
: `${/https/gi.test(location.protocol) ? 'wss' : 'ws'}://${location.host}/`
|
||||||
|
|
||||||
this.connect(url, password, username)
|
this.connect(url, password, displayname)
|
||||||
}
|
}
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
this.disconnect()
|
this.disconnect()
|
||||||
this.cleanup()
|
this.cleanup()
|
||||||
this.$vue.$swal({
|
this.$vue.$swal({
|
||||||
title: 'You have logged out!',
|
title: this.$vue.$t('connection.logged_out'),
|
||||||
icon: 'info',
|
icon: 'info',
|
||||||
confirmButtonText: 'ok',
|
confirmButtonText: this.$vue.$t('connection.button_confirm') as string,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,13 +69,14 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected [EVENT.CONNECTED]() {
|
protected [EVENT.CONNECTED]() {
|
||||||
|
this.$accessor.user.setMember(this.id)
|
||||||
this.$accessor.setConnected(true)
|
this.$accessor.setConnected(true)
|
||||||
this.$accessor.setConnected(true)
|
this.$accessor.setConnected(true)
|
||||||
|
|
||||||
this.$vue.$notify({
|
this.$vue.$notify({
|
||||||
group: 'neko',
|
group: 'neko',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: 'Successfully connected',
|
title: this.$vue.$t('connection.connected') as string,
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
speed: 1000,
|
speed: 1000,
|
||||||
})
|
})
|
||||||
@ -89,7 +87,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
this.$vue.$notify({
|
this.$vue.$notify({
|
||||||
group: 'neko',
|
group: 'neko',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title: `Disconnected:`,
|
title: this.$vue.$t('connection.disconnected') as string,
|
||||||
text: reason ? reason.message : undefined,
|
text: reason ? reason.message : undefined,
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
speed: 1000,
|
speed: 1000,
|
||||||
@ -114,20 +112,13 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
protected [EVENT.SYSTEM.DISCONNECT]({ message }: DisconnectPayload) {
|
protected [EVENT.SYSTEM.DISCONNECT]({ message }: DisconnectPayload) {
|
||||||
this.onDisconnected(new Error(message))
|
this.onDisconnected(new Error(message))
|
||||||
this.$vue.$swal({
|
this.$vue.$swal({
|
||||||
title: 'Disconnected!',
|
title: this.$vue.$t('connection.disconnected'),
|
||||||
text: message,
|
text: message,
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
confirmButtonText: 'ok',
|
confirmButtonText: this.$vue.$t('connection.button_confirm') as string,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////
|
|
||||||
// Identity Events
|
|
||||||
/////////////////////////////
|
|
||||||
protected [EVENT.IDENTITY.PROVIDE]({ id }: IdentityPayload) {
|
|
||||||
this.$accessor.user.setMember(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// Member Events
|
// Member Events
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
@ -135,7 +126,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
this.$accessor.user.setMembers(members)
|
this.$accessor.user.setMembers(members)
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id: this.id,
|
id: this.id,
|
||||||
content: 'connected',
|
content: this.$vue.$t('notifications.connected', { name: '' }) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -147,7 +138,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
if (member.id !== this.id) {
|
if (member.id !== this.id) {
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id: member.id,
|
id: member.id,
|
||||||
content: 'connected',
|
content: this.$vue.$t('notifications.connected', { name: '' }) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -162,7 +153,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id: member.id,
|
id: member.id,
|
||||||
content: 'disconnected',
|
content: this.$vue.$t('notifications.disconnected', { name: '' }) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -175,6 +166,8 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
protected [EVENT.CONTROL.LOCKED]({ id }: ControlPayload) {
|
protected [EVENT.CONTROL.LOCKED]({ id }: ControlPayload) {
|
||||||
this.$accessor.remote.setHost(id)
|
this.$accessor.remote.setHost(id)
|
||||||
|
this.$accessor.remote.changeKeyboard()
|
||||||
|
|
||||||
const member = this.member(id)
|
const member = this.member(id)
|
||||||
if (!member) {
|
if (!member) {
|
||||||
return
|
return
|
||||||
@ -184,7 +177,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
this.$vue.$notify({
|
this.$vue.$notify({
|
||||||
group: 'neko',
|
group: 'neko',
|
||||||
type: 'info',
|
type: 'info',
|
||||||
title: `You have the controls`,
|
title: this.$vue.$t('notifications.controls_taken', { name: this.$vue.$t('you') }) as string,
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
speed: 1000,
|
speed: 1000,
|
||||||
})
|
})
|
||||||
@ -192,7 +185,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id: member.id,
|
id: member.id,
|
||||||
content: 'took the controls',
|
content: this.$vue.$t('notifications.controls_taken', { name: '' }) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -209,7 +202,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
this.$vue.$notify({
|
this.$vue.$notify({
|
||||||
group: 'neko',
|
group: 'neko',
|
||||||
type: 'info',
|
type: 'info',
|
||||||
title: `You released the controls`,
|
title: this.$vue.$t('notifications.controls_released', { name: this.$vue.$t('you') }) as string,
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
speed: 1000,
|
speed: 1000,
|
||||||
})
|
})
|
||||||
@ -217,7 +210,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id: member.id,
|
id: member.id,
|
||||||
content: 'released the controls',
|
content: this.$vue.$t('notifications.controls_released', { name: '' }) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -232,8 +225,8 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
this.$vue.$notify({
|
this.$vue.$notify({
|
||||||
group: 'neko',
|
group: 'neko',
|
||||||
type: 'info',
|
type: 'info',
|
||||||
title: `${member.username} has the controls`,
|
title: this.$vue.$t('notifications.controls_has', { name: member.displayname }) as string,
|
||||||
text: 'But I let them know you wanted it',
|
text: this.$vue.$t('notifications.controls_has_alt') as string,
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
speed: 1000,
|
speed: 1000,
|
||||||
})
|
})
|
||||||
@ -248,7 +241,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
this.$vue.$notify({
|
this.$vue.$notify({
|
||||||
group: 'neko',
|
group: 'neko',
|
||||||
type: 'info',
|
type: 'info',
|
||||||
title: `${member.username} is requesting the controls`,
|
title: this.$vue.$t('notifications.controls_requesting', { name: member.displayname }) as string,
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
speed: 1000,
|
speed: 1000,
|
||||||
})
|
})
|
||||||
@ -261,9 +254,13 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.$accessor.remote.setHost(member)
|
this.$accessor.remote.setHost(member)
|
||||||
|
this.$accessor.remote.changeKeyboard()
|
||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `gave the controls to ${member.id == this.id ? 'you' : member.username}`,
|
content: this.$vue.$t('notifications.controls_given', {
|
||||||
|
name: member.id == this.id ? this.$vue.$t('you') : member.displayname,
|
||||||
|
}) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -320,12 +317,23 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `chaned the resolution to ${width}x${height}@${rate}`,
|
content: this.$vue.$t('notifications.resolution', {
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
rate: rate,
|
||||||
|
}) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////////
|
||||||
|
// Broadcast Events
|
||||||
|
/////////////////////////////
|
||||||
|
protected [EVENT.BROADCAST.STATUS](payload: BroadcastStatusPayload) {
|
||||||
|
this.$accessor.settings.broadcastStatus(payload)
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// Admin Events
|
// Admin Events
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
@ -341,7 +349,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `banned ${member.id == this.id ? 'you' : member.username}`,
|
content: this.$vue.$t('notifications.banned', {
|
||||||
|
name: member.id == this.id ? this.$vue.$t('you') : member.displayname,
|
||||||
|
}) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -359,7 +369,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `kicked ${member.id == this.id ? 'you' : member.username}`,
|
content: this.$vue.$t('notifications.kicked', {
|
||||||
|
name: member.id == this.id ? this.$vue.$t('you') : member.displayname,
|
||||||
|
}) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -379,7 +391,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `muted ${member.id == this.id ? 'you' : member.username}`,
|
content: this.$vue.$t('notifications.muted', {
|
||||||
|
name: member.id == this.id ? this.$vue.$t('you') : member.displayname,
|
||||||
|
}) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -399,7 +413,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `unmuted ${member.username}`,
|
content: this.$vue.$t('notifications.unmuted', {
|
||||||
|
name: member.id == this.id ? this.$vue.$t('you') : member.displayname,
|
||||||
|
}) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -409,7 +425,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
this.$accessor.setLocked(true)
|
this.$accessor.setLocked(true)
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `locked the room`,
|
content: this.$vue.$t('notifications.room_locked') as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -419,7 +435,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
this.$accessor.setLocked(false)
|
this.$accessor.setLocked(false)
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `unlocked the room`,
|
content: this.$vue.$t('notifications.room_unlocked') as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -427,11 +443,12 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
|
|
||||||
protected [EVENT.ADMIN.CONTROL]({ id, target }: AdminTargetPayload) {
|
protected [EVENT.ADMIN.CONTROL]({ id, target }: AdminTargetPayload) {
|
||||||
this.$accessor.remote.setHost(id)
|
this.$accessor.remote.setHost(id)
|
||||||
|
this.$accessor.remote.changeKeyboard()
|
||||||
|
|
||||||
if (!target) {
|
if (!target) {
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `force took the controls`,
|
content: this.$vue.$t('notifications.controls_taken_force') as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -445,7 +462,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `took the controls from ${member.id == this.id ? 'you' : member.username}`,
|
content: this.$vue.$t('notifications.controls_taken_steal', {
|
||||||
|
name: member.id == this.id ? this.$vue.$t('you') : member.displayname,
|
||||||
|
}) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -456,7 +475,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
if (!target) {
|
if (!target) {
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `force released the controls`,
|
content: this.$vue.$t('notifications.controls_released_force') as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -470,7 +489,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `released the controls from ${member.id == this.id ? 'you' : member.username}`,
|
content: this.$vue.$t('notifications.controls_released_steal', {
|
||||||
|
name: member.id == this.id ? this.$vue.$t('you') : member.displayname,
|
||||||
|
}) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
@ -487,10 +508,13 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.$accessor.remote.setHost(member)
|
this.$accessor.remote.setHost(member)
|
||||||
|
this.$accessor.remote.changeKeyboard()
|
||||||
|
|
||||||
this.$accessor.chat.newMessage({
|
this.$accessor.chat.newMessage({
|
||||||
id,
|
id,
|
||||||
content: `gave the controls to ${member.id == this.id ? 'you' : member.username}`,
|
content: this.$vue.$t('notifications.controls_given', {
|
||||||
|
name: member.id == this.id ? this.$vue.$t('you') : member.displayname,
|
||||||
|
}) as string,
|
||||||
type: 'event',
|
type: 'event',
|
||||||
created: new Date(),
|
created: new Date(),
|
||||||
})
|
})
|
||||||
|
@ -3,7 +3,6 @@ import {
|
|||||||
WebSocketEvents,
|
WebSocketEvents,
|
||||||
SystemEvents,
|
SystemEvents,
|
||||||
ControlEvents,
|
ControlEvents,
|
||||||
IdentityEvents,
|
|
||||||
MemberEvents,
|
MemberEvents,
|
||||||
SignalEvents,
|
SignalEvents,
|
||||||
ChatEvents,
|
ChatEvents,
|
||||||
@ -14,29 +13,32 @@ import { Member, ScreenConfigurations, ScreenResolution } from './types'
|
|||||||
|
|
||||||
export type WebSocketMessages =
|
export type WebSocketMessages =
|
||||||
| WebSocketMessage
|
| WebSocketMessage
|
||||||
| IdentityMessage
|
| SignalProvideMessage
|
||||||
| SignalMessage
|
| SignalAnswerMessage
|
||||||
| MemberListMessage
|
| MemberListMessage
|
||||||
| MembeConnectMessage
|
| MemberConnectMessage
|
||||||
| MembeDisconnectMessage
|
| MemberDisconnectMessage
|
||||||
| ControlMessage
|
| ControlMessage
|
||||||
| ScreenResolutionMessage
|
| ScreenResolutionMessage
|
||||||
| ScreenConfigurationsMessage
|
| ScreenConfigurationsMessage
|
||||||
| ChatMessage
|
| ChatMessage
|
||||||
|
|
||||||
export type WebSocketPayloads =
|
export type WebSocketPayloads =
|
||||||
| IdentityPayload
|
| SignalProvidePayload
|
||||||
| SignalPayload
|
| SignalAnswerPayload
|
||||||
| MemberListPayload
|
| MemberListPayload
|
||||||
| Member
|
| Member
|
||||||
| ControlPayload
|
| ControlPayload
|
||||||
| ControlClipboardPayload
|
| ControlClipboardPayload
|
||||||
|
| ControlKeyboardPayload
|
||||||
| ChatPayload
|
| ChatPayload
|
||||||
| ChatSendPayload
|
| ChatSendPayload
|
||||||
| EmojiSendPayload
|
| EmojiSendPayload
|
||||||
| ScreenResolutionPayload
|
| ScreenResolutionPayload
|
||||||
| ScreenConfigurationsPayload
|
| ScreenConfigurationsPayload
|
||||||
| AdminPayload
|
| AdminPayload
|
||||||
|
| BroadcastStatusPayload
|
||||||
|
| BroadcastCreatePayload
|
||||||
|
|
||||||
export interface WebSocketMessage {
|
export interface WebSocketMessage {
|
||||||
event: WebSocketEvents | string
|
event: WebSocketEvents | string
|
||||||
@ -53,26 +55,27 @@ export interface DisconnectPayload {
|
|||||||
message: string
|
message: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
IDENTITY MESSAGES/PAYLOADS
|
|
||||||
*/
|
|
||||||
// identity/provide
|
|
||||||
export interface IdentityMessage extends WebSocketMessage, IdentityPayload {
|
|
||||||
event: typeof EVENT.IDENTITY.PROVIDE
|
|
||||||
}
|
|
||||||
export interface IdentityPayload {
|
|
||||||
id: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SIGNAL MESSAGES/PAYLOADS
|
SIGNAL MESSAGES/PAYLOADS
|
||||||
*/
|
*/
|
||||||
|
// signal/provide
|
||||||
|
export interface SignalProvideMessage extends WebSocketMessage, SignalProvidePayload {
|
||||||
|
event: typeof EVENT.SIGNAL.PROVIDE
|
||||||
|
}
|
||||||
|
export interface SignalProvidePayload {
|
||||||
|
id: string
|
||||||
|
lite: boolean
|
||||||
|
ice: string[]
|
||||||
|
sdp: string
|
||||||
|
}
|
||||||
|
|
||||||
// signal/answer
|
// signal/answer
|
||||||
export interface SignalMessage extends WebSocketMessage, SignalPayload {
|
export interface SignalAnswerMessage extends WebSocketMessage, SignalAnswerPayload {
|
||||||
event: typeof EVENT.SIGNAL.ANSWER
|
event: typeof EVENT.SIGNAL.ANSWER
|
||||||
}
|
}
|
||||||
export interface SignalPayload {
|
export interface SignalAnswerPayload {
|
||||||
sdp: string
|
sdp: string
|
||||||
|
displayname: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -87,13 +90,13 @@ export interface MemberListPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// member/connected
|
// member/connected
|
||||||
export interface MembeConnectMessage extends WebSocketMessage, MemberPayload {
|
export interface MemberConnectMessage extends WebSocketMessage, MemberPayload {
|
||||||
event: typeof EVENT.MEMBER.CONNECTED
|
event: typeof EVENT.MEMBER.CONNECTED
|
||||||
}
|
}
|
||||||
export type MemberPayload = Member
|
export type MemberPayload = Member
|
||||||
|
|
||||||
// member/disconnected
|
// member/disconnected
|
||||||
export interface MembeDisconnectMessage extends WebSocketMessage, MemberPayload {
|
export interface MemberDisconnectMessage extends WebSocketMessage, MemberPayload {
|
||||||
event: typeof EVENT.MEMBER.DISCONNECTED
|
event: typeof EVENT.MEMBER.DISCONNECTED
|
||||||
}
|
}
|
||||||
export interface MemberDisconnectPayload {
|
export interface MemberDisconnectPayload {
|
||||||
@ -120,6 +123,13 @@ export interface ControlClipboardPayload {
|
|||||||
text: string
|
text: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ControlKeyboardPayload {
|
||||||
|
layout?: string
|
||||||
|
capsLock?: boolean
|
||||||
|
numLock?: boolean
|
||||||
|
scrollLock?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
CHAT PAYLOADS
|
CHAT PAYLOADS
|
||||||
*/
|
*/
|
||||||
@ -169,6 +179,18 @@ export interface ScreenConfigurationsPayload {
|
|||||||
configurations: ScreenConfigurations
|
configurations: ScreenConfigurations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
BROADCAST PAYLOADS
|
||||||
|
*/
|
||||||
|
export interface BroadcastCreatePayload {
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BroadcastStatusPayload {
|
||||||
|
url: string
|
||||||
|
isActive: boolean
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ADMIN PAYLOADS
|
ADMIN PAYLOADS
|
||||||
*/
|
*/
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export interface Member {
|
export interface Member {
|
||||||
id: string
|
id: string
|
||||||
username: string
|
displayname: string
|
||||||
admin: boolean
|
admin: boolean
|
||||||
muted: boolean
|
muted: boolean
|
||||||
connected?: boolean
|
connected?: boolean
|
||||||
|
10
client/src/plugins/i18n.ts
Normal file
10
client/src/plugins/i18n.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import VueI18n from 'vue-i18n'
|
||||||
|
import { messages } from '~/locale'
|
||||||
|
|
||||||
|
Vue.use(VueI18n)
|
||||||
|
|
||||||
|
export const i18n = new VueI18n({
|
||||||
|
locale: 'en',
|
||||||
|
messages,
|
||||||
|
})
|
@ -37,7 +37,7 @@ class VueSweetalert2 {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (Object.prototype.hasOwnProperty.call(Swal, methodName) && typeof Swal[methodName] === 'function') {
|
if (Object.prototype.hasOwnProperty.call(Swal, methodName) && typeof Swal[methodName] === 'function') {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
swalFunction[methodName] = (method => {
|
swalFunction[methodName] = ((method) => {
|
||||||
return (...args: any[]) => {
|
return (...args: any[]) => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return Swal[method].apply(Swal, args)
|
return Swal[method].apply(Swal, args)
|
||||||
|
@ -61,7 +61,7 @@ export const actions = actionTree(
|
|||||||
initialise() {
|
initialise() {
|
||||||
$http
|
$http
|
||||||
.get<Emojis>('/emoji.json')
|
.get<Emojis>('/emoji.json')
|
||||||
.then(req => {
|
.then((req) => {
|
||||||
for (const group of req.data.groups) {
|
for (const group of req.data.groups) {
|
||||||
accessor.emoji.addGroup(group)
|
accessor.emoji.addGroup(group)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import { useAccessor, mutationTree, actionTree } from 'typed-vuex'
|
import { useAccessor, mutationTree, actionTree } from 'typed-vuex'
|
||||||
|
import { EVENT } from '~/neko/events'
|
||||||
import { get, set } from '~/utils/localstorage'
|
import { get, set } from '~/utils/localstorage'
|
||||||
|
|
||||||
import * as video from './video'
|
import * as video from './video'
|
||||||
@ -12,16 +13,21 @@ import * as client from './client'
|
|||||||
import * as emoji from './emoji'
|
import * as emoji from './emoji'
|
||||||
|
|
||||||
export const state = () => ({
|
export const state = () => ({
|
||||||
username: get<string>('username', ''),
|
displayname: get<string>('displayname', ''),
|
||||||
password: get<string>('password', ''),
|
password: get<string>('password', ''),
|
||||||
|
active: false,
|
||||||
connecting: false,
|
connecting: false,
|
||||||
connected: false,
|
connected: false,
|
||||||
locked: false,
|
locked: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const mutations = mutationTree(state, {
|
export const mutations = mutationTree(state, {
|
||||||
setLogin(state, { username, password }: { username: string; password: string }) {
|
setActive(state) {
|
||||||
state.username = username
|
state.active = true
|
||||||
|
},
|
||||||
|
|
||||||
|
setLogin(state, { displayname, password }: { displayname: string; password: string }) {
|
||||||
|
state.displayname = displayname
|
||||||
state.password = password
|
state.password = password
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -38,7 +44,7 @@ export const mutations = mutationTree(state, {
|
|||||||
state.connected = connected
|
state.connected = connected
|
||||||
state.connecting = false
|
state.connecting = false
|
||||||
if (connected) {
|
if (connected) {
|
||||||
set('username', state.username)
|
set('displayname', state.displayname)
|
||||||
set('password', state.password)
|
set('password', state.password)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -49,16 +55,33 @@ export const actions = actionTree(
|
|||||||
{
|
{
|
||||||
initialise(store) {
|
initialise(store) {
|
||||||
accessor.emoji.initialise()
|
accessor.emoji.initialise()
|
||||||
|
accessor.settings.initialise()
|
||||||
},
|
},
|
||||||
|
|
||||||
login({ state }, { username, password }: { username: string; password: string }) {
|
lock() {
|
||||||
accessor.setLogin({ username, password })
|
if (!accessor.connected || !accessor.user.admin) {
|
||||||
$client.login(password, username)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$client.sendMessage(EVENT.ADMIN.LOCK)
|
||||||
|
},
|
||||||
|
|
||||||
|
unlock() {
|
||||||
|
if (!accessor.connected || !accessor.user.admin) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$client.sendMessage(EVENT.ADMIN.UNLOCK)
|
||||||
|
},
|
||||||
|
|
||||||
|
login({ state }, { displayname, password }: { displayname: string; password: string }) {
|
||||||
|
accessor.setLogin({ displayname, password })
|
||||||
|
$client.login(password, displayname)
|
||||||
},
|
},
|
||||||
|
|
||||||
logout({ state }) {
|
logout({ state }) {
|
||||||
accessor.setLogin({ username: '', password: '' })
|
accessor.setLogin({ displayname: '', password: '' })
|
||||||
set('username', '')
|
set('displayname', '')
|
||||||
set('password', '')
|
set('password', '')
|
||||||
$client.logout()
|
$client.logout()
|
||||||
},
|
},
|
||||||
|
@ -3,11 +3,18 @@ import { Member } from '~/neko/types'
|
|||||||
import { EVENT } from '~/neko/events'
|
import { EVENT } from '~/neko/events'
|
||||||
import { accessor } from '~/store'
|
import { accessor } from '~/store'
|
||||||
|
|
||||||
|
const keyboardModifierState =
|
||||||
|
(capsLock: boolean, numLock: boolean, scrollLock: boolean) =>
|
||||||
|
Number(capsLock) + 2*Number(numLock) + 4*Number(scrollLock)
|
||||||
|
|
||||||
export const namespaced = true
|
export const namespaced = true
|
||||||
|
|
||||||
export const state = () => ({
|
export const state = () => ({
|
||||||
id: '',
|
id: '',
|
||||||
clipboard: '',
|
clipboard: '',
|
||||||
|
locked: false,
|
||||||
|
|
||||||
|
keyboardModifierState: -1,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getters = getterTree(state, {
|
export const getters = getterTree(state, {
|
||||||
@ -35,9 +42,19 @@ export const mutations = mutationTree(state, {
|
|||||||
state.clipboard = clipboard
|
state.clipboard = clipboard
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setKeyboardModifierState(state, { capsLock, numLock, scrollLock }) {
|
||||||
|
state.keyboardModifierState = keyboardModifierState(capsLock, numLock, scrollLock)
|
||||||
|
},
|
||||||
|
|
||||||
|
setLocked(state, locked: boolean) {
|
||||||
|
state.locked = locked
|
||||||
|
},
|
||||||
|
|
||||||
reset(state) {
|
reset(state) {
|
||||||
state.id = ''
|
state.id = ''
|
||||||
state.clipboard = ''
|
state.clipboard = ''
|
||||||
|
state.locked = false
|
||||||
|
state.keyboardModifierState = -1
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -128,20 +145,21 @@ export const actions = actionTree(
|
|||||||
$client.sendMessage(EVENT.ADMIN.GIVE, { id: member.id })
|
$client.sendMessage(EVENT.ADMIN.GIVE, { id: member.id })
|
||||||
},
|
},
|
||||||
|
|
||||||
lock() {
|
changeKeyboard({ getters }) {
|
||||||
if (!accessor.connected || !accessor.user.admin) {
|
if (!accessor.connected || !getters.hosting) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
$client.sendMessage(EVENT.ADMIN.LOCK)
|
$client.sendMessage(EVENT.CONTROL.KEYBOARD, { layout: accessor.settings.keyboard_layout })
|
||||||
},
|
},
|
||||||
|
|
||||||
unlock() {
|
syncKeyboardModifierState({ state, getters }, { capsLock, numLock, scrollLock }) {
|
||||||
if (!accessor.connected || !accessor.user.admin) {
|
if (state.keyboardModifierState === keyboardModifierState(capsLock, numLock, scrollLock)) {
|
||||||
return
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
$client.sendMessage(EVENT.ADMIN.UNLOCK)
|
accessor.remote.setKeyboardModifierState({ capsLock, numLock, scrollLock })
|
||||||
},
|
$client.sendMessage(EVENT.CONTROL.KEYBOARD, { capsLock, numLock, scrollLock })
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
import { getterTree, mutationTree } from 'typed-vuex'
|
import { getterTree, mutationTree, actionTree } from 'typed-vuex'
|
||||||
import { get, set } from '~/utils/localstorage'
|
import { get, set } from '~/utils/localstorage'
|
||||||
|
import { EVENT } from '~/neko/events'
|
||||||
|
import { accessor } from '~/store'
|
||||||
|
|
||||||
export const namespaced = true
|
export const namespaced = true
|
||||||
|
|
||||||
|
interface KeyboardLayouts {
|
||||||
|
[code: string]: string
|
||||||
|
}
|
||||||
|
|
||||||
export const state = () => {
|
export const state = () => {
|
||||||
return {
|
return {
|
||||||
scroll: get<number>('scroll', 10),
|
scroll: get<number>('scroll', 10),
|
||||||
@ -10,6 +16,12 @@ export const state = () => {
|
|||||||
autoplay: get<boolean>('autoplay', true),
|
autoplay: get<boolean>('autoplay', true),
|
||||||
ignore_emotes: get<boolean>('ignore_emotes', false),
|
ignore_emotes: get<boolean>('ignore_emotes', false),
|
||||||
chat_sound: get<boolean>('chat_sound', true),
|
chat_sound: get<boolean>('chat_sound', true),
|
||||||
|
keyboard_layout: get<string>('keyboard_layout', 'us'),
|
||||||
|
|
||||||
|
keyboard_layouts_list: {} as KeyboardLayouts,
|
||||||
|
|
||||||
|
broadcast_is_active: false,
|
||||||
|
broadcast_url: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,4 +52,42 @@ export const mutations = mutationTree(state, {
|
|||||||
state.chat_sound = value
|
state.chat_sound = value
|
||||||
set('chat_sound', value)
|
set('chat_sound', value)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setKeyboardLayout(state, value: string) {
|
||||||
|
state.keyboard_layout = value
|
||||||
|
set('keyboard_layout', value)
|
||||||
|
},
|
||||||
|
|
||||||
|
setKeyboardLayoutsList(state, value: KeyboardLayouts) {
|
||||||
|
state.keyboard_layouts_list = value
|
||||||
|
},
|
||||||
|
setBroadcastStatus(state, { url, isActive }) {
|
||||||
|
state.broadcast_url = url,
|
||||||
|
state.broadcast_is_active = isActive
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const actions = actionTree(
|
||||||
|
{ state, getters, mutations },
|
||||||
|
{
|
||||||
|
initialise() {
|
||||||
|
$http
|
||||||
|
.get<KeyboardLayouts>('/keyboard_layouts.json')
|
||||||
|
.then((req) => {
|
||||||
|
accessor.settings.setKeyboardLayoutsList(req.data)
|
||||||
|
console.log(req.data)
|
||||||
|
})
|
||||||
|
.catch(console.error)
|
||||||
|
},
|
||||||
|
|
||||||
|
broadcastStatus({ getters }, { url, isActive }) {
|
||||||
|
accessor.settings.setBroadcastStatus({ url, isActive })
|
||||||
|
},
|
||||||
|
broadcastCreate({ getters }, url: string) {
|
||||||
|
$client.sendMessage(EVENT.BROADCAST.CREATE, { url })
|
||||||
|
},
|
||||||
|
broadcastDestroy({ getters }) {
|
||||||
|
$client.sendMessage(EVENT.BROADCAST.DESTROY)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
@ -16,9 +16,9 @@ export const state = () => ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const getters = getterTree(state, {
|
export const getters = getterTree(state, {
|
||||||
member: state => state.members[state.id] || null,
|
member: (state) => state.members[state.id] || null,
|
||||||
admin: state => (state.members[state.id] ? state.members[state.id].admin : false),
|
admin: (state) => (state.members[state.id] ? state.members[state.id].admin : false),
|
||||||
muted: state => (state.members[state.id] ? state.members[state.id].muted : false),
|
muted: (state) => (state.members[state.id] ? state.members[state.id].muted : false),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const mutations = mutationTree(state, {
|
export const mutations = mutationTree(state, {
|
||||||
|
@ -23,9 +23,9 @@ export const state = () => ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const getters = getterTree(state, {
|
export const getters = getterTree(state, {
|
||||||
stream: state => state.streams[state.index],
|
stream: (state) => state.streams[state.index],
|
||||||
track: state => state.tracks[state.index],
|
track: (state) => state.tracks[state.index],
|
||||||
resolution: state => ({ w: state.width, h: state.height }),
|
resolution: (state) => ({ w: state.width, h: state.height }),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const mutations = mutationTree(state, {
|
export const mutations = mutationTree(state, {
|
||||||
@ -47,6 +47,11 @@ export const mutations = mutationTree(state, {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setMuted(state, muted: boolean) {
|
||||||
|
state.muted = muted
|
||||||
|
set('mute', muted)
|
||||||
|
},
|
||||||
|
|
||||||
toggleMute(state) {
|
toggleMute(state) {
|
||||||
state.muted = !state.muted
|
state.muted = !state.muted
|
||||||
set('mute', state.muted)
|
set('mute', state.muted)
|
||||||
|
1515
client/src/utils/guacamole-keyboard.js
Normal file
1515
client/src/utils/guacamole-keyboard.js
Normal file
File diff suppressed because it is too large
Load Diff
76
client/src/utils/guacamole-keyboard.ts
Normal file
76
client/src/utils/guacamole-keyboard.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import GuacamoleKeyboard from './guacamole-keyboard.js'
|
||||||
|
|
||||||
|
export interface GuacamoleKeyboardInterface {
|
||||||
|
/**
|
||||||
|
* Fired whenever the user presses a key with the element associated
|
||||||
|
* with this Guacamole.Keyboard in focus.
|
||||||
|
*
|
||||||
|
* @event
|
||||||
|
* @param {Number} keysym The keysym of the key being pressed.
|
||||||
|
* @return {Boolean} true if the key event should be allowed through to the
|
||||||
|
* browser, false otherwise.
|
||||||
|
*/
|
||||||
|
onkeydown?: (keysym: number) => boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired whenever the user releases a key with the element associated
|
||||||
|
* with this Guacamole.Keyboard in focus.
|
||||||
|
*
|
||||||
|
* @event
|
||||||
|
* @param {Number} keysym The keysym of the key being released.
|
||||||
|
*/
|
||||||
|
onkeyup?: (keysym: number) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a key as pressed, firing the keydown event if registered. Key
|
||||||
|
* repeat for the pressed key will start after a delay if that key is
|
||||||
|
* not a modifier. The return value of this function depends on the
|
||||||
|
* return value of the keydown event handler, if any.
|
||||||
|
*
|
||||||
|
* @param {Number} keysym The keysym of the key to press.
|
||||||
|
* @return {Boolean} true if event should NOT be canceled, false otherwise.
|
||||||
|
*/
|
||||||
|
press: (keysym: number) => boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a key as released, firing the keyup event if registered.
|
||||||
|
*
|
||||||
|
* @param {Number} keysym The keysym of the key to release.
|
||||||
|
*/
|
||||||
|
release: (keysym: number) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Presses and releases the keys necessary to type the given string of
|
||||||
|
* text.
|
||||||
|
*
|
||||||
|
* @param {String} str
|
||||||
|
* The string to type.
|
||||||
|
*/
|
||||||
|
type: (str: string) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the state of this keyboard, releasing all keys, and firing keyup
|
||||||
|
* events for each released key.
|
||||||
|
*/
|
||||||
|
reset: () => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches event listeners to the given Element, automatically translating
|
||||||
|
* received key, input, and composition events into simple keydown/keyup
|
||||||
|
* events signalled through this Guacamole.Keyboard's onkeydown and
|
||||||
|
* onkeyup handlers.
|
||||||
|
*
|
||||||
|
* @param {Element|Document} element
|
||||||
|
* The Element to attach event listeners to for the sake of handling
|
||||||
|
* key or input events.
|
||||||
|
*/
|
||||||
|
listenTo: (element: Element | Document) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function(element?: Element): GuacamoleKeyboardInterface {
|
||||||
|
var Keyboard = {};
|
||||||
|
|
||||||
|
GuacamoleKeyboard.bind(Keyboard, element)();
|
||||||
|
|
||||||
|
return Keyboard as GuacamoleKeyboardInterface;
|
||||||
|
}
|
20
docker-compose.dev.yaml
Normal file
20
docker-compose.dev.yaml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
version: "3.4"
|
||||||
|
services:
|
||||||
|
neko:
|
||||||
|
build: .m1k1o/chromium
|
||||||
|
container_name: neko_chromium
|
||||||
|
restart: always
|
||||||
|
shm_size: "3gb"
|
||||||
|
ports:
|
||||||
|
- "3005:8080"
|
||||||
|
- "52000-52010:52000-52010/udp"
|
||||||
|
cap_add:
|
||||||
|
- SYS_ADMIN
|
||||||
|
environment:
|
||||||
|
DISPLAY: :99.0
|
||||||
|
NEKO_SCREEN: '1920x1080@30'
|
||||||
|
NEKO_PASSWORD: neko
|
||||||
|
NEKO_PASSWORD_ADMIN: admin
|
||||||
|
NEKO_BIND: :8080
|
||||||
|
NEKO_EPR: 52000-52010
|
||||||
|
NEKO_NAT1TO1: 192.168.1.20
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user