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
|
||||
|
||||
#
|
||||
# cluster fuck of packages for neko, node, go and gstreamer
|
||||
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).
|
||||
# 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.
|
||||
ARG USERNAME=neko
|
||||
ARG USER_UID=1000
|
||||
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"
|
||||
|
||||
#
|
||||
# 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_SHA="dev-mode"
|
||||
|
||||
@ -172,24 +21,24 @@ ARG COMMON_SCRIPT_SHA="dev-mode"
|
||||
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; \
|
||||
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; \
|
||||
/bin/bash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID"; \
|
||||
rm /tmp/common-setup.sh; \
|
||||
#
|
||||
# install docker
|
||||
# Install docker
|
||||
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); \
|
||||
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; \
|
||||
#
|
||||
# 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; \
|
||||
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; \
|
||||
chown ${USERNAME}:root /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 )/.."
|
||||
|
||||
build_gst() {
|
||||
if [ ! -d /gst ]; then
|
||||
if [ ! -L /gst || ! -d /gst ]; then
|
||||
sudo rm -rf /gst;
|
||||
sudo mkdir -p /workspace/.build/gst
|
||||
sudo ln -s /workspace/.build/gst /gst
|
||||
sudo chown -R neko /workspace/.build
|
||||
@ -41,47 +42,67 @@ build_gst() {
|
||||
|
||||
build_base() {
|
||||
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; 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; \
|
||||
cd $DIR/.docker/files/firefox; \
|
||||
sudo docker build -f Dockerfile -t nurdism/neko:firefox -t nurdism/neko:latest . ;
|
||||
cd $DIR; sudo docker build -f .docker/files/$1/Dockerfile -t nurdism/neko:latest . ;
|
||||
}
|
||||
|
||||
build_chromium() {
|
||||
build_image() {
|
||||
set -eux; \
|
||||
cd $DIR/.docker/files/chromium; \
|
||||
sudo docker build -f Dockerfile -t nurdism/neko:chromium . ;
|
||||
cd $DIR; sudo docker build -f .docker/files/$1/Dockerfile -t nurdism/neko:$1 . ;
|
||||
}
|
||||
|
||||
build_docker() {
|
||||
build() {
|
||||
if [ ! -d /gst/local ]; then
|
||||
build_gst
|
||||
fi
|
||||
|
||||
if [ $1 != "" ]; then
|
||||
build_image $1
|
||||
else
|
||||
set -eux; \
|
||||
build_image "deps"; \
|
||||
build_image "base"; \
|
||||
build_base; \
|
||||
build_firefox; \
|
||||
build_chromium; \
|
||||
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() {
|
||||
if [ $1 != "" ]; then
|
||||
sudo docker push nurdism/neko:$1
|
||||
else
|
||||
sudo docker push nurdism/neko:deps
|
||||
sudo docker push nurdism/neko:base
|
||||
sudo docker push nurdism/neko:latest
|
||||
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
|
||||
push) build_push ;;
|
||||
docker) build_docker ;;
|
||||
images) build;;
|
||||
image) build $2 ;;
|
||||
push) push $2 ;;
|
||||
latest) build_latest ;;
|
||||
base) build_image "base" ;;
|
||||
deps) build_image "deps" ;;
|
||||
dev) build_image "dev" ;;
|
||||
gst) build_gst ;;
|
||||
*) build_docker ;;
|
||||
esac
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM debian:stretch-slim
|
||||
FROM nurdism/neko:deps
|
||||
|
||||
#
|
||||
# avoid warnings by switching to noninteractive
|
||||
@ -11,8 +11,7 @@ ARG USER_GID=$USER_UID
|
||||
#
|
||||
# install neko dependencies
|
||||
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 libxcb1 libxrandr2 libxv1 libopus0 libvpx4; \
|
||||
apt-get install -y --no-install-recommends wget ca-certificates supervisor; \
|
||||
#
|
||||
# create a non-root user
|
||||
groupadd --gid $USER_GID $USERNAME; \
|
||||
@ -36,41 +35,25 @@ RUN set -eux; apt-get update; \
|
||||
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/
|
||||
|
||||
#
|
||||
# env
|
||||
ENV USER=$USERNAME
|
||||
ENV DISPLAY=:99.0
|
||||
ENV NEKO_PASSWORD=neko
|
||||
ENV NEKO_PASSWORD_ADMIN=admin
|
||||
ENV NEKO_BIND=:8080
|
||||
|
||||
#
|
||||
# copy configuation files
|
||||
COPY .docker/files/dbus /usr/bin/dbus
|
||||
COPY .docker/files/openbox.xml /etc/neko/openbox.xml
|
||||
COPY .docker/files/neko/supervisord.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 config
|
||||
COPY .docker/files/base/supervisord.conf /etc/neko/supervisord.conf
|
||||
COPY .docker/files/base/xorg.conf /etc/neko/xorg.conf
|
||||
COPY .docker/files/base/neko.conf /etc/neko/supervisord/neko.conf
|
||||
|
||||
#
|
||||
# neko files
|
||||
# neko dist
|
||||
COPY client/dist/ /var/www
|
||||
COPY server/bin/neko /usr/bin/neko
|
||||
|
||||
#
|
||||
# neko env
|
||||
ENV NEKO_PASSWORD=neko
|
||||
ENV NEKO_ADMIN=admin
|
||||
ENV NEKO_BIND=:8080
|
||||
|
||||
#
|
||||
# run neko
|
||||
CMD ["/usr/bin/supervisord", "-c", "/etc/neko/supervisord.conf"]
|
@ -9,6 +9,3 @@ stdout_logfile=/var/log/neko/neko.log
|
||||
stdout_logfile_maxbytes=100MB
|
||||
stdout_logfile_backups=10
|
||||
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
|
||||
@ -19,6 +19,7 @@ RUN set -eux; apt-get update; \
|
||||
|
||||
#
|
||||
# copy configuation files
|
||||
COPY supervisord.conf /etc/neko/supervisord/chromium.conf
|
||||
COPY preferences.json /usr/share/chromium/master_preferences
|
||||
COPY policies.json /etc/chromium/policies/managed/policies.json
|
||||
COPY .docker/files/chromium/supervisord.conf /etc/neko/supervisord/chromium.conf
|
||||
COPY .docker/files/chromium/preferences.json /usr/share/chromium/master_preferences
|
||||
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>
|
||||
<!-- 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">
|
||||
<decor>no</decor>
|
||||
<maximized>true</maximized>
|
||||
@ -144,7 +138,7 @@
|
||||
|
||||
use obconf if you want to change these without having to log out
|
||||
and back in -->
|
||||
<number>4</number>
|
||||
<number>1</number>
|
||||
<firstdesk>1</firstdesk>
|
||||
<names>
|
||||
<!-- set names up here if you want to, like this:
|
@ -2,7 +2,7 @@
|
||||
# https://peter.sh/experiments/chromium-command-line-switches/ --no-sandbox
|
||||
[program:chromium]
|
||||
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
|
||||
priority=800
|
||||
user=%(ENV_USER)s
|
||||
@ -10,6 +10,3 @@ stdout_logfile=/var/log/neko/chromium.log
|
||||
stdout_logfile_maxbytes=100MB
|
||||
stdout_logfile_backups=10
|
||||
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
|
||||
@ -16,7 +16,8 @@ RUN set -eux; apt-get update; \
|
||||
|
||||
#
|
||||
# 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 .docker/files/firefox/supervisord.conf /etc/neko/supervisord/firefox.conf
|
||||
COPY .docker/files/firefox/neko.js /usr/lib/firefox-esr/mozilla.cfg
|
||||
COPY .docker/files/firefox/autoconfig.js /usr/lib/firefox-esr/defaults/pref/autoconfig.js
|
||||
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>
|
@ -9,6 +9,3 @@ stdout_logfile=/var/log/neko/firefox-esr.log
|
||||
stdout_logfile_maxbytes=100MB
|
||||
stdout_logfile_backups=10
|
||||
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:
|
||||
DISPLAY: :99.0
|
||||
NEKO_PASSWORD: neko
|
||||
NEKO_ADMIN: admin
|
||||
NEKO_PASSWORD_ADMIN: admin
|
||||
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
|
||||
redirect_stderr=true
|
||||
|
||||
[program:openbox]
|
||||
[program:neko]
|
||||
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
|
||||
priority=300
|
||||
priority=800
|
||||
user=%(ENV_USER)s
|
||||
stdout_logfile=/var/log/neko/openbox.log
|
||||
stdout_logfile=/var/log/neko/neko.log
|
||||
stdout_logfile_maxbytes=100MB
|
||||
stdout_logfile_backups=10
|
||||
redirect_stderr=true
|
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
|
131
README.md
131
README.md
@ -1,5 +1,13 @@
|
||||
<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>
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/github/v/release/nurdism/neko" alt="release">
|
||||
<img src="https://img.shields.io/github/license/nurdism/neko" alt="license">
|
||||
<img src="https://img.shields.io/docker/pulls/nurdism/neko" alt="pulls">
|
||||
<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"/>
|
||||
@ -7,33 +15,106 @@
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
# n.eko
|
||||
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.
|
||||
# n.eko (m1k1o fork)
|
||||
This app uses Web RTC to stream a desktop inside of a docker container. This is fork of https://github.com/nurdism/neko.
|
||||
|
||||
## Features
|
||||
* 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
|
||||
## Differences to original repository.
|
||||
|
||||
## Why n.eko?
|
||||
I like cats 🐱 (`Neko` is the Japanese word for cat), I'm a weeb/nerd
|
||||
### New Features
|
||||
- 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)
|
||||
* [Quick Start](https://n.eko.moe/#/quick-start)
|
||||
* [Configuration](https://n.eko.moe/#/configuration)
|
||||
* [Development](https://n.eko.moe/#/development)
|
||||
* [Client](https://n.eko.moe/#/client)
|
||||
* [Server](https://n.eko.moe/#/server)
|
||||
* [Docker](https://n.eko.moe/#/docker)
|
||||
* [Non Goals](https://n.eko.moe/#/non-goals)
|
||||
* [Contributing](https://n.eko.moe/#/contributing)
|
||||
* [Change logs](https://n.eko.moe/#/change-logs/)
|
||||
* [Technologies](https://n.eko.moe/#/technologies)
|
||||
* [Glossary](https://n.eko.moe/#/glossary)
|
||||
# Getting started & FAQ
|
||||
|
||||
Use following docker images:
|
||||
- `m1k1o/neko:latest` - for Firefox.
|
||||
- `m1k1o/neko:chromium` - for Chromium Ungoogled (needs `--cap-add=SYS_ADMIN`).
|
||||
- `m1k1o/neko:base` - for custom base.
|
||||
|
||||
Networking:
|
||||
- If you want to use n.eko in **external** network, you can omit `NEKO_NAT1TO1`. It will automatically get your Public IP.
|
||||
- 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`)-
|
||||
|
||||
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",
|
||||
"version": "0.1.0",
|
||||
"version": "2.0.0",
|
||||
"description": "Client for neko streaming server",
|
||||
"license": "Apache License 2.0",
|
||||
"author": "Nurdism <https://github.com/nurdism>",
|
||||
@ -19,46 +19,49 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.12.0",
|
||||
"animejs": "^3.1.0",
|
||||
"@fortawesome/fontawesome-free": "^5.14.0",
|
||||
"animejs": "^3.2.0",
|
||||
"axios": "^0.19.1",
|
||||
"date-fns": "^2.9.0",
|
||||
"date-fns": "^2.16.1",
|
||||
"emoji-datasource": "^5.0.1",
|
||||
"emojilib": "^2.4.0",
|
||||
"eventemitter3": "^4.0.0",
|
||||
"eventemitter3": "^4.0.7",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"simple-markdown": "^0.7.2",
|
||||
"sweetalert2": "^9.6.1",
|
||||
"typed-vuex": "^0.1.15",
|
||||
"sweetalert2": "^9.17.2",
|
||||
"typed-vuex": "^0.1.21",
|
||||
"v-tooltip": "^2.0.3",
|
||||
"vue": "^2.6.10",
|
||||
"vue-class-component": "^7.0.2",
|
||||
"vue": "^2.6.12",
|
||||
"vue-class-component": "^7.2.6",
|
||||
"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-property-decorator": "^8.3.0",
|
||||
"vuex": "^3.1.2"
|
||||
"vue-property-decorator": "^8.5.1",
|
||||
"vuex": "^3.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/animejs": "^3.1.0",
|
||||
"@types/node": "^13.7.0",
|
||||
"@types/animejs": "^3.1.2",
|
||||
"@types/node": "^13.13.21",
|
||||
"@types/vue": "^2.0.0",
|
||||
"@types/vue-clickaway": "^2.2.0",
|
||||
"@vue/cli-plugin-babel": "^4.1.0",
|
||||
"@vue/cli-plugin-eslint": "^4.1.0",
|
||||
"@vue/cli-plugin-typescript": "^4.1.0",
|
||||
"@vue/cli-plugin-vuex": "^4.1.0",
|
||||
"@vue/cli-service": "^4.1.0",
|
||||
"@vue/eslint-config-prettier": "^5.0.0",
|
||||
"@vue/eslint-config-typescript": "^4.0.0",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-plugin-prettier": "^3.1.1",
|
||||
"eslint-plugin-vue": "^5.0.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"prettier": "^1.19.1",
|
||||
"@typescript-eslint/eslint-plugin": "^2.34.0",
|
||||
"@typescript-eslint/parser": "^2.34.0",
|
||||
"@vue/cli-plugin-babel": "^4.5.6",
|
||||
"@vue/cli-plugin-eslint": "^4.5.6",
|
||||
"@vue/cli-plugin-typescript": "^4.5.6",
|
||||
"@vue/cli-plugin-vuex": "^4.5.6",
|
||||
"@vue/cli-service": "^4.5.6",
|
||||
"@vue/eslint-config-prettier": "^6.0.0",
|
||||
"@vue/eslint-config-typescript": "^5.1.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"node-sass": "^4.14.1",
|
||||
"prettier": "^2.1.2",
|
||||
"sass-loader": "^8.0.0",
|
||||
"ts-node": "^8.6.2",
|
||||
"typescript": "~3.5.3",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
"ts-node": "^8.10.2",
|
||||
"typescript": "^3.9.7",
|
||||
"vue-template-compiler": "^2.6.12"
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<div id="neko"></div>
|
||||
</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-connect v-if="!connected" />
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -148,18 +148,18 @@
|
||||
this.loading = true
|
||||
this.$http
|
||||
.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', {
|
||||
text: res.data,
|
||||
mode: 'gfm',
|
||||
context: 'github/gollum',
|
||||
})
|
||||
})
|
||||
.then(res => {
|
||||
.then((res) => {
|
||||
this.$accessor.client.setAbout(res.data)
|
||||
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">
|
||||
<li :key="index" class="message" v-if="message.type === 'text'">
|
||||
<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 class="content">
|
||||
<div class="content-head">
|
||||
<span>{{ member(message.id).username }}</span>
|
||||
<span>{{ member(message.id).displayname }}</span>
|
||||
<span class="timestamp">{{ timestamp(message.created) }}</span>
|
||||
</div>
|
||||
<neko-markdown class="content-body" :source="message.content" />
|
||||
@ -24,8 +24,8 @@
|
||||
boundariesElement: 'body',
|
||||
}"
|
||||
>
|
||||
<strong v-if="message.id === id">You</strong>
|
||||
<strong v-else>{{ member(message.id).username }}</strong>
|
||||
<strong v-if="message.id === id">{{ $t('you') }}</strong>
|
||||
<strong v-else>{{ member(message.id).displayname }}</strong>
|
||||
{{ message.content }}
|
||||
</div>
|
||||
</li>
|
||||
@ -35,7 +35,7 @@
|
||||
<div v-if="!muted" class="chat-send">
|
||||
<div class="accent" />
|
||||
<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" />
|
||||
<i class="emoji-menu fas fa-laugh" @click.stop.prevent="onEmoji"></i>
|
||||
</div>
|
||||
@ -106,7 +106,7 @@
|
||||
background: $style-primary;
|
||||
margin: 0px 10px 10px 0px;
|
||||
|
||||
img {
|
||||
.avatar {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@ -329,6 +329,7 @@
|
||||
import Markdown from './markdown'
|
||||
import Content from './context.vue'
|
||||
import Emoji from './emoji.vue'
|
||||
import Avatar from './avatar.vue'
|
||||
|
||||
const length = 512 // max length of message
|
||||
|
||||
@ -338,6 +339,7 @@
|
||||
'neko-markdown': Markdown,
|
||||
'neko-context': Content,
|
||||
'neko-emoji': Emoji,
|
||||
'neko-avatar': Avatar,
|
||||
},
|
||||
})
|
||||
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>
|
||||
</div>
|
||||
<form class="message" v-if="!connecting" @submit.stop.prevent="connect">
|
||||
<span>Please Login</span>
|
||||
<input type="text" placeholder="Username" v-model="username" />
|
||||
<input type="password" placeholder="Password" v-model="password" />
|
||||
<span>{{ $t('connect.title') }}</span>
|
||||
<input type="text" :placeholder="$t('connect.displayname')" v-model="displayname" />
|
||||
<input type="password" :placeholder="$t('connect.password')" v-model="password" />
|
||||
<button type="submit" @click.stop.prevent="login">
|
||||
Connect
|
||||
{{ $t('connect.connect') }}
|
||||
</button>
|
||||
</form>
|
||||
<div class="loader" v-if="connecting">
|
||||
@ -150,12 +150,12 @@
|
||||
|
||||
@Component({ name: 'neko-connect' })
|
||||
export default class extends Vue {
|
||||
private username = ''
|
||||
private displayname = ''
|
||||
private password = ''
|
||||
|
||||
mounted() {
|
||||
if (this.$accessor.username !== '' && this.$accessor.password !== '') {
|
||||
this.$accessor.login({ username: this.$accessor.username, password: this.$accessor.password })
|
||||
if (this.$accessor.displayname !== '' && this.$accessor.password !== '') {
|
||||
this.$accessor.login({ displayname: this.$accessor.displayname, password: this.$accessor.password })
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@
|
||||
}
|
||||
|
||||
login() {
|
||||
this.$accessor.login({ username: this.username, password: this.password })
|
||||
this.$accessor.login({ displayname: this.displayname, password: this.password })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -3,44 +3,46 @@
|
||||
<template slot-scope="child" v-if="child.data">
|
||||
<li class="header">
|
||||
<div class="user">
|
||||
<img :src="`https://api.adorable.io/avatars/25/${child.data.member.username}.png`" />
|
||||
<strong>{{ child.data.member.username }}</strong>
|
||||
<neko-avatar class="avatar" :seed="child.data.member.displayname" :size="25" />
|
||||
<strong>{{ child.data.member.displayname }}</strong>
|
||||
</div>
|
||||
</li>
|
||||
<li class="seperator" />
|
||||
<li>
|
||||
<span @click="ignore(child.data.member)" v-if="!child.data.member.ignored">Ignore</span>
|
||||
<span @click="unignore(child.data.member)" v-else>Unignore</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>{{ $t('context.unignore') }}</span>
|
||||
</li>
|
||||
|
||||
<template v-if="admin">
|
||||
<li>
|
||||
<span @click="mute(child.data.member)" v-if="!child.data.member.muted">Mute</span>
|
||||
<span @click="unmute(child.data.member)" v-else>Unmute</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>{{ $t('context.unmute') }}</span>
|
||||
</li>
|
||||
<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 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>
|
||||
<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>
|
||||
</template>
|
||||
<template v-else>
|
||||
<li v-if="hosting">
|
||||
<span @click="give(child.data.member)">Give Controls</span>
|
||||
<span @click="give(child.data.member)">{{ $t('context.give') }}</span>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<template v-if="admin">
|
||||
<template v-if="admin && !child.data.member.admin">
|
||||
<li class="seperator" />
|
||||
<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>
|
||||
<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>
|
||||
</template>
|
||||
</template>
|
||||
@ -78,7 +80,7 @@
|
||||
align-content: center;
|
||||
padding: 5px 0;
|
||||
|
||||
img {
|
||||
.avatar {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
@ -135,11 +137,13 @@
|
||||
|
||||
// @ts-ignore
|
||||
import { VueContext } from 'vue-context'
|
||||
import Avatar from './avatar.vue'
|
||||
|
||||
@Component({
|
||||
name: 'neko-context',
|
||||
components: {
|
||||
'vue-context': VueContext,
|
||||
'neko-avatar': Avatar,
|
||||
},
|
||||
})
|
||||
export default class extends Vue {
|
||||
@ -163,11 +167,12 @@
|
||||
|
||||
kick(member: Member) {
|
||||
this.$swal({
|
||||
title: `Kick ${member.username}?`,
|
||||
text: `Are you sure you want to kick ${member.username}?`,
|
||||
title: this.$t('context.confirm.kick_title', { name: member.displayname }) as string,
|
||||
text: this.$t('context.confirm.kick_text', { name: member.displayname }) as string,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes',
|
||||
confirmButtonText: this.$t('context.confirm.button_yes') as string,
|
||||
cancelButtonText: this.$t('context.confirm.button_cancel') as string,
|
||||
}).then(({ value }) => {
|
||||
if (value) {
|
||||
this.$accessor.user.kick(member)
|
||||
@ -177,11 +182,12 @@
|
||||
|
||||
ban(member: Member) {
|
||||
this.$swal({
|
||||
title: `Ban ${member.username}?`,
|
||||
text: `Are you sure you want to ban ${member.username}? You will need to restart the server to undo this.`,
|
||||
title: this.$t('context.confirm.ban_title', { name: member.displayname }) as string,
|
||||
text: this.$t('context.confirm.ban_text', { name: member.displayname }) as string,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes',
|
||||
confirmButtonText: this.$t('context.confirm.button_yes') as string,
|
||||
cancelButtonText: this.$t('context.confirm.button_cancel') as string,
|
||||
}).then(({ value }) => {
|
||||
if (value) {
|
||||
this.$accessor.user.ban(member)
|
||||
@ -191,11 +197,12 @@
|
||||
|
||||
mute(member: Member) {
|
||||
this.$swal({
|
||||
title: `Mute ${member.username}?`,
|
||||
text: `Are you sure you want to mute ${member.username}?`,
|
||||
title: this.$t('context.confirm.mute_title', { name: member.displayname }) as string,
|
||||
text: this.$t('context.confirm.mute_text', { name: member.displayname }) as string,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes',
|
||||
confirmButtonText: this.$t('context.confirm.button_yes') as string,
|
||||
cancelButtonText: this.$t('context.confirm.button_cancel') as string,
|
||||
}).then(({ value }) => {
|
||||
if (value) {
|
||||
this.$accessor.user.mute(member)
|
||||
@ -205,11 +212,12 @@
|
||||
|
||||
unmute(member: Member) {
|
||||
this.$swal({
|
||||
title: `Unmute ${member.username}?`,
|
||||
text: `Are you sure you want to unmute ${member.username}?`,
|
||||
title: this.$t('context.confirm.unmute_title', { name: member.displayname }) as string,
|
||||
text: this.$t('context.confirm.unmute_text', { name: member.displayname }) as string,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes',
|
||||
confirmButtonText: this.$t('context.confirm.button_yes') as string,
|
||||
cancelButtonText: this.$t('context.confirm.button_cancel') as string,
|
||||
}).then(({ value }) => {
|
||||
if (value) {
|
||||
this.$accessor.user.unmute(member)
|
||||
|
@ -9,9 +9,31 @@
|
||||
'fa-keyboard',
|
||||
'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"
|
||||
/>
|
||||
</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>
|
||||
<i
|
||||
:class="[{ disabled: !playable }, playing ? 'fa-pause-circle' : 'fa-play-circle', 'fas', 'play']"
|
||||
@ -43,7 +65,7 @@
|
||||
cursor: pointer;
|
||||
|
||||
i {
|
||||
padding: 0 10px;
|
||||
padding: 0 5px;
|
||||
|
||||
&.faded {
|
||||
color: rgba($color: $text-normal, $alpha: 0.4);
|
||||
@ -66,7 +88,7 @@
|
||||
input[type='range'] {
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
width: 200px;
|
||||
width: 150px;
|
||||
height: 20px;
|
||||
-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>
|
||||
@ -149,6 +234,14 @@
|
||||
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() {
|
||||
if (!this.playable) {
|
||||
return
|
||||
|
@ -329,7 +329,7 @@
|
||||
for (const emoji of this.list) {
|
||||
if (
|
||||
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
|
||||
) {
|
||||
filtered.push(emoji)
|
||||
|
@ -150,7 +150,7 @@
|
||||
'cold',
|
||||
'blush',
|
||||
'sad',
|
||||
].filter(v => !this.recent.includes(v))
|
||||
].filter((v) => !this.recent.includes(v))
|
||||
}
|
||||
|
||||
get muted() {
|
||||
|
@ -9,6 +9,19 @@
|
||||
<i
|
||||
:class="[{ disabled: !admin }, { 'fa-lock-open': !locked }, { 'fa-lock': locked }, 'fas', 'lock']"
|
||||
@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>
|
||||
@ -106,9 +119,9 @@
|
||||
toggleLock() {
|
||||
if (this.admin) {
|
||||
if (this.locked) {
|
||||
this.$accessor.remote.unlock()
|
||||
this.$accessor.unlock()
|
||||
} else {
|
||||
this.$accessor.remote.lock()
|
||||
this.$accessor.lock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ function htmlTag(
|
||||
if (attributes.class && state.cssModuleNames) {
|
||||
attributes.class = attributes.class
|
||||
.split(' ')
|
||||
.map(cl => state.cssModuleNames[cl] || cl)
|
||||
.map((cl) => state.cssModuleNames[cl] || cl)
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
@ -199,7 +199,7 @@ const rules: MarkdownRules = {
|
||||
},
|
||||
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) {
|
||||
if (state.escapeHTML) {
|
||||
return md.sanitizeText(node.content)
|
||||
@ -214,7 +214,7 @@ const rules: MarkdownRules = {
|
||||
},
|
||||
emoji: {
|
||||
order: md.defaultRules.strong.order,
|
||||
match: source => /^:([a-zA-z_-]*):/.exec(source),
|
||||
match: (source) => /^:([a-zA-z_-]*):/.exec(source),
|
||||
parse(capture) {
|
||||
return {
|
||||
id: capture[1],
|
||||
@ -235,7 +235,7 @@ const rules: MarkdownRules = {
|
||||
},
|
||||
emoticon: {
|
||||
order: md.defaultRules.text.order,
|
||||
match: source => /^(¯\\_\(ツ\)_\/¯)/.exec(source),
|
||||
match: (source) => /^(¯\\_\(ツ\)_\/¯)/.exec(source),
|
||||
parse(capture) {
|
||||
return {
|
||||
type: 'text',
|
||||
@ -248,7 +248,7 @@ const rules: MarkdownRules = {
|
||||
},
|
||||
spoiler: {
|
||||
order: 0,
|
||||
match: source => /^\|\|([\s\S]+?)\|\|/.exec(source),
|
||||
match: (source) => /^\|\|([\s\S]+?)\|\|/.exec(source),
|
||||
parse(capture, parse, state) {
|
||||
return {
|
||||
content: parse(capture[1], state),
|
||||
|
@ -4,20 +4,20 @@
|
||||
<ul class="members-list">
|
||||
<li v-if="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>
|
||||
</li>
|
||||
<template v-for="(member, index) in members">
|
||||
<li
|
||||
v-if="member.id !== id && member.connected"
|
||||
: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']">
|
||||
<img
|
||||
:src="`https://api.adorable.io/avatars/50/${member.username}.png`"
|
||||
<div
|
||||
:class="[{ host: member.id === host, admin: member.admin }, 'member']"
|
||||
@contextmenu.stop.prevent="onContext($event, { member })"
|
||||
/>
|
||||
>
|
||||
<neko-avatar class="avatar" :seed="member.displayname" :size="50" />
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
@ -130,7 +130,7 @@
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
img {
|
||||
.avatar {
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
@ -161,11 +161,13 @@
|
||||
import { Member } from '~/neko/types'
|
||||
|
||||
import Content from './context.vue'
|
||||
import Avatar from './avatar.vue'
|
||||
|
||||
@Component({
|
||||
name: 'neko-members',
|
||||
components: {
|
||||
'neko-context': Content,
|
||||
'neko-avatar': Avatar,
|
||||
},
|
||||
})
|
||||
export default class extends Vue {
|
||||
|
@ -5,7 +5,7 @@
|
||||
<i
|
||||
class="fas fa-shield-alt"
|
||||
v-tooltip="{
|
||||
content: 'You are logged in as an admin',
|
||||
content: $t('admin_loggedin'),
|
||||
placement: 'right',
|
||||
offset: 5,
|
||||
boundariesElement: 'body',
|
||||
|
@ -2,41 +2,63 @@
|
||||
<div class="settings">
|
||||
<ul>
|
||||
<li>
|
||||
<span>Scroll Sensitivity</span>
|
||||
<span>{{ $t('setting.scroll') }}</span>
|
||||
<label class="slider">
|
||||
<input type="range" min="5" max="100" v-model="scroll" />
|
||||
<input type="range" min="1" max="100" v-model="scroll" />
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<span>Invert Scroll</span>
|
||||
<span>{{ $t('setting.scroll_invert') }}</span>
|
||||
<label class="switch">
|
||||
<input type="checkbox" v-model="scroll_invert" />
|
||||
<span />
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<span>Autoplay Video</span>
|
||||
<span>{{ $t('setting.autoplay') }}</span>
|
||||
<label class="switch">
|
||||
<input type="checkbox" v-model="autoplay" />
|
||||
<span />
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<span>Ignore Emotes</span>
|
||||
<span>{{ $t('setting.ignore_emotes') }}</span>
|
||||
<label class="switch">
|
||||
<input type="checkbox" v-model="ignore_emotes" />
|
||||
<span />
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<span>Play Chat Sound</span>
|
||||
<span>{{ $t('setting.chat_sound') }}</span>
|
||||
<label class="switch">
|
||||
<input type="checkbox" v-model="chat_sound" />
|
||||
<span />
|
||||
</label>
|
||||
</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">
|
||||
<button @click.stop.prevent="logout">Logout</button>
|
||||
<button @click.stop.prevent="logout">{{ $t('logout') }}</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -108,7 +130,7 @@
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: $background-tertiary;
|
||||
transition: 0.4s;
|
||||
transition: 0.2s;
|
||||
border-radius: 34px;
|
||||
|
||||
&: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' })
|
||||
export default class extends Vue {
|
||||
private broadcast_url: string = '';
|
||||
|
||||
get admin() {
|
||||
return this.$accessor.user.admin
|
||||
}
|
||||
|
||||
get connected() {
|
||||
return this.$accessor.connected
|
||||
}
|
||||
@ -236,6 +326,40 @@
|
||||
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() {
|
||||
this.$accessor.logout()
|
||||
}
|
||||
|
@ -4,11 +4,11 @@
|
||||
<ul>
|
||||
<li :class="{ active: tab === 'chat' }" @click.stop.prevent="change('chat')">
|
||||
<i class="fas fa-comment-alt" />
|
||||
<span>Chat</span>
|
||||
<span>{{ $t('side.chat') }}</span>
|
||||
</li>
|
||||
<li :class="{ active: tab === 'settings' }" @click.stop.prevent="change('settings')">
|
||||
<i class="fas fa-sliders-h" />
|
||||
<span>Settings</span>
|
||||
<span>{{ $t('side.settings') }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<span><b>n</b>.eko</span>
|
||||
</div>
|
||||
<div class="message">
|
||||
<span>this browser does not support webrtc</span>
|
||||
<span>{{ $t('unsupported') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -20,19 +20,34 @@
|
||||
@mouseup.stop.prevent="onMouseUp"
|
||||
@mouseenter.stop.prevent="onMouseEnter"
|
||||
@mouseleave.stop.prevent="onMouseLeave"
|
||||
@keydown.stop.prevent="onKeyDown"
|
||||
@keyup.stop.prevent="onKeyUp"
|
||||
/>
|
||||
<div v-if="!playing" class="player-overlay">
|
||||
<i @click.stop.prevent="toggle" v-if="playable" class="fas fa-play-circle" />
|
||||
</div>
|
||||
<div ref="aspect" class="player-aspect" />
|
||||
</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 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>
|
||||
<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>
|
||||
</template>
|
||||
@ -51,7 +66,14 @@
|
||||
.video-menu {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
|
||||
&.top {
|
||||
top: 15px;
|
||||
}
|
||||
|
||||
&.bottom {
|
||||
bottom: 15px;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 0 0 10px 0;
|
||||
@ -66,6 +88,28 @@
|
||||
text-align: center;
|
||||
color: rgba($color: #fff, $alpha: 0.6);
|
||||
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 Resolution from './resolution.vue'
|
||||
import Clipboard from './clipboard.vue'
|
||||
|
||||
import GuacamoleKeyboard from '~/utils/guacamole-keyboard.ts'
|
||||
|
||||
@Component({
|
||||
name: 'neko-video',
|
||||
components: {
|
||||
'neko-emote': Emote,
|
||||
'neko-resolution': Resolution,
|
||||
'neko-clipboard': Clipboard,
|
||||
},
|
||||
})
|
||||
export default class extends Vue {
|
||||
@ -157,7 +205,9 @@
|
||||
@Ref('player') readonly _player!: HTMLElement
|
||||
@Ref('video') readonly _video!: HTMLVideoElement
|
||||
@Ref('resolution') readonly _resolution!: any
|
||||
@Ref('clipboard') readonly _clipboard!: any
|
||||
|
||||
private keyboard = GuacamoleKeyboard()
|
||||
private observer = new ResizeObserver(this.onResise.bind(this))
|
||||
private focused = false
|
||||
private fullscreen = false
|
||||
@ -178,6 +228,10 @@
|
||||
return this.$accessor.remote.hosting
|
||||
}
|
||||
|
||||
get hosted() {
|
||||
return this.$accessor.remote.hosted
|
||||
}
|
||||
|
||||
get volume() {
|
||||
return this.$accessor.video.volume
|
||||
}
|
||||
@ -206,6 +260,10 @@
|
||||
return this.$accessor.settings.autoplay
|
||||
}
|
||||
|
||||
get locked() {
|
||||
return this.$accessor.remote.locked
|
||||
}
|
||||
|
||||
get scroll() {
|
||||
return this.$accessor.settings.scroll
|
||||
}
|
||||
@ -214,6 +272,10 @@
|
||||
return this.$accessor.settings.scroll_invert
|
||||
}
|
||||
|
||||
get clipboard_available() {
|
||||
return 'clipboard' in navigator
|
||||
}
|
||||
|
||||
get clipboard() {
|
||||
return this.$accessor.remote.clipboard
|
||||
}
|
||||
@ -240,8 +302,6 @@
|
||||
|
||||
@Watch('width')
|
||||
onWidthChanged(width: number) {
|
||||
const { videoWidth, videoHeight } = this._video
|
||||
console.log({ videoWidth, videoHeight })
|
||||
this.onResise()
|
||||
}
|
||||
|
||||
@ -289,7 +349,7 @@
|
||||
|
||||
@Watch('clipboard')
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -310,6 +370,11 @@
|
||||
this._video.addEventListener('canplaythrough', () => {
|
||||
this.$accessor.video.setPlayable(true)
|
||||
if (this.autoplay) {
|
||||
if (!document.hasFocus() || !this.$accessor.active) {
|
||||
this.$accessor.video.setMuted(true)
|
||||
this._video.muted = true
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$accessor.video.play()
|
||||
})
|
||||
@ -320,18 +385,37 @@
|
||||
this.$accessor.video.setPlayable(false)
|
||||
})
|
||||
|
||||
this._video.addEventListener('error', event => {
|
||||
console.error(event.error)
|
||||
this._video.addEventListener('error', (event) => {
|
||||
this.$log.error(event.error)
|
||||
this.$accessor.video.setPlayable(false)
|
||||
})
|
||||
|
||||
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() {
|
||||
this.observer.disconnect()
|
||||
this.$accessor.video.setPlayable(false)
|
||||
document.removeEventListener('focusin', this.onFocus.bind(this))
|
||||
/* Guacamole Keyboard does not provide destroy functions */
|
||||
}
|
||||
|
||||
play() {
|
||||
@ -339,12 +423,16 @@
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
this._video
|
||||
.play()
|
||||
.then(() => {
|
||||
this.onResise()
|
||||
})
|
||||
.catch(err => console.log(err))
|
||||
.catch((err) => this.$log.error)
|
||||
} catch (err) {
|
||||
this.$log.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
pause() {
|
||||
@ -367,25 +455,40 @@
|
||||
}
|
||||
}
|
||||
|
||||
toggleControl() {
|
||||
if (!this.playable) {
|
||||
return
|
||||
}
|
||||
|
||||
this.$accessor.remote.toggle()
|
||||
}
|
||||
|
||||
requestFullscreen() {
|
||||
this._player.requestFullscreen()
|
||||
this.onResise()
|
||||
}
|
||||
|
||||
requestPictureInPicture() {
|
||||
//@ts-ignore
|
||||
this._video.requestPictureInPicture()
|
||||
this.onResise()
|
||||
}
|
||||
|
||||
onFocus() {
|
||||
if (!document.hasFocus()) {
|
||||
if (!document.hasFocus() || !this.$accessor.active) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.hosting && navigator.clipboard && typeof navigator.clipboard.readText === 'function') {
|
||||
if (this.hosting && this.clipboard_available && typeof navigator.clipboard.readText === 'function') {
|
||||
navigator.clipboard
|
||||
.readText()
|
||||
.then(text => {
|
||||
.then((text) => {
|
||||
if (this.clipboard !== text) {
|
||||
this.$accessor.remote.setClipboard(text)
|
||||
this.$accessor.remote.sendClipboard(text)
|
||||
}
|
||||
})
|
||||
.catch(console.error)
|
||||
.catch(this.$log.error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,7 +502,7 @@
|
||||
}
|
||||
|
||||
onWheel(e: WheelEvent) {
|
||||
if (!this.hosting) {
|
||||
if (!this.hosting || this.locked) {
|
||||
return
|
||||
}
|
||||
this.onMousePos(e)
|
||||
@ -419,52 +522,56 @@
|
||||
}
|
||||
|
||||
onMouseDown(e: MouseEvent) {
|
||||
if (!this.hosting) {
|
||||
if (!this.hosting || this.locked) {
|
||||
return
|
||||
}
|
||||
this.onMousePos(e)
|
||||
this.$client.sendData('mousedown', { key: e.button })
|
||||
this.$client.sendData('mousedown', { key: e.button + 1 })
|
||||
}
|
||||
|
||||
onMouseUp(e: MouseEvent) {
|
||||
if (!this.hosting) {
|
||||
if (!this.hosting || this.locked) {
|
||||
return
|
||||
}
|
||||
this.onMousePos(e)
|
||||
this.$client.sendData('mouseup', { key: e.button })
|
||||
this.$client.sendData('mouseup', { key: e.button + 1 })
|
||||
}
|
||||
|
||||
onMouseMove(e: MouseEvent) {
|
||||
if (!this.hosting) {
|
||||
if (!this.hosting || this.locked) {
|
||||
return
|
||||
}
|
||||
|
||||
this.onMousePos(e)
|
||||
}
|
||||
|
||||
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.onFocus()
|
||||
this.focused = true
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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() {
|
||||
let height = 0
|
||||
if (!this.fullscreen) {
|
||||
@ -484,5 +591,9 @@
|
||||
onResolution(event: MouseEvent) {
|
||||
this._resolution.open(event)
|
||||
}
|
||||
|
||||
onClipboard(event: MouseEvent) {
|
||||
this._clipboard.open(event)
|
||||
}
|
||||
}
|
||||
</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 Anime from './plugins/anime'
|
||||
|
||||
import { i18n } from './plugins/i18n'
|
||||
import store from './store'
|
||||
import app from './app.vue'
|
||||
|
||||
@ -24,9 +25,19 @@ Vue.use(Anime)
|
||||
Vue.use(Client)
|
||||
|
||||
new Vue({
|
||||
i18n,
|
||||
store,
|
||||
render: h => h(app),
|
||||
render: (h) => h(app),
|
||||
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.$accessor.initialise()
|
||||
},
|
||||
|
@ -2,15 +2,7 @@ import EventEmitter from 'eventemitter3'
|
||||
import { OPCODE } from './data'
|
||||
import { EVENT, WebSocketEvents } from './events'
|
||||
|
||||
import {
|
||||
WebSocketMessages,
|
||||
WebSocketPayloads,
|
||||
IdentityPayload,
|
||||
SignalPayload,
|
||||
MemberListPayload,
|
||||
MemberPayload,
|
||||
ControlPayload,
|
||||
} from './messages'
|
||||
import { WebSocketMessages, WebSocketPayloads, SignalProvidePayload } from './messages'
|
||||
|
||||
export interface BaseEvents {
|
||||
info: (...message: any[]) => void
|
||||
@ -24,8 +16,13 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
protected _peer?: RTCPeerConnection
|
||||
protected _channel?: RTCDataChannel
|
||||
protected _timeout?: NodeJS.Timeout
|
||||
protected _username?: string
|
||||
protected _displayname?: string
|
||||
protected _state: RTCIceConnectionState = 'disconnected'
|
||||
protected _id = ''
|
||||
|
||||
get id() {
|
||||
return this._id
|
||||
}
|
||||
|
||||
get supported() {
|
||||
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
|
||||
}
|
||||
|
||||
public connect(url: string, password: string, username: string) {
|
||||
public connect(url: string, password: string, displayname: string) {
|
||||
if (this.socketOpen) {
|
||||
this.emit('warn', `attempting to create websocket while connection open`)
|
||||
return
|
||||
@ -54,11 +51,11 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
return
|
||||
}
|
||||
|
||||
if (username === '') {
|
||||
throw new Error('Must add a username') // TODO: Better handleing
|
||||
if (displayname === '') {
|
||||
throw new Error('Must add a displayname') // TODO: Better handling
|
||||
}
|
||||
|
||||
this._username = username
|
||||
this._displayname = displayname
|
||||
this[EVENT.CONNECTING]()
|
||||
|
||||
try {
|
||||
@ -93,13 +90,15 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
}
|
||||
|
||||
this._state = 'disconnected'
|
||||
this._displayname = undefined
|
||||
this._id = ''
|
||||
}
|
||||
|
||||
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: string, data: any) {
|
||||
if (!this.connected) {
|
||||
this.emit('warn', `attemping to send data while dissconneted`)
|
||||
this.emit('warn', `attempting to send data while disconnected`)
|
||||
return
|
||||
}
|
||||
|
||||
@ -124,19 +123,19 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
break
|
||||
case 'keydown':
|
||||
case 'mousedown':
|
||||
buffer = new ArrayBuffer(5)
|
||||
buffer = new ArrayBuffer(11)
|
||||
payload = new DataView(buffer)
|
||||
payload.setUint8(0, OPCODE.KEY_DOWN)
|
||||
payload.setUint16(1, 1, true)
|
||||
payload.setUint16(3, data.key, true)
|
||||
payload.setUint16(1, 8, true)
|
||||
payload.setBigUint64(3, BigInt(data.key), true)
|
||||
break
|
||||
case 'keyup':
|
||||
case 'mouseup':
|
||||
buffer = new ArrayBuffer(5)
|
||||
buffer = new ArrayBuffer(11)
|
||||
payload = new DataView(buffer)
|
||||
payload.setUint8(0, OPCODE.KEY_UP)
|
||||
payload.setUint16(1, 1, true)
|
||||
payload.setUint16(3, data.key, true)
|
||||
payload.setUint16(1, 8, true)
|
||||
payload.setBigUint64(3, BigInt(data.key), true)
|
||||
break
|
||||
default:
|
||||
this.emit('warn', `unknown data event: ${event}`)
|
||||
@ -150,14 +149,14 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
|
||||
public sendMessage(event: WebSocketEvents, payload?: WebSocketPayloads) {
|
||||
if (!this.connected) {
|
||||
this.emit('warn', `attemping to send message while dissconneted`)
|
||||
this.emit('warn', `attempting to send message while disconnected`)
|
||||
return
|
||||
}
|
||||
this.emit('debug', `sending event '${event}' ${payload ? `with payload: ` : ''}`, payload)
|
||||
this._ws!.send(JSON.stringify({ event, ...payload }))
|
||||
}
|
||||
|
||||
public createPeer() {
|
||||
public createPeer(sdp: string, lite: boolean, servers: string[]) {
|
||||
this.emit('debug', `creating peer`)
|
||||
if (!this.socketOpen) {
|
||||
this.emit(
|
||||
@ -174,23 +173,24 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
}
|
||||
|
||||
this._peer = new RTCPeerConnection()
|
||||
|
||||
this._peer.onicecandidate = event => {
|
||||
if (event.candidate === null && this._peer!.localDescription) {
|
||||
this.emit('debug', `sending event '${EVENT.SIGNAL.PROVIDE}' with payload`, this._peer!.localDescription.sdp)
|
||||
this._ws!.send(
|
||||
JSON.stringify({
|
||||
event: EVENT.SIGNAL.PROVIDE,
|
||||
sdp: this._peer!.localDescription.sdp,
|
||||
}),
|
||||
)
|
||||
if (lite !== true) {
|
||||
this._peer = new RTCPeerConnection({
|
||||
iceServers: [{ urls: servers }],
|
||||
})
|
||||
}
|
||||
|
||||
this._peer.onconnectionstatechange = event => {
|
||||
this.emit('debug', `peer connection state changed`, this._peer ? this._peer.connectionState : undefined)
|
||||
}
|
||||
|
||||
this._peer.onsignalingstatechange = event => {
|
||||
this.emit('debug', `peer signaling state changed`, this._peer ? this._peer.signalingState : undefined)
|
||||
}
|
||||
|
||||
this._peer.oniceconnectionstatechange = event => {
|
||||
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) {
|
||||
case 'checking':
|
||||
@ -219,34 +219,34 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
this._channel.onmessage = this.onData.bind(this)
|
||||
this._channel.onclose = this.onDisconnected.bind(this, new Error('peer data channel closed'))
|
||||
|
||||
this._peer.setRemoteDescription({ type: 'offer', sdp })
|
||||
this._peer
|
||||
.createOffer()
|
||||
.then(d => this._peer!.setLocalDescription(d))
|
||||
.createAnswer()
|
||||
.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))
|
||||
}
|
||||
|
||||
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) {
|
||||
const { event, ...payload } = JSON.parse(e.data) as WebSocketMessages
|
||||
|
||||
this.emit('debug', `received websocket event ${event} ${payload ? `with payload: ` : ''}`, payload)
|
||||
|
||||
switch (event) {
|
||||
case EVENT.IDENTITY.PROVIDE:
|
||||
this[EVENT.IDENTITY.PROVIDE](payload as IdentityPayload)
|
||||
this.createPeer()
|
||||
break
|
||||
case EVENT.SIGNAL.ANSWER:
|
||||
this.setRemoteDescription(payload as SignalPayload)
|
||||
break
|
||||
default:
|
||||
if (event === EVENT.SIGNAL.PROVIDE) {
|
||||
const { sdp, lite, ice, id } = payload as SignalProvidePayload
|
||||
this._id = id
|
||||
this.createPeer(sdp, lite, ice)
|
||||
return
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
if (typeof this[event] === 'function') {
|
||||
// @ts-ignore
|
||||
@ -255,7 +255,6 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
this[EVENT.MESSAGE](event, payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onData(e: MessageEvent) {
|
||||
this[EVENT.DATA](e.data)
|
||||
@ -285,20 +284,12 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
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[EVENT.CONNECTED]()
|
||||
}
|
||||
|
||||
private onTimeout() {
|
||||
this.emit('debug', `connection timedout`)
|
||||
this.emit('debug', `connection timeout`)
|
||||
if (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.TRACK](event: RTCTrackEvent): 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',
|
||||
PROVIDE: 'signal/provide',
|
||||
},
|
||||
IDENTITY: {
|
||||
PROVIDE: 'identity/provide',
|
||||
DETAILS: 'identity/details',
|
||||
},
|
||||
MEMBER: {
|
||||
LIST: 'member/list',
|
||||
CONNECTED: 'member/connected',
|
||||
@ -31,6 +27,7 @@ export const EVENT = {
|
||||
REQUESTING: 'control/requesting',
|
||||
CLIPBOARD: 'control/clipboard',
|
||||
GIVE: 'control/give',
|
||||
KEYBOARD: 'control/keyboard',
|
||||
},
|
||||
CHAT: {
|
||||
MESSAGE: 'chat/message',
|
||||
@ -41,6 +38,11 @@ export const EVENT = {
|
||||
RESOLUTION: 'screen/resolution',
|
||||
SET: 'screen/set',
|
||||
},
|
||||
BROADCAST: {
|
||||
STATUS: "broadcast/status",
|
||||
CREATE: "broadcast/create",
|
||||
DESTROY: "broadcast/destroy",
|
||||
},
|
||||
ADMIN: {
|
||||
BAN: 'admin/ban',
|
||||
KICK: 'admin/kick',
|
||||
@ -59,11 +61,11 @@ export type Events = typeof EVENT
|
||||
export type WebSocketEvents =
|
||||
| SystemEvents
|
||||
| ControlEvents
|
||||
| IdentityEvents
|
||||
| MemberEvents
|
||||
| SignalEvents
|
||||
| ChatEvents
|
||||
| ScreenEvents
|
||||
| BroadcastEvents
|
||||
| AdminEvents
|
||||
|
||||
export type ControlEvents =
|
||||
@ -72,14 +74,19 @@ export type ControlEvents =
|
||||
| typeof EVENT.CONTROL.REQUEST
|
||||
| typeof EVENT.CONTROL.GIVE
|
||||
| typeof EVENT.CONTROL.CLIPBOARD
|
||||
| typeof EVENT.CONTROL.KEYBOARD
|
||||
|
||||
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 SignalEvents = typeof EVENT.SIGNAL.ANSWER | typeof EVENT.SIGNAL.PROVIDE
|
||||
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 BroadcastEvents =
|
||||
| typeof EVENT.BROADCAST.STATUS
|
||||
| typeof EVENT.BROADCAST.CREATE
|
||||
| typeof EVENT.BROADCAST.DESTROY
|
||||
|
||||
export type AdminEvents =
|
||||
| typeof EVENT.ADMIN.BAN
|
||||
| typeof EVENT.ADMIN.KICK
|
||||
|
@ -7,7 +7,7 @@ import { accessor } from '~/store'
|
||||
|
||||
import {
|
||||
DisconnectPayload,
|
||||
IdentityPayload,
|
||||
SignalProvidePayload,
|
||||
MemberListPayload,
|
||||
MemberDisconnectPayload,
|
||||
MemberPayload,
|
||||
@ -18,6 +18,7 @@ import {
|
||||
ControlClipboardPayload,
|
||||
ScreenConfigurationsPayload,
|
||||
ScreenResolutionPayload,
|
||||
BroadcastStatusPayload,
|
||||
AdminPayload,
|
||||
AdminTargetPayload,
|
||||
} from './messages'
|
||||
@ -28,10 +29,6 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
private $vue!: Vue
|
||||
private $accessor!: typeof accessor
|
||||
|
||||
private get id() {
|
||||
return this.$accessor.user.id
|
||||
}
|
||||
|
||||
init(vue: Vue) {
|
||||
this.$vue = vue
|
||||
this.$accessor = vue.$accessor
|
||||
@ -45,22 +42,22 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
this.$accessor.chat.reset()
|
||||
}
|
||||
|
||||
login(password: string, username: string) {
|
||||
login(password: string, displayname: string) {
|
||||
const url =
|
||||
process.env.NODE_ENV === 'development'
|
||||
? `ws://${location.host.split(':')[0]}:${process.env.VUE_APP_SERVER_PORT}/`
|
||||
: `${/https/gi.test(location.protocol) ? 'wss' : 'ws'}://${location.host}/`
|
||||
|
||||
this.connect(url, password, username)
|
||||
this.connect(url, password, displayname)
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.disconnect()
|
||||
this.cleanup()
|
||||
this.$vue.$swal({
|
||||
title: 'You have logged out!',
|
||||
title: this.$vue.$t('connection.logged_out'),
|
||||
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]() {
|
||||
this.$accessor.user.setMember(this.id)
|
||||
this.$accessor.setConnected(true)
|
||||
this.$accessor.setConnected(true)
|
||||
|
||||
this.$vue.$notify({
|
||||
group: 'neko',
|
||||
type: 'success',
|
||||
title: 'Successfully connected',
|
||||
title: this.$vue.$t('connection.connected') as string,
|
||||
duration: 5000,
|
||||
speed: 1000,
|
||||
})
|
||||
@ -89,7 +87,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
this.$vue.$notify({
|
||||
group: 'neko',
|
||||
type: 'error',
|
||||
title: `Disconnected:`,
|
||||
title: this.$vue.$t('connection.disconnected') as string,
|
||||
text: reason ? reason.message : undefined,
|
||||
duration: 5000,
|
||||
speed: 1000,
|
||||
@ -114,20 +112,13 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
protected [EVENT.SYSTEM.DISCONNECT]({ message }: DisconnectPayload) {
|
||||
this.onDisconnected(new Error(message))
|
||||
this.$vue.$swal({
|
||||
title: 'Disconnected!',
|
||||
title: this.$vue.$t('connection.disconnected'),
|
||||
text: message,
|
||||
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
|
||||
/////////////////////////////
|
||||
@ -135,7 +126,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
this.$accessor.user.setMembers(members)
|
||||
this.$accessor.chat.newMessage({
|
||||
id: this.id,
|
||||
content: 'connected',
|
||||
content: this.$vue.$t('notifications.connected', { name: '' }) as string,
|
||||
type: 'event',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -147,7 +138,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
if (member.id !== this.id) {
|
||||
this.$accessor.chat.newMessage({
|
||||
id: member.id,
|
||||
content: 'connected',
|
||||
content: this.$vue.$t('notifications.connected', { name: '' }) as string,
|
||||
type: 'event',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -162,7 +153,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
id: member.id,
|
||||
content: 'disconnected',
|
||||
content: this.$vue.$t('notifications.disconnected', { name: '' }) as string,
|
||||
type: 'event',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -175,6 +166,8 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
/////////////////////////////
|
||||
protected [EVENT.CONTROL.LOCKED]({ id }: ControlPayload) {
|
||||
this.$accessor.remote.setHost(id)
|
||||
this.$accessor.remote.changeKeyboard()
|
||||
|
||||
const member = this.member(id)
|
||||
if (!member) {
|
||||
return
|
||||
@ -184,7 +177,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
this.$vue.$notify({
|
||||
group: 'neko',
|
||||
type: 'info',
|
||||
title: `You have the controls`,
|
||||
title: this.$vue.$t('notifications.controls_taken', { name: this.$vue.$t('you') }) as string,
|
||||
duration: 5000,
|
||||
speed: 1000,
|
||||
})
|
||||
@ -192,7 +185,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
id: member.id,
|
||||
content: 'took the controls',
|
||||
content: this.$vue.$t('notifications.controls_taken', { name: '' }) as string,
|
||||
type: 'event',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -209,7 +202,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
this.$vue.$notify({
|
||||
group: 'neko',
|
||||
type: 'info',
|
||||
title: `You released the controls`,
|
||||
title: this.$vue.$t('notifications.controls_released', { name: this.$vue.$t('you') }) as string,
|
||||
duration: 5000,
|
||||
speed: 1000,
|
||||
})
|
||||
@ -217,7 +210,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
id: member.id,
|
||||
content: 'released the controls',
|
||||
content: this.$vue.$t('notifications.controls_released', { name: '' }) as string,
|
||||
type: 'event',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -232,8 +225,8 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
this.$vue.$notify({
|
||||
group: 'neko',
|
||||
type: 'info',
|
||||
title: `${member.username} has the controls`,
|
||||
text: 'But I let them know you wanted it',
|
||||
title: this.$vue.$t('notifications.controls_has', { name: member.displayname }) as string,
|
||||
text: this.$vue.$t('notifications.controls_has_alt') as string,
|
||||
duration: 5000,
|
||||
speed: 1000,
|
||||
})
|
||||
@ -248,7 +241,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
this.$vue.$notify({
|
||||
group: 'neko',
|
||||
type: 'info',
|
||||
title: `${member.username} is requesting the controls`,
|
||||
title: this.$vue.$t('notifications.controls_requesting', { name: member.displayname }) as string,
|
||||
duration: 5000,
|
||||
speed: 1000,
|
||||
})
|
||||
@ -261,9 +254,13 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
}
|
||||
|
||||
this.$accessor.remote.setHost(member)
|
||||
this.$accessor.remote.changeKeyboard()
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
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',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -320,12 +317,23 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
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',
|
||||
created: new Date(),
|
||||
})
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// Broadcast Events
|
||||
/////////////////////////////
|
||||
protected [EVENT.BROADCAST.STATUS](payload: BroadcastStatusPayload) {
|
||||
this.$accessor.settings.broadcastStatus(payload)
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// Admin Events
|
||||
/////////////////////////////
|
||||
@ -341,7 +349,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
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',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -359,7 +369,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
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',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -379,7 +391,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
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',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -399,7 +413,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
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',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -409,7 +425,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
this.$accessor.setLocked(true)
|
||||
this.$accessor.chat.newMessage({
|
||||
id,
|
||||
content: `locked the room`,
|
||||
content: this.$vue.$t('notifications.room_locked') as string,
|
||||
type: 'event',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -419,7 +435,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
this.$accessor.setLocked(false)
|
||||
this.$accessor.chat.newMessage({
|
||||
id,
|
||||
content: `unlocked the room`,
|
||||
content: this.$vue.$t('notifications.room_unlocked') as string,
|
||||
type: 'event',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -427,11 +443,12 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
protected [EVENT.ADMIN.CONTROL]({ id, target }: AdminTargetPayload) {
|
||||
this.$accessor.remote.setHost(id)
|
||||
this.$accessor.remote.changeKeyboard()
|
||||
|
||||
if (!target) {
|
||||
this.$accessor.chat.newMessage({
|
||||
id,
|
||||
content: `force took the controls`,
|
||||
content: this.$vue.$t('notifications.controls_taken_force') as string,
|
||||
type: 'event',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -445,7 +462,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
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',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -456,7 +475,7 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
if (!target) {
|
||||
this.$accessor.chat.newMessage({
|
||||
id,
|
||||
content: `force released the controls`,
|
||||
content: this.$vue.$t('notifications.controls_released_force') as string,
|
||||
type: 'event',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -470,7 +489,9 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
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',
|
||||
created: new Date(),
|
||||
})
|
||||
@ -487,10 +508,13 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
|
||||
}
|
||||
|
||||
this.$accessor.remote.setHost(member)
|
||||
this.$accessor.remote.changeKeyboard()
|
||||
|
||||
this.$accessor.chat.newMessage({
|
||||
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',
|
||||
created: new Date(),
|
||||
})
|
||||
|
@ -3,7 +3,6 @@ import {
|
||||
WebSocketEvents,
|
||||
SystemEvents,
|
||||
ControlEvents,
|
||||
IdentityEvents,
|
||||
MemberEvents,
|
||||
SignalEvents,
|
||||
ChatEvents,
|
||||
@ -14,29 +13,32 @@ import { Member, ScreenConfigurations, ScreenResolution } from './types'
|
||||
|
||||
export type WebSocketMessages =
|
||||
| WebSocketMessage
|
||||
| IdentityMessage
|
||||
| SignalMessage
|
||||
| SignalProvideMessage
|
||||
| SignalAnswerMessage
|
||||
| MemberListMessage
|
||||
| MembeConnectMessage
|
||||
| MembeDisconnectMessage
|
||||
| MemberConnectMessage
|
||||
| MemberDisconnectMessage
|
||||
| ControlMessage
|
||||
| ScreenResolutionMessage
|
||||
| ScreenConfigurationsMessage
|
||||
| ChatMessage
|
||||
|
||||
export type WebSocketPayloads =
|
||||
| IdentityPayload
|
||||
| SignalPayload
|
||||
| SignalProvidePayload
|
||||
| SignalAnswerPayload
|
||||
| MemberListPayload
|
||||
| Member
|
||||
| ControlPayload
|
||||
| ControlClipboardPayload
|
||||
| ControlKeyboardPayload
|
||||
| ChatPayload
|
||||
| ChatSendPayload
|
||||
| EmojiSendPayload
|
||||
| ScreenResolutionPayload
|
||||
| ScreenConfigurationsPayload
|
||||
| AdminPayload
|
||||
| BroadcastStatusPayload
|
||||
| BroadcastCreatePayload
|
||||
|
||||
export interface WebSocketMessage {
|
||||
event: WebSocketEvents | string
|
||||
@ -53,26 +55,27 @@ export interface DisconnectPayload {
|
||||
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/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
|
||||
export interface SignalMessage extends WebSocketMessage, SignalPayload {
|
||||
export interface SignalAnswerMessage extends WebSocketMessage, SignalAnswerPayload {
|
||||
event: typeof EVENT.SIGNAL.ANSWER
|
||||
}
|
||||
export interface SignalPayload {
|
||||
export interface SignalAnswerPayload {
|
||||
sdp: string
|
||||
displayname: string
|
||||
}
|
||||
|
||||
/*
|
||||
@ -87,13 +90,13 @@ export interface MemberListPayload {
|
||||
}
|
||||
|
||||
// member/connected
|
||||
export interface MembeConnectMessage extends WebSocketMessage, MemberPayload {
|
||||
export interface MemberConnectMessage extends WebSocketMessage, MemberPayload {
|
||||
event: typeof EVENT.MEMBER.CONNECTED
|
||||
}
|
||||
export type MemberPayload = Member
|
||||
|
||||
// member/disconnected
|
||||
export interface MembeDisconnectMessage extends WebSocketMessage, MemberPayload {
|
||||
export interface MemberDisconnectMessage extends WebSocketMessage, MemberPayload {
|
||||
event: typeof EVENT.MEMBER.DISCONNECTED
|
||||
}
|
||||
export interface MemberDisconnectPayload {
|
||||
@ -120,6 +123,13 @@ export interface ControlClipboardPayload {
|
||||
text: string
|
||||
}
|
||||
|
||||
export interface ControlKeyboardPayload {
|
||||
layout?: string
|
||||
capsLock?: boolean
|
||||
numLock?: boolean
|
||||
scrollLock?: boolean
|
||||
}
|
||||
|
||||
/*
|
||||
CHAT PAYLOADS
|
||||
*/
|
||||
@ -169,6 +179,18 @@ export interface ScreenConfigurationsPayload {
|
||||
configurations: ScreenConfigurations
|
||||
}
|
||||
|
||||
/*
|
||||
BROADCAST PAYLOADS
|
||||
*/
|
||||
export interface BroadcastCreatePayload {
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface BroadcastStatusPayload {
|
||||
url: string
|
||||
isActive: boolean
|
||||
}
|
||||
|
||||
/*
|
||||
ADMIN PAYLOADS
|
||||
*/
|
||||
|
@ -1,6 +1,6 @@
|
||||
export interface Member {
|
||||
id: string
|
||||
username: string
|
||||
displayname: string
|
||||
admin: boolean
|
||||
muted: 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
|
||||
if (Object.prototype.hasOwnProperty.call(Swal, methodName) && typeof Swal[methodName] === 'function') {
|
||||
// @ts-ignore
|
||||
swalFunction[methodName] = (method => {
|
||||
swalFunction[methodName] = ((method) => {
|
||||
return (...args: any[]) => {
|
||||
// @ts-ignore
|
||||
return Swal[method].apply(Swal, args)
|
||||
|
@ -61,7 +61,7 @@ export const actions = actionTree(
|
||||
initialise() {
|
||||
$http
|
||||
.get<Emojis>('/emoji.json')
|
||||
.then(req => {
|
||||
.then((req) => {
|
||||
for (const group of req.data.groups) {
|
||||
accessor.emoji.addGroup(group)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import { useAccessor, mutationTree, actionTree } from 'typed-vuex'
|
||||
import { EVENT } from '~/neko/events'
|
||||
import { get, set } from '~/utils/localstorage'
|
||||
|
||||
import * as video from './video'
|
||||
@ -12,16 +13,21 @@ import * as client from './client'
|
||||
import * as emoji from './emoji'
|
||||
|
||||
export const state = () => ({
|
||||
username: get<string>('username', ''),
|
||||
displayname: get<string>('displayname', ''),
|
||||
password: get<string>('password', ''),
|
||||
active: false,
|
||||
connecting: false,
|
||||
connected: false,
|
||||
locked: false,
|
||||
})
|
||||
|
||||
export const mutations = mutationTree(state, {
|
||||
setLogin(state, { username, password }: { username: string; password: string }) {
|
||||
state.username = username
|
||||
setActive(state) {
|
||||
state.active = true
|
||||
},
|
||||
|
||||
setLogin(state, { displayname, password }: { displayname: string; password: string }) {
|
||||
state.displayname = displayname
|
||||
state.password = password
|
||||
},
|
||||
|
||||
@ -38,7 +44,7 @@ export const mutations = mutationTree(state, {
|
||||
state.connected = connected
|
||||
state.connecting = false
|
||||
if (connected) {
|
||||
set('username', state.username)
|
||||
set('displayname', state.displayname)
|
||||
set('password', state.password)
|
||||
}
|
||||
},
|
||||
@ -49,16 +55,33 @@ export const actions = actionTree(
|
||||
{
|
||||
initialise(store) {
|
||||
accessor.emoji.initialise()
|
||||
accessor.settings.initialise()
|
||||
},
|
||||
|
||||
login({ state }, { username, password }: { username: string; password: string }) {
|
||||
accessor.setLogin({ username, password })
|
||||
$client.login(password, username)
|
||||
lock() {
|
||||
if (!accessor.connected || !accessor.user.admin) {
|
||||
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 }) {
|
||||
accessor.setLogin({ username: '', password: '' })
|
||||
set('username', '')
|
||||
accessor.setLogin({ displayname: '', password: '' })
|
||||
set('displayname', '')
|
||||
set('password', '')
|
||||
$client.logout()
|
||||
},
|
||||
|
@ -3,11 +3,18 @@ import { Member } from '~/neko/types'
|
||||
import { EVENT } from '~/neko/events'
|
||||
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 state = () => ({
|
||||
id: '',
|
||||
clipboard: '',
|
||||
locked: false,
|
||||
|
||||
keyboardModifierState: -1,
|
||||
})
|
||||
|
||||
export const getters = getterTree(state, {
|
||||
@ -35,9 +42,19 @@ export const mutations = mutationTree(state, {
|
||||
state.clipboard = clipboard
|
||||
},
|
||||
|
||||
setKeyboardModifierState(state, { capsLock, numLock, scrollLock }) {
|
||||
state.keyboardModifierState = keyboardModifierState(capsLock, numLock, scrollLock)
|
||||
},
|
||||
|
||||
setLocked(state, locked: boolean) {
|
||||
state.locked = locked
|
||||
},
|
||||
|
||||
reset(state) {
|
||||
state.id = ''
|
||||
state.clipboard = ''
|
||||
state.locked = false
|
||||
state.keyboardModifierState = -1
|
||||
},
|
||||
})
|
||||
|
||||
@ -128,20 +145,21 @@ export const actions = actionTree(
|
||||
$client.sendMessage(EVENT.ADMIN.GIVE, { id: member.id })
|
||||
},
|
||||
|
||||
lock() {
|
||||
if (!accessor.connected || !accessor.user.admin) {
|
||||
changeKeyboard({ getters }) {
|
||||
if (!accessor.connected || !getters.hosting) {
|
||||
return
|
||||
}
|
||||
|
||||
$client.sendMessage(EVENT.ADMIN.LOCK)
|
||||
$client.sendMessage(EVENT.CONTROL.KEYBOARD, { layout: accessor.settings.keyboard_layout })
|
||||
},
|
||||
|
||||
unlock() {
|
||||
if (!accessor.connected || !accessor.user.admin) {
|
||||
return
|
||||
syncKeyboardModifierState({ state, getters }, { capsLock, numLock, scrollLock }) {
|
||||
if (state.keyboardModifierState === keyboardModifierState(capsLock, numLock, scrollLock)) {
|
||||
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 { EVENT } from '~/neko/events'
|
||||
import { accessor } from '~/store'
|
||||
|
||||
export const namespaced = true
|
||||
|
||||
interface KeyboardLayouts {
|
||||
[code: string]: string
|
||||
}
|
||||
|
||||
export const state = () => {
|
||||
return {
|
||||
scroll: get<number>('scroll', 10),
|
||||
@ -10,6 +16,12 @@ export const state = () => {
|
||||
autoplay: get<boolean>('autoplay', true),
|
||||
ignore_emotes: get<boolean>('ignore_emotes', false),
|
||||
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
|
||||
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, {
|
||||
member: state => state.members[state.id] || null,
|
||||
admin: state => (state.members[state.id] ? state.members[state.id].admin : false),
|
||||
muted: state => (state.members[state.id] ? state.members[state.id].muted : false),
|
||||
member: (state) => state.members[state.id] || null,
|
||||
admin: (state) => (state.members[state.id] ? state.members[state.id].admin : false),
|
||||
muted: (state) => (state.members[state.id] ? state.members[state.id].muted : false),
|
||||
})
|
||||
|
||||
export const mutations = mutationTree(state, {
|
||||
|
@ -23,9 +23,9 @@ export const state = () => ({
|
||||
})
|
||||
|
||||
export const getters = getterTree(state, {
|
||||
stream: state => state.streams[state.index],
|
||||
track: state => state.tracks[state.index],
|
||||
resolution: state => ({ w: state.width, h: state.height }),
|
||||
stream: (state) => state.streams[state.index],
|
||||
track: (state) => state.tracks[state.index],
|
||||
resolution: (state) => ({ w: state.width, h: state.height }),
|
||||
})
|
||||
|
||||
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) {
|
||||
state.muted = !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