Let there be light!

This commit is contained in:
raichoo 2020-02-05 10:02:33 +00:00
commit 9e81a0fa92
97 changed files with 13822 additions and 0 deletions

125
.boring Normal file
View File

@ -0,0 +1,125 @@
# This file contains a list of extended regular expressions, one per
# line. A file path matching any of these expressions will be filtered
# out during `darcs add`, or when the `--look-for-adds` flag is passed
# to `darcs whatsnew` and `record`. The entries in ~/.darcs/boring (if
# it exists) supplement those in this file.
#
# Blank lines, and lines beginning with an octothorpe (#) are ignored.
# See regex(7) for a description of extended regular expressions.
### compiler and interpreter intermediate files
# haskell (ghc) interfaces
\.hi$
\.hi-boot$
\.o-boot$
# object files
\.o$
\.o\.cmd$
# profiling haskell
\.p_hi$
\.p_o$
# haskell program coverage resp. profiling info
\.tix$
\.prof$
# fortran module files
\.mod$
# linux kernel
\.ko\.cmd$
\.mod\.c$
(^|/)\.tmp_versions($|/)
# *.ko files aren't boring by default because they might
# be Korean translations rather than kernel modules
# \.ko$
# python, emacs, java byte code
\.py[co]$
\.elc$
\.class$
# objects and libraries; lo and la are libtool things
\.(obj|a|exe|so|lo|la)$
# compiled zsh configuration files
\.zwc$
# Common LISP output files for CLISP and CMUCL
\.(fas|fasl|sparcf|x86f)$
### build and packaging systems
# cabal intermediates
\.installed-pkg-config
\.setup-config
# standard cabal build dir, might not be boring for everybody
# ^dist(/|$)
# autotools
(^|/)autom4te\.cache($|/)
(^|/)config\.(log|status)$
# microsoft web expression, visual studio metadata directories
\_vti_cnf$
\_vti_pvt$
# gentoo tools
\.revdep-rebuild.*
# generated dependencies
^\.depend$
### version control systems
# cvs
(^|/)CVS($|/)
\.cvsignore$
# cvs, emacs locks
^\.#
# rcs
(^|/)RCS($|/)
,v$
# subversion
(^|/)\.svn($|/)
# mercurial
(^|/)\.hg($|/)
# git
(^|/)\.git($|/)
# bzr
\.bzr$
# sccs
(^|/)SCCS($|/)
# darcs
(^|/)_darcs($|/)
(^|/)\.darcsrepo($|/)
# gnu arch
(^|/)(\+|,)
(^|/)vssver\.scc$
\.swp$
(^|/)MT($|/)
(^|/)\{arch\}($|/)
(^|/).arch-ids($|/)
# bitkeeper
(^|/)BitKeeper($|/)
(^|/)ChangeSet($|/)
### miscellaneous
# backup files
~$
\.bak$
\.BAK$
# patch originals and rejects
\.orig$
\.rej$
# X server
\..serverauth.*
# image spam
\#
(^|/)Thumbs\.db$
# vi, emacs tags
(^|/)(tags|TAGS)$
#(^|/)\.[^/]
# core dumps
(^|/|\.)core$
# partial broken files (KIO copy operations)
\.part$
# waf files, see http://code.google.com/p/waf/
(^|/)\.waf-[[:digit:].]+-[[:digit:]]+($|/)
(^|/)\.lock-wscript$
# mac os finder
(^|/)\.DS_Store$
# emacs saved sessions (desktops)
(^|.*/)\.emacs\.desktop(\.lock)?$
# stack
(^|/)\.stack-work($|/)
^hikari$
^hikari-unlocker$
^xdg-shell-protocol.h$

126
.clang-format Normal file
View File

@ -0,0 +1,126 @@
---
Language: Cpp
# BasedOnStyle: Mozilla
AccessModifierOffset: -2
AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowAllArgumentsOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: TopLevel
AlwaysBreakAfterReturnType: TopLevel
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: true
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: false
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- wl_list_for_each
- wl_list_for_each_reverse
- wl_list_for_each_safe
- wl_list_for_each_reverse_safe
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: false
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseTab: Never
...

9
LICENSE Normal file
View File

@ -0,0 +1,9 @@
Copyright 2020 raichoo
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

129
Makefile Normal file
View File

@ -0,0 +1,129 @@
OBJS = \
background.o \
border.o \
command.o \
completion.o \
configuration.o \
exec.o \
exec_select_mode.o \
font.o \
geometry.o \
group.o \
group_assign_mode.o \
indicator.o \
indicator_bar.o \
indicator_frame.o \
input_buffer.o \
keybinding.o \
keyboard.o \
keyboard_grab_mode.o \
layout.o \
main.o \
mark.o \
mark_assign_mode.o \
mark_select_mode.o \
maximized_state.o \
memory.o \
move_mode.o \
normal_mode.o \
output.o \
pointer_config.o \
resize_mode.o \
server.o \
sheet.o \
split.o \
tile.o \
tiling_mode.o \
unlocker.o \
view.o \
view_autoconf.o \
workspace.o \
xdg_view.o \
xwayland_unmanaged_view.o \
xwayland_view.o
WAYLAND_PROTOCOLS = /usr/local/share/wayland-protocols
.PHONY: clean debug
.PATH: src
.ifmake debug
CFLAGS = -g -O0 -fsanitize=address
.else
CFLAGS += -DNDEBUG
.endif
CFLAGS += -Wall -I. -Iinclude
WLROOTS_CFLAGS ?= `pkg-config --cflags wlroots`
WLROOTS_LIBS ?= `pkg-config --libs wlroots`
WLROOTS_CFLAGS += -DWLR_USE_UNSTABLE=1
EPOLLSHIM_LIBS ?= `pkg-config --libs epoll-shim`
PANGO_CFLAGS ?= `pkg-config --cflags pangocairo`
PANGO_LIBS ?= `pkg-config --libs pangocairo`
CAIRO_CFLAGS ?= `pkg-config --cflags cairo`
CAIRO_LIBS ?= `pkg-config --libs cairo`
GLIB_CFLAGS ?= `pkg-config --cflags glib-2.0`
GLIB_LIBS ?= `pkg-config --libs glib-2.0`
PIXMAN_CFLAGS ?= `pkg-config --cflags pixman-1`
PIXMAN_LIBS ?= `pkg-config --libs pixman-1`
XKBCOMMON_CFLAGS ?= `pkg-config --cflags xkbcommon`
XKBCOMMON_LIBS ?= `pkg-config --libs xkbcommon`
WAYLAND_CFLAGS ?= `pkg-config --cflags wayland-server`
WAYLAND_LIBS ?= `pkg-config --libs wayland-server`
LIBINPUT_CFLAGS ?= `pkg-config --cflags libinput`
LIBINPUT_LIBS ?= `pkg-config --libs libinput`
UCL_CFLAGS ?= `pkg-config --cflags libucl`
UCL_LIBS ?= `pkg-config --libs libucl`
CFLAGS += \
${WLROOTS_CFLAGS} \
${PANGO_CFLAGS} \
${CAIRO_CFLAGS} \
${GLIB_CFLAGS} \
${PIXMAN_CFLAGS} \
${XKBCOMMON_CFLAGS} \
${WAYLAND_CFLAGS} \
${LIBINPUT_CFLAGS} \
${UCL_CFLAGS}
LIBS = \
${WLROOTS_LIBS} \
${EPOLLSHIM_LIBS} \
${PANGO_LIBS} \
${CAIRO_LIBS} \
${GLIB_LIBS} \
${PIXMAN_LIBS} \
${XKBCOMMON_LIBS} \
${WAYLAND_LIBS} \
${LIBINPUT_LIBS} \
${UCL_LIBS}
all: hikari hikari-unlocker
hikari: xdg-shell-protocol.h ${OBJS}
${CC} ${LDFLAGS} ${CFLAGS} ${INCLUDES} ${LIBS} ${OBJS} -o ${.TARGET}
xdg-shell-protocol.h:
wayland-scanner server-header ${WAYLAND_PROTOCOLS}/stable/xdg-shell/xdg-shell.xml ${.TARGET}
hikari-unlocker: hikari_unlocker.c
${CC} -lpam hikari_unlocker.c -o hikari-unlocker
clean:
rm *.o ||:
rm hikari ||:
rm hikari-unlocker ||:
rm xdg-shell-protocol.h ||:
debug: hikari

125
README.md Normal file
View File

@ -0,0 +1,125 @@
# Hikari - Wayland Compositor
![Screenshot](https://acmelabs.space/~raichoo/hikari.png)
## Description
_hikari_ is a stacking Wayland compositor with additional tiling capabilities,
it is heavily inspired by the Calm Window manager (cwm(1)). Its core concepts
are *views*, *groups*, *sheets* and the *workspace*.
The workspace is the set of views that are currently visible.
A sheet is a collection of views, each view can only be a member of a single
sheet. Switching between sheets will replace the current content of the
workspace with all the views that are a member of the selected sheet. _hikari_
has 9 general purpose sheets that correspond to the numbers **1** to **9** and a
special purpose sheet **0**. Views that are a member of sheet **0** will
always be visible but stacked below the views of the selected sheet.
Groups are a bit more fine grained than sheets. Like sheets, groups are a
collection of views. Unlike sheets you can have a arbitrary number of groups
and each group can have an arbitrary name. Views from one group can be spread
among all available sheets. Some operations act on entire groups rather than
individual views.
Please note that `hikari` is currently in `alpha` state and Wayland still
requires some work on FreeBSD. This release is targeted towards people who want
to help improving `hikari` by either providing feedback, patches
and/or help improving Wayland on FreeBSD.
## Setting up Wayland on FreeBSD
Wayland currently requires some care to work properly on FreeBSD. This section
aims to document the recent state of how to enable Wayland on the FreeBSD
`STABLE` branch and will change once support is being improved.
### Local `devfs.rules`
NOTE: this should only be used on single user setups since it allows members of
the `video` group to gain access to the `input` devices. This is a temporary
solution until FreeBSD offers ways to handle this in a better way.
Add the following to `/etc/devfs.rules`
```
[localrules=10]
add path 'input/*' mode 0660 group video
```
Add `devfs_system_ruleset="localrules"` to `/etc/rc.conf`.
### Start `moused`
Some systems might require `moused` for mice to work. Enable it with `service
moused enable`
### Setting up XDG\_RUNTIME\_DIR
This section describes how to use `/tmp` as your `XDG_RUNTIME_DIR`. Some Wayland
clients (e.g. native Wayland `firefox`) require `posix_fallocate` to work in
that directory. This is not supported by ZFS, therefore you should prevent the
ZFS tmp dataset from mounting to `/tmp` and `mount -t tmpfs tmpfs /tmp`. To
persist this setting edit your `/etc/fstab` appropriately to automatically mount
`tmpfs` during boot.
Additionally set `XDG_RUNTIME_DIR` to `/tmp` in your environment.
### Setting up XKB
`hikari` currently gets its `xkb` settings settings the appropriate environment
variables to something like the following.
```
XKB_DEFAULT_RULES "evdev"
XKB_DEFAULT_LAYOUT "de(nodeadkeys),de"
```
## Building
`hikari` currently only works on FreeBSD. This will likely change in the future.
### Dependencies
* wlroots
* pango
* cairo
* libinput
* xkbcommon
* pixman
* libucl
* glib
* epoll-shim
### Compiling and Installing
To build all executables required to run `hikari` simply run `make`, this will
produce two binaries `hikari` and `hikari-unlocker`. The latter one is used to
check credentials for unlocking the screen. Both need to be installed with
root setuid in your `PATH`.
`hikari` can be configured via `$HOME/.config/hikari/hikari.conf`, an example
can be found under `doc/example_hikari.conf`.
## TODO before 1.0
* Keybindings currently only work with `libinput` keycodes.
* Popups are not positioned correctly on multi monitor setups.
* Configuration processing is still buggy and can lead to issues when errors are
encountered.
* Manpage is still missing.
## Community
The `hikari` community gears to be inclusive and welcoming to everyone, this is
why we chose to adere to the [Geekfeminism Code of
Conduct](https://geekfeminismdotorg.wordpress.com/about/code-of-conduct/).
If you care to be a part of our community, please join our Matrix chat at
`#hikari:acmelabs.space` and/or subscribe to our mailing list by sending a mail
to `hikari+subscribe@acmelabs.space`.
## Contributing
Please make sure you use `clang-format` with the accompanying `.clag-format`
configuration before submitting any patches.

275
doc/example_hikari.conf Normal file
View File

@ -0,0 +1,275 @@
colorscheme {
background = 0x282C34
foreground = 0x000000
indicator_selected = 0xE6DB74
indicator_grouped = 0xFD971F
indicator_first = 0xB8E673
indicator_conflict = 0xEF5939
indicator_insert = 0x66D9EF
border_active = 0xFFFFFF
border_inactive = 0x465457
}
border = 1
gap = 5
inputs {
pointers {
"System mouse" = {
accel = 1
scroll-method = on-button-down
scroll-button = 274
}
}
}
backgrounds {
eDP-1 = ".wallpaper"
}
font = "DejaVu Sans Mono 10"
execute {
c = "sakura --name cmus -c 150 -r 50 -e /usr/local/bin/cmus"
f = "/usr/local/bin/firefox"
m = "sakura -t mutt --name mutt -c 125 -r 37 -e /usr/local/bin/mutt"
i = "sakura --name irssi -r 65 -c 227 -e irssi"
t = "sakura -t top --name top -e /usr/bin/top -I -P -t -s5"
s = "sakura -t systat --name systat -e /usr/bin/systat -vm 5"
}
autoconf {
shell = {
group = shell
}
rootshell = {
group = rootshell
mark = r
}
jabber = {
group = communication
sheet = 1
mark = j
position = {
x = 30
y = 20
}
focus = true
}
irssi = {
group = communication
sheet = 1
mark = i
position = {
x = 940
y = 20
}
focus = true
}
mutt = {
group = communication
sheet = 1
mark = m
position = {
x = 30
y = 860
}
focus = true
}
cmus = {
group = music
mark = c
}
top = {
group = monitor
sheet = 0
position = {
x = 1997 # 2560 - 1 - 562
y = 1077 # 1440 - 1 - 362
}
}
systat = {
group = monitor
sheet = 0
position = {
x = 1429 # 2560 - 2 - 2 * 562 - 5
y = 1077 # 1440 - 1 - 362
}
focus = true
}
firefox = {
group = web
sheet = 2
mark = f
}
}
layouts {
stack = {
vertical {
ratio = 0.25
left = {
container {
views = 1
type = full
}
}
right = {
container {
type = horizontal
}
}
}
}
grid = {
container {
type = grid
}
}
vertical = {
container {
type = vertical
}
}
horizontal = {
container {
type = horizontal
}
}
full = {
container {
type = full
}
}
}
actions {
shell = "sakura --name shell"
rootshell = "sakura --name rootshell -e su - root -c fish"
volup = "mixer -s vol +5"
voldown = "mixer -s vol -5"
}
bindings {
keyboard {
L-11 = sheet-switch-to-0
L-2 = sheet-switch-to-1
L-3 = sheet-switch-to-2
L-4 = sheet-switch-to-3
L-5 = sheet-switch-to-4
L-6 = sheet-switch-to-5
L-7 = sheet-switch-to-6
L-8 = sheet-switch-to-7
L-9 = sheet-switch-to-8
L-10 = sheet-switch-to-9
L-43 = sheet-switch-to-alternate # #
L-52 = sheet-switch-to-current # .
L-36 = sheet-switch-to-next # j
L-37 = sheet-switch-to-prev # k
L-51 = sheet-switch-to-next-inhabited
LS-51 = sheet-switch-to-prev-inhabited
LC-23 = sheet-show-iconified
LC-31 = sheet-show-all
L-31 = sheet-cycle-view-next
LS-31 = sheet-cycle-view-prev
LA-19 = sheet-reset-layout
LA-102 = sheet-cycle-layout-view-first # Pos1
LA-107 = sheet-cycle-layout-view-last # Ende
L-38 = sheet-cycle-layout-view-next
LS-38 = sheet-cycle-layout-view-prev
L-45 = sheet-exchange-layout-view-next
LS-45 = sheet-exchange-layout-view-prev
LA-45 = sheet-exchange-layout-view-main
LS-11 = view-pin-to-sheet-0
LS-2 = view-pin-to-sheet-1
LS-3 = view-pin-to-sheet-2
LS-4 = view-pin-to-sheet-3
LS-5 = view-pin-to-sheet-4
LS-6 = view-pin-to-sheet-5
LS-7 = view-pin-to-sheet-6
LS-8 = view-pin-to-sheet-7
LS-9 = view-pin-to-sheet-8
LS-10 = view-pin-to-sheet-9
LS-43 = view-pin-to-sheet-alternate
LS-52 = view-pin-to-sheet-current # .
LS-36 = view-pin-to-sheet-next # j
LS-37 = view-pin-to-sheet-prev # k
L-22 = view-raise # u
L-32 = view-lower # d
L-24 = view-only
L-35 = view-hide
L-16 = view-quit
L-103 = view-move-up
L-108 = view-move-down
L-105 = view-move-left
L-106 = view-move-right
LA-103 = view-decrease-size-up
LA-108 = view-increase-size-down
LA-105 = view-decrease-size-left
LA-106 = view-increase-size-right
LS-103 = view-snap-up
LS-108 = view-snap-down
LS-105 = view-snap-left
LS-106 = view-snap-right
L-19 = view-reset-geometry
L-53 = view-toggle-maximize-vertical
L-86 = view-toggle-maximize-horizontal
L-33 = view-toggle-maximize-full
L5-27 = view-toggle-floating
L-23 = view-toggle-iconified
LS-24 = group-only
LS-35 = group-hide
LS-22 = group-raise # u
LS-32 = group-lower # d
L-15 = group-cycle-next
LS-15 = group-cycle-prev
L-41 = group-cycle-view-next # grave
LS-41 = group-cycle-view-prev
L-102 = group-cycle-view-first # Pos1
L-107 = group-cycle-view-last # Ende
L-18 = mode-enter-execute
L-34 = mode-enter-group-assign
L-50 = mode-enter-mark-assign
L-13 = mode-enter-mark-select
LS-13 = mode-enter-mark-switch-select
LCA-34 = mode-enter-keyboard-grab
LS-14 = lock
LCA-16 = quit
L-28 = action-shell
LS-28 = action-rootshell
0-115 = action-volup
0-114 = action-voldown
LA-31 = layout-stack
LA-47 = layout-vertical
LA-35 = layout-horizontal
LA-34 = layout-grid
LA-33 = layout-full
}
mouse {
L-272 = mode-enter-move
L-273 = mode-enter-resize
}
}

88
hikari_unlocker.c Normal file
View File

@ -0,0 +1,88 @@
#include <pwd.h>
#include <security/pam_appl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/mman.h>
#include <unistd.h>
static char *input_buffer = NULL;
const int INPUT_BUFFER_SIZE = 1024;
static int
conversation_handler(int num_msg,
const struct pam_message **msg,
struct pam_response **resp,
void *data)
{
struct pam_response *pam_reply = calloc(num_msg, sizeof(struct pam_response));
if (pam_reply == NULL) {
return PAM_ABORT;
}
*resp = pam_reply;
for (int i = 0; i < num_msg; ++i) {
switch (msg[i]->msg_style) {
case PAM_PROMPT_ECHO_OFF:
case PAM_PROMPT_ECHO_ON:
pam_reply[i].resp = strdup(input_buffer);
if (pam_reply[i].resp == NULL) {
return PAM_ABORT;
}
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
break;
}
}
return PAM_SUCCESS;
}
bool
check_password(void)
{
struct passwd *passwd = getpwuid(getuid());
char *username = passwd->pw_name;
const struct pam_conv conv = {
.conv = conversation_handler,
.appdata_ptr = NULL,
};
bool success = false;
pam_handle_t *auth_handle = NULL;
if (pam_start("passwd", username, &conv, &auth_handle) != PAM_SUCCESS) {
return false;
}
read(0, input_buffer, INPUT_BUFFER_SIZE - 1);
int pam_status = pam_authenticate(auth_handle, 0);
bzero(input_buffer, INPUT_BUFFER_SIZE);
success = pam_status == PAM_SUCCESS;
write(1, &success, sizeof(bool));
pam_end(auth_handle, pam_status);
return success;
}
int
main(int argc, char **argv)
{
char input;
bool success = false;
input_buffer = malloc(INPUT_BUFFER_SIZE);
mlock(input_buffer, INPUT_BUFFER_SIZE);
while (!success) {
success = check_password();
}
munlock(input_buffer, INPUT_BUFFER_SIZE);
free(input_buffer);
return 0;
}

View File

@ -0,0 +1,20 @@
#if !defined(HIKARI_BACKGROUND_H)
#define HIKARI_BACKGROUND_H
#include <wayland-util.h>
struct hikari_background {
struct wl_list link;
char *output_name;
char *path;
};
void
hikari_background_init(
struct hikari_background *background, const char *output_name, char *path);
void
hikari_background_fini(struct hikari_background *background);
#endif

40
include/hikari/border.h Normal file
View File

@ -0,0 +1,40 @@
#if !defined(HIKARI_BORDER_H)
#define HIKARI_BORDER_H
#include <wlr/types/wlr_box.h>
#include <hikari/output.h>
struct hikari_render_data;
enum hikari_border_state {
HIKARI_BORDER_NONE,
HIKARI_BORDER_INACTIVE,
HIKARI_BORDER_ACTIVE
};
struct hikari_border {
enum hikari_border_state state;
struct wlr_box geometry;
struct wlr_box top;
struct wlr_box bottom;
struct wlr_box left;
struct wlr_box right;
};
static inline struct wlr_box *
hikari_border_geometry(struct hikari_border *border)
{
return &border->geometry;
}
void
hikari_border_render(
struct hikari_border *border, struct hikari_render_data *render_data);
void
hikari_border_refresh_geometry(
struct hikari_border *border, struct wlr_box *geometry);
#endif

15
include/hikari/color.h Normal file
View File

@ -0,0 +1,15 @@
#if !defined(HIKARI_COLOR_H)
#define HIKARI_COLOR_H
#include <stdint.h>
static inline void
hikari_color_convert(float dst[static 4], uint32_t color)
{
dst[0] = ((color >> 16) & 0xff) / 255.0;
dst[1] = ((color >> 8) & 0xff) / 255.0;
dst[2] = (color & 0xff) / 255.0;
dst[3] = 1.0;
}
#endif

7
include/hikari/command.h Normal file
View File

@ -0,0 +1,7 @@
#if !defined(HIKARI_COMMAND_H)
#define HIKARI_COMMAND_H
void
hikari_command_execute(const char *cmd);
#endif

View File

@ -0,0 +1,34 @@
#if !defined(HIKARI_COMPLETION_H)
#define HIKARI_COMPLETION_H
#include <wayland-util.h>
struct hikari_completion_item {
char data[256];
struct wl_list completion_items;
};
struct hikari_completion {
struct hikari_completion_item *current_item;
struct wl_list items;
};
void
hikari_completion_init(struct hikari_completion *completion, char *data);
void
hikari_completion_fini(struct hikari_completion *completion);
void
hikari_completion_add(struct hikari_completion *completion, char *data);
char *
hikari_completion_cancel(struct hikari_completion *completion);
char *
hikari_completion_next(struct hikari_completion *completion);
char *
hikari_completion_prev(struct hikari_completion *completion);
#endif

View File

@ -0,0 +1,72 @@
#if !defined(HIKARI_CONFIGURATION_H)
#define HIKARI_CONFIGURATION_H
#include <stdbool.h>
#include <stdint.h>
#include <wayland-util.h>
#include <hikari/font.h>
struct hikari_group;
struct hikari_keybinding;
struct hikari_sheet;
struct hikari_view;
struct hikari_pointer_config;
struct hikari_configuration {
float clear[4];
float foreground[4];
float indicator_selected[4];
float indicator_grouped[4];
float indicator_first[4];
float indicator_conflict[4];
float indicator_insert[4];
float border_active[4];
float border_inactive[4];
struct hikari_font font;
int border;
int gap;
struct {
uint8_t nkeybindings[256];
struct hikari_keybinding *keybindings[256];
uint8_t nmousebindings[256];
struct hikari_keybinding *mousebindings[256];
} normal_mode;
struct wl_list autoconfs;
struct wl_list backgrounds;
struct wl_list pointer_configs;
};
extern struct hikari_configuration hikari_configuration;
void
hikari_configuration_init(struct hikari_configuration *configuration);
void
hikari_configuration_fini(struct hikari_configuration *configuration);
void
hikari_configuration_resolve_view_autoconf(
struct hikari_configuration *configuration,
const char *app_id,
struct hikari_view *view,
struct hikari_sheet **sheet,
struct hikari_group **group,
int *x,
int *y,
bool *focus);
char *
hikari_configuration_resolve_background(
struct hikari_configuration *configuration, const char *output_name);
struct hikari_pointer_config *
hikari_configuration_resolve_pointer_config(
struct hikari_configuration *configuration, const char *pointer_name);
#endif

45
include/hikari/exec.h Normal file
View File

@ -0,0 +1,45 @@
#if !defined(HIKARI_EXEC_H)
#define HIKARI_EXEC_H
static const int HIKARI_NR_OF_EXECS = 26;
struct hikari_exec {
char *command;
};
extern struct hikari_exec execs[HIKARI_NR_OF_EXECS];
static struct hikari_exec *HIKARI_EXEC_a = &execs[0];
static struct hikari_exec *HIKARI_EXEC_b = &execs[1];
static struct hikari_exec *HIKARI_EXEC_c = &execs[2];
static struct hikari_exec *HIKARI_EXEC_d = &execs[3];
static struct hikari_exec *HIKARI_EXEC_e = &execs[4];
static struct hikari_exec *HIKARI_EXEC_f = &execs[5];
static struct hikari_exec *HIKARI_EXEC_g = &execs[6];
static struct hikari_exec *HIKARI_EXEC_h = &execs[7];
static struct hikari_exec *HIKARI_EXEC_i = &execs[8];
static struct hikari_exec *HIKARI_EXEC_j = &execs[9];
static struct hikari_exec *HIKARI_EXEC_k = &execs[10];
static struct hikari_exec *HIKARI_EXEC_l = &execs[11];
static struct hikari_exec *HIKARI_EXEC_m = &execs[12];
static struct hikari_exec *HIKARI_EXEC_n = &execs[13];
static struct hikari_exec *HIKARI_EXEC_o = &execs[14];
static struct hikari_exec *HIKARI_EXEC_p = &execs[15];
static struct hikari_exec *HIKARI_EXEC_q = &execs[16];
static struct hikari_exec *HIKARI_EXEC_r = &execs[17];
static struct hikari_exec *HIKARI_EXEC_s = &execs[18];
static struct hikari_exec *HIKARI_EXEC_t = &execs[19];
static struct hikari_exec *HIKARI_EXEC_u = &execs[20];
static struct hikari_exec *HIKARI_EXEC_v = &execs[21];
static struct hikari_exec *HIKARI_EXEC_w = &execs[22];
static struct hikari_exec *HIKARI_EXEC_x = &execs[23];
static struct hikari_exec *HIKARI_EXEC_y = &execs[24];
static struct hikari_exec *HIKARI_EXEC_z = &execs[25];
void
hikari_execs_init(void);
void
hikari_execs_fini(void);
#endif

View File

@ -0,0 +1,15 @@
#if !defined(HIKARI_EXEC_SELECT_MODE_H)
#define HIKARI_EXEC_SELECT_MODE_H
#include <stdbool.h>
#include <hikari/mode.h>
struct hikari_exec_select_mode {
struct hikari_mode mode;
};
void
hikari_exec_select_mode_init(struct hikari_exec_select_mode *exec_select_mode);
#endif

20
include/hikari/font.h Normal file
View File

@ -0,0 +1,20 @@
#if !defined(HIKARI_FONT_H)
#define HIKARI_FONT_H
#include <pango/pangocairo.h>
struct hikari_font {
PangoFontDescription *desc;
};
void
hikari_font_init(struct hikari_font *font, const char *font_name);
void
hikari_font_fini(struct hikari_font *font);
void
hikari_font_metrics(
struct hikari_font *font, const char *text, int *width, int *height);
#endif

30
include/hikari/geometry.h Normal file
View File

@ -0,0 +1,30 @@
#if !defined(HIKARI_GEOMETRY_H)
#define HIKARI_GEOMETRY_H
#include <wlr/types/wlr_box.h>
void
hikari_geometry_split_vertical(struct wlr_box *src,
float factor,
int gap,
struct wlr_box *left,
struct wlr_box *right);
void
hikari_geometry_split_horizontal(struct wlr_box *src,
float factor,
int gap,
struct wlr_box *top,
struct wlr_box *bottom);
void
hikari_geometry_shrink(struct wlr_box *geometry, int gap);
void
hikari_geometry_constrain_position(struct wlr_box *geometry,
int screen_width,
int screen_height,
int x,
int y);
#endif

View File

@ -0,0 +1,10 @@
#if !defined(HIKARI_KEYBOARD_GRAB_MODE_H)
#define HIKARI_KEYBOARD_GRAB_MODE_H
#include <hikari/mode.h>
struct hikari_keyboard_grab_mode {
struct hikari_mode mode;
};
#endif

43
include/hikari/group.h Normal file
View File

@ -0,0 +1,43 @@
#if !defined(HIKARIGROUP_H)
#define HIKARIGROUP_H
#include <stdbool.h>
#include <wayland-util.h>
struct hikari_sheet;
struct hikari_view;
struct hikari_workspace;
struct hikari_group {
char *name;
struct hikari_sheet *sheet;
struct wl_list views;
struct wl_list visible_views;
struct wl_list server_groups;
struct wl_list visible_server_groups;
};
void
hikari_group_init(struct hikari_group *group, const char *name);
void
hikari_group_fini(struct hikari_group *group);
struct hikari_view *
hikari_group_first_view(
struct hikari_group *group, struct hikari_workspace *workspace);
struct hikari_view *
hikari_group_last_view(
struct hikari_group *group, struct hikari_workspace *workspace);
static inline bool
hikari_group_is_sheet(struct hikari_group *group)
{
return group->sheet != NULL;
}
#endif

View File

@ -0,0 +1,20 @@
#if !defined(HIKARI_GROUP_ASSIGN_MODE_H)
#define HIKARI_GROUP_ASSIGN_MODE_H
#include <hikari/input_buffer.h>
#include <hikari/mode.h>
struct hikari_group;
struct hikari_group_assign_mode {
struct hikari_mode mode;
struct hikari_input_buffer input_buffer;
struct hikari_completion *completion;
struct hikari_group *group;
};
void
hikari_group_assign_mode_init(
struct hikari_group_assign_mode *group_assign_mode);
#endif

View File

@ -0,0 +1,83 @@
#if !defined(HIKARI_INDICATOR_H)
#define HIKARI_INDICATOR_H
#include <hikari/font.h>
#include <hikari/indicator_bar.h>
#include <hikari/sheet.h>
struct hikari_render_data;
struct hikari_view;
struct hikari_output;
struct hikari_indicator {
struct hikari_indicator_bar title;
struct hikari_indicator_bar sheet;
struct hikari_indicator_bar group;
struct hikari_indicator_bar mark;
int bar_height;
};
void
hikari_indicator_init(
struct hikari_indicator *indicator, float color[static 4]);
void
hikari_indicator_fini(struct hikari_indicator *indicator);
void
hikari_indicator_render(
struct hikari_indicator *indicator, struct hikari_render_data *render_data);
void
hikari_indicator_update(struct hikari_indicator *indicator,
struct hikari_view *view,
float background[static 4]);
void
hikari_indicator_update_sheet(struct hikari_indicator *indicator,
struct wlr_box *view_geometry,
struct hikari_output *output,
struct hikari_sheet *sheet,
float background[static 4],
bool iconified,
bool floating);
void
hikari_indicator_damage(
struct hikari_indicator *indicator, struct hikari_view *view);
static inline void
hikari_indicator_update_title(struct hikari_indicator *indicator,
struct wlr_box *view_geometry,
struct hikari_output *output,
const char *text,
float background[static 4])
{
hikari_indicator_bar_update(
&indicator->title, view_geometry, output, text, background);
}
static inline void
hikari_indicator_update_group(struct hikari_indicator *indicator,
struct wlr_box *view_geometry,
struct hikari_output *output,
const char *text,
float background[static 4])
{
hikari_indicator_bar_update(
&indicator->group, view_geometry, output, text, background);
}
static inline void
hikari_indicator_update_mark(struct hikari_indicator *indicator,
struct wlr_box *view_geometry,
struct hikari_output *output,
const char *text,
float background[static 4])
{
hikari_indicator_bar_update(
&indicator->mark, view_geometry, output, text, background);
}
#endif

View File

@ -0,0 +1,42 @@
#if !defined(HIKARI_INDICATOR_BAR_H)
#define HIKARI_INDICATOR_BAR_H
#include <wlr/types/wlr_surface.h>
struct hikari_indicator;
struct hikari_render_data;
struct hikari_output;
struct hikari_indicator_bar {
struct wlr_texture *texture;
struct hikari_indicator *indicator;
int width;
int offset;
};
void
hikari_indicator_bar_init(struct hikari_indicator_bar *indicator_bar,
struct hikari_indicator *indicator,
int offset);
void
hikari_indicator_bar_fini(struct hikari_indicator_bar *indicator_bar);
void
hikari_indicator_bar_update(struct hikari_indicator_bar *indicator_bar,
struct wlr_box *view_geometry,
struct hikari_output *output,
const char *text,
float background[static 4]);
void
hikari_indicator_bar_render(struct hikari_indicator_bar *indicator_bar,
struct hikari_render_data *render_data);
void
hikari_indicator_bar_damage(struct hikari_indicator_bar *indicator_bar,
struct wlr_box *view_geometry,
struct hikari_output *output);
#endif

View File

@ -0,0 +1,25 @@
#if !defined(HIKARIINDICATOR_FRAME_H)
#define HIKARIINDICATOR_FRAME_H
#include <wlr/types/wlr_box.h>
struct hikari_view;
struct hikari_render_data;
struct hikari_indicator_frame {
struct wlr_box top;
struct wlr_box bottom;
struct wlr_box left;
struct wlr_box right;
};
void
hikari_indicator_frame_refresh_geometry(
struct hikari_indicator_frame *indicator_frame, struct hikari_view *view);
void
hikari_indicator_frame_render(struct hikari_indicator_frame *indicator_frame,
float color[static 4],
struct hikari_render_data *render_data);
#endif

View File

@ -0,0 +1,36 @@
#if !defined(HIKARI_INPUT_BUFFER_H)
#define HIKARI_INPUT_BUFFER_H
#include <stdint.h>
#include <stdlib.h>
struct hikari_input_buffer {
char buffer[256];
size_t pos;
};
struct hikari_input_buffer *
input_buffer_init(struct hikari_input_buffer *input_buffer, char *content);
void
hikari_input_buffer_add_char(
struct hikari_input_buffer *input_buffer, char input);
void
hikari_input_buffer_add_utf32_char(
struct hikari_input_buffer *input_buffer, uint32_t codepoint);
void
hikari_input_buffer_replace(
struct hikari_input_buffer *input_buffer, char *content);
void
hikari_input_buffer_remove_char(struct hikari_input_buffer *input_buffer);
void
hikari_input_buffer_clear(struct hikari_input_buffer *input_buffer);
char *
hikari_input_buffer_read(struct hikari_input_buffer *input_buffer);
#endif

View File

@ -0,0 +1,18 @@
#if !defined(HIKARI_KEYBINDING_H)
#define HIKARI_KEYBINDING_H
#include <stdint.h>
struct hikari_keybinding {
uint32_t keycode;
uint32_t modifiers;
void (*action)(void *);
void (*cleanup)(void *);
void *arg;
};
void
hikari_keybinding_fini(struct hikari_keybinding *keybinding);
#endif

25
include/hikari/keyboard.h Normal file
View File

@ -0,0 +1,25 @@
#if !defined(HIKARI_KEYBOARD_H)
#define HIKARI_KEYBOARD_H
#include <wayland-server-core.h>
#include <wayland-util.h>
#include <wlr/types/wlr_input_device.h>
struct hikari_keyboard {
struct wl_list link;
struct wlr_input_device *device;
struct wl_listener modifiers;
struct wl_listener key;
struct wl_listener destroy;
};
void
hikari_keyboard_init(
struct hikari_keyboard *keyboard, struct wlr_input_device *device);
void
hikari_keyboard_fini(struct hikari_keyboard *keyboard);
#endif

View File

@ -0,0 +1,14 @@
#if !defined(HIKARI_KEYBOARD_GRAB_MODE_H)
#define HIKARI_KEYBOARD_GRAB_MODE_H
#include <hikari/mode.h>
struct hikari_keyboard_grab_mode {
struct hikari_mode mode;
};
void
hikari_keyboard_grab_mode_init(
struct hikari_keyboard_grab_mode *keyboard_grab_mode);
#endif

27
include/hikari/layout.h Normal file
View File

@ -0,0 +1,27 @@
#if !defined(HIKARI_LAYOUT_H)
#define HIKARI_LAYOUT_H
#include <wayland-util.h>
struct hikari_split;
struct hikari_view;
struct hikari_layout {
struct hikari_split *split;
struct wl_list tiles;
};
void
hikari_layout_init(struct hikari_layout *layout, struct hikari_split *split);
void
hikari_layout_fini(struct hikari_layout *layout);
struct hikari_view *
hikari_layout_first_view(struct hikari_layout *layout);
struct hikari_view *
hikari_layout_last_view(struct hikari_layout *layout);
#endif

54
include/hikari/mark.h Normal file
View File

@ -0,0 +1,54 @@
#if !defined(HIKARI_MARK_H)
#define HIKARI_MARK_H
struct hikari_view;
struct hikari_mark {
char *name;
struct hikari_view *view;
};
static const int HIKARI_NR_OF_MARKS = 26;
extern struct hikari_mark marks[HIKARI_NR_OF_MARKS];
static struct hikari_mark *const HIKARI_MARK_a = &marks[0];
static struct hikari_mark *const HIKARI_MARK_b = &marks[1];
static struct hikari_mark *const HIKARI_MARK_c = &marks[2];
static struct hikari_mark *const HIKARI_MARK_d = &marks[3];
static struct hikari_mark *const HIKARI_MARK_e = &marks[4];
static struct hikari_mark *const HIKARI_MARK_f = &marks[5];
static struct hikari_mark *const HIKARI_MARK_g = &marks[6];
static struct hikari_mark *const HIKARI_MARK_h = &marks[7];
static struct hikari_mark *const HIKARI_MARK_i = &marks[8];
static struct hikari_mark *const HIKARI_MARK_j = &marks[9];
static struct hikari_mark *const HIKARI_MARK_k = &marks[10];
static struct hikari_mark *const HIKARI_MARK_l = &marks[11];
static struct hikari_mark *const HIKARI_MARK_m = &marks[12];
static struct hikari_mark *const HIKARI_MARK_n = &marks[13];
static struct hikari_mark *const HIKARI_MARK_o = &marks[14];
static struct hikari_mark *const HIKARI_MARK_p = &marks[15];
static struct hikari_mark *const HIKARI_MARK_q = &marks[16];
static struct hikari_mark *const HIKARI_MARK_r = &marks[17];
static struct hikari_mark *const HIKARI_MARK_s = &marks[18];
static struct hikari_mark *const HIKARI_MARK_t = &marks[19];
static struct hikari_mark *const HIKARI_MARK_u = &marks[20];
static struct hikari_mark *const HIKARI_MARK_v = &marks[21];
static struct hikari_mark *const HIKARI_MARK_w = &marks[22];
static struct hikari_mark *const HIKARI_MARK_x = &marks[23];
static struct hikari_mark *const HIKARI_MARK_y = &marks[24];
static struct hikari_mark *const HIKARI_MARK_z = &marks[25];
void
hikari_marks_init(void);
void
hikari_marks_fini(void);
void
hikari_mark_clear(struct hikari_mark *mark);
void
hikari_mark_set(struct hikari_mark *mark, struct hikari_view *view);
#endif

View File

@ -0,0 +1,21 @@
#if !defined(HIKARI_MARK_ASSIGN_MODE_H)
#define HIKARI_MARK_ASSIGN_MODE_H
#include <hikari/indicator.h>
#include <hikari/mode.h>
struct hikari_mark;
struct hikari_mark_assign_mode {
struct hikari_mode mode;
struct hikari_mark *pending_mark;
struct hikari_indicator indicator;
};
void
hikari_mark_assign_mode_init(struct hikari_mark_assign_mode *mark_assign_mode);
void
hikari_mark_assign_mode_fini(struct hikari_mark_assign_mode *mark_assign_mode);
#endif

View File

@ -0,0 +1,17 @@
#if !defined(HIKARI_MARK_SELECT_MODE_H)
#define HIKARI_MARK_SELECT_MODE_H
#include <stdbool.h>
#include <hikari/mode.h>
struct hikari_mark_select_mode {
struct hikari_mode mode;
bool switch_workspace;
};
void
hikari_mark_select_mode_init(struct hikari_mark_select_mode *mark_select_mode);
#endif

View File

@ -0,0 +1,38 @@
#if !defined(HIKARIMAXIMIZED_STATE_H)
#define HIKARIMAXIMIZED_STATE_H
#include <stdlib.h>
#include <wlr/types/wlr_box.h>
#include <hikari/memory.h>
struct hikari_view;
enum hikari_maximization {
HIKARI_MAXIMIZATION_FULLY_MAXIMIZED,
HIKARI_MAXIMIZATION_VERTICALLY_MAXIMIZED,
HIKARI_MAXIMIZATION_HORIZONTALLY_MAXIMIZED
};
struct hikari_maximized_state {
enum hikari_maximization maximization;
struct wlr_box geometry;
};
struct hikari_maximized_state *
hikari_maximized_state_full(struct hikari_view *view, int width, int height);
static inline struct hikari_maximized_state *
hikari_maximized_state_alloc(void)
{
return hikari_malloc(sizeof(struct hikari_maximized_state));
}
static inline void
hikari_maximized_state_destroy(struct hikari_maximized_state *maximized_state)
{
hikari_free(maximized_state);
}
#endif

15
include/hikari/memory.h Normal file
View File

@ -0,0 +1,15 @@
#if !defined(HIKARI_MEMORY_H)
#define HIKARI_MEMORY_H
#include <stdlib.h>
void *
hikari_malloc(size_t size);
void *
hikari_calloc(size_t number, size_t size);
void
hikari_free(void *ptr);
#endif

36
include/hikari/mode.h Normal file
View File

@ -0,0 +1,36 @@
#if !defined(HIKARI_MODE_H)
#define HIKARI_MODE_H
#include <wlr/types/wlr_keyboard.h>
struct hikari_keyboard;
struct hikari_output;
struct hikari_render_data;
struct hikari_workspace;
enum hikari_mode_type {
HIKARI_MODE_TYPE_NORMAL,
HIKARI_MODE_TYPE_GROUP_CHANGE,
HIKARI_MODE_TYPE_ASSIGN_MARK,
HIKARI_MODE_TYPE_SELECT_MARK,
HIKARI_MODE_TYPE_SELECT_EXEC,
HIKARI_MODE_TYPE_GRAB_KEYBOARD,
HIKARI_MODE_TYPE_MOVE,
HIKARI_MODE_TYPE_TILING
};
struct hikari_mode {
enum hikari_mode_type type;
void (*key_handler)(struct wl_listener *listener, void *data);
void (*modifier_handler)(struct wl_listener *listener, void *data);
void (*button_handler)(struct wl_listener *listener, void *data);
void (*cancel)(void);
void (*cursor_move)(void);
void (*render)(
struct hikari_output *output, struct hikari_render_data *render_data);
};
#endif

View File

@ -0,0 +1,15 @@
#if !defined(HIKARI_MOVE_MODE_H)
#define HIKARI_MOVE_MODE_H
#include <hikari/mode.h>
struct hikari_keybinding;
struct hikari_move_mode {
struct hikari_mode mode;
};
void
hikari_move_mode_init(struct hikari_move_mode *move_mode);
#endif

View File

@ -0,0 +1,15 @@
#if !defined(HIKARI_NORMAL_MODE_H)
#define HIKARI_NORMAL_MODE_H
#include <hikari/mode.h>
struct hikari_keybinding;
struct hikari_normal_mode {
struct hikari_mode mode;
};
void
hikari_normal_mode_init(struct hikari_normal_mode *normal_mode);
#endif

View File

@ -0,0 +1,27 @@
#if !defined(HIKARI_OPERATION_H)
#define HIKARI_OPERATION_H
#include <wlr/types/wlr_box.h>
struct hikari_tile;
enum hikari_operation_type {
HIKARI_OPERATION_TYPE_RESIZE,
HIKARI_OPERATION_TYPE_RESET,
HIKARI_OPERATION_TYPE_UNMAXIMIZE,
HIKARI_OPERATION_TYPE_FULL_MAXIMIZE,
HIKARI_OPERATION_TYPE_VERTICAL_MAXIMIZE,
HIKARI_OPERATION_TYPE_HORIZONTAL_MAXIMIZE,
HIKARI_OPERATION_TYPE_TILE
};
struct hikari_operation {
enum hikari_operation_type type;
bool dirty;
bool center;
uint32_t serial;
struct wlr_box geometry;
struct hikari_tile *tile;
};
#endif

60
include/hikari/output.h Normal file
View File

@ -0,0 +1,60 @@
#if !defined(HIKARI_OUTPUT_H)
#define HIKARI_OUTPUT_H
#include <assert.h>
#include <wayland-server-core.h>
#include <wayland-util.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_surface.h>
struct hikari_output {
struct wl_list link;
struct wlr_output *output;
struct wlr_output_damage *damage;
struct hikari_workspace *workspace;
struct wl_listener damage_frame;
/* struct wl_listener mode; */
struct wl_listener destroy;
struct wl_list views;
#ifdef HAVE_XWAYLAND
struct wl_list unmanaged_xwayland_views;
#endif
struct wl_list server_outputs;
struct wlr_box geometry;
};
void
hikari_output_init(struct hikari_output *output, struct wlr_output *wlr_output);
void
hikari_output_fini(struct hikari_output *output);
void
hikari_output_scissor_render(struct wlr_output *wlr_output,
struct wlr_renderer *renderer,
pixman_box32_t *rect);
void
hikari_output_damage_whole(struct hikari_output *output);
void
hikari_output_disable(struct hikari_output *output);
void
hikari_output_enable(struct hikari_output *output);
static inline void
hikari_output_add_damage(struct hikari_output *output, struct wlr_box *region)
{
assert(output != NULL);
assert(region != NULL);
wlr_output_damage_add_box(output->damage, region);
}
#endif

View File

@ -0,0 +1,20 @@
#if !defined(HIKARI_POINTER_CONFIG_H)
#define HIKARI_POINTER_CONFIG_H
#include <libinput.h>
#include <wayland-util.h>
struct hikari_pointer_config {
struct wl_list link;
char *name;
double accel;
enum libinput_config_scroll_method scroll_method;
uint32_t scroll_button;
};
void
hikari_pointer_config_fini(struct hikari_pointer_config *pointer_config);
#endif

View File

@ -0,0 +1,18 @@
#if !defined(HIKARI_RENDER_DATA_H)
#define HIKARI_RENDER_DATA_H
#include <wlr/types/wlr_box.h>
struct wlr_output *output;
struct wlr_renderer *renderer;
struct timespec *when;
struct hikari_render_data {
struct wlr_output *output;
struct wlr_renderer *renderer;
pixman_region32_t *damage;
struct wlr_box *geometry;
struct timespec *when;
};
#endif

View File

@ -0,0 +1,15 @@
#if !defined(HIKARI_RESIZE_MODE_H)
#define HIKARI_RESIZE_MODE_H
#include <hikari/mode.h>
struct hikari_keybinding;
struct hikari_resize_mode {
struct hikari_mode mode;
};
void
hikari_resize_mode_init(struct hikari_resize_mode *resize_mode);
#endif

294
include/hikari/server.h Normal file
View File

@ -0,0 +1,294 @@
#if !defined(HIKARI_SERVER_H)
#define HIKARI_SERVER_H
#include <wayland-server-core.h>
#include <wayland-util.h>
#include <hikari/exec_select_mode.h>
#include <hikari/group_assign_mode.h>
#include <hikari/indicator.h>
#include <hikari/keyboard_grab_mode.h>
#include <hikari/mark_assign_mode.h>
#include <hikari/mark_select_mode.h>
#include <hikari/move_mode.h>
#include <hikari/normal_mode.h>
#include <hikari/resize_mode.h>
#include <hikari/tiling_mode.h>
#include <hikari/workspace.h>
struct wlr_input_device;
struct wlr_xcursor_manager;
struct hikari_output;
struct hikari_group;
struct hikari_server {
bool locked;
bool cycling;
#ifndef NDEBUG
bool track_damage;
#endif
const char *socket;
struct hikari_indicator indicator;
struct wl_display *display;
struct wl_event_loop *event_loop;
struct wlr_backend *backend;
struct wlr_renderer *renderer;
struct wlr_xdg_output_manager_v1 *output_manager;
struct wlr_data_device_manager *data_device_manager;
struct wl_listener new_output;
struct wl_listener new_input;
struct wl_listener new_xdg_surface;
struct wl_listener cursor_motion_absolute;
struct wl_listener cursor_motion;
struct wl_listener cursor_frame;
struct wl_listener cursor_axis;
struct wl_listener cursor_button;
struct wl_listener request_set_primary_selection;
struct wl_listener request_set_selection;
struct wl_listener output_layout_change;
struct wl_listener new_decoration;
#ifdef HAVE_XWAYLAND
struct wl_listener new_xwayland_surface;
struct wlr_xwayland *xwayland;
#endif
struct wlr_compositor *compositor;
struct wlr_server_decoration_manager *decoration_manager;
struct wlr_xdg_shell *xdg_shell;
struct wlr_output_layout *output_layout;
struct wlr_seat *seat;
struct hikari_workspace *workspace;
struct wlr_cursor *cursor;
struct wlr_xcursor_manager *cursor_mgr;
struct wl_list keyboards;
struct wl_list outputs;
struct wl_list groups;
struct wl_list visible_groups;
struct wl_list workspaces;
struct hikari_mode *mode;
struct hikari_normal_mode normal_mode;
struct hikari_mark_select_mode mark_select_mode;
struct hikari_mark_assign_mode mark_assign_mode;
struct hikari_exec_select_mode exec_select_mode;
struct hikari_group_assign_mode group_assign_mode;
struct hikari_keyboard_grab_mode keyboard_grab_mode;
struct hikari_tiling_mode tiling_mode;
struct hikari_move_mode move_mode;
struct hikari_resize_mode resize_mode;
struct {
uint32_t modifiers;
bool mod_released;
bool mod_changed;
bool mod_pressed;
} keyboard_state;
};
extern struct hikari_server hikari_server;
static inline bool
hikari_server_is_cycling(void)
{
return hikari_server.cycling;
}
static inline void
hikari_server_set_cycling(void)
{
hikari_server.cycling = true;
}
static inline void
hikari_server_unset_cycling(void)
{
hikari_server.cycling = false;
}
void
hikari_server_activate_cursor(void);
void
hikari_server_deactivate_cursor(void);
void
hikari_server_start(void);
void
hikari_server_stop();
void
hikari_server_terminate(void *arg);
void
hikari_server_cursor_focus(void);
void
hikari_server_lock(void *arg);
void
hikari_server_execute_command(void *arg);
void
hikari_server_unlock(void);
struct hikari_group *
hikari_server_find_group(const char *group_name);
struct hikari_group *
hikari_server_find_or_create_group(const char *group_name);
#define SHEET_ACTIONS(n) \
static inline void hikari_server_display_sheet_##n(void *arg) \
{ \
hikari_workspace_display_sheet_##n(hikari_server.workspace); \
} \
\
static inline void hikari_server_pin_view_to_sheet_##n(void *arg) \
{ \
hikari_workspace_pin_view_to_sheet_##n(hikari_server.workspace); \
}
SHEET_ACTIONS(0)
SHEET_ACTIONS(1)
SHEET_ACTIONS(2)
SHEET_ACTIONS(3)
SHEET_ACTIONS(4)
SHEET_ACTIONS(5)
SHEET_ACTIONS(6)
SHEET_ACTIONS(7)
SHEET_ACTIONS(8)
SHEET_ACTIONS(9)
SHEET_ACTIONS(alternate)
SHEET_ACTIONS(current)
SHEET_ACTIONS(next)
SHEET_ACTIONS(prev)
#undef SHEET_ACTIONS
#define MOVE_RESIZE_ACTIONS(dir, x, y) \
static inline void hikari_server_move_view_##dir(void *arg) \
{ \
hikari_workspace_move_view(hikari_server.workspace, x, y); \
} \
\
static inline void hikari_server_decrease_view_size_##dir(void *arg) \
{ \
hikari_workspace_resize_view(hikari_server.workspace, x, y); \
} \
\
static inline void hikari_server_increase_view_size_##dir(void *arg) \
{ \
hikari_workspace_resize_view(hikari_server.workspace, x, y); \
} \
\
static inline void hikari_server_snap_view_##dir(void *arg) \
{ \
hikari_workspace_snap_view_##dir(hikari_server.workspace); \
}
MOVE_RESIZE_ACTIONS(up, 0, -100)
MOVE_RESIZE_ACTIONS(down, 0, 100)
MOVE_RESIZE_ACTIONS(left, -100, 0)
MOVE_RESIZE_ACTIONS(right, 100, 0)
#undef MOVE_RESIZE_ACTIONS
#define CYCLE_ACTION(n) void hikari_server_cycle_##n(void *arg);
CYCLE_ACTION(first_group_view)
CYCLE_ACTION(last_group_view)
CYCLE_ACTION(next_group_view)
CYCLE_ACTION(prev_group_view)
CYCLE_ACTION(next_layout_view)
CYCLE_ACTION(prev_layout_view)
CYCLE_ACTION(first_layout_view)
CYCLE_ACTION(last_layout_view)
CYCLE_ACTION(next_group)
CYCLE_ACTION(prev_group)
CYCLE_ACTION(next_sheet_view)
CYCLE_ACTION(prev_sheet_view)
#undef CYCLE_ACTION
#define WORKSPACE_ACTION(name) \
static inline void hikari_server_##name(void *arg) \
{ \
hikari_workspace_##name(hikari_server.workspace); \
}
WORKSPACE_ACTION(toggle_view_vertical_maximize)
WORKSPACE_ACTION(toggle_view_horizontal_maximize)
WORKSPACE_ACTION(toggle_view_full_maximize)
WORKSPACE_ACTION(toggle_view_floating)
WORKSPACE_ACTION(toggle_view_iconified)
WORKSPACE_ACTION(only_view)
WORKSPACE_ACTION(only_group)
WORKSPACE_ACTION(hide_view)
WORKSPACE_ACTION(hide_group)
WORKSPACE_ACTION(show_group)
WORKSPACE_ACTION(raise_view)
WORKSPACE_ACTION(raise_group)
WORKSPACE_ACTION(lower_view)
WORKSPACE_ACTION(lower_group)
WORKSPACE_ACTION(show_iconified_sheet_views)
WORKSPACE_ACTION(show_all_iconified_views)
WORKSPACE_ACTION(reset_view_geometry)
WORKSPACE_ACTION(quit_view)
WORKSPACE_ACTION(exchange_next_view)
WORKSPACE_ACTION(exchange_prev_view)
WORKSPACE_ACTION(exchange_main_layout_view)
WORKSPACE_ACTION(show_all_group_views)
WORKSPACE_ACTION(switch_to_next_inhabited_sheet)
WORKSPACE_ACTION(switch_to_prev_inhabited_sheet)
WORKSPACE_ACTION(show_all_sheet_views)
#undef WORKSPACE_ACTION
static inline void
hikari_server_clear_workspace(void *arg)
{
hikari_workspace_clear(hikari_server.workspace);
}
#define MODE(name) \
void hikari_server_enter_##name##_mode(void *arg); \
\
static inline bool hikari_server_in_##name##_mode(void) \
{ \
return hikari_server.mode == \
(struct hikari_mode *)&hikari_server.name##_mode; \
}
MODE(normal)
MODE(group_assign)
MODE(keyboard_grab)
MODE(tiling)
MODE(mark_assign)
MODE(mark_select)
MODE(exec_select)
MODE(move)
MODE(resize)
void
hikari_server_enter_mark_select_switch_mode(void *arg);
#undef MODE
void
hikari_server_refresh_indication(void);
void
hikari_server_reset_sheet_layout(void *arg);
void
hikari_server_layout_sheet(void *arg);
#endif

92
include/hikari/sheet.h Normal file
View File

@ -0,0 +1,92 @@
#if !defined(HIKARI_SHEET_H)
#define HIKARI_SHEET_H
#include <wayland-util.h>
#include <wlr/types/wlr_box.h>
struct hikari_group;
struct hikari_layout;
struct hikari_split;
struct hikari_workspace;
struct hikari_sheet {
uint8_t nr;
struct wl_list views;
struct hikari_layout *layout;
struct hikari_group *group;
struct hikari_workspace *workspace;
};
void
hikari_sheet_init(
struct hikari_sheet *sheet, int nr, struct hikari_workspace *workspace);
void
hikari_sheet_fini(struct hikari_sheet *sheet);
static const int HIKARI_NR_OF_SHEETS = 10;
struct hikari_view *
hikari_sheet_first_view(struct hikari_sheet *sheet);
struct hikari_view *
hikari_sheet_last_view(struct hikari_sheet *sheet);
struct hikari_view *
hikari_sheet_next_view(struct hikari_sheet *sheet, struct hikari_view *view);
struct hikari_view *
hikari_sheet_prev_view(struct hikari_sheet *sheet, struct hikari_view *view);
struct hikari_view *
hikari_sheet_first_tileable_view(struct hikari_sheet *sheet);
struct hikari_view *
hikari_sheet_vertical_layout(struct hikari_sheet *sheet,
struct hikari_view *first,
struct wlr_box *frame,
int max);
struct hikari_view *
hikari_sheet_horizontal_layout(struct hikari_sheet *sheet,
struct hikari_view *first,
struct wlr_box *frame,
int max);
struct hikari_view *
hikari_sheet_grid_layout(struct hikari_sheet *sheet,
struct hikari_view *first,
struct wlr_box *frame,
int max);
struct hikari_view *
hikari_sheet_full_layout(struct hikari_sheet *sheet,
struct hikari_view *first,
struct wlr_box *frame,
int max);
int
hikari_sheet_tileable_views(struct hikari_sheet *sheet);
void
hikari_sheet_reset_layout(struct hikari_sheet *sheet);
struct hikari_sheet *
hikari_sheet_next(struct hikari_sheet *sheet);
struct hikari_sheet *
hikari_sheet_prev(struct hikari_sheet *sheet);
struct hikari_sheet *
hikari_sheet_next_inhabited(struct hikari_sheet *sheet);
struct hikari_sheet *
hikari_sheet_prev_inhabited(struct hikari_sheet *sheet);
void
hikari_sheet_apply_split(
struct hikari_sheet *sheet, struct hikari_split *split);
#endif

82
include/hikari/split.h Normal file
View File

@ -0,0 +1,82 @@
#if !defined(HIKARI_SPLIT_H)
#define HIKARI_SPLIT_H
#include <wlr/types/wlr_box.h>
struct hikari_render_data;
struct hikari_sheet;
struct hikari_view;
typedef struct hikari_view *(*layout_func_t)(
struct hikari_sheet *, struct hikari_view *, struct wlr_box *, int);
enum hikari_split_type {
HIKARI_SPLIT_TYPE_VERTICAL,
HIKARI_SPLIT_TYPE_HORIZONTAL,
HIKARI_SPLIT_TYPE_CONTAINER
};
struct hikari_split {
enum hikari_split_type type;
};
struct hikari_vertical_split {
struct hikari_split split;
float factor;
struct hikari_split *left;
struct hikari_split *right;
};
struct hikari_horizontal_split {
struct hikari_split split;
float factor;
struct hikari_split *top;
struct hikari_split *bottom;
};
struct hikari_container {
struct hikari_split split;
struct wlr_box geometry;
int max;
layout_func_t layout;
};
void
hikari_split_apply(struct hikari_split *split,
struct wlr_box *geometry,
struct hikari_view *first);
void
hikari_container_init(
struct hikari_container *container, int nr_of_views, layout_func_t layout);
void
hikari_split_fini(struct hikari_split *split);
void
hikari_vertical_split_init(struct hikari_vertical_split *vertical_split,
float factor,
struct hikari_split *left,
struct hikari_split *right);
void
hikari_horizontal_split_init(struct hikari_horizontal_split *horizontal_split,
float factor,
struct hikari_split *left,
struct hikari_split *right);
void
hikari_split_render(
struct hikari_split *split, struct hikari_render_data *render_data);
void
hikari_container_render(
struct hikari_container *container, struct hikari_render_data *render_data);
#endif

32
include/hikari/tile.h Normal file
View File

@ -0,0 +1,32 @@
#if !defined(HIKARI_TILE_H)
#define HIKARI_TILE_H
#include <wlr/types/wlr_box.h>
struct hikari_layout;
struct hikari_view;
struct hikari_tile {
struct hikari_view *view;
struct wlr_box view_geometry;
struct wlr_box tile_geometry;
struct wl_list layout_tiles;
};
void
hikari_tile_init(struct hikari_tile *tile,
struct hikari_view *view,
struct wlr_box *tile_geometry,
struct wlr_box *view_geometry);
void
hikari_tile_fini(struct hikari_tile *tile);
struct hikari_view *
hikari_tile_next_view(struct hikari_tile *tile);
struct hikari_view *
hikari_tile_prev_view(struct hikari_tile *tile);
#endif

View File

@ -0,0 +1,13 @@
#if !defined(HIKARI_TILING_MODE_H)
#define HIKARI_TILING_MODE_H
#include <hikari/mode.h>
struct hikari_tiling_mode {
struct hikari_mode mode;
};
void
hikari_tiling_mode_init(struct hikari_tiling_mode *tiling_mode);
#endif

18
include/hikari/unlocker.h Normal file
View File

@ -0,0 +1,18 @@
#if !defined(HIKARI_UNLOCKER_H)
#define HIKARI_UNLOCKER_H
#include <wayland-server-core.h>
void
hikari_unlocker_init(void);
void
hikari_unlocker_fini(void);
void
hikari_unlocker_start(void);
void
hikari_unlocker_key_handler(struct wl_listener *listener, void *data);
#endif

42
include/hikari/utf8.h Normal file
View File

@ -0,0 +1,42 @@
#if !defined(HIKARI_UTF8_H)
#define HIKARI_UTF8_H
#include <stdint.h>
static inline size_t
utf8_chsize(uint32_t codepoint)
{
if (codepoint < 0x80) {
return 1;
} else if (codepoint < 0x800) {
return 2;
} else if (codepoint < 0x10000) {
return 3;
}
return 4;
}
static inline void
utf8_encode(char *buffer, size_t length, uint32_t codepoint)
{
uint8_t first;
if (codepoint < 0x80) {
first = 0;
} else if (codepoint < 0x800) {
first = 0xc0;
} else if (codepoint < 0x10000) {
first = 0xe0;
} else {
first = 0xf0;
}
for (size_t i = length - 1; i > 0; --i) {
buffer[i] = (codepoint & 0x3f) | 0x80;
codepoint >>= 6;
}
buffer[0] = codepoint | first;
}
#endif

323
include/hikari/view.h Normal file
View File

@ -0,0 +1,323 @@
#if !defined(HIKARI_VIEW_H)
#define HIKARI_VIEW_H
#include <assert.h>
#include <wayland-util.h>
#include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_surface.h>
#include <hikari/border.h>
#include <hikari/group.h>
#include <hikari/indicator_frame.h>
#include <hikari/maximized_state.h>
#include <hikari/operation.h>
#include <hikari/output.h>
#include <hikari/server.h>
#include <hikari/sheet.h>
#include <hikari/tile.h>
#include <hikari/view_interface.h>
#include <hikari/workspace.h>
struct hikari_mark;
struct hikari_render_data;
enum hikari_view_type { HIKARI_XDG_VIEW, HIKARI_XWAYLAND_VIEW };
struct hikari_view;
struct hikari_view_decoration {
struct wlr_server_decoration *wlr_decoration;
struct hikari_view *view;
struct wl_listener mode;
};
struct hikari_view {
struct hikari_view_interface view_interface;
enum hikari_view_type type;
struct hikari_sheet *sheet;
struct hikari_group *group;
struct hikari_mark *mark;
struct hikari_output *output;
struct wlr_surface *surface;
bool use_csd;
unsigned int flags;
char *title;
struct hikari_border border;
struct hikari_indicator_frame indicator_frame;
struct hikari_tile *tile;
struct wlr_box geometry;
struct hikari_maximized_state *maximized_state;
struct wl_list children;
struct wl_list output_views;
struct wl_list workspace_views;
struct wl_list sheet_views;
struct wl_list group_views;
struct wl_list visible_group_views;
struct hikari_operation pending_operation;
struct wlr_box *current_geometry;
struct wlr_box *current_unmaximized_geometry;
struct hikari_view_decoration decoration;
uint32_t (*resize)(struct hikari_view *, int, int);
void (*move)(struct hikari_view *, int, int);
void (*activate)(struct hikari_view *, bool);
void (*quit)(struct hikari_view *);
void (*hide)(struct hikari_view *);
void (*show)(struct hikari_view *);
void (*constraints)(struct hikari_view *, int *, int *, int *, int *);
};
struct hikari_view_child {
struct wl_list link;
struct wlr_surface *surface;
struct hikari_view *parent;
struct wl_listener commit;
struct wl_listener new_subsurface;
};
void
hikari_view_child_init(struct hikari_view_child *view_child,
struct hikari_view *parent,
struct wlr_surface *surface);
void
hikari_view_child_fini(struct hikari_view_child *view_child);
struct hikari_view_subsurface {
struct hikari_view_child view_child;
struct wlr_subsurface *subsurface;
struct wl_listener destroy;
};
void
hikari_view_subsurface_init(struct hikari_view_subsurface *view_subsurface,
struct hikari_view *parent,
struct wlr_subsurface *subsurface);
void
hikari_view_subsurface_fini(struct hikari_view_subsurface *view_subsurface);
#define FLAG(name, shift) \
static const unsigned long hikari_view_##name##_flag = 1UL << shift; \
\
static inline bool hikari_view_is_##name(struct hikari_view *view) \
{ \
assert(view != NULL); \
return (view->flags & hikari_view_##name##_flag); \
} \
\
static inline void hikari_view_set_##name(struct hikari_view *view) \
{ \
assert(view != NULL); \
view->flags |= hikari_view_##name##_flag; \
} \
\
static inline void hikari_view_unset_##name(struct hikari_view *view) \
{ \
assert(view != NULL); \
view->flags &= ~hikari_view_##name##_flag; \
}
FLAG(hidden, 0UL)
FLAG(iconified, 1UL)
FLAG(floating, 2UL)
#undef FLAG
void
hikari_view_init(struct hikari_view *view,
enum hikari_view_type type,
struct hikari_workspace *workspace);
void
hikari_view_fini(struct hikari_view *view);
void
hikari_view_manage(struct hikari_view *view,
struct hikari_sheet *sheet,
struct hikari_group *group);
void
hikari_view_set_title(struct hikari_view *view, const char *title);
#define VIEW_ACTION(name) void hikari_view_##name(struct hikari_view *view);
VIEW_ACTION(show)
VIEW_ACTION(hide)
VIEW_ACTION(raise)
VIEW_ACTION(raise_hidden)
VIEW_ACTION(lower)
VIEW_ACTION(toggle_full_maximize)
VIEW_ACTION(toggle_vertical_maximize)
VIEW_ACTION(toggle_horizontal_maximize)
VIEW_ACTION(toggle_floating)
VIEW_ACTION(damage_whole)
VIEW_ACTION(commit_pending_geometry)
VIEW_ACTION(top_left_cursor)
VIEW_ACTION(bottom_right_cursor)
VIEW_ACTION(center_cursor)
VIEW_ACTION(toggle_iconified)
VIEW_ACTION(reset_geometry)
#undef VIEW_ACTION
void
hikari_view_pin_to_sheet(struct hikari_view *view, struct hikari_sheet *sheet);
void
hikari_view_group(struct hikari_view *view, struct hikari_group *group);
void
hikari_view_resize(struct hikari_view *view, int width, int height);
void
hikari_view_move(struct hikari_view *view, int x, int y);
void
hikari_view_move_absolute(struct hikari_view *view, int x, int y);
void
hikari_view_resize_absolute(struct hikari_view *view, int x, int y);
void
hikari_view_assign_sheet(struct hikari_view *view, struct hikari_sheet *sheet);
void
hikari_view_tile(struct hikari_view *view, struct wlr_box *geometry);
void
hikari_view_exchange(struct hikari_view *from, struct hikari_view *to);
void
hikari_view_commit_pending_operation(struct hikari_view *view);
void
hikari_view_damage_surface(
struct hikari_view *view, struct wlr_surface *surface, bool whole);
void
hikari_view_refresh_geometry(
struct hikari_view *view, struct wlr_box *geometry);
void
hikari_view_activate(struct hikari_view *view, bool active);
static inline bool
hikari_view_is_dirty(struct hikari_view *view)
{
assert(view != NULL);
return view->pending_operation.dirty;
}
static inline void
hikari_view_set_dirty(struct hikari_view *view)
{
assert(view != NULL);
view->pending_operation.dirty = true;
}
static inline void
hikari_view_unset_dirty(struct hikari_view *view)
{
assert(view != NULL);
view->pending_operation.dirty = false;
}
static inline bool
hikari_view_was_updated(struct hikari_view *view, uint32_t serial)
{
assert(view != NULL);
return hikari_view_is_dirty(view) && serial >= view->pending_operation.serial;
}
static inline void
hikari_view_quit(struct hikari_view *view)
{
assert(view != NULL);
if (view->quit) {
view->quit(view);
}
}
static inline bool
hikari_view_is_fully_maximized(struct hikari_view *view)
{
assert(view != NULL);
return view->maximized_state != NULL &&
view->maximized_state->maximization ==
HIKARI_MAXIMIZATION_FULLY_MAXIMIZED;
}
static inline void
hikari_view_for_each_surface(
struct hikari_view *view, wlr_surface_iterator_func_t func, void *data)
{
assert(view != NULL);
assert(view->surface != NULL);
wlr_surface_for_each_surface(view->surface, func, data);
}
static inline struct wlr_box *
hikari_view_geometry(struct hikari_view *view)
{
assert(view != NULL);
return view->current_geometry;
}
static inline struct wlr_box *
hikari_view_border_geometry(struct hikari_view *view)
{
assert(view != NULL);
return &view->border.geometry;
}
static inline bool
hikari_view_has_focus(struct hikari_view *view)
{
assert(view != NULL);
return hikari_server.workspace->focus_view == view;
}
static inline bool
hikari_view_wants_border(struct hikari_view *view)
{
assert(view != NULL);
return view->border.state != HIKARI_BORDER_NONE;
}
static inline bool
hikari_view_is_tileable(struct hikari_view *view)
{
assert(view != NULL);
return !(view->flags &
(hikari_view_hidden_flag | hikari_view_floating_flag)) &&
!hikari_view_is_dirty(view);
}
static inline bool
hikari_view_is_tiled(struct hikari_view *view)
{
assert(view != NULL);
return view->tile != NULL;
}
static inline bool
hikari_view_is_mapped(struct hikari_view *view)
{
assert(view != NULL);
return view->surface != NULL;
}
#endif

View File

@ -0,0 +1,30 @@
#if !defined(HIKARI_VIEW_AUTOCONF_H)
#define HIKARI_VIEW_AUTOCONF_H
#include <stdbool.h>
#include <wayland-util.h>
struct hikari_mark;
struct hikari_view_autoconf {
struct wl_list link;
char *app_id;
char *group_name;
int sheet_nr;
struct hikari_mark *mark;
struct {
int x;
int y;
} position;
bool focus;
};
void
hikari_view_autoconf_fini(struct hikari_view_autoconf *autoconf);
#endif

View File

@ -0,0 +1,46 @@
#if !defined(HIKARI_VIEW_INTERFACE_H)
#define HIKARI_VIEW_INTERFACE_H
struct wlr_surface;
struct hikari_view_interface {
struct wlr_surface *(*surface_at)(
struct hikari_view_interface *view_interface,
double ox,
double oy,
double *sx,
double *sy);
void (*focus)(struct hikari_view_interface *view_interface);
void (*for_each_surface)(struct hikari_view_interface *view_interface,
void (*func)(struct wlr_surface *, int, int, void *),
void *data);
};
static inline struct wlr_surface *
hikari_view_interface_surface_at(struct hikari_view_interface *view_interface,
double ox,
double oy,
double *sx,
double *sy)
{
return view_interface->surface_at(view_interface, ox, oy, sx, sy);
}
static inline void
hikari_view_interface_focus(struct hikari_view_interface *view_interface)
{
view_interface->focus(view_interface);
}
static inline void
hikari_view_interface_for_each_surface(
struct hikari_view_interface *view_interface,
void (*func)(struct wlr_surface *, int, int, void *),
void *data)
{
view_interface->for_each_surface(view_interface, func, data);
}
#endif

142
include/hikari/workspace.h Normal file
View File

@ -0,0 +1,142 @@
#if !defined(HIKARI_WORKSPACE_H)
#define HIKARI_WORKSPACE_H
#include <wayland-server-core.h>
#include <wayland-util.h>
struct hikari_output;
struct hikari_render_data;
struct hikari_sheet;
struct hikari_view;
struct wlr_texture;
struct hikari_workspace {
struct hikari_sheet *sheet;
struct hikari_sheet *alternate_sheet;
struct hikari_output *output;
struct hikari_sheet *sheets;
struct hikari_view *focus_view;
struct wlr_texture *background;
struct wl_list views;
struct wl_list server_workspaces;
};
void
hikari_workspace_init(
struct hikari_workspace *workspace, struct hikari_output *output);
void
hikari_workspace_fini(struct hikari_workspace *workspace);
void
hikari_workspace_render_background(
struct hikari_workspace *workspace, struct hikari_render_data *render_data);
void
hikari_workspace_focus_view(
struct hikari_workspace *workspace, struct hikari_view *view);
void
hikari_workspace_move_view(struct hikari_workspace *workspace, int dx, int dy);
void
hikari_workspace_resize_view(
struct hikari_workspace *workspace, int dwidth, int dheight);
#define WORKSPACE_CYCLE_ACTION(name) \
struct hikari_view *hikari_workspace_##name( \
struct hikari_workspace *workspace);
WORKSPACE_CYCLE_ACTION(first_view)
WORKSPACE_CYCLE_ACTION(last_view)
WORKSPACE_CYCLE_ACTION(next_view)
WORKSPACE_CYCLE_ACTION(prev_view)
WORKSPACE_CYCLE_ACTION(next_layout_view)
WORKSPACE_CYCLE_ACTION(prev_layout_view)
WORKSPACE_CYCLE_ACTION(first_layout_view)
WORKSPACE_CYCLE_ACTION(last_layout_view)
WORKSPACE_CYCLE_ACTION(first_group_view)
WORKSPACE_CYCLE_ACTION(last_group_view)
WORKSPACE_CYCLE_ACTION(next_group_view)
WORKSPACE_CYCLE_ACTION(prev_group_view)
WORKSPACE_CYCLE_ACTION(next_group)
WORKSPACE_CYCLE_ACTION(prev_group)
WORKSPACE_CYCLE_ACTION(next_sheet_view)
WORKSPACE_CYCLE_ACTION(prev_sheet_view)
#undef WORKSPACE_CYCLE_ACTION
#define WORKSPACE_ACTION(name) \
void hikari_workspace_##name(struct hikari_workspace *workspace);
WORKSPACE_ACTION(clear)
WORKSPACE_ACTION(quit_view)
WORKSPACE_ACTION(display_sheet_0)
WORKSPACE_ACTION(display_sheet_1)
WORKSPACE_ACTION(display_sheet_2)
WORKSPACE_ACTION(display_sheet_3)
WORKSPACE_ACTION(display_sheet_4)
WORKSPACE_ACTION(display_sheet_5)
WORKSPACE_ACTION(display_sheet_6)
WORKSPACE_ACTION(display_sheet_7)
WORKSPACE_ACTION(display_sheet_8)
WORKSPACE_ACTION(display_sheet_9)
WORKSPACE_ACTION(display_sheet_alternate)
WORKSPACE_ACTION(display_sheet_current)
WORKSPACE_ACTION(display_sheet_next)
WORKSPACE_ACTION(display_sheet_prev)
WORKSPACE_ACTION(switch_to_next_sheet)
WORKSPACE_ACTION(switch_to_prev_sheet)
WORKSPACE_ACTION(switch_to_next_inhabited_sheet)
WORKSPACE_ACTION(switch_to_prev_inhabited_sheet)
WORKSPACE_ACTION(raise_view)
WORKSPACE_ACTION(raise_group)
WORKSPACE_ACTION(lower_view)
WORKSPACE_ACTION(lower_group)
WORKSPACE_ACTION(hide_view)
WORKSPACE_ACTION(hide_group)
WORKSPACE_ACTION(snap_view_up)
WORKSPACE_ACTION(snap_view_down)
WORKSPACE_ACTION(snap_view_left)
WORKSPACE_ACTION(snap_view_right)
WORKSPACE_ACTION(only_view)
WORKSPACE_ACTION(only_group)
WORKSPACE_ACTION(pin_view_to_sheet_0)
WORKSPACE_ACTION(pin_view_to_sheet_1)
WORKSPACE_ACTION(pin_view_to_sheet_2)
WORKSPACE_ACTION(pin_view_to_sheet_3)
WORKSPACE_ACTION(pin_view_to_sheet_4)
WORKSPACE_ACTION(pin_view_to_sheet_5)
WORKSPACE_ACTION(pin_view_to_sheet_6)
WORKSPACE_ACTION(pin_view_to_sheet_7)
WORKSPACE_ACTION(pin_view_to_sheet_8)
WORKSPACE_ACTION(pin_view_to_sheet_9)
WORKSPACE_ACTION(pin_view_to_sheet_alternate)
WORKSPACE_ACTION(pin_view_to_sheet_current)
WORKSPACE_ACTION(pin_view_to_sheet_next)
WORKSPACE_ACTION(pin_view_to_sheet_prev)
WORKSPACE_ACTION(toggle_view_iconified)
WORKSPACE_ACTION(toggle_view_floating)
WORKSPACE_ACTION(toggle_view_full_maximize)
WORKSPACE_ACTION(toggle_view_vertical_maximize)
WORKSPACE_ACTION(toggle_view_horizontal_maximize)
WORKSPACE_ACTION(toggle_view_horizontal_maximize)
WORKSPACE_ACTION(reset_view_geometry)
WORKSPACE_ACTION(show_iconified_sheet_views)
WORKSPACE_ACTION(show_all_iconified_views)
WORKSPACE_ACTION(exchange_next_view)
WORKSPACE_ACTION(exchange_prev_view)
WORKSPACE_ACTION(exchange_main_layout_view)
WORKSPACE_ACTION(show_group)
WORKSPACE_ACTION(show_all_group_views)
WORKSPACE_ACTION(show_all_sheet_views)
#undef WORKSPACE_ACTION
void
hikari_workspace_switch_sheet(
struct hikari_workspace *workspace, struct hikari_sheet *sheet);
#endif

43
include/hikari/xdg_view.h Normal file
View File

@ -0,0 +1,43 @@
#if !defined(HIKARI_XDG_VIEW_H)
#define HIKARI_XDG_VIEW_H
#include <wayland-server-core.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <hikari/view.h>
struct hikari_render_data;
struct hikari_xdg_view {
struct hikari_view view;
struct wlr_xdg_surface *surface;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
struct wl_listener commit;
struct wl_listener new_popup;
struct wl_listener new_subsurface;
struct wl_listener set_title;
struct wl_listener request_fullscreen;
};
void
hikari_xdg_view_init(struct hikari_xdg_view *xdg_view,
struct wlr_xdg_surface *xdg_surface,
struct hikari_workspace *workspace);
struct hikari_xdg_popup {
struct hikari_view_child view_child;
struct wlr_xdg_popup *popup;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
struct wl_listener new_popup;
};
#endif

View File

@ -0,0 +1,39 @@
#if !defined(HIKARI_XWAYLAND_UNMANAGED_VIEW_H)
#define HIKARI_XWAYLAND_UNMANAGED_VIEW_H
#include <wayland-server-core.h>
#include <wayland-util.h>
#include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_surface.h>
#include <hikari/view_interface.h>
struct hikari_workspace;
struct hikari_xwayland_unmanaged_view {
struct hikari_view_interface view_interface;
struct wlr_xwayland_surface *surface;
struct hikari_workspace *workspace;
bool hidden;
struct wlr_box geometry;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
struct wl_listener request_configure;
struct wl_listener commit;
struct wl_list unmanaged_server_views;
};
void
hikari_xwayland_unmanaged_view_init(
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view,
struct wlr_xwayland_surface *xwayland_surface,
struct hikari_workspace *workspace);
#endif

View File

@ -0,0 +1,28 @@
#if !defined(HIKARI_XWAYLAND_VIEW_H)
#define HIKARI_XWAYLAND_VIEW_H
#include <wayland-server-core.h>
#include <hikari/view.h>
struct hikari_render_data;
struct hikari_xwayland_view {
struct hikari_view view;
struct wlr_xwayland_surface *surface;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
struct wl_listener request_configure;
struct wl_listener commit;
struct wl_listener set_title;
};
void
hikari_xwayland_view_init(struct hikari_xwayland_view *xwayland_view,
struct wlr_xwayland_surface *xwayland_surface,
struct hikari_workspace *workspace);
#endif

16
main.c Normal file
View File

@ -0,0 +1,16 @@
#include <stdlib.h>
#include <wlr/util/log.h>
#include <hikari/server.h>
int
main(int argc, char **argv)
{
#ifndef NDEBUG
wlr_log_init(WLR_DEBUG, NULL);
#endif
hikari_server_start();
hikari_server_stop();
return EXIT_SUCCESS;
}

28
src/background.c Normal file
View File

@ -0,0 +1,28 @@
#include <hikari/background.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <hikari/memory.h>
void
hikari_background_init(
struct hikari_background *background, const char *output_name, char *path)
{
size_t output_name_len = strlen(output_name);
background->output_name = hikari_malloc(output_name_len + 1);
strcpy(background->output_name, output_name);
background->path = path;
}
void
hikari_background_fini(struct hikari_background *background)
{
assert(background != NULL);
hikari_free(background->output_name);
hikari_free(background->path);
}

151
src/border.c Normal file
View File

@ -0,0 +1,151 @@
#include <hikari/border.h>
#include <assert.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h>
#include <hikari/color.h>
#include <hikari/configuration.h>
#include <hikari/output.h>
#include <hikari/render_data.h>
#include <hikari/view_interface.h>
static void
rect_render(float color[static 4],
struct wlr_box *box,
struct hikari_render_data *render_data)
{
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_union_rect(
&damage, &damage, box->x, box->y, box->width, box->height);
pixman_region32_intersect(&damage, &damage, render_data->damage);
bool damaged = pixman_region32_not_empty(&damage);
if (!damaged) {
goto buffer_damage_finish;
}
struct wlr_renderer *renderer = render_data->renderer;
assert(renderer);
float matrix[9];
wlr_matrix_project_box(matrix,
box,
WL_OUTPUT_TRANSFORM_NORMAL,
0,
render_data->output->transform_matrix);
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; i++) {
hikari_output_scissor_render(render_data->output, renderer, &rects[i]);
wlr_render_quad_with_matrix(renderer, color, matrix);
}
buffer_damage_finish:
pixman_region32_fini(&damage);
}
void
hikari_border_render(
struct hikari_border *border, struct hikari_render_data *render_data)
{
if (border->state == HIKARI_BORDER_NONE) {
return;
}
struct wlr_box *geometry = &border->geometry;
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_union_rect(&damage,
&damage,
geometry->x,
geometry->y,
geometry->width,
geometry->height);
pixman_region32_intersect(&damage, &damage, render_data->damage);
bool damaged = pixman_region32_not_empty(&damage);
if (!damaged) {
goto buffer_damage_finish;
}
float *color;
switch (border->state) {
case HIKARI_BORDER_INACTIVE:
color = hikari_configuration.border_inactive;
break;
case HIKARI_BORDER_ACTIVE:
color = hikari_configuration.border_active;
break;
default:
goto buffer_damage_finish;
}
struct wlr_renderer *renderer = render_data->renderer;
assert(renderer);
float matrix[9];
wlr_matrix_project_box(matrix,
geometry,
WL_OUTPUT_TRANSFORM_NORMAL,
0,
render_data->output->transform_matrix);
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; i++) {
hikari_output_scissor_render(render_data->output, renderer, &rects[i]);
rect_render(color, &border->top, render_data);
rect_render(color, &border->bottom, render_data);
rect_render(color, &border->left, render_data);
rect_render(color, &border->right, render_data);
}
buffer_damage_finish:
pixman_region32_fini(&damage);
}
void
hikari_border_refresh_geometry(
struct hikari_border *border, struct wlr_box *geometry)
{
if (border->state == HIKARI_BORDER_NONE) {
border->geometry = *geometry;
return;
} else {
border->geometry.x = geometry->x - hikari_configuration.border;
border->geometry.y = geometry->y - hikari_configuration.border;
border->geometry.width = geometry->width + hikari_configuration.border * 2;
border->geometry.height =
geometry->height + hikari_configuration.border * 2;
}
border->top.x = border->geometry.x;
border->top.y = border->geometry.y;
border->top.width = border->geometry.width;
border->top.height = hikari_configuration.border;
border->bottom.x = border->geometry.x;
border->bottom.y = border->geometry.y + border->geometry.height -
hikari_configuration.border;
border->bottom.width = border->geometry.width;
border->bottom.height = hikari_configuration.border;
border->left.x = border->geometry.x;
border->left.y = border->geometry.y;
border->left.width = hikari_configuration.border;
border->left.height = border->geometry.height;
border->right.x =
border->geometry.x + border->geometry.width - hikari_configuration.border;
border->right.y = border->geometry.y;
border->right.width = hikari_configuration.border;
border->right.height = border->geometry.height;
}

32
src/command.c Normal file
View File

@ -0,0 +1,32 @@
#include <hikari/command.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
void
hikari_command_execute(const char *cmd)
{
pid_t child;
int status;
child = fork();
if (child == 0) {
child = fork();
if (child == 0) {
setsid();
execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
}
_exit(child == -1);
}
for (;;) {
waitpid(child, &status, 0);
if (errno == EINTR) {
continue;
} else {
return;
}
}
}

83
src/completion.c Normal file
View File

@ -0,0 +1,83 @@
#include <hikari/completion.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <hikari/memory.h>
void
hikari_completion_init(struct hikari_completion *completion, char *data)
{
struct hikari_completion_item *item;
wl_list_init(&completion->items);
hikari_completion_add(completion, data);
item = wl_container_of(completion->items.next, item, completion_items);
completion->current_item = item;
}
void
hikari_completion_fini(struct hikari_completion *completion)
{
assert(completion != NULL);
struct hikari_completion_item *item = NULL, *item_temp;
wl_list_for_each_safe (
item, item_temp, &completion->items, completion_items) {
wl_list_remove(&item->completion_items);
hikari_free(item);
}
}
void
hikari_completion_add(struct hikari_completion *completion, char *data)
{
assert(completion != NULL);
struct hikari_completion_item *completion_item =
hikari_malloc(sizeof(struct hikari_completion_item));
strncpy(completion_item->data, data, sizeof(completion_item->data) - 1);
wl_list_insert(completion->items.prev, &completion_item->completion_items);
}
char *
hikari_completion_cancel(struct hikari_completion *completion)
{
assert(completion != NULL);
assert(!wl_list_empty(&completion->items));
struct hikari_completion_item *item =
wl_container_of(completion->items.next, item, completion_items);
completion->current_item = item;
return item->data;
}
#define COMPLETION(link) \
char *hikari_completion_##link(struct hikari_completion *completion) \
{ \
assert(completion != NULL); \
assert(!wl_list_empty(&completion->items)); \
\
struct wl_list *link; \
struct hikari_completion_item *item; \
\
link = completion->current_item->completion_items.link; \
if (link == &completion->items) { \
item = wl_container_of(completion->items.link, item, completion_items); \
} else { \
item = wl_container_of(link, item, completion_items); \
} \
\
completion->current_item = item; \
\
return item->data; \
}
COMPLETION(next)
COMPLETION(prev)
#undef COMPLETION

1427
src/configuration.c Normal file

File diff suppressed because it is too large Load Diff

26
src/exec.c Normal file
View File

@ -0,0 +1,26 @@
#include <hikari/exec.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <hikari/memory.h>
#include <hikari/view.h>
struct hikari_exec execs[HIKARI_NR_OF_EXECS];
void
hikari_execs_init(void)
{
/* for (int i = 0; i < HIKARI_NR_OF_EXECS; i++) { */
/* execs[i].command = NULL; */
/* } */
}
void
hikari_execs_fini(void)
{
for (int i = 0; i < HIKARI_NR_OF_EXECS; i++) {
hikari_free(execs[i].command);
}
}

230
src/exec_select_mode.c Normal file
View File

@ -0,0 +1,230 @@
#include <hikari/exec_select_mode.h>
#include <stdbool.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_keyboard.h>
#include <hikari/command.h>
#include <hikari/exec.h>
#include <hikari/indicator.h>
#include <hikari/indicator_frame.h>
#include <hikari/keyboard.h>
#include <hikari/normal_mode.h>
#include <hikari/render_data.h>
#include <hikari/view.h>
#include <hikari/workspace.h>
static struct hikari_exec *
lookup_exec(struct wlr_event_keyboard_key *event,
struct hikari_keyboard *keyboard,
bool *selected)
{
uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
*selected = false;
struct hikari_exec *exec = NULL;
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_a:
exec = HIKARI_EXEC_a;
*selected = true;
break;
case XKB_KEY_b:
exec = HIKARI_EXEC_b;
*selected = true;
break;
case XKB_KEY_c:
exec = HIKARI_EXEC_c;
*selected = true;
break;
case XKB_KEY_d:
exec = HIKARI_EXEC_d;
*selected = true;
break;
case XKB_KEY_e:
exec = HIKARI_EXEC_e;
*selected = true;
break;
case XKB_KEY_f:
exec = HIKARI_EXEC_f;
*selected = true;
break;
case XKB_KEY_g:
exec = HIKARI_EXEC_g;
*selected = true;
break;
case XKB_KEY_h:
exec = HIKARI_EXEC_h;
*selected = true;
break;
case XKB_KEY_i:
exec = HIKARI_EXEC_i;
*selected = true;
break;
case XKB_KEY_j:
exec = HIKARI_EXEC_j;
*selected = true;
break;
case XKB_KEY_k:
exec = HIKARI_EXEC_k;
*selected = true;
break;
case XKB_KEY_l:
exec = HIKARI_EXEC_l;
*selected = true;
break;
case XKB_KEY_m:
exec = HIKARI_EXEC_m;
*selected = true;
break;
case XKB_KEY_n:
exec = HIKARI_EXEC_n;
*selected = true;
break;
case XKB_KEY_o:
exec = HIKARI_EXEC_o;
*selected = true;
break;
case XKB_KEY_p:
exec = HIKARI_EXEC_p;
*selected = true;
break;
case XKB_KEY_q:
exec = HIKARI_EXEC_q;
*selected = true;
break;
case XKB_KEY_r:
exec = HIKARI_EXEC_r;
*selected = true;
break;
case XKB_KEY_s:
exec = HIKARI_EXEC_s;
*selected = true;
break;
case XKB_KEY_t:
exec = HIKARI_EXEC_t;
*selected = true;
break;
case XKB_KEY_u:
exec = HIKARI_EXEC_u;
*selected = true;
break;
case XKB_KEY_v:
exec = HIKARI_EXEC_v;
*selected = true;
break;
case XKB_KEY_w:
exec = HIKARI_EXEC_w;
*selected = true;
break;
case XKB_KEY_x:
exec = HIKARI_EXEC_x;
*selected = true;
break;
case XKB_KEY_y:
exec = HIKARI_EXEC_y;
*selected = true;
break;
case XKB_KEY_z:
exec = HIKARI_EXEC_z;
*selected = true;
break;
case XKB_KEY_BackSpace:
exec = NULL;
*selected = true;
break;
}
}
return exec;
}
static void
exec_select(struct hikari_workspace *workspace,
struct wlr_event_keyboard_key *event,
struct hikari_keyboard *keyboard)
{
bool selected;
struct hikari_exec *exec = lookup_exec(event, keyboard, &selected);
hikari_server_enter_normal_mode(NULL);
if (exec != NULL && exec->command != NULL) {
hikari_command_execute(exec->command);
}
}
static void
key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
struct hikari_workspace *workspace = hikari_server.workspace;
if (event->state == WLR_KEY_PRESSED) {
exec_select(workspace, event, keyboard);
}
}
static void
modifier_handler(struct wl_listener *listener, void *data)
{}
static void
button_handler(struct wl_listener *listener, void *data)
{}
static void
render(struct hikari_output *output, struct hikari_render_data *render_data)
{}
static void
cancel(void)
{}
static void
cursor_move(void)
{}
void
hikari_exec_select_mode_init(struct hikari_exec_select_mode *exec_select_mode)
{
exec_select_mode->mode.type = HIKARI_MODE_TYPE_SELECT_EXEC;
exec_select_mode->mode.key_handler = key_handler;
exec_select_mode->mode.button_handler = button_handler;
exec_select_mode->mode.modifier_handler = modifier_handler;
exec_select_mode->mode.render = render;
exec_select_mode->mode.cancel = cancel;
exec_select_mode->mode.cursor_move = cursor_move;
}

37
src/font.c Normal file
View File

@ -0,0 +1,37 @@
#include <hikari/font.h>
#include <cairo/cairo.h>
#include <string.h>
void
hikari_font_init(struct hikari_font *font, const char *font_name)
{
font->desc = pango_font_description_from_string(font_name);
}
void
hikari_font_fini(struct hikari_font *font)
{
pango_font_description_free(font->desc);
}
void
hikari_font_metrics(
struct hikari_font *font, const char *text, int *width, int *height)
{
cairo_surface_t *surface =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
cairo_t *cairo = cairo_create(surface);
PangoLayout *layout = pango_cairo_create_layout(cairo);
pango_layout_set_font_description(layout, font->desc);
pango_layout_set_text(layout, text, -1);
pango_cairo_update_layout(cairo, layout);
pango_cairo_show_layout(cairo, layout);
pango_layout_get_pixel_size(layout, width, height);
g_object_unref(layout);
cairo_surface_destroy(surface);
cairo_destroy(cairo);
}

55
src/geometry.c Normal file
View File

@ -0,0 +1,55 @@
#include <hikari/geometry.h>
#include <hikari/configuration.h>
#define SPLIT(n, x, y, width, height) \
void hikari_geometry_split_##n(struct wlr_box *src, \
float factor, \
int gap, \
struct wlr_box *dst1, \
struct wlr_box *dst2) \
{ \
int width = (src->width - gap) * factor; \
int rest = src->width - gap - width * 2; \
\
dst1->x = src->x; \
dst1->y = src->y; \
dst1->width = width + rest; \
dst1->height = src->height; \
\
dst2->x = src->x + dst1->width + gap; \
dst2->y = src->y; \
dst2->width = width; \
dst2->height = src->height; \
}
SPLIT(vertical, x, y, width, height)
SPLIT(horizontal, y, x, height, width)
#undef SPLIT
void
hikari_geometry_shrink(struct wlr_box *geometry, int gap)
{
geometry->x += gap;
geometry->y += gap;
geometry->width -= gap * 2;
geometry->height -= gap * 2;
}
void
hikari_geometry_constrain_position(
struct wlr_box *geometry, int screen_width, int screen_height, int x, int y)
{
if (x + geometry->width + hikari_configuration.border > screen_width) {
geometry->x = screen_width - geometry->width - hikari_configuration.border;
} else {
geometry->x = x;
}
if (y + geometry->height + hikari_configuration.border > screen_height) {
geometry->y =
screen_height - geometry->height - hikari_configuration.border;
} else {
geometry->y = y;
}
}

61
src/group.c Normal file
View File

@ -0,0 +1,61 @@
#include <hikari/group.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <hikari/memory.h>
#include <hikari/view.h>
void
hikari_group_init(struct hikari_group *group, const char *name)
{
int length = strlen(name) + 1;
group->name = hikari_malloc(length);
strcpy(group->name, name);
wl_list_init(&group->views);
wl_list_init(&group->visible_views);
wl_list_insert(&hikari_server.groups, &group->server_groups);
}
void
hikari_group_fini(struct hikari_group *group)
{
hikari_free(group->name);
wl_list_remove(&group->server_groups);
}
struct hikari_view *
hikari_group_first_view(
struct hikari_group *group, struct hikari_workspace *workspace)
{
assert(group != NULL);
struct hikari_view *view = NULL;
wl_list_for_each (view, &group->visible_views, visible_group_views) {
if (view->sheet->workspace == workspace) {
return view;
}
}
return NULL;
}
struct hikari_view *
hikari_group_last_view(
struct hikari_group *group, struct hikari_workspace *workspace)
{
assert(group != NULL);
struct hikari_view *view = NULL;
wl_list_for_each_reverse (view, &group->visible_views, visible_group_views) {
if (view->sheet->workspace == workspace) {
return view;
}
}
return NULL;
}

412
src/group_assign_mode.c Normal file
View File

@ -0,0 +1,412 @@
#include <hikari/group_assign_mode.h>
#include <stdbool.h>
#include <string.h>
#include <wayland-util.h>
#include <hikari/color.h>
#include <hikari/completion.h>
#include <hikari/configuration.h>
#include <hikari/group.h>
#include <hikari/indicator.h>
#include <hikari/indicator_frame.h>
#include <hikari/keyboard.h>
#include <hikari/memory.h>
#include <hikari/normal_mode.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
#include <hikari/sheet.h>
#include <hikari/view.h>
#include <hikari/workspace.h>
static bool
check_confirmation(
struct wlr_event_keyboard_key *event, struct hikari_keyboard *keyboard)
{
uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_Return:
return true;
break;
}
}
return false;
}
static bool
check_cancellation(
struct wlr_event_keyboard_key *event, struct hikari_keyboard *keyboard)
{
uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_Escape:
return true;
break;
}
}
return false;
}
static void
init_completion(void)
{
struct hikari_group_assign_mode *mode =
(struct hikari_group_assign_mode *)hikari_server.mode;
assert(mode == (struct hikari_group_assign_mode *)hikari_server.mode);
if (mode->completion != NULL) {
return;
}
struct hikari_group *group;
struct hikari_completion *completion =
hikari_malloc(sizeof(struct hikari_completion));
char *input = mode->input_buffer.buffer;
hikari_completion_init(completion, input);
wl_list_for_each (group, &hikari_server.groups, server_groups) {
char *name = group->name;
if (strstr(name, input) == name && strcmp(name, input) != 0) {
hikari_completion_add(completion, name);
}
}
mode->completion = completion;
}
static void
fini_completion(void)
{
struct hikari_group_assign_mode *mode =
(struct hikari_group_assign_mode *)hikari_server.mode;
assert(mode == (struct hikari_group_assign_mode *)hikari_server.mode);
if (mode->completion == NULL) {
return;
}
hikari_completion_fini(mode->completion);
hikari_free(mode->completion);
mode->completion = NULL;
}
static void
put_char(struct hikari_input_buffer *input_buffer,
struct xkb_state *xkb_state,
uint32_t keycode)
{
uint32_t codepoint = xkb_state_key_get_utf32(xkb_state, keycode);
if (codepoint) {
fini_completion();
hikari_input_buffer_add_utf32_char(input_buffer, codepoint);
}
}
static void
process_input_key(struct hikari_workspace *workspace,
struct wlr_event_keyboard_key *event,
struct hikari_keyboard *keyboard)
{
struct hikari_group_assign_mode *mode =
(struct hikari_group_assign_mode *)hikari_server.mode;
uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard);
const xkb_keysym_t *syms;
uint32_t keycode = event->keycode + 8;
char *text;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_Caps_Lock:
case XKB_KEY_Shift_L:
case XKB_KEY_Shift_R:
case XKB_KEY_Control_L:
case XKB_KEY_Control_R:
case XKB_KEY_Meta_L:
case XKB_KEY_Meta_R:
case XKB_KEY_Alt_L:
case XKB_KEY_Alt_R:
case XKB_KEY_Super_L:
case XKB_KEY_Super_R:
break;
case XKB_KEY_e:
if (modifiers == WLR_MODIFIER_CTRL) {
if (mode->completion != NULL) {
text = hikari_completion_cancel(mode->completion);
hikari_input_buffer_replace(&mode->input_buffer, text);
fini_completion();
}
} else {
put_char(&mode->input_buffer,
keyboard->device->keyboard->xkb_state,
keycode);
}
break;
case XKB_KEY_h:
fini_completion();
if (modifiers == WLR_MODIFIER_CTRL) {
hikari_input_buffer_remove_char(&mode->input_buffer);
} else {
put_char(&mode->input_buffer,
keyboard->device->keyboard->xkb_state,
keycode);
}
break;
case XKB_KEY_w:
fini_completion();
if (modifiers == WLR_MODIFIER_CTRL) {
hikari_input_buffer_clear(&mode->input_buffer);
} else {
put_char(&mode->input_buffer,
keyboard->device->keyboard->xkb_state,
keycode);
}
break;
case XKB_KEY_BackSpace:
fini_completion();
hikari_input_buffer_remove_char(&mode->input_buffer);
break;
case XKB_KEY_Tab:
init_completion();
text = hikari_completion_next(mode->completion);
hikari_input_buffer_replace(&mode->input_buffer, text);
break;
case XKB_KEY_ISO_Left_Tab:
init_completion();
text = hikari_completion_prev(mode->completion);
hikari_input_buffer_replace(&mode->input_buffer, text);
break;
default:
put_char(&mode->input_buffer,
keyboard->device->keyboard->xkb_state,
keycode);
break;
}
}
}
static void
confirm_group_assign(struct hikari_workspace *workspace)
{
struct hikari_group_assign_mode *mode =
(struct hikari_group_assign_mode *)&hikari_server.group_assign_mode;
assert(mode == (struct hikari_group_assign_mode *)hikari_server.mode);
struct wlr_box *geometry = hikari_view_geometry(workspace->focus_view);
struct hikari_group *group;
if (!strcmp(mode->input_buffer.buffer, "")) {
group = workspace->sheet->group;
hikari_indicator_update_group(&hikari_server.indicator,
geometry,
workspace->output,
"",
hikari_configuration.indicator_selected);
} else {
group = hikari_server_find_or_create_group(mode->input_buffer.buffer);
if (group->sheet == NULL) {
hikari_indicator_update_group(&hikari_server.indicator,
geometry,
workspace->output,
group->name,
hikari_configuration.indicator_selected);
} else {
hikari_indicator_update_group(&hikari_server.indicator,
geometry,
workspace->output,
"",
hikari_configuration.indicator_selected);
}
}
hikari_view_group(hikari_server.workspace->focus_view, group);
hikari_server_enter_normal_mode(NULL);
}
static void
cancel_group_assign(struct hikari_workspace *workspace)
{
struct wlr_box *geometry = hikari_view_geometry(workspace->focus_view);
hikari_indicator_update_group(&hikari_server.indicator,
geometry,
workspace->output,
workspace->focus_view->group->name,
hikari_configuration.indicator_selected);
hikari_server_enter_normal_mode(NULL);
}
static void
update_state(struct hikari_workspace *workspace,
struct hikari_keyboard *keyboard,
struct wlr_event_keyboard_key *event)
{
struct hikari_group_assign_mode *mode =
(struct hikari_group_assign_mode *)&hikari_server.group_assign_mode;
assert(mode == (struct hikari_group_assign_mode *)hikari_server.mode);
struct wlr_box *geometry = hikari_view_border_geometry(workspace->focus_view);
struct hikari_group *group;
process_input_key(workspace, event, keyboard);
group = hikari_server_find_group(mode->input_buffer.buffer);
if (!strcmp(mode->input_buffer.buffer, "")) {
hikari_indicator_update_group(&hikari_server.indicator,
geometry,
workspace->output,
" ",
hikari_configuration.indicator_insert);
} else {
hikari_indicator_update_group(&hikari_server.indicator,
geometry,
workspace->output,
mode->input_buffer.buffer,
hikari_configuration.indicator_insert);
}
if (group != mode->group) {
mode->group = group;
hikari_server_refresh_indication();
}
}
static void
assign_group(struct hikari_workspace *workspace,
struct wlr_event_keyboard_key *event,
struct hikari_keyboard *keyboard)
{
if (check_confirmation(event, keyboard)) {
confirm_group_assign(workspace);
} else if (check_cancellation(event, keyboard)) {
cancel_group_assign(workspace);
} else {
update_state(workspace, keyboard, event);
}
}
static void
key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
struct hikari_workspace *workspace = hikari_server.workspace;
if (event->state == WLR_KEY_PRESSED) {
assign_group(workspace, event, keyboard);
}
}
static void
modifier_handler(struct wl_listener *listener, void *data)
{}
static void
render(struct hikari_output *output, struct hikari_render_data *render_data)
{
struct hikari_group_assign_mode *mode = &hikari_server.group_assign_mode;
assert(mode == (struct hikari_group_assign_mode *)hikari_server.mode);
struct hikari_view *focus_view = hikari_server.workspace->focus_view;
assert(focus_view != NULL);
struct hikari_group *group = mode->group;
if (group != NULL) {
struct hikari_view *view;
wl_list_for_each_reverse (
view, &group->visible_views, visible_group_views) {
if (view->output == output && view != focus_view) {
render_data->geometry = hikari_view_border_geometry(view);
if (hikari_group_first_view(group, hikari_server.workspace) == view) {
hikari_indicator_frame_render(&view->indicator_frame,
hikari_configuration.indicator_first,
render_data);
} else {
hikari_indicator_frame_render(&view->indicator_frame,
hikari_configuration.indicator_grouped,
render_data);
}
}
}
}
if (focus_view->output == output) {
render_data->geometry = hikari_view_border_geometry(focus_view);
hikari_indicator_frame_render(&focus_view->indicator_frame,
hikari_configuration.indicator_selected,
render_data);
hikari_indicator_render(&hikari_server.indicator, render_data);
}
}
static void
cancel(void)
{
hikari_input_buffer_clear(&hikari_server.group_assign_mode.input_buffer);
fini_completion();
hikari_server.group_assign_mode.group = NULL;
}
static void
button_handler(struct wl_listener *listener, void *data)
{}
static void
cursor_move(void)
{}
void
hikari_group_assign_mode_init(
struct hikari_group_assign_mode *group_assign_mode)
{
group_assign_mode->mode.type = HIKARI_MODE_TYPE_GROUP_CHANGE;
group_assign_mode->mode.key_handler = key_handler;
group_assign_mode->mode.button_handler = button_handler;
group_assign_mode->mode.modifier_handler = modifier_handler;
group_assign_mode->mode.render = render;
group_assign_mode->mode.cancel = cancel;
group_assign_mode->mode.cursor_move = cursor_move;
group_assign_mode->group = NULL;
group_assign_mode->completion = NULL;
}

156
src/indicator.c Normal file
View File

@ -0,0 +1,156 @@
#include <hikari/indicator.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_matrix.h>
#include <hikari/configuration.h>
#include <hikari/mark.h>
#include <hikari/render_data.h>
#include <hikari/sheet.h>
#include <hikari/view.h>
void
hikari_indicator_init(struct hikari_indicator *indicator, float color[static 4])
{
int width;
hikari_font_metrics(
&hikari_configuration.font, "", &width, &indicator->bar_height);
indicator->bar_height += 8;
int offset = 5;
hikari_indicator_bar_init(&indicator->title, indicator, offset);
offset += indicator->bar_height + 5;
hikari_indicator_bar_init(&indicator->sheet, indicator, offset);
offset += indicator->bar_height + 5;
hikari_indicator_bar_init(&indicator->group, indicator, offset);
offset += indicator->bar_height + 5;
hikari_indicator_bar_init(&indicator->mark, indicator, offset);
}
void
hikari_indicator_fini(struct hikari_indicator *indicator)
{
hikari_indicator_bar_fini(&indicator->title);
hikari_indicator_bar_fini(&indicator->sheet);
hikari_indicator_bar_fini(&indicator->group);
hikari_indicator_bar_fini(&indicator->mark);
}
void
hikari_indicator_update(struct hikari_indicator *indicator,
struct hikari_view *view,
float background[static 4])
{
assert(view != NULL);
struct wlr_box *geometry = hikari_view_geometry(view);
struct hikari_output *output = view->output;
hikari_indicator_update_title(
indicator, geometry, output, view->title, background);
hikari_indicator_update_sheet(indicator,
geometry,
output,
view->sheet,
background,
hikari_view_is_iconified(view),
hikari_view_is_floating(view));
if (view->sheet->group != view->group) {
hikari_indicator_update_group(
indicator, geometry, output, view->group->name, background);
} else {
hikari_indicator_update_group(indicator, geometry, output, "", background);
}
if (view->mark != NULL) {
hikari_indicator_update_mark(
indicator, geometry, output, view->mark->name, background);
} else {
hikari_indicator_update_mark(indicator, geometry, output, "", background);
}
}
void
hikari_indicator_render(
struct hikari_indicator *indicator, struct hikari_render_data *render_data)
{
struct wlr_box *border_geometry = render_data->geometry;
struct wlr_box geometry = *border_geometry;
render_data->geometry = &geometry;
geometry.x += 5;
struct hikari_indicator_bar *title_bar = &indicator->title;
geometry.y += 5;
hikari_indicator_bar_render(title_bar, render_data);
struct hikari_indicator_bar *sheet_bar = &indicator->sheet;
geometry.y += indicator->bar_height + 5;
hikari_indicator_bar_render(sheet_bar, render_data);
struct hikari_indicator_bar *group_bar = &indicator->group;
geometry.y += indicator->bar_height + 5;
hikari_indicator_bar_render(group_bar, render_data);
struct hikari_indicator_bar *mark_bar = &indicator->mark;
geometry.y += indicator->bar_height + 5;
hikari_indicator_bar_render(mark_bar, render_data);
render_data->geometry = border_geometry;
}
void
hikari_indicator_update_sheet(struct hikari_indicator *indicator,
struct wlr_box *view_geometry,
struct hikari_output *output,
struct hikari_sheet *sheet,
float background[static 4],
bool iconified,
bool floating)
{
char text[9];
int i = 0;
if (floating) {
text[i++] = '~';
}
if (iconified) {
text[i++] = '[';
text[i++] = sheet->group->name[0];
text[i++] = ']';
} else {
text[i++] = sheet->group->name[0];
}
if (sheet->workspace->sheet != sheet) {
text[i++] = ' ';
text[i++] = '@';
text[i++] = ' ';
text[i++] = sheet->workspace->sheet->group->name[0];
}
text[i] = '\0';
hikari_indicator_bar_update(
&indicator->sheet, view_geometry, output, text, background);
}
void
hikari_indicator_damage(
struct hikari_indicator *indicator, struct hikari_view *view)
{
assert(indicator != NULL);
assert(view != NULL);
struct wlr_box *geometry = hikari_view_border_geometry(view);
struct hikari_output *output = view->output;
hikari_indicator_bar_damage(&indicator->title, geometry, output);
hikari_indicator_bar_damage(&indicator->sheet, geometry, output);
hikari_indicator_bar_damage(&indicator->group, geometry, output);
hikari_indicator_bar_damage(&indicator->mark, geometry, output);
}

154
src/indicator_bar.c Normal file
View File

@ -0,0 +1,154 @@
#include <hikari/indicator_bar.h>
#include <cairo/cairo.h>
#include <pango/pangocairo.h>
#include <string.h>
#include <wlr/backend.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/render/wlr_texture.h>
#include <wlr/types/wlr_matrix.h>
#include <hikari/color.h>
#include <hikari/configuration.h>
#include <hikari/font.h>
#include <hikari/indicator.h>
#include <hikari/output.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
#include <hikari/view.h>
void
hikari_indicator_bar_init(struct hikari_indicator_bar *indicator_bar,
struct hikari_indicator *indicator,
int offset)
{
indicator_bar->texture = NULL;
indicator_bar->indicator = indicator;
indicator_bar->offset = offset;
}
void
hikari_indicator_bar_fini(struct hikari_indicator_bar *indicator_bar)
{
wlr_texture_destroy(indicator_bar->texture);
indicator_bar->texture = NULL;
}
static void
damage(struct hikari_indicator_bar *indicator_bar,
struct wlr_box *geometry,
struct hikari_output *output)
{
geometry->x += 5;
geometry->y += indicator_bar->offset;
geometry->width = indicator_bar->width;
geometry->height = indicator_bar->indicator->bar_height;
hikari_output_add_damage(output, geometry);
}
void
hikari_indicator_bar_damage(struct hikari_indicator_bar *indicator_bar,
struct wlr_box *view_geometry,
struct hikari_output *output)
{
struct wlr_box geometry = *view_geometry;
damage(indicator_bar, &geometry, output);
}
void
hikari_indicator_bar_update(struct hikari_indicator_bar *indicator_bar,
struct wlr_box *view_geometry,
struct hikari_output *output,
const char *text,
float background[static 4])
{
if (indicator_bar->texture != NULL) {
hikari_indicator_bar_fini(indicator_bar);
}
if (text == NULL || !strcmp(text, "")) {
return;
}
int font_width, font_height;
int width, height;
struct hikari_font *font = &hikari_configuration.font;
struct wlr_box geometry = *view_geometry;
damage(indicator_bar, &geometry, output);
hikari_font_metrics(font, text, &font_width, &font_height);
width = geometry.width = indicator_bar->width = font_width + 8;
height = indicator_bar->indicator->bar_height;
hikari_output_add_damage(output, &geometry);
cairo_surface_t *surface =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
cairo_t *cairo = cairo_create(surface);
PangoLayout *layout = pango_cairo_create_layout(cairo);
cairo_set_source_rgba(
cairo, background[0], background[1], background[2], background[3]);
cairo_paint(cairo);
cairo_set_source_rgba(cairo,
hikari_configuration.border_inactive[0],
hikari_configuration.border_inactive[1],
hikari_configuration.border_inactive[2],
hikari_configuration.border_inactive[3]);
cairo_rectangle(cairo, 0, 0, width, height);
cairo_set_line_width(cairo, 1);
cairo_stroke(cairo);
cairo_set_source_rgba(cairo, 0, 0, 0, 1);
pango_layout_set_font_description(layout, font->desc);
cairo_move_to(cairo, 4, 4);
pango_layout_set_text(layout, text, -1);
pango_cairo_update_layout(cairo, layout);
pango_cairo_show_layout(cairo, layout);
cairo_surface_flush(surface);
unsigned char *data = cairo_image_surface_get_data(surface);
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
struct wlr_renderer *renderer = wlr_backend_get_renderer(
hikari_server.workspace->output->output->backend);
indicator_bar->texture = wlr_texture_from_pixels(
renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data);
cairo_surface_destroy(surface);
g_object_unref(layout);
cairo_destroy(cairo);
}
void
hikari_indicator_bar_render(struct hikari_indicator_bar *indicator_bar,
struct hikari_render_data *render_data)
{
if (indicator_bar->texture == NULL) {
return;
}
struct wlr_box *geometry = render_data->geometry;
struct wlr_renderer *renderer = render_data->renderer;
struct wlr_output *output = render_data->output;
float matrix[9];
geometry->width = indicator_bar->width;
geometry->height = indicator_bar->indicator->bar_height;
wlr_renderer_scissor(renderer, geometry);
wlr_matrix_project_box(matrix, geometry, 0, 0, output->transform_matrix);
wlr_render_texture_with_matrix(renderer, indicator_bar->texture, matrix, 1);
}

113
src/indicator_frame.c Normal file
View File

@ -0,0 +1,113 @@
#include <hikari/indicator_frame.h>
#include <assert.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h>
#include <hikari/border.h>
#include <hikari/color.h>
#include <hikari/configuration.h>
#include <hikari/output.h>
#include <hikari/render_data.h>
#include <hikari/view.h>
void
hikari_indicator_frame_render(struct hikari_indicator_frame *indicator_frame,
float color[static 4],
struct hikari_render_data *render_data)
{
struct wlr_box *box = render_data->geometry;
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_union_rect(
&damage, &damage, box->x, box->y, box->width, box->height);
pixman_region32_intersect(&damage, &damage, render_data->damage);
bool damaged = pixman_region32_not_empty(&damage);
if (!damaged) {
goto buffer_damage_finish;
}
struct wlr_renderer *renderer = render_data->renderer;
assert(renderer);
float top_matrix[9];
float bottom_matrix[9];
float left_matrix[9];
float right_matrix[9];
wlr_matrix_project_box(top_matrix,
&indicator_frame->top,
WL_OUTPUT_TRANSFORM_NORMAL,
0,
render_data->output->transform_matrix);
wlr_matrix_project_box(bottom_matrix,
&indicator_frame->bottom,
WL_OUTPUT_TRANSFORM_NORMAL,
0,
render_data->output->transform_matrix);
wlr_matrix_project_box(left_matrix,
&indicator_frame->left,
WL_OUTPUT_TRANSFORM_NORMAL,
0,
render_data->output->transform_matrix);
wlr_matrix_project_box(right_matrix,
&indicator_frame->right,
WL_OUTPUT_TRANSFORM_NORMAL,
0,
render_data->output->transform_matrix);
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; i++) {
hikari_output_scissor_render(render_data->output, renderer, &rects[i]);
wlr_render_quad_with_matrix(renderer, color, top_matrix);
wlr_render_quad_with_matrix(renderer, color, bottom_matrix);
wlr_render_quad_with_matrix(renderer, color, left_matrix);
wlr_render_quad_with_matrix(renderer, color, right_matrix);
}
buffer_damage_finish:
pixman_region32_fini(&damage);
}
void
hikari_indicator_frame_refresh_geometry(
struct hikari_indicator_frame *indicator_frame, struct hikari_view *view)
{
struct wlr_box *geometry;
if (view->border.state == HIKARI_BORDER_NONE) {
geometry = hikari_view_geometry(view);
} else {
geometry = hikari_view_border_geometry(view);
}
indicator_frame->top.x = geometry->x;
indicator_frame->top.y = geometry->y;
indicator_frame->top.width = geometry->width;
indicator_frame->top.height = hikari_configuration.border;
indicator_frame->bottom.x = geometry->x;
indicator_frame->bottom.y =
geometry->y + geometry->height - hikari_configuration.border;
indicator_frame->bottom.width = geometry->width;
indicator_frame->bottom.height = hikari_configuration.border;
indicator_frame->left.x = geometry->x;
indicator_frame->left.y = geometry->y;
indicator_frame->left.width = hikari_configuration.border;
indicator_frame->left.height = geometry->height;
indicator_frame->right.x =
geometry->x + geometry->width - hikari_configuration.border;
indicator_frame->right.y = geometry->y;
indicator_frame->right.width = hikari_configuration.border;
indicator_frame->right.height = geometry->height;
}

81
src/input_buffer.c Normal file
View File

@ -0,0 +1,81 @@
#include <hikari/input_buffer.h>
#include <string.h>
#include <hikari/utf8.h>
struct hikari_input_buffer *
hikari_input_buffer_init(
struct hikari_input_buffer *input_buffer, char *content)
{
strncpy(input_buffer->buffer, content, sizeof(input_buffer->buffer) - 1);
input_buffer->pos =
strnlen(input_buffer->buffer, sizeof(input_buffer->buffer));
return input_buffer;
}
void
hikari_input_buffer_add_char(
struct hikari_input_buffer *input_buffer, char input)
{
if (input_buffer->pos == sizeof(input_buffer->buffer) - 1) {
return;
}
input_buffer->buffer[input_buffer->pos] = input;
input_buffer->pos++;
}
void
hikari_input_buffer_add_utf32_char(
struct hikari_input_buffer *input_buffer, uint32_t codepoint)
{
size_t length = utf8_chsize(codepoint);
if (input_buffer->pos + length > sizeof(input_buffer->buffer) - 1) {
return;
}
utf8_encode(&input_buffer->buffer[input_buffer->pos], length, codepoint);
input_buffer->pos += length;
}
void
hikari_input_buffer_remove_char(struct hikari_input_buffer *input_buffer)
{
if (input_buffer->pos == 0) {
input_buffer->buffer[0] = '\0';
return;
}
input_buffer->pos--;
input_buffer->buffer[input_buffer->pos] = '\0';
}
void
hikari_input_buffer_clear(struct hikari_input_buffer *input_buffer)
{
memset(input_buffer->buffer, 0, sizeof(input_buffer->buffer));
input_buffer->pos = 0;
}
void
hikari_input_buffer_replace(
struct hikari_input_buffer *input_buffer, char *content)
{
hikari_input_buffer_clear(input_buffer);
char *c = content;
for (int i = 0; i < sizeof(input_buffer->buffer) && *c != '\0'; i++) {
hikari_input_buffer_add_char(input_buffer, *c);
c++;
}
}
char *
hikari_input_buffer_read(struct hikari_input_buffer *input_buffer)
{
return input_buffer->buffer;
}

14
src/keybinding.c Normal file
View File

@ -0,0 +1,14 @@
#include <hikari/keybinding.h>
#include <assert.h>
#include <hikari/memory.h>
void
hikari_keybinding_fini(struct hikari_keybinding *keybinding)
{
assert(keybinding != NULL);
if (keybinding->cleanup != NULL) {
keybinding->cleanup(keybinding->arg);
}
}

118
src/keyboard.c Normal file
View File

@ -0,0 +1,118 @@
#include <hikari/keyboard.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_seat.h>
#include <hikari/command.h>
#include <hikari/completion.h>
#include <hikari/indicator.h>
#include <hikari/input_buffer.h>
#include <hikari/mark.h>
#include <hikari/mode.h>
#include <hikari/server.h>
#include <hikari/sheet.h>
#include <hikari/unlocker.h>
#include <hikari/view.h>
#include <hikari/workspace.h>
static void
update_mod_state(struct hikari_keyboard *keyboard)
{
uint32_t modifier_keys =
wlr_keyboard_get_modifiers(keyboard->device->keyboard);
bool was_pressed = hikari_server.keyboard_state.mod_pressed;
bool is_pressed = modifier_keys & WLR_MODIFIER_LOGO;
hikari_server.keyboard_state.modifiers = modifier_keys;
hikari_server.keyboard_state.mod_released = was_pressed && !is_pressed;
hikari_server.keyboard_state.mod_changed = was_pressed != is_pressed;
hikari_server.keyboard_state.mod_pressed = is_pressed;
}
static void
key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
if (hikari_server.locked) {
hikari_unlocker_key_handler(listener, data);
return;
}
hikari_server.mode->key_handler(listener, data);
}
static void
modifiers_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard =
wl_container_of(listener, keyboard, modifiers);
update_mod_state(keyboard);
if (hikari_server.locked) {
return;
}
hikari_server.mode->modifier_handler(listener, data);
}
static void
destroy_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard =
wl_container_of(listener, keyboard, destroy);
hikari_keyboard_fini(keyboard);
hikari_free(keyboard);
/* uint32_t caps = WL_SEAT_CAPABILITY_POINTER; */
/* wlr_seat_set_capabilities(hikari_server.seat, caps); */
}
void
hikari_keyboard_init(
struct hikari_keyboard *keyboard, struct wlr_input_device *device)
{
keyboard->device = device;
struct xkb_rule_names rules = { 0 };
rules.rules = getenv("XKB_DEFAULT_RULES");
rules.model = getenv("XKB_DEFAULT_MODEL");
rules.layout = getenv("XKB_DEFAULT_LAYOUT");
rules.variant = getenv("XKB_DEFAULT_VARIANT");
rules.options = getenv("XKB_DEFAULT_OPTIONS");
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
struct xkb_keymap *keymap =
xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
wlr_keyboard_set_keymap(device->keyboard, keymap);
xkb_keymap_unref(keymap);
xkb_context_unref(context);
wlr_keyboard_set_repeat_info(device->keyboard, 25, 600);
keyboard->modifiers.notify = modifiers_handler;
wl_signal_add(&device->keyboard->events.modifiers, &keyboard->modifiers);
keyboard->key.notify = key_handler;
wl_signal_add(&device->keyboard->events.key, &keyboard->key);
keyboard->destroy.notify = destroy_handler;
wl_signal_add(&device->keyboard->events.destroy, &keyboard->destroy);
wlr_seat_set_keyboard(hikari_server.seat, device);
wl_list_insert(&hikari_server.keyboards, &keyboard->link);
}
void
hikari_keyboard_fini(struct hikari_keyboard *keyboard)
{
wl_list_remove(&keyboard->modifiers.link);
wl_list_remove(&keyboard->key.link);
wl_list_remove(&keyboard->destroy.link);
wl_list_remove(&keyboard->link);
}

110
src/keyboard_grab_mode.c Normal file
View File

@ -0,0 +1,110 @@
#include <hikari/keyboard_grab_mode.h>
#include <assert.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_seat.h>
#include <hikari/color.h>
#include <hikari/configuration.h>
#include <hikari/indicator_frame.h>
#include <hikari/keyboard.h>
#include <hikari/normal_mode.h>
#include <hikari/output.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
#include <hikari/view.h>
#include <hikari/workspace.h>
static void
keyboard_grab_key_handler(struct hikari_workspace *workspace,
struct wlr_event_keyboard_key *event,
struct hikari_keyboard *keyboard)
{
uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard);
if ((modifiers & WLR_MODIFIER_LOGO) && event->state == WLR_KEY_PRESSED) {
uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_g:
if (modifiers ==
(WLR_MODIFIER_LOGO | WLR_MODIFIER_ALT | WLR_MODIFIER_CTRL)) {
hikari_server_enter_normal_mode(NULL);
hikari_server_refresh_indication();
hikari_server_cursor_focus();
return;
}
}
}
}
wlr_seat_set_keyboard(hikari_server.seat, keyboard->device);
wlr_seat_keyboard_notify_key(
hikari_server.seat, event->time_msec, event->keycode, event->state);
}
static void
render(struct hikari_output *output, struct hikari_render_data *render_data)
{
assert(hikari_server.workspace->focus_view != NULL);
struct hikari_view *view = hikari_server.workspace->focus_view;
if (view->output == output) {
render_data->geometry = hikari_view_border_geometry(view);
hikari_indicator_frame_render(&view->indicator_frame,
hikari_configuration.indicator_insert,
render_data);
}
}
static void
modifier_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard =
wl_container_of(listener, keyboard, modifiers);
wlr_seat_keyboard_notify_modifiers(
hikari_server.seat, &keyboard->device->keyboard->modifiers);
}
static void
key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
struct hikari_workspace *workspace = hikari_server.workspace;
keyboard_grab_key_handler(workspace, event, keyboard);
}
static void
cancel(void)
{}
static void
button_handler(struct wl_listener *listener, void *data)
{}
static void
cursor_move(void)
{}
void
hikari_keyboard_grab_mode_init(
struct hikari_keyboard_grab_mode *keyboard_grab_mode)
{
keyboard_grab_mode->mode.type = HIKARI_MODE_TYPE_GRAB_KEYBOARD;
keyboard_grab_mode->mode.key_handler = key_handler;
keyboard_grab_mode->mode.button_handler = button_handler;
keyboard_grab_mode->mode.modifier_handler = modifier_handler;
keyboard_grab_mode->mode.render = render;
keyboard_grab_mode->mode.cancel = cancel;
keyboard_grab_mode->mode.cursor_move = cursor_move;
}

47
src/layout.c Normal file
View File

@ -0,0 +1,47 @@
#include <hikari/layout.h>
#include <assert.h>
#include <hikari/split.h>
#include <hikari/tile.h>
#include <hikari/view.h>
void
hikari_layout_init(struct hikari_layout *layout, struct hikari_split *split)
{
layout->split = split;
wl_list_init(&layout->tiles);
}
void
hikari_layout_fini(struct hikari_layout *layout)
{
/* hikari_split_fini(layout->split); */
}
#define CYCLE_LAYOUT(name, link) \
struct hikari_view *hikari_layout_##name##_view( \
struct hikari_layout *layout) \
{ \
struct wl_list *link = layout->tiles.link; \
struct hikari_tile *link##_tile; \
\
do { \
if (link == &layout->tiles) { \
return NULL; \
} else { \
link##_tile = wl_container_of(link, link##_tile, layout_tiles); \
} \
link = link->link; \
} while (hikari_view_is_hidden(link##_tile->view)); \
\
assert(link##_tile != NULL); \
assert(link##_tile->view != NULL); \
assert(!hikari_view_is_hidden(link##_tile->view)); \
\
return link##_tile->view; \
}
CYCLE_LAYOUT(first, next)
CYCLE_LAYOUT(last, prev)
#undef CYCLE_LAYOUT

58
src/mark.c Normal file
View File

@ -0,0 +1,58 @@
#include <hikari/mark.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <hikari/memory.h>
#include <hikari/view.h>
struct hikari_mark marks[HIKARI_NR_OF_MARKS];
void
hikari_marks_init(void)
{
char *name;
for (int i = 0; i < HIKARI_NR_OF_MARKS; i++) {
name = hikari_malloc(2);
snprintf(name, 2, "%c", 'a' + i);
marks[i].name = name;
marks[i].view = NULL;
}
}
void
hikari_marks_fini(void)
{
for (int i = 0; i < HIKARI_NR_OF_MARKS; i++) {
hikari_free(marks[i].name);
}
}
void
hikari_mark_clear(struct hikari_mark *mark)
{
assert(mark != NULL);
if (mark->view != NULL) {
mark->view->mark = NULL;
mark->view = NULL;
;
}
}
void
hikari_mark_set(struct hikari_mark *mark, struct hikari_view *view)
{
assert(mark != NULL);
assert(view != NULL);
if (view->mark != NULL) {
hikari_mark_clear(view->mark);
}
hikari_mark_clear(mark);
mark->view = view;
view->mark = mark;
}

432
src/mark_assign_mode.c Normal file
View File

@ -0,0 +1,432 @@
#include <hikari/mark_assign_mode.h>
#include <wlr/types/wlr_seat.h>
#include <hikari/color.h>
#include <hikari/configuration.h>
#include <hikari/indicator.h>
#include <hikari/indicator_frame.h>
#include <hikari/keyboard.h>
#include <hikari/mark.h>
#include <hikari/normal_mode.h>
#include <hikari/render_data.h>
#include <hikari/view.h>
static bool
check_confirmation(
struct wlr_event_keyboard_key *event, struct hikari_keyboard *keyboard)
{
uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_Return:
return true;
break;
}
}
return false;
}
static bool
check_cancellation(
struct wlr_event_keyboard_key *event, struct hikari_keyboard *keyboard)
{
uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_Escape:
return true;
break;
}
}
return false;
}
static struct hikari_mark *
lookup_mark(struct wlr_event_keyboard_key *event,
struct hikari_keyboard *keyboard,
bool *selected)
{
uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
*selected = false;
struct hikari_mark *mark = NULL;
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_a:
mark = HIKARI_MARK_a;
*selected = true;
break;
case XKB_KEY_b:
mark = HIKARI_MARK_b;
*selected = true;
break;
case XKB_KEY_c:
mark = HIKARI_MARK_c;
*selected = true;
break;
case XKB_KEY_d:
mark = HIKARI_MARK_d;
*selected = true;
break;
case XKB_KEY_e:
mark = HIKARI_MARK_e;
*selected = true;
break;
case XKB_KEY_f:
mark = HIKARI_MARK_f;
*selected = true;
break;
case XKB_KEY_g:
mark = HIKARI_MARK_g;
*selected = true;
break;
case XKB_KEY_h:
mark = HIKARI_MARK_h;
*selected = true;
break;
case XKB_KEY_i:
mark = HIKARI_MARK_i;
*selected = true;
break;
case XKB_KEY_j:
mark = HIKARI_MARK_j;
*selected = true;
break;
case XKB_KEY_k:
mark = HIKARI_MARK_k;
*selected = true;
break;
case XKB_KEY_l:
mark = HIKARI_MARK_l;
*selected = true;
break;
case XKB_KEY_m:
mark = HIKARI_MARK_m;
*selected = true;
break;
case XKB_KEY_n:
mark = HIKARI_MARK_n;
*selected = true;
break;
case XKB_KEY_o:
mark = HIKARI_MARK_o;
*selected = true;
break;
case XKB_KEY_p:
mark = HIKARI_MARK_p;
*selected = true;
break;
case XKB_KEY_q:
mark = HIKARI_MARK_q;
*selected = true;
break;
case XKB_KEY_r:
mark = HIKARI_MARK_r;
*selected = true;
break;
case XKB_KEY_s:
mark = HIKARI_MARK_s;
*selected = true;
break;
case XKB_KEY_t:
mark = HIKARI_MARK_t;
*selected = true;
break;
case XKB_KEY_u:
mark = HIKARI_MARK_u;
*selected = true;
break;
case XKB_KEY_v:
mark = HIKARI_MARK_v;
*selected = true;
break;
case XKB_KEY_w:
mark = HIKARI_MARK_w;
*selected = true;
break;
case XKB_KEY_x:
mark = HIKARI_MARK_x;
*selected = true;
break;
case XKB_KEY_y:
mark = HIKARI_MARK_y;
*selected = true;
break;
case XKB_KEY_z:
mark = HIKARI_MARK_z;
*selected = true;
break;
case XKB_KEY_BackSpace:
mark = NULL;
*selected = true;
break;
}
}
return mark;
}
static void
clear_conflict(void)
{
struct hikari_mark_assign_mode *mode = &hikari_server.mark_assign_mode;
assert(mode == (struct hikari_mark_assign_mode *)hikari_server.mode);
struct hikari_mark *mark = mode->pending_mark;
if (mark != NULL && mark->view != NULL) {
hikari_view_damage_whole(mark->view);
hikari_indicator_damage(&mode->indicator, mark->view);
}
}
static void
update_state(struct hikari_mark *mark,
struct wlr_box *geometry,
struct hikari_output *output)
{
struct hikari_mark_assign_mode *mode = &hikari_server.mark_assign_mode;
assert(mode == (struct hikari_mark_assign_mode *)hikari_server.mode);
if (mark) {
hikari_indicator_update_mark(&hikari_server.indicator,
geometry,
output,
mark->name,
hikari_configuration.indicator_insert);
} else {
hikari_indicator_update_mark(&hikari_server.indicator,
geometry,
output,
" ",
hikari_configuration.indicator_insert);
}
if (mode->pending_mark != mark) {
clear_conflict();
if (mark != NULL && mark->view != NULL) {
hikari_indicator_update(&mode->indicator,
mark->view,
hikari_configuration.indicator_conflict);
hikari_view_damage_whole(mark->view);
}
mode->pending_mark = mark;
}
}
static void
confirm_mark_assign(struct wlr_box *geometry, struct hikari_output *output)
{
struct hikari_mark_assign_mode *mode = &hikari_server.mark_assign_mode;
assert(mode == (struct hikari_mark_assign_mode *)hikari_server.mode);
struct hikari_view *focus_view = hikari_server.workspace->focus_view;
struct hikari_mark *mark = mode->pending_mark;
if (mark) {
clear_conflict();
hikari_mark_set(mark, focus_view);
hikari_indicator_update_mark(&hikari_server.indicator,
geometry,
output,
mode->pending_mark->name,
hikari_configuration.indicator_selected);
mode->pending_mark = NULL;
} else {
if (focus_view->mark != NULL) {
hikari_mark_clear(focus_view->mark);
}
hikari_indicator_update_mark(&hikari_server.indicator,
geometry,
output,
"",
hikari_configuration.indicator_selected);
}
hikari_server_enter_normal_mode(NULL);
}
static void
cancel_mark_assign(struct hikari_mark *mark,
struct wlr_box *geometry,
struct hikari_output *output)
{
assert(&hikari_server.mark_assign_mode.mode == hikari_server.mode);
struct hikari_view *view = hikari_server.workspace->focus_view;
clear_conflict();
if (view->mark != NULL) {
hikari_indicator_update_mark(&hikari_server.indicator,
geometry,
output,
view->mark->name,
hikari_configuration.indicator_selected);
} else {
hikari_indicator_update_mark(&hikari_server.indicator,
geometry,
output,
"",
hikari_configuration.indicator_selected);
}
hikari_server_enter_normal_mode(NULL);
}
static void
assign_mark(struct hikari_workspace *workspace,
struct wlr_event_keyboard_key *event,
struct hikari_keyboard *keyboard)
{
assert(hikari_server.workspace->focus_view != NULL);
bool selected;
struct hikari_mark *mark = lookup_mark(event, keyboard, &selected);
struct wlr_box *geometry = hikari_view_border_geometry(workspace->focus_view);
struct hikari_output *output = workspace->output;
if (selected) {
update_state(mark, geometry, output);
hikari_server_refresh_indication();
} else if (check_confirmation(event, keyboard)) {
confirm_mark_assign(geometry, output);
} else if (check_cancellation(event, keyboard)) {
cancel_mark_assign(mark, geometry, output);
hikari_server_refresh_indication();
}
}
static void
key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
struct hikari_workspace *workspace = hikari_server.workspace;
uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard);
if (event->state == WLR_KEY_PRESSED && modifiers == 0) {
assign_mark(workspace, event, keyboard);
}
}
static void
modifier_handler(struct wl_listener *listener, void *data)
{}
static void
render(struct hikari_output *output, struct hikari_render_data *render_data)
{
assert(hikari_server.workspace->focus_view != NULL);
struct hikari_view *view = hikari_server.workspace->focus_view;
struct hikari_mark_assign_mode *mode =
(struct hikari_mark_assign_mode *)hikari_server.mode;
if (mode->pending_mark != NULL && mode->pending_mark->view != NULL &&
mode->pending_mark->view->output == output) {
render_data->geometry =
hikari_view_border_geometry(mode->pending_mark->view);
hikari_indicator_frame_render(&mode->pending_mark->view->indicator_frame,
hikari_configuration.indicator_conflict,
render_data);
hikari_indicator_render(&mode->indicator, render_data);
}
if (view->output == output) {
render_data->geometry = hikari_view_border_geometry(view);
hikari_indicator_frame_render(&view->indicator_frame,
hikari_configuration.indicator_selected,
render_data);
hikari_indicator_render(&hikari_server.indicator, render_data);
}
}
static void
cancel(void)
{
hikari_server.mark_assign_mode.pending_mark = NULL;
}
static void
button_handler(struct wl_listener *listener, void *data)
{}
static void
cursor_move(void)
{}
void
hikari_mark_assign_mode_init(struct hikari_mark_assign_mode *mark_assign_mode)
{
mark_assign_mode->mode.type = HIKARI_MODE_TYPE_ASSIGN_MARK;
mark_assign_mode->mode.key_handler = key_handler;
mark_assign_mode->mode.button_handler = button_handler;
mark_assign_mode->mode.modifier_handler = modifier_handler;
mark_assign_mode->mode.render = render;
mark_assign_mode->mode.cancel = cancel;
mark_assign_mode->mode.cursor_move = cursor_move;
hikari_indicator_init(
&mark_assign_mode->indicator, hikari_configuration.indicator_conflict);
}
void
hikari_mark_assign_mode_fini(struct hikari_mark_assign_mode *mark_assign_mode)
{
hikari_indicator_fini(&mark_assign_mode->indicator);
}

250
src/mark_select_mode.c Normal file
View File

@ -0,0 +1,250 @@
#include <hikari/mark_select_mode.h>
#include <stdbool.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_keyboard.h>
#include <hikari/indicator.h>
#include <hikari/indicator_frame.h>
#include <hikari/keyboard.h>
#include <hikari/mark.h>
#include <hikari/normal_mode.h>
#include <hikari/render_data.h>
#include <hikari/view.h>
#include <hikari/workspace.h>
static struct hikari_mark *
lookup_mark(struct wlr_event_keyboard_key *event,
struct hikari_keyboard *keyboard,
bool *selected)
{
uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
*selected = false;
struct hikari_mark *mark = NULL;
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_a:
mark = HIKARI_MARK_a;
*selected = true;
break;
case XKB_KEY_b:
mark = HIKARI_MARK_b;
*selected = true;
break;
case XKB_KEY_c:
mark = HIKARI_MARK_c;
*selected = true;
break;
case XKB_KEY_d:
mark = HIKARI_MARK_d;
*selected = true;
break;
case XKB_KEY_e:
mark = HIKARI_MARK_e;
*selected = true;
break;
case XKB_KEY_f:
mark = HIKARI_MARK_f;
*selected = true;
break;
case XKB_KEY_g:
mark = HIKARI_MARK_g;
*selected = true;
break;
case XKB_KEY_h:
mark = HIKARI_MARK_h;
*selected = true;
break;
case XKB_KEY_i:
mark = HIKARI_MARK_i;
*selected = true;
break;
case XKB_KEY_j:
mark = HIKARI_MARK_j;
*selected = true;
break;
case XKB_KEY_k:
mark = HIKARI_MARK_k;
*selected = true;
break;
case XKB_KEY_l:
mark = HIKARI_MARK_l;
*selected = true;
break;
case XKB_KEY_m:
mark = HIKARI_MARK_m;
*selected = true;
break;
case XKB_KEY_n:
mark = HIKARI_MARK_n;
*selected = true;
break;
case XKB_KEY_o:
mark = HIKARI_MARK_o;
*selected = true;
break;
case XKB_KEY_p:
mark = HIKARI_MARK_p;
*selected = true;
break;
case XKB_KEY_q:
mark = HIKARI_MARK_q;
*selected = true;
break;
case XKB_KEY_r:
mark = HIKARI_MARK_r;
*selected = true;
break;
case XKB_KEY_s:
mark = HIKARI_MARK_s;
*selected = true;
break;
case XKB_KEY_t:
mark = HIKARI_MARK_t;
*selected = true;
break;
case XKB_KEY_u:
mark = HIKARI_MARK_u;
*selected = true;
break;
case XKB_KEY_v:
mark = HIKARI_MARK_v;
*selected = true;
break;
case XKB_KEY_w:
mark = HIKARI_MARK_w;
*selected = true;
break;
case XKB_KEY_x:
mark = HIKARI_MARK_x;
*selected = true;
break;
case XKB_KEY_y:
mark = HIKARI_MARK_y;
*selected = true;
break;
case XKB_KEY_z:
mark = HIKARI_MARK_z;
*selected = true;
break;
case XKB_KEY_BackSpace:
mark = NULL;
*selected = true;
break;
}
}
return mark;
}
static void
mark_select(struct hikari_workspace *workspace,
struct wlr_event_keyboard_key *event,
struct hikari_keyboard *keyboard)
{
bool selected;
struct hikari_mark *mark = lookup_mark(event, keyboard, &selected);
hikari_server_enter_normal_mode(NULL);
if (mark != NULL && mark->view != NULL) {
struct hikari_view *view = mark->view;
if (hikari_server.mark_select_mode.switch_workspace) {
hikari_workspace_switch_sheet(view->sheet->workspace, view->sheet);
}
if (!hikari_view_is_hidden(view)) {
hikari_view_raise(view);
} else {
hikari_view_raise_hidden(view);
hikari_view_show(view);
}
if (view != hikari_server.workspace->focus_view) {
hikari_workspace_focus_view(workspace, view);
}
hikari_view_center_cursor(view);
}
hikari_server_cursor_focus();
}
static void
key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
struct hikari_workspace *workspace = hikari_server.workspace;
if (event->state == WLR_KEY_PRESSED) {
mark_select(workspace, event, keyboard);
}
}
static void
modifier_handler(struct wl_listener *listener, void *data)
{}
static void
render(struct hikari_output *output, struct hikari_render_data *render_data)
{}
static void
cancel(void)
{}
static void
button_handler(struct wl_listener *listener, void *data)
{}
static void
cursor_move(void)
{}
void
hikari_mark_select_mode_init(struct hikari_mark_select_mode *mark_select_mode)
{
mark_select_mode->mode.type = HIKARI_MODE_TYPE_SELECT_MARK;
mark_select_mode->mode.key_handler = key_handler;
mark_select_mode->mode.button_handler = button_handler;
mark_select_mode->mode.modifier_handler = modifier_handler;
mark_select_mode->mode.render = render;
mark_select_mode->mode.cancel = cancel;
mark_select_mode->mode.cursor_move = cursor_move;
mark_select_mode->switch_workspace = false;
}

24
src/maximized_state.c Normal file
View File

@ -0,0 +1,24 @@
#include <hikari/maximized_state.h>
#include <hikari/view.h>
struct hikari_maximized_state *
hikari_maximized_state_full(struct hikari_view *view, int width, int height)
{
struct hikari_maximized_state *maximized_state;
if (view->maximized_state == NULL) {
maximized_state = hikari_maximized_state_alloc();
} else {
maximized_state = view->maximized_state;
}
maximized_state->maximization = HIKARI_MAXIMIZATION_FULLY_MAXIMIZED;
maximized_state->geometry.x = 0;
maximized_state->geometry.y = 0;
maximized_state->geometry.width = width;
maximized_state->geometry.height = height;
return maximized_state;
}

21
src/memory.c Normal file
View File

@ -0,0 +1,21 @@
#include <hikari/memory.h>
#include <stdlib.h>
void *
hikari_malloc(size_t size)
{
return malloc(size);
}
void *
hikari_calloc(size_t number, size_t size)
{
return calloc(number, size);
}
void
hikari_free(void *ptr)
{
return free(ptr);
}

93
src/move_mode.c Normal file
View File

@ -0,0 +1,93 @@
#include <hikari/move_mode.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_seat.h>
#include <hikari/configuration.h>
#include <hikari/keybinding.h>
#include <hikari/keyboard.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
#include <hikari/view.h>
static void
cancel(void)
{
struct hikari_view *focus_view = hikari_server.workspace->focus_view;
if (focus_view != NULL) {
hikari_indicator_update(&hikari_server.indicator,
focus_view,
hikari_configuration.indicator_selected);
hikari_view_center_cursor(focus_view);
}
}
static void
key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
if (event->state == WLR_KEY_RELEASED) {
hikari_server_enter_normal_mode(NULL);
}
}
static void
modifier_handler(struct wl_listener *listener, void *data)
{}
static void
render(struct hikari_output *output, struct hikari_render_data *render_data)
{
struct hikari_view *focus_view = hikari_server.workspace->focus_view;
if (focus_view->output == output) {
render_data->geometry = hikari_view_border_geometry(focus_view);
hikari_indicator_frame_render(&focus_view->indicator_frame,
hikari_configuration.indicator_insert,
render_data);
hikari_indicator_render(&hikari_server.indicator, render_data);
}
}
static void
cursor_move(void)
{
struct hikari_view *focus_view = hikari_server.workspace->focus_view;
assert(focus_view != NULL);
struct hikari_output *output = focus_view->output;
hikari_view_move_absolute(focus_view,
hikari_server.cursor->x - output->geometry.x,
hikari_server.cursor->y - output->geometry.y);
}
static void
button_handler(struct wl_listener *listener, void *data)
{
struct wlr_event_pointer_button *event = data;
if (event->state == WLR_BUTTON_RELEASED) {
hikari_server_enter_normal_mode(NULL);
}
}
void
hikari_move_mode_init(struct hikari_move_mode *move_mode)
{
move_mode->mode.type = HIKARI_MODE_TYPE_MOVE;
move_mode->mode.key_handler = key_handler;
move_mode->mode.button_handler = button_handler;
move_mode->mode.modifier_handler = modifier_handler;
move_mode->mode.render = render;
move_mode->mode.cancel = cancel;
move_mode->mode.cursor_move = cursor_move;
}

238
src/normal_mode.c Normal file
View File

@ -0,0 +1,238 @@
#include <hikari/normal_mode.h>
#include <wlr/types/wlr_seat.h>
#include <hikari/color.h>
#include <hikari/command.h>
#include <hikari/configuration.h>
#include <hikari/geometry.h>
#include <hikari/indicator.h>
#include <hikari/indicator_frame.h>
#include <hikari/keybinding.h>
#include <hikari/keyboard.h>
#include <hikari/layout.h>
#include <hikari/output.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
#include <hikari/view.h>
#include <hikari/workspace.h>
#include <hikari/sheet.h>
static void
normal_mode_keyboard_handler(struct hikari_workspace *workspace,
struct wlr_event_keyboard_key *event,
struct hikari_keyboard *keyboard)
{
if (event->state == WLR_KEY_PRESSED) {
uint32_t modifiers = hikari_server.keyboard_state.modifiers;
for (int i = 0;
i < hikari_configuration.normal_mode.nkeybindings[modifiers];
i++) {
struct hikari_keybinding *keybinding =
&hikari_configuration.normal_mode.keybindings[modifiers][i];
if (keybinding->modifiers == modifiers &&
keybinding->keycode == event->keycode) {
keybinding->action(keybinding->arg);
return;
}
}
}
wlr_seat_set_keyboard(hikari_server.seat, keyboard->device);
wlr_seat_keyboard_notify_key(
hikari_server.seat, event->time_msec, event->keycode, event->state);
}
static void
normal_mode_button_handler(
struct hikari_workspace *workspace, struct wlr_event_pointer_button *event)
{
if (hikari_server.keyboard_state.mod_pressed &&
event->state == WLR_BUTTON_PRESSED) {
uint32_t modifiers = hikari_server.keyboard_state.modifiers;
for (int i = 0;
i < hikari_configuration.normal_mode.nmousebindings[modifiers];
i++) {
struct hikari_keybinding *mousebinding =
&hikari_configuration.normal_mode.mousebindings[modifiers][i];
if (mousebinding->modifiers == modifiers &&
mousebinding->keycode == event->button) {
mousebinding->action(mousebinding->arg);
return;
}
}
}
wlr_seat_pointer_notify_button(
hikari_server.seat, event->time_msec, event->button, event->state);
}
static void
button_handler(struct wl_listener *listener, void *data)
{
struct wlr_event_pointer_button *event = data;
struct hikari_workspace *workspace = hikari_server.workspace;
normal_mode_button_handler(workspace, event);
}
static void
key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
struct hikari_workspace *workspace = hikari_server.workspace;
normal_mode_keyboard_handler(workspace, event, keyboard);
}
#ifndef NDEBUG
static void
dump_debug(struct hikari_server *server)
{
printf("---------------------------------------------------------------------"
"\n");
printf("GROUPS\n");
printf("---------------------------------------------------------------------"
"\n");
struct hikari_group *group = NULL;
struct hikari_view *view;
wl_list_for_each (
group, &hikari_server.visible_groups, visible_server_groups) {
printf("%s ", group->name);
view = NULL;
wl_list_for_each (view, &group->views, group_views) {
printf("%p ", view);
}
printf("/ ");
view = NULL;
wl_list_for_each (view, &group->visible_views, visible_group_views) {
printf("%p ", view);
}
printf("\n");
}
printf("---------------------------------------------------------------------"
"\n");
printf("SHEETS\n");
printf("---------------------------------------------------------------------"
"\n");
struct hikari_sheet *sheets = hikari_server.workspace->sheets;
struct hikari_sheet *sheet;
for (int i = 0; i < 10; i++) {
sheet = &sheets[i];
printf("%d ", sheet->nr);
view = NULL;
wl_list_for_each (view, &sheet->views, sheet_views) {
printf("%p ", view);
}
printf("\n");
}
printf("---------------------------------------------------------------------"
"\n");
if (hikari_server.workspace->sheet->layout != NULL) {
printf("-------------------------------------------------------------------"
"--\n");
printf("LAYOUT\n");
struct hikari_tile *tile;
wl_list_for_each (
tile, &hikari_server.workspace->sheet->layout->tiles, layout_tiles) {
printf("%p ", tile->view);
}
printf("\n");
printf("-------------------------------------------------------------------"
"--\n");
}
}
#endif
static void
modifier_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard =
wl_container_of(listener, keyboard, modifiers);
wlr_seat_set_keyboard(hikari_server.seat, keyboard->device);
if (hikari_server.keyboard_state.mod_released) {
struct hikari_view *focus_view = hikari_server.workspace->focus_view;
if (hikari_server_is_cycling() && focus_view != NULL) {
hikari_view_raise(focus_view);
hikari_view_center_cursor(focus_view);
}
hikari_server_unset_cycling();
}
if (hikari_server.keyboard_state.mod_changed) {
hikari_server_refresh_indication();
#ifndef NDEBUG
dump_debug(&hikari_server);
#endif
}
wlr_seat_keyboard_notify_modifiers(
hikari_server.seat, &keyboard->device->keyboard->modifiers);
}
static void
render(struct hikari_output *output, struct hikari_render_data *render_data)
{
struct hikari_view *focus_view = hikari_server.workspace->focus_view;
if (hikari_server.keyboard_state.mod_pressed && focus_view != NULL) {
struct hikari_workspace *workspace = hikari_server.workspace;
struct hikari_group *group = focus_view->group;
struct hikari_view *view;
wl_list_for_each_reverse (
view, &group->visible_views, visible_group_views) {
if (view != focus_view && view->output == output) {
render_data->geometry = hikari_view_border_geometry(view);
if (hikari_group_first_view(group, workspace) == view) {
hikari_indicator_frame_render(&view->indicator_frame,
hikari_configuration.indicator_first,
render_data);
} else {
hikari_indicator_frame_render(&view->indicator_frame,
hikari_configuration.indicator_grouped,
render_data);
}
}
}
if (focus_view->output == output) {
render_data->geometry = hikari_view_border_geometry(focus_view);
hikari_indicator_frame_render(&focus_view->indicator_frame,
hikari_configuration.indicator_selected,
render_data);
hikari_indicator_render(&hikari_server.indicator, render_data);
}
}
}
static void
cancel(void)
{}
void
hikari_normal_mode_init(struct hikari_normal_mode *normal_mode)
{
normal_mode->mode.type = HIKARI_MODE_TYPE_NORMAL;
normal_mode->mode.key_handler = key_handler;
normal_mode->mode.button_handler = button_handler;
normal_mode->mode.modifier_handler = modifier_handler;
normal_mode->mode.render = render;
normal_mode->mode.cancel = cancel;
normal_mode->mode.cursor_move = NULL;
}

412
src/output.c Normal file
View File

@ -0,0 +1,412 @@
#include <hikari/output.h>
#include <stdlib.h>
#include <wlr/backend.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/region.h>
#ifdef HAVE_XWAYLAND
#include <wlr/xwayland.h>
#endif
#include <hikari/color.h>
#include <hikari/configuration.h>
#include <hikari/indicator.h>
#include <hikari/indicator_bar.h>
#include <hikari/indicator_frame.h>
#include <hikari/memory.h>
#include <hikari/mode.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
#include <hikari/workspace.h>
#include <hikari/xdg_view.h>
#ifdef HAVE_XWAYLAND
#include <hikari/xwayland_unmanaged_view.h>
#include <hikari/xwayland_view.h>
#endif
static void
load_background(struct hikari_workspace *workspace, const char *path)
{
cairo_surface_t *image;
image = cairo_image_surface_create_from_png(path);
int width = workspace->output->geometry.width;
int height = workspace->output->geometry.height;
unsigned char *data = cairo_image_surface_get_data(image);
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
struct wlr_renderer *renderer =
wlr_backend_get_renderer(workspace->output->output->backend);
workspace->background = wlr_texture_from_pixels(
renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data);
cairo_surface_destroy(image);
}
static void
render_texture(struct wlr_output *output,
pixman_region32_t *damage,
struct wlr_texture *texture,
struct wlr_renderer *renderer,
const float matrix[static 9],
struct wlr_box *box)
{
pixman_region32_t local_damage;
pixman_region32_init(&local_damage);
pixman_region32_union_rect(
&local_damage, &local_damage, box->x, box->y, box->width, box->height);
pixman_region32_intersect(&local_damage, &local_damage, damage);
bool damaged = pixman_region32_not_empty(&local_damage);
if (!damaged) {
goto damage_finish;
}
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&local_damage, &nrects);
for (int i = 0; i < nrects; ++i) {
hikari_output_scissor_render(output, renderer, &rects[i]);
wlr_render_texture_with_matrix(renderer, texture, matrix, 1);
}
damage_finish:
pixman_region32_fini(&local_damage);
}
static void
render_surface(struct wlr_surface *surface, int sx, int sy, void *data)
{
assert(surface != NULL);
struct wlr_texture *texture = wlr_surface_get_texture(surface);
if (texture == NULL) {
return;
}
struct hikari_render_data *render_data = data;
struct wlr_box *geometry = render_data->geometry;
struct wlr_output *wlr_output = render_data->output;
double ox = geometry->x + sx;
double oy = geometry->y + sy;
struct wlr_box box = { .x = ox * wlr_output->scale,
.y = oy * wlr_output->scale,
.width = surface->current.width * wlr_output->scale,
.height = surface->current.height * wlr_output->scale };
float matrix[9];
enum wl_output_transform transform =
wlr_output_transform_invert(surface->current.transform);
wlr_matrix_project_box(
matrix, &box, transform, 0, wlr_output->transform_matrix);
render_texture(wlr_output,
render_data->damage,
texture,
render_data->renderer,
matrix,
&box);
}
static void
render_output(struct hikari_output *output,
pixman_region32_t *damage,
struct timespec *now)
{
struct wlr_renderer *renderer =
wlr_backend_get_renderer(output->output->backend);
struct wlr_output *wlr_output = output->output;
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
if (!pixman_region32_not_empty(damage)) {
goto render_end;
}
float *clear_color = hikari_configuration.clear;
#ifndef NDEBUG
if (hikari_server.track_damage) {
float damage_color[4];
hikari_color_convert(damage_color, 0x000000);
wlr_renderer_clear(renderer, damage_color);
}
#endif
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
for (int i = 0; i < nrects; ++i) {
hikari_output_scissor_render(wlr_output, renderer, &rects[i]);
wlr_renderer_clear(renderer, clear_color);
}
struct hikari_render_data render_data = {
.output = wlr_output, .renderer = renderer, .when = now, .damage = damage
};
hikari_workspace_render_background(output->workspace, &render_data);
struct hikari_view *view = NULL;
wl_list_for_each_reverse (view, &output->workspace->views, workspace_views) {
render_data.geometry = hikari_view_border_geometry(view);
if (hikari_view_wants_border(view)) {
hikari_border_render(&view->border, &render_data);
}
render_data.geometry = hikari_view_geometry(view);
hikari_view_interface_for_each_surface(
(struct hikari_view_interface *)view, render_surface, &render_data);
}
#ifdef HAVE_XWAYLAND
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view = NULL;
wl_list_for_each_reverse (xwayland_unmanaged_view,
&output->unmanaged_xwayland_views,
unmanaged_server_views) {
render_data.geometry = xwayland_unmanaged_view->geometry;
wlr_surface_for_each_surface(xwayland_unmanaged_view->surface->surface,
render_surface,
&render_data);
}
#endif
hikari_server.mode->render(output, &render_data);
render_end:
wlr_renderer_scissor(renderer, NULL);
wlr_output_render_software_cursors(wlr_output, NULL);
wlr_renderer_end(renderer);
int width, height;
wlr_output_transformed_resolution(wlr_output, &width, &height);
pixman_region32_t frame_damage;
pixman_region32_init(&frame_damage);
enum wl_output_transform transform =
wlr_output_transform_invert(wlr_output->transform);
wlr_region_transform(
&frame_damage, &output->damage->current, transform, width, height);
wlr_output_set_damage(wlr_output, &frame_damage);
pixman_region32_fini(&frame_damage);
wlr_output_commit(wlr_output);
}
static void
send_frame_done(struct wlr_surface *surface, int sx, int sy, void *data)
{
assert(surface != NULL);
struct timespec *now = data;
wlr_surface_send_frame_done(surface, now);
}
static void
damage_frame_handler(struct wl_listener *listener, void *data)
{
assert(!hikari_server.locked);
bool needs_frame;
struct timespec now;
struct hikari_output *output =
wl_container_of(listener, output, damage_frame);
pixman_region32_t buffer_damage;
pixman_region32_init(&buffer_damage);
if (!wlr_output_damage_attach_render(
output->damage, &needs_frame, &buffer_damage)) {
goto buffer_damage_end;
}
if (needs_frame) {
clock_gettime(CLOCK_MONOTONIC, &now);
render_output(output, &buffer_damage, &now);
}
buffer_damage_end:
pixman_region32_fini(&buffer_damage);
struct hikari_view *view = NULL;
wl_list_for_each_reverse (view, &output->workspace->views, workspace_views) {
hikari_view_interface_for_each_surface(
(struct hikari_view_interface *)view, send_frame_done, &now);
}
#ifdef HAVE_XWAYLAND
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view = NULL;
wl_list_for_each_reverse (xwayland_unmanaged_view,
&output->unmanaged_xwayland_views,
unmanaged_server_views) {
wlr_surface_for_each_surface(
xwayland_unmanaged_view->surface->surface, send_frame_done, &now);
}
#endif
}
void
hikari_output_damage_whole(struct hikari_output *output)
{
assert(output != NULL);
wlr_output_damage_add_whole(output->damage);
}
void
hikari_output_disable(struct hikari_output *output)
{
assert(output != NULL);
struct wlr_output *wlr_output = output->output;
wl_list_remove(&output->damage_frame.link);
wlr_output_rollback(wlr_output);
wlr_output_enable(wlr_output, false);
wlr_output_commit(wlr_output);
}
void
hikari_output_enable(struct hikari_output *output)
{
assert(output != NULL);
output->damage_frame.notify = damage_frame_handler;
wl_signal_add(&output->damage->events.frame, &output->damage_frame);
wlr_output_enable(output->output, true);
wlr_output_commit(output->output);
hikari_output_damage_whole(output);
}
void
hikari_output_scissor_render(struct wlr_output *wlr_output,
struct wlr_renderer *renderer,
pixman_box32_t *rect)
{
assert(wlr_output != NULL);
struct wlr_box box = { .x = rect->x1,
.y = rect->y1,
.width = rect->x2 - rect->x1,
.height = rect->y2 - rect->y1 };
/* int ow, oh; */
/* wlr_output_transformed_resolution(wlr_output, &ow, &oh); */
/* enum wl_output_transform transform = */
/* wlr_output_transform_invert(wlr_output->transform); */
/* wlr_box_transform(&box, &box, transform, ow, oh); */
wlr_renderer_scissor(renderer, &box);
}
static void
output_geometry(struct hikari_output *output)
{
struct wlr_box *output_box =
wlr_output_layout_get_box(hikari_server.output_layout, output->output);
output->geometry.x = output_box->x;
output->geometry.y = output_box->y;
output->geometry.width = output_box->width;
output->geometry.height = output_box->height;
}
/* static void */
/* mode_handler(struct wl_listener *listener, void *data) */
/* { */
/* #if !defined(NDEBUG) */
/* printf("MODE\n"); */
/* #endif */
/* struct hikari_output *output = wl_container_of( */
/* listener, */
/* output, */
/* mode); */
/* output_geometry(output); */
/* } */
static void
destroy_handler(struct wl_listener *listener, void *data)
{
struct hikari_output *output = wl_container_of(listener, output, destroy);
hikari_output_fini(output);
hikari_free(output);
}
void
hikari_output_init(struct hikari_output *output, struct wlr_output *wlr_output)
{
output->output = wlr_output;
output->damage = wlr_output_damage_create(wlr_output);
#ifdef HAVE_XWAYLAND
wl_list_init(&output->unmanaged_xwayland_views);
#endif
wl_list_init(&output->views);
/* output->mode.notify = mode_handler; */
/* wl_signal_add(&wlr_output->events.mode, &output->mode); */
output->destroy.notify = destroy_handler;
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
wlr_output_layout_add_auto(hikari_server.output_layout, wlr_output);
wlr_output_create_global(wlr_output);
output->workspace = hikari_malloc(sizeof(struct hikari_workspace));
hikari_workspace_init(output->workspace, output);
wl_list_insert(&hikari_server.outputs, &output->server_outputs);
if (!wl_list_empty(&wlr_output->modes)) {
struct wlr_output_mode *mode =
wl_container_of(wlr_output->modes.prev, mode, link);
wlr_output_set_mode(wlr_output, mode);
}
wlr_output->data = output;
output_geometry(output);
char *background = hikari_configuration_resolve_background(
&hikari_configuration, wlr_output->name);
hikari_output_enable(output);
if (background != NULL) {
load_background(output->workspace, background);
}
}
void
hikari_output_fini(struct hikari_output *output)
{
wl_list_remove(&output->damage_frame.link);
/* wl_list_remove(&output->mode.link); */
wl_list_remove(&output->destroy.link);
hikari_workspace_fini(output->workspace);
hikari_free(output->workspace);
}

9
src/pointer_config.c Normal file
View File

@ -0,0 +1,9 @@
#include <hikari/pointer_config.h>
#include <hikari/memory.h>
void
hikari_pointer_config_fini(struct hikari_pointer_config *pointer_config)
{
hikari_free(pointer_config->name);
}

100
src/resize_mode.c Normal file
View File

@ -0,0 +1,100 @@
#include <hikari/resize_mode.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_seat.h>
#include <hikari/configuration.h>
#include <hikari/keybinding.h>
#include <hikari/keyboard.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
#include <hikari/view.h>
static void
cancel(void)
{
struct hikari_view *focus_view = hikari_server.workspace->focus_view;
if (focus_view != NULL) {
hikari_indicator_update(&hikari_server.indicator,
focus_view,
hikari_configuration.indicator_selected);
hikari_view_center_cursor(focus_view);
}
}
static void
key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
if (event->state == WLR_KEY_RELEASED) {
hikari_server_enter_normal_mode(NULL);
}
}
static void
modifier_handler(struct wl_listener *listener, void *data)
{}
static void
render(struct hikari_output *output, struct hikari_render_data *render_data)
{
struct hikari_view *focus_view = hikari_server.workspace->focus_view;
if (focus_view->output == output) {
render_data->geometry = hikari_view_border_geometry(focus_view);
hikari_indicator_frame_render(&focus_view->indicator_frame,
hikari_configuration.indicator_insert,
render_data);
hikari_indicator_render(&hikari_server.indicator, render_data);
}
}
static void
cursor_move(void)
{
struct hikari_view *focus_view = hikari_server.workspace->focus_view;
assert(focus_view != NULL);
struct hikari_output *output = focus_view->output;
struct wlr_box *geometry = hikari_view_geometry(focus_view);
int cursor_x = hikari_server.cursor->x - output->geometry.x;
int cursor_y = hikari_server.cursor->y - output->geometry.y;
int new_width = cursor_x - geometry->x - hikari_configuration.border;
int new_height = cursor_y - geometry->y - hikari_configuration.border;
if (new_width > 0 && new_height > 0) {
hikari_view_resize_absolute(focus_view, new_width, new_height);
}
}
static void
button_handler(struct wl_listener *listener, void *data)
{
struct wlr_event_pointer_button *event = data;
if (event->state == WLR_BUTTON_RELEASED) {
hikari_server_enter_normal_mode(NULL);
}
}
void
hikari_resize_mode_init(struct hikari_resize_mode *resize_mode)
{
resize_mode->mode.type = HIKARI_MODE_TYPE_MOVE;
resize_mode->mode.key_handler = key_handler;
resize_mode->mode.button_handler = button_handler;
resize_mode->mode.modifier_handler = modifier_handler;
resize_mode->mode.render = render;
resize_mode->mode.cancel = cancel;
resize_mode->mode.cursor_move = cursor_move;
}

1033
src/server.c Normal file

File diff suppressed because it is too large Load Diff

415
src/sheet.c Normal file
View File

@ -0,0 +1,415 @@
#include <hikari/sheet.h>
#include <stdio.h>
#include <stdlib.h>
#include <hikari/configuration.h>
#include <hikari/group.h>
#include <hikari/layout.h>
#include <hikari/memory.h>
#include <hikari/split.h>
#include <hikari/view.h>
void
hikari_sheet_init(
struct hikari_sheet *sheet, int nr, struct hikari_workspace *workspace)
{
char sheet_name[2];
wl_list_init(&sheet->views);
sheet->nr = nr;
sprintf(sheet_name, "%d", nr);
sheet->group = hikari_malloc(sizeof(struct hikari_group));
hikari_group_init(sheet->group, sheet_name);
sheet->group->sheet = sheet;
sheet->workspace = workspace;
sheet->layout = NULL;
}
void
hikari_sheet_fini(struct hikari_sheet *sheet)
{
hikari_group_fini(sheet->group);
hikari_free(sheet->group);
}
static struct hikari_view *
scan_next_tileable_view(struct hikari_view *view)
{
assert(view != NULL);
struct wl_list *next = view->sheet_views.next;
while (next != &view->sheet->views) {
view = wl_container_of(next, view, sheet_views);
if (hikari_view_is_tileable(view)) {
return view;
}
next = view->sheet_views.next;
}
return NULL;
}
struct hikari_view *
hikari_sheet_first_tileable_view(struct hikari_sheet *sheet)
{
assert(sheet != NULL);
struct wl_list *next = sheet->views.next;
struct hikari_view *view = NULL;
while (next != &sheet->views) {
view = wl_container_of(next, view, sheet_views);
if (hikari_view_is_tileable(view)) {
return view;
}
next = view->sheet_views.next;
}
return NULL;
}
static int
tileable_views(struct hikari_view *view)
{
int result;
if (hikari_view_is_tileable(view)) {
result = 1;
} else {
result = 0;
}
struct wl_list *next = view->sheet_views.next;
while (next != &view->sheet->views) {
view = wl_container_of(next, view, sheet_views);
if (hikari_view_is_tileable(view)) {
result++;
}
next = view->sheet_views.next;
}
return result;
}
static struct hikari_view *
single_layout(struct wlr_box *frame, struct hikari_view *first, int nr_of_views)
{
hikari_view_tile(first, frame);
return scan_next_tileable_view(first);
}
static struct hikari_view *
full_layout(struct wlr_box *frame, struct hikari_view *first, int nr_of_views)
{
struct hikari_view *view = first;
for (int i = 0; i < nr_of_views && view != NULL; i++) {
if (hikari_view_is_tileable(view)) {
hikari_view_tile(view, frame);
}
view = scan_next_tileable_view(view);
}
return view;
}
#define LAYOUT_VIEWS(nr_of_views, view, frame) \
if (nr_of_views == 0) { \
return NULL; \
} else if (nr_of_views == 1) { \
hikari_view_tile(view, frame); \
} else
static struct hikari_view *
grid_layout(struct wlr_box *frame, struct hikari_view *first, int nr_of_views)
{
int nr_of_rows = 1;
int nr_of_cols = 1;
for (int i = 1; i <= nr_of_views; i++) {
if (i > nr_of_rows * nr_of_cols) {
if (nr_of_cols > nr_of_rows) {
assert(nr_of_cols == nr_of_rows + 1);
nr_of_rows++;
} else {
nr_of_cols++;
}
}
}
struct hikari_view *view = first;
LAYOUT_VIEWS(nr_of_views, first, frame)
{
int border = 2 * hikari_configuration.border;
int row_gaps = nr_of_rows - 1;
int col_gaps = nr_of_cols - 1;
int gaps_height = hikari_configuration.gap * row_gaps;
int gaps_width = hikari_configuration.gap * col_gaps;
int views_height = frame->height - border * nr_of_rows - gaps_height;
int views_width = frame->width - border * nr_of_cols - gaps_width;
int width = views_width / nr_of_cols;
int height = views_height / nr_of_rows;
int rest_width =
frame->width - border * col_gaps - gaps_width - width * nr_of_cols;
int rest_height =
frame->height - border * row_gaps - gaps_height - height * nr_of_rows;
struct wlr_box geometry = { .y = frame->y, .x = frame->x };
geometry.height = height + rest_height;
for (int g_y = 0; g_y < nr_of_rows; g_y++) {
if (g_y == 1) {
geometry.height = height;
}
geometry.width = width + rest_width;
for (int g_x = 0; g_x < nr_of_cols; g_x++) {
if (g_x == 1) {
geometry.width = width;
}
hikari_view_tile(view, &geometry);
view = scan_next_tileable_view(view);
if (view == NULL) {
return NULL;
}
geometry.x += hikari_configuration.gap + border + geometry.width;
}
geometry.x = frame->x;
geometry.y += hikari_configuration.gap + border + geometry.height;
}
}
return scan_next_tileable_view(view);
}
#define SPLIT_LAYOUT(name, x, y, width, height) \
static struct hikari_view *name##_layout( \
struct wlr_box *frame, struct hikari_view *first, int nr_of_views) \
{ \
struct hikari_view *view = first; \
int border = 2 * hikari_configuration.border; \
int gaps = nr_of_views - 1; \
int gaps_##width = hikari_configuration.gap * gaps; \
\
LAYOUT_VIEWS(nr_of_views, first, frame) \
{ \
int views_width = frame->width - border * gaps - gaps_##width; \
int width = views_width / nr_of_views; \
int rest = views_width - width * nr_of_views; \
\
struct wlr_box geometry = { .x = frame->x, \
.y = frame->y, \
.width = width + rest, \
.height = frame->height }; \
\
hikari_view_tile(first, &geometry); \
\
geometry.x += hikari_configuration.gap + border + width + rest; \
geometry.width = width; \
for (int n = 1; n < nr_of_views; n++) { \
view = scan_next_tileable_view(view); \
hikari_view_tile(view, &geometry); \
geometry.x += hikari_configuration.gap + border + width; \
} \
} \
\
return scan_next_tileable_view(view); \
}
SPLIT_LAYOUT(vertical, x, y, width, height)
SPLIT_LAYOUT(horizontal, y, x, height, width)
#undef SPLIT_LAYOUT
#define LAYOUT(name) \
struct hikari_view *hikari_sheet_##name##_layout(struct hikari_sheet *sheet, \
struct hikari_view *first, \
struct wlr_box *frame, \
int max) \
{ \
int nr_of_views = tileable_views(first); \
if (nr_of_views > max) { \
nr_of_views = max; \
} \
\
if (nr_of_views == 0) { \
return NULL; \
} \
\
return name##_layout(frame, first, nr_of_views); \
}
LAYOUT(vertical)
LAYOUT(horizontal)
LAYOUT(grid)
LAYOUT(full)
LAYOUT(single)
#undef LAYOUT
#undef LAYOUT_WINDOWS
void
hikari_sheet_reset_layout(struct hikari_sheet *sheet)
{
struct hikari_layout *layout = sheet->layout;
if (layout == NULL) {
return;
}
struct hikari_view *view;
wl_list_for_each (view, &sheet->views, sheet_views) {
if (hikari_view_is_tiled(view)) {
hikari_view_reset_geometry(view);
}
}
}
#define SHEET_VIEW(name, link) \
struct hikari_view *hikari_sheet_##name##_view(struct hikari_sheet *sheet) \
{ \
struct wl_list *link = sheet->views.link; \
struct hikari_view *view; \
\
while (link != &sheet->views) { \
view = wl_container_of(link, view, sheet_views); \
if (!hikari_view_is_hidden(view)) { \
return view; \
} \
link = view->sheet_views.link; \
} \
\
return NULL; \
}
SHEET_VIEW(first, next)
SHEET_VIEW(last, prev)
#undef SHEET_VIEW
#define SHEET_VIEW(link, fallback) \
struct hikari_view *hikari_sheet_##link##_view( \
struct hikari_sheet *sheet, struct hikari_view *view) \
{ \
struct wl_list *link = view->sheet_views.link; \
\
while (link != &view->sheet->views) { \
view = wl_container_of(link, view, sheet_views); \
if (!hikari_view_is_hidden(view)) { \
return view; \
} \
link = view->sheet_views.link; \
} \
\
return hikari_sheet_##fallback##_view(sheet); \
}
SHEET_VIEW(next, first)
SHEET_VIEW(prev, last)
#undef SHEET_VIEW
int
hikari_sheet_tileable_views(struct hikari_sheet *sheet)
{
int nr_of_views = 0;
struct hikari_view *view;
wl_list_for_each (view, &sheet->views, sheet_views) {
if (hikari_view_is_tileable(view)) {
nr_of_views++;
}
}
return nr_of_views;
}
struct hikari_sheet *
hikari_sheet_next(struct hikari_sheet *sheet)
{
struct hikari_sheet *sheets = sheet->workspace->sheets;
if (sheet->nr == 9) {
return &sheets[1];
}
return &sheets[sheet->nr + 1];
}
struct hikari_sheet *
hikari_sheet_prev(struct hikari_sheet *sheet)
{
struct hikari_sheet *sheets = sheet->workspace->sheets;
if (sheet->nr == 0 || sheet->nr == 1) {
return &sheets[9];
}
return &sheets[sheet->nr - 1];
}
struct hikari_sheet *
hikari_sheet_next_inhabited(struct hikari_sheet *sheet)
{
struct hikari_sheet *sheets = sheet->workspace->sheets;
if (sheet->nr == 0 || sheet->nr == 9) {
return sheet;
}
for (uint8_t i = sheet->nr + 1; i < HIKARI_NR_OF_SHEETS; i++) {
if (!wl_list_empty(&sheets[i].views)) {
return &sheets[i];
}
}
return sheet;
}
struct hikari_sheet *
hikari_sheet_prev_inhabited(struct hikari_sheet *sheet)
{
struct hikari_sheet *sheets = sheet->workspace->sheets;
if (sheet->nr <= 1) {
return sheet;
}
for (uint8_t i = sheet->nr - 1; i > 0; i--) {
if (!wl_list_empty(&sheets[i].views)) {
return &sheets[i];
}
}
return sheet;
}
void
hikari_sheet_apply_split(struct hikari_sheet *sheet, struct hikari_split *split)
{
if (sheet->layout != NULL) {
struct hikari_tile *tile;
wl_list_for_each (tile, &sheet->layout->tiles, layout_tiles) {
if (hikari_view_is_dirty(tile->view)) {
return;
}
}
} else {
sheet->layout = hikari_malloc(sizeof(struct hikari_layout));
hikari_layout_init(sheet->layout, split);
}
struct wlr_box geometry = { .x = 0, .y = 0 };
struct hikari_view *first = hikari_sheet_first_tileable_view(sheet);
wlr_output_effective_resolution(
sheet->workspace->output->output, &geometry.width, &geometry.height);
sheet->layout->split = split;
hikari_split_apply(split, &geometry, first);
}

219
src/split.c Normal file
View File

@ -0,0 +1,219 @@
#include <hikari/split.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_matrix.h>
#include <hikari/color.h>
#include <hikari/configuration.h>
#include <hikari/geometry.h>
#include <hikari/render_data.h>
#include <hikari/view.h>
static struct hikari_view *
apply_split(struct hikari_split *split,
struct wlr_box *geometry,
struct hikari_view *first)
{
if (first == NULL) {
return NULL;
}
struct hikari_view *view = first;
switch (split->type) {
case HIKARI_SPLIT_TYPE_VERTICAL: {
struct wlr_box left, right;
struct hikari_vertical_split *vertical_split =
(struct hikari_vertical_split *)split;
hikari_geometry_split_vertical(geometry,
vertical_split->factor,
hikari_configuration.gap + hikari_configuration.border * 2,
&left,
&right);
view = apply_split(vertical_split->left, &left, view);
view = apply_split(vertical_split->right, &right, view);
} break;
case HIKARI_SPLIT_TYPE_HORIZONTAL: {
struct wlr_box top, bottom;
struct hikari_horizontal_split *horizontal_split =
(struct hikari_horizontal_split *)split;
hikari_geometry_split_horizontal(geometry,
horizontal_split->factor,
hikari_configuration.gap + hikari_configuration.border * 2,
&top,
&bottom);
view = apply_split(horizontal_split->top, &top, view);
view = apply_split(horizontal_split->bottom, &bottom, view);
} break;
case HIKARI_SPLIT_TYPE_CONTAINER: {
struct hikari_container *container = (struct hikari_container *)split;
container->geometry = *geometry;
view = container->layout(view->sheet, view, geometry, container->max);
} break;
}
return view;
}
void
hikari_split_apply(struct hikari_split *split,
struct wlr_box *geometry,
struct hikari_view *first)
{
if (first == NULL) {
return;
}
hikari_geometry_shrink(
geometry, hikari_configuration.gap + hikari_configuration.border);
apply_split(split, geometry, first);
}
void
hikari_container_init(
struct hikari_container *container, int nr_of_views, layout_func_t layout)
{
container->split.type = HIKARI_SPLIT_TYPE_CONTAINER;
container->max = nr_of_views;
container->layout = layout;
container->geometry = (struct wlr_box){ 0 };
}
void
hikari_vertical_split_init(struct hikari_vertical_split *vertical_split,
float factor,
struct hikari_split *left,
struct hikari_split *right)
{
vertical_split->split.type = HIKARI_SPLIT_TYPE_VERTICAL;
vertical_split->factor = factor;
vertical_split->left = left;
vertical_split->right = right;
}
void
hikari_horizontal_split_init(struct hikari_horizontal_split *horizontal_split,
float factor,
struct hikari_split *top,
struct hikari_split *bottom)
{
horizontal_split->split.type = HIKARI_SPLIT_TYPE_HORIZONTAL;
horizontal_split->factor = factor;
horizontal_split->top = top;
horizontal_split->bottom = bottom;
}
static void
rect_render(float color[static 4],
struct wlr_box *box,
struct hikari_render_data *render_data)
{
pixman_region32_t damage;
pixman_region32_init(&damage);
pixman_region32_union_rect(
&damage, &damage, box->x, box->y, box->width, box->height);
pixman_region32_intersect(&damage, &damage, render_data->damage);
bool damaged = pixman_region32_not_empty(&damage);
if (!damaged) {
goto buffer_damage_finish;
}
struct wlr_renderer *renderer = render_data->renderer;
assert(renderer);
float matrix[9];
wlr_matrix_project_box(matrix,
box,
WL_OUTPUT_TRANSFORM_NORMAL,
0,
render_data->output->transform_matrix);
int nrects;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
for (int i = 0; i < nrects; i++) {
hikari_output_scissor_render(render_data->output, renderer, &rects[i]);
wlr_render_quad_with_matrix(renderer, color, matrix);
}
buffer_damage_finish:
pixman_region32_fini(&damage);
}
void
hikari_split_fini(struct hikari_split *split)
{
switch (split->type) {
case HIKARI_SPLIT_TYPE_VERTICAL: {
struct hikari_vertical_split *vertical_split =
(struct hikari_vertical_split *)split;
hikari_split_fini(vertical_split->left);
hikari_split_fini(vertical_split->right);
hikari_free(vertical_split);
} break;
case HIKARI_SPLIT_TYPE_HORIZONTAL: {
struct hikari_horizontal_split *horizontal_split =
(struct hikari_horizontal_split *)split;
hikari_split_fini(horizontal_split->top);
hikari_split_fini(horizontal_split->bottom);
hikari_free(horizontal_split);
} break;
case HIKARI_SPLIT_TYPE_CONTAINER: {
struct hikari_container *container = (struct hikari_container *)split;
hikari_free(container);
} break;
}
}
void
hikari_split_render(
struct hikari_split *split, struct hikari_render_data *render_data)
{
switch (split->type) {
case HIKARI_SPLIT_TYPE_VERTICAL: {
struct hikari_vertical_split *vertical_split =
(struct hikari_vertical_split *)split;
hikari_split_render(vertical_split->left, render_data);
hikari_split_render(vertical_split->right, render_data);
} break;
case HIKARI_SPLIT_TYPE_HORIZONTAL: {
struct hikari_horizontal_split *horizontal_split =
(struct hikari_horizontal_split *)split;
hikari_split_render(horizontal_split->top, render_data);
hikari_split_render(horizontal_split->bottom, render_data);
} break;
case HIKARI_SPLIT_TYPE_CONTAINER: {
struct hikari_container *container = (struct hikari_container *)split;
hikari_container_render(container, render_data);
} break;
}
}
void
hikari_container_render(
struct hikari_container *container, struct hikari_render_data *render_data)
{
float color[4];
hikari_color_convert(color, 0xAE81FF);
color[3] = 0.5;
render_data->geometry = &container->geometry;
rect_render(color, &container->geometry, render_data);
}

54
src/tile.c Normal file
View File

@ -0,0 +1,54 @@
#include <hikari/tile.h>
#include <wayland-util.h>
#include <hikari/layout.h>
#include <hikari/sheet.h>
#include <hikari/view.h>
void
hikari_tile_init(struct hikari_tile *tile,
struct hikari_view *view,
struct wlr_box *tile_geometry,
struct wlr_box *view_geometry)
{
tile->view = view;
tile->tile_geometry = *tile_geometry;
tile->view_geometry = *view_geometry;
}
void
hikari_tile_fini(struct hikari_tile *tile)
{
assert(tile->view->tile == NULL);
wl_list_remove(&tile->layout_tiles);
}
#define CYCLE_LAYOUT(link) \
struct hikari_view *hikari_tile_##link##_view(struct hikari_tile *tile) \
{ \
assert(!hikari_view_is_hidden(tile->view)); \
\
struct wl_list *link = tile->layout_tiles.link; \
struct hikari_tile *link##_tile; \
struct wl_list *tiles = &hikari_server.workspace->sheet->layout->tiles; \
\
do { \
if (link == tiles) { \
link##_tile = wl_container_of(tiles->link, link##_tile, layout_tiles); \
} else { \
link##_tile = wl_container_of(link, link##_tile, layout_tiles); \
} \
link = link->link; \
} while (hikari_view_is_hidden(link##_tile->view)); \
\
assert(link##_tile != NULL); \
assert(link##_tile->view != NULL); \
assert(!hikari_view_is_hidden(link##_tile->view)); \
\
return link##_tile->view; \
}
CYCLE_LAYOUT(next)
CYCLE_LAYOUT(prev)
#undef CYCLE_LAYOUT

104
src/tiling_mode.c Normal file
View File

@ -0,0 +1,104 @@
#include <hikari/tiling_mode.h>
#include <assert.h>
#include <wlr/types/wlr_seat.h>
#include <hikari/color.h>
#include <hikari/configuration.h>
#include <hikari/indicator_frame.h>
#include <hikari/keyboard.h>
#include <hikari/layout.h>
#include <hikari/normal_mode.h>
#include <hikari/output.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
#include <hikari/sheet.h>
#include <hikari/split.h>
#include <hikari/view.h>
#include <hikari/workspace.h>
static void
tiling_key_handler(struct hikari_workspace *workspace,
struct wlr_event_keyboard_key *event,
struct hikari_keyboard *keyboard)
{
uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard);
if ((modifiers & WLR_MODIFIER_LOGO) && event->state == WLR_KEY_PRESSED) {
uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_space:
if (modifiers == WLR_MODIFIER_LOGO) {
hikari_server_enter_normal_mode(NULL);
hikari_output_damage_whole(workspace->output);
hikari_server_cursor_focus();
return;
}
}
}
}
wlr_seat_set_keyboard(hikari_server.seat, keyboard->device);
wlr_seat_keyboard_notify_key(
hikari_server.seat, event->time_msec, event->keycode, event->state);
}
static void
render(struct hikari_output *output, struct hikari_render_data *render_data)
{
struct hikari_workspace *workspace = hikari_server.workspace;
assert(workspace->sheet->layout->split != NULL);
hikari_split_render(workspace->sheet->layout->split, render_data);
}
static void
modifier_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard =
wl_container_of(listener, keyboard, modifiers);
wlr_seat_keyboard_notify_modifiers(
hikari_server.seat, &keyboard->device->keyboard->modifiers);
}
static void
key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
struct hikari_workspace *workspace = hikari_server.workspace;
tiling_key_handler(workspace, event, keyboard);
}
static void
cancel(void)
{}
static void
button_handler(struct wl_listener *listener, void *data)
{}
static void
cursor_move(void)
{}
void
hikari_tiling_mode_init(struct hikari_tiling_mode *tiling_mode)
{
tiling_mode->mode.type = HIKARI_MODE_TYPE_TILING;
tiling_mode->mode.key_handler = key_handler;
tiling_mode->mode.button_handler = button_handler;
tiling_mode->mode.modifier_handler = modifier_handler;
tiling_mode->mode.render = render;
tiling_mode->mode.cancel = cancel;
tiling_mode->mode.cursor_move = cursor_move;
}

153
src/unlocker.c Normal file
View File

@ -0,0 +1,153 @@
#include <hikari/unlocker.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wlr/types/wlr_input_device.h>
#include <hikari/keyboard.h>
#include <hikari/server.h>
#include <hikari/utf8.h>
static const size_t BUFFER_SIZE = 1024;
static char input_buffer[BUFFER_SIZE];
static int cursor = 0;
static int locker_pipe[2][2] = { { -1, -1 }, { -1, -1 } };
void
hikari_unlocker_init(void)
{
mlock(input_buffer, BUFFER_SIZE);
bzero(input_buffer, BUFFER_SIZE);
}
void
hikari_unlocker_start(void)
{
cursor = 0;
bzero(input_buffer, BUFFER_SIZE);
pipe(locker_pipe[0]);
pipe(locker_pipe[1]);
pid_t locker = fork();
if (locker == 0) {
close(locker_pipe[0][1]);
close(locker_pipe[1][0]);
close(0);
close(1);
dup2(locker_pipe[0][0], 0);
dup2(locker_pipe[1][1], 1);
execl("/bin/sh", "/bin/sh", "-c", "hikari-unlocker", NULL);
exit(0);
} else {
close(locker_pipe[0][0]);
close(locker_pipe[1][1]);
}
}
static void
put_char(uint32_t codepoint)
{
size_t length = utf8_chsize(codepoint);
if (cursor + length < BUFFER_SIZE) {
utf8_encode(&input_buffer[cursor], length, codepoint);
cursor += length;
}
}
static void
delete_char(void)
{
if (cursor == 0) {
return;
}
input_buffer[--cursor] = '\0';
}
static void
submit_password(void)
{
size_t password_length = strnlen(input_buffer, 1023) + 1;
bool success = false;
write(locker_pipe[0][1], input_buffer, password_length);
bzero(input_buffer, BUFFER_SIZE);
cursor = 0;
read(locker_pipe[1][0], &success, sizeof(bool));
if (success) {
int status;
hikari_server_unlock();
close(locker_pipe[1][0]);
close(locker_pipe[0][1]);
wait(&status);
}
}
void
hikari_unlocker_key_handler(struct wl_listener *listener, void *data)
{
struct hikari_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct wlr_event_keyboard_key *event = data;
if (event->state == WLR_KEY_PRESSED) {
const xkb_keysym_t *syms;
uint32_t keycode = event->keycode + 8;
uint32_t codepoint;
int nsyms = xkb_state_key_get_syms(
keyboard->device->keyboard->xkb_state, keycode, &syms);
for (int i = 0; i < nsyms; i++) {
switch (syms[i]) {
case XKB_KEY_Caps_Lock:
case XKB_KEY_Shift_L:
case XKB_KEY_Shift_R:
case XKB_KEY_Control_L:
case XKB_KEY_Control_R:
case XKB_KEY_Meta_L:
case XKB_KEY_Meta_R:
case XKB_KEY_Alt_L:
case XKB_KEY_Alt_R:
case XKB_KEY_Super_L:
case XKB_KEY_Super_R:
break;
case XKB_KEY_BackSpace:
delete_char();
break;
case XKB_KEY_Return:
submit_password();
break;
default:
codepoint = xkb_state_key_get_utf32(
keyboard->device->keyboard->xkb_state, keycode);
if (codepoint) {
put_char(codepoint);
}
break;
}
}
}
}
void
hikari_unlocker_fini(void)
{
munlock(input_buffer, BUFFER_SIZE);
}

1527
src/view.c Normal file

File diff suppressed because it is too large Load Diff

15
src/view_autoconf.c Normal file
View File

@ -0,0 +1,15 @@
#include <hikari/view_autoconf.h>
#include <assert.h>
#include <stdlib.h>
#include <hikari/memory.h>
void
hikari_view_autoconf_fini(struct hikari_view_autoconf *autoconf)
{
assert(autoconf != NULL);
hikari_free(autoconf->app_id);
hikari_free(autoconf->group_name);
}

1064
src/workspace.c Normal file

File diff suppressed because it is too large Load Diff

533
src/xdg_view.c Normal file
View File

@ -0,0 +1,533 @@
#include <hikari/xdg_view.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_surface.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/edges.h>
#include <hikari/configuration.h>
#include <hikari/geometry.h>
#include <hikari/mark.h>
#include <hikari/output.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
#include <hikari/sheet.h>
#include <hikari/view.h>
#include <hikari/view_autoconf.h>
#include <hikari/workspace.h>
static void
set_title_handler(struct wl_listener *listener, void *data)
{
struct hikari_xdg_view *xdg_view =
wl_container_of(listener, xdg_view, set_title);
hikari_view_set_title(
(struct hikari_view *)xdg_view, xdg_view->surface->toplevel->title);
}
static void
commit_handler(struct wl_listener *listener, void *data)
{
struct hikari_xdg_view *xdg_view =
wl_container_of(listener, xdg_view, commit);
struct hikari_view *view = (struct hikari_view *)xdg_view;
assert(!hikari_view_is_hidden(view));
struct wlr_box *geometry = hikari_view_geometry(view);
assert(view->surface != NULL);
uint32_t serial = xdg_view->surface->configure_serial;
if (hikari_view_was_updated(view, serial)) {
switch (view->pending_operation.type) {
case HIKARI_OPERATION_TYPE_TILE:
case HIKARI_OPERATION_TYPE_FULL_MAXIMIZE:
case HIKARI_OPERATION_TYPE_VERTICAL_MAXIMIZE:
case HIKARI_OPERATION_TYPE_HORIZONTAL_MAXIMIZE:
wlr_xdg_toplevel_set_tiled(xdg_view->surface,
WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
break;
case HIKARI_OPERATION_TYPE_RESET:
case HIKARI_OPERATION_TYPE_UNMAXIMIZE:
wlr_xdg_toplevel_set_tiled(xdg_view->surface, WLR_EDGE_NONE);
break;
case HIKARI_OPERATION_TYPE_RESIZE:
break;
}
hikari_view_commit_pending_operation(view);
} else {
struct wlr_box new_geometry;
wlr_xdg_surface_get_geometry(xdg_view->surface, &new_geometry);
if (new_geometry.width != geometry->width ||
new_geometry.height != geometry->height) {
hikari_view_damage_whole(view);
geometry->width = new_geometry.width;
geometry->height = new_geometry.height;
hikari_view_refresh_geometry(view, geometry);
hikari_view_damage_whole(view);
} else {
pixman_region32_t damage;
pixman_region32_init(&damage);
wlr_surface_get_effective_damage(xdg_view->surface->surface, &damage);
pixman_region32_translate(&damage, geometry->x, geometry->y);
wlr_output_damage_add(view->output->damage, &damage);
pixman_region32_fini(&damage);
}
}
}
static void
first_map(struct hikari_xdg_view *xdg_view, bool *focus)
{
assert(xdg_view->surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
struct hikari_sheet *sheet;
struct hikari_group *group;
struct hikari_view *view = (struct hikari_view *)xdg_view;
struct wlr_box *geometry = &xdg_view->view.geometry;
struct hikari_output *output = hikari_server.workspace->output;
int screen_width, screen_height;
wlr_output_effective_resolution(
output->output, &screen_width, &screen_height);
wlr_xdg_surface_get_geometry(xdg_view->surface, geometry);
const char *app_id = xdg_view->surface->toplevel->app_id;
#if !defined(NDEBUG)
printf("APP ID %s\n", app_id);
#endif
int x;
int y;
hikari_configuration_resolve_view_autoconf(
&hikari_configuration, app_id, view, &sheet, &group, &x, &y, focus);
hikari_view_manage(view, sheet, group);
hikari_view_set_title(view, xdg_view->surface->toplevel->title);
xdg_view->set_title.notify = set_title_handler;
wl_signal_add(
&xdg_view->surface->toplevel->events.set_title, &xdg_view->set_title);
hikari_geometry_constrain_position(
geometry, screen_width, screen_height, x, y);
hikari_view_refresh_geometry(view, geometry);
}
static struct wlr_surface *
surface_at(struct hikari_view_interface *view_interface,
double ox,
double oy,
double *sx,
double *sy)
{
struct hikari_xdg_view *xdg_view = (struct hikari_xdg_view *)view_interface;
struct hikari_view *view = (struct hikari_view *)view_interface;
struct wlr_box *geometry = hikari_view_geometry(view);
double x = ox - geometry->x;
double y = oy - geometry->y;
return wlr_xdg_surface_surface_at(xdg_view->surface, x, y, sx, sy);
}
static void
map(struct hikari_view *view, bool focus)
{
#if !defined(NDEBUG)
printf("XDG MAP %p\n", view);
#endif
struct hikari_xdg_view *xdg_view = (struct hikari_xdg_view *)view;
view->surface = xdg_view->surface->surface;
hikari_view_show(view);
if (focus) {
hikari_view_center_cursor(view);
}
hikari_server_cursor_focus();
}
static void
map_handler(struct wl_listener *listener, void *data)
{
struct hikari_xdg_view *xdg_view = wl_container_of(listener, xdg_view, map);
struct hikari_view *view = (struct hikari_view *)xdg_view;
bool focus = false;
if (view->sheet == NULL) {
first_map(xdg_view, &focus);
}
map(view, focus);
}
static void
unmap(struct hikari_view *view)
{
#if !defined(NDEBUG)
printf("XDG UNMAP %p\n", view);
#endif
if (!hikari_view_is_hidden(view)) {
hikari_view_hide(view);
hikari_server_cursor_focus();
}
struct hikari_xdg_view *xdg_view = (struct hikari_xdg_view *)view;
if (xdg_view->surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
wl_list_remove(&xdg_view->set_title.link);
}
view->surface = NULL;
}
static void
unmap_handler(struct wl_listener *listener, void *data)
{
struct hikari_xdg_view *xdg_view = wl_container_of(listener, xdg_view, unmap);
unmap((struct hikari_view *)xdg_view);
}
static void
activate(struct hikari_view *view, bool active)
{
struct hikari_xdg_view *xdg_view = (struct hikari_xdg_view *)view;
if (xdg_view->surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
wlr_xdg_toplevel_set_activated(xdg_view->surface, active);
hikari_view_damage_whole(view);
}
}
static uint32_t
resize(struct hikari_view *view, int width, int height)
{
struct hikari_xdg_view *xdg_view = (struct hikari_xdg_view *)view;
if (xdg_view->surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
return wlr_xdg_toplevel_set_size(xdg_view->surface, width, height);
}
return 0;
}
static void
quit(struct hikari_view *view)
{
struct hikari_xdg_view *xdg_view = (struct hikari_xdg_view *)view;
wlr_xdg_toplevel_send_close(xdg_view->surface);
}
static void
destroy_handler(struct wl_listener *listener, void *data)
{
struct hikari_xdg_view *xdg_view =
wl_container_of(listener, xdg_view, destroy);
struct hikari_view *view = (struct hikari_view *)xdg_view;
if (hikari_view_is_mapped(view)) {
unmap(view);
}
wl_list_remove(&xdg_view->map.link);
wl_list_remove(&xdg_view->unmap.link);
wl_list_remove(&xdg_view->destroy.link);
wl_list_remove(&xdg_view->new_popup.link);
wl_list_remove(&xdg_view->new_subsurface.link);
wl_list_remove(&xdg_view->request_fullscreen.link);
hikari_view_fini(view);
hikari_free(xdg_view);
}
static void
focus(struct hikari_view_interface *view_interface)
{
struct hikari_view *view = (struct hikari_view *)view_interface;
hikari_workspace_focus_view(view->sheet->workspace, view);
}
static void
for_each_surface(struct hikari_view_interface *view_interface,
void (*func)(struct wlr_surface *, int, int, void *),
void *data)
{
struct hikari_xdg_view *xdg_view = (struct hikari_xdg_view *)view_interface;
wlr_xdg_surface_for_each_surface(xdg_view->surface, func, data);
}
static void
destroy_popup_handler(struct wl_listener *listener, void *data)
{
#if !defined(NDEBUG)
printf("DESTROY POPUP\n");
#endif
struct hikari_xdg_popup *popup = wl_container_of(listener, popup, destroy);
hikari_view_child_fini(&popup->view_child);
wl_list_remove(&popup->destroy.link);
wl_list_remove(&popup->unmap.link);
wl_list_remove(&popup->map.link);
wl_list_remove(&popup->new_popup.link);
hikari_free(popup);
}
static void
xdg_popup_create(struct wlr_xdg_popup *wlr_popup, struct hikari_view *parent);
static void
new_popup_popup_handler(struct wl_listener *listener, void *data)
{
struct hikari_xdg_popup *xdg_popup =
wl_container_of(listener, xdg_popup, new_popup);
struct wlr_xdg_popup *wlr_popup = data;
xdg_popup_create(wlr_popup, xdg_popup->view_child.parent);
}
static void
new_popup_handler(struct wl_listener *listener, void *data)
{
struct hikari_xdg_view *xdg_view =
wl_container_of(listener, xdg_view, new_popup);
struct wlr_xdg_popup *wlr_popup = data;
xdg_popup_create(wlr_popup, &xdg_view->view);
}
static void
popup_map(struct wl_listener *listener, void *data)
{
#if !defined(NDEBUG)
printf("POPUP MAP\n");
#endif
struct hikari_xdg_popup *xdg_popup =
wl_container_of(listener, xdg_popup, map);
struct hikari_view *parent = xdg_popup->view_child.parent;
hikari_view_damage_surface(parent, xdg_popup->view_child.surface, true);
}
static void
popup_unmap(struct wl_listener *listener, void *data)
{
#if !defined(NDEBUG)
printf("POPUP UNMAP\n");
#endif
struct hikari_xdg_popup *xdg_popup =
wl_container_of(listener, xdg_popup, unmap);
struct hikari_view *parent = xdg_popup->view_child.parent;
hikari_view_damage_surface(parent, xdg_popup->view_child.surface, true);
}
static void
popup_unconstrain(struct hikari_xdg_popup *popup)
{
struct hikari_view *view = popup->view_child.parent;
struct wlr_xdg_popup *wlr_popup = popup->popup;
struct hikari_output *output = view->output;
struct wlr_box *geometry = hikari_view_geometry(view);
struct wlr_box output_toplevel_sx_box = {
.x = output->geometry.x - geometry->x,
.y = output->geometry.y - geometry->y,
.width = output->geometry.width,
.height = output->geometry.height,
};
wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
}
static void
xdg_popup_create(struct wlr_xdg_popup *wlr_popup, struct hikari_view *parent)
{
struct hikari_xdg_popup *popup =
hikari_malloc(sizeof(struct hikari_xdg_popup));
#if !defined(NDEBUG)
printf("CREATE POPUP\n");
#endif
popup->view_child.parent = parent;
popup->popup = wlr_popup;
wlr_popup->base->surface->data = parent;
popup->destroy.notify = destroy_popup_handler;
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
popup->new_popup.notify = new_popup_popup_handler;
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
popup->map.notify = popup_map;
wl_signal_add(&wlr_popup->base->events.map, &popup->map);
popup->unmap.notify = popup_unmap;
wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap);
hikari_view_child_init(
(struct hikari_view_child *)popup, parent, wlr_popup->base->surface);
// TODO this does not work correctly with multi monitor
popup_unconstrain(popup);
}
static void
new_subsurface_handler(struct wl_listener *listener, void *data)
{
struct hikari_xdg_view *xdg_view =
wl_container_of(listener, xdg_view, new_subsurface);
struct wlr_subsurface *subsurface = data;
struct hikari_view_subsurface *view_subsurface =
hikari_malloc(sizeof(struct hikari_view_subsurface));
hikari_view_subsurface_init(view_subsurface, &xdg_view->view, subsurface);
#if !defined(NDEBUG)
printf("SUBSURFACE\n");
#endif
}
static void
request_fullscreen_handler(struct wl_listener *listener, void *data)
{
struct hikari_xdg_view *xdg_view =
wl_container_of(listener, xdg_view, request_fullscreen);
struct wlr_xdg_toplevel_set_fullscreen_event *event = data;
wlr_xdg_toplevel_set_fullscreen(xdg_view->surface, event->fullscreen);
}
static void
hide(struct hikari_view *view)
{
struct hikari_xdg_view *xdg_view = (struct hikari_xdg_view *)view;
wl_list_remove(&xdg_view->commit.link);
}
static void
show(struct hikari_view *view)
{
struct hikari_xdg_view *xdg_view = (struct hikari_xdg_view *)view;
xdg_view->commit.notify = commit_handler;
wl_signal_add(&xdg_view->surface->surface->events.commit, &xdg_view->commit);
}
static void
constraints(struct hikari_view *view,
int *min_width,
int *min_height,
int *max_width,
int *max_height)
{
struct hikari_xdg_view *xdg_view = (struct hikari_xdg_view *)view;
struct wlr_xdg_toplevel_state *state = &xdg_view->surface->toplevel->current;
*min_width = state->min_width > 0 ? state->min_width : 0;
*min_height = state->min_height > 0 ? state->min_height : 0;
*max_width =
state->max_width > 0 ? state->max_width : view->output->geometry.width;
*max_height =
state->max_height > 0 ? state->max_height : view->output->geometry.height;
}
void
hikari_xdg_view_init(struct hikari_xdg_view *xdg_view,
struct wlr_xdg_surface *xdg_surface,
struct hikari_workspace *workspace)
{
hikari_view_init(&xdg_view->view, HIKARI_XDG_VIEW, workspace);
#if !defined(NDEBUG)
printf("NEW XDG %p\n", xdg_view);
#endif
xdg_view->view.view_interface.surface_at = surface_at;
wlr_xdg_surface_ping(xdg_surface);
xdg_view->surface = xdg_surface;
xdg_view->surface->data = xdg_view;
xdg_view->map.notify = map_handler;
wl_signal_add(&xdg_surface->events.map, &xdg_view->map);
xdg_view->unmap.notify = unmap_handler;
wl_signal_add(&xdg_surface->events.unmap, &xdg_view->unmap);
xdg_view->destroy.notify = destroy_handler;
wl_signal_add(&xdg_surface->events.destroy, &xdg_view->destroy);
xdg_view->new_popup.notify = new_popup_handler;
wl_signal_add(&xdg_surface->events.new_popup, &xdg_view->new_popup);
xdg_view->new_subsurface.notify = new_subsurface_handler;
wl_signal_add(
&xdg_surface->surface->events.new_subsurface, &xdg_view->new_subsurface);
xdg_view->request_fullscreen.notify = request_fullscreen_handler;
wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
&xdg_view->request_fullscreen);
assert(xdg_view->surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
xdg_view->view.view_interface.focus = focus;
xdg_view->view.view_interface.for_each_surface = for_each_surface;
xdg_view->view.activate = activate;
xdg_view->view.resize = resize;
xdg_view->view.quit = quit;
xdg_view->view.hide = hide;
xdg_view->view.constraints = constraints;
xdg_view->view.show = show;
xdg_view->view.move = NULL;
}

View File

@ -0,0 +1,207 @@
#ifdef HAVE_XWAYLAND
#include <hikari/xwayland_unmanaged_view.h>
#include <wlr/xwayland.h>
#include <hikari/memory.h>
#include <hikari/output.h>
#include <hikari/server.h>
#include <hikari/workspace.h>
static bool
was_updated(struct wlr_xwayland_surface *surface,
struct wlr_box *geometry,
struct hikari_output *output)
{
return !((output->geometry.x + surface->x == geometry->x) &&
(output->geometry.y + surface->y == geometry->y) &&
(surface->width == geometry->width) &&
(surface->height == geometry->height));
}
static void
commit_handler(struct wl_listener *listener, void *data)
{
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view =
wl_container_of(listener, xwayland_unmanaged_view, commit);
struct hikari_output *output = xwayland_unmanaged_view->workspace->output;
struct wlr_xwayland_surface *surface = xwayland_unmanaged_view->surface;
struct wlr_box *geometry = &xwayland_unmanaged_view->geometry;
if (was_updated(surface, geometry, output)) {
hikari_output_add_damage(output, &xwayland_unmanaged_view->geometry);
geometry->x = surface->x - output->geometry.x;
geometry->y = surface->y - output->geometry.y;
geometry->width = surface->width;
geometry->height = surface->height;
hikari_output_add_damage(output, geometry);
} else {
pixman_region32_t damage;
pixman_region32_init(&damage);
wlr_surface_get_effective_damage(surface->surface, &damage);
pixman_region32_translate(&damage, geometry->x, geometry->y);
wlr_output_damage_add(output->damage, &damage);
pixman_region32_fini(&damage);
wlr_output_schedule_frame(output->output);
}
}
static void
map_handler(struct wl_listener *listener, void *data)
{
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view =
wl_container_of(listener, xwayland_unmanaged_view, map);
#if !defined(NDEBUG)
printf("UNMANAGED XWAYLAND MAP %p %d %d\n",
xwayland_unmanaged_view,
xwayland_unmanaged_view->surface->x,
xwayland_unmanaged_view->surface->y);
#endif
struct wlr_box *geometry = &xwayland_unmanaged_view->geometry;
struct wlr_xwayland_surface *xwayland_surface =
xwayland_unmanaged_view->surface;
struct hikari_output *output = xwayland_unmanaged_view->workspace->output;
xwayland_unmanaged_view->hidden = false;
geometry->x = xwayland_surface->x - output->geometry.x;
geometry->y = xwayland_surface->y - output->geometry.y;
geometry->width = xwayland_surface->width;
geometry->height = xwayland_surface->height;
xwayland_unmanaged_view->commit.notify = commit_handler;
wl_signal_add(&xwayland_surface->surface->events.commit,
&xwayland_unmanaged_view->commit);
wl_list_insert(&output->unmanaged_xwayland_views,
&xwayland_unmanaged_view->unmanaged_server_views);
hikari_output_add_damage(output, geometry);
}
static void
unmap(struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view)
{
wl_list_remove(&xwayland_unmanaged_view->commit.link);
wl_list_remove(&xwayland_unmanaged_view->unmanaged_server_views);
xwayland_unmanaged_view->hidden = true;
hikari_output_add_damage(xwayland_unmanaged_view->workspace->output,
&xwayland_unmanaged_view->geometry);
}
static void
unmap_handler(struct wl_listener *listener, void *data)
{
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view =
wl_container_of(listener, xwayland_unmanaged_view, unmap);
#if !defined(NDEBUG)
printf("UNMANAGED XWAYLAND UNMAP %p\n", xwayland_unmanaged_view);
#endif
unmap(xwayland_unmanaged_view);
}
static void
destroy_handler(struct wl_listener *listener, void *data)
{
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view =
wl_container_of(listener, xwayland_unmanaged_view, destroy);
#if !defined(NDEBUG)
printf("UNMANAGED XWAYLAND DESTROY %p\n", xwayland_unmanaged_view);
#endif
if (!xwayland_unmanaged_view->hidden) {
unmap(xwayland_unmanaged_view);
hikari_server_cursor_focus();
}
wl_list_remove(&xwayland_unmanaged_view->map.link);
wl_list_remove(&xwayland_unmanaged_view->unmap.link);
wl_list_remove(&xwayland_unmanaged_view->destroy.link);
wl_list_remove(&xwayland_unmanaged_view->request_configure.link);
hikari_free(xwayland_unmanaged_view);
}
static void
request_configure_handler(struct wl_listener *listener, void *data)
{
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view =
wl_container_of(listener, xwayland_unmanaged_view, request_configure);
struct wlr_xwayland_surface *surface = xwayland_unmanaged_view->surface;
struct wlr_xwayland_surface_configure_event *event = data;
wlr_xwayland_surface_configure(
surface, event->x, event->y, event->width, event->height);
}
static struct wlr_surface *
surface_at(struct hikari_view_interface *view_interface,
double lx,
double ly,
double *sx,
double *sy)
{
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view =
(struct hikari_xwayland_unmanaged_view *)view_interface;
struct wlr_box *geometry = &xwayland_unmanaged_view->geometry;
double x = lx - geometry->x;
double y = ly - geometry->y;
return wlr_surface_surface_at(
xwayland_unmanaged_view->surface->surface, x, y, sx, sy);
}
static void
focus(struct hikari_view_interface *view_interface)
{}
void
hikari_xwayland_unmanaged_view_init(
struct hikari_xwayland_unmanaged_view *xwayland_unmanaged_view,
struct wlr_xwayland_surface *xwayland_surface,
struct hikari_workspace *workspace)
{
xwayland_unmanaged_view->workspace = workspace;
xwayland_unmanaged_view->view_interface.surface_at = surface_at;
xwayland_unmanaged_view->view_interface.focus = focus;
#if !defined(NDEBUG)
printf("UNMANAGED XWAYLAND NEW %p\n", xwayland_unmanaged_view);
#endif
wlr_xwayland_surface_ping(xwayland_surface);
xwayland_unmanaged_view->surface = xwayland_surface;
xwayland_unmanaged_view->surface->data =
(struct hikari_view_interface *)xwayland_unmanaged_view;
xwayland_unmanaged_view->hidden = true;
xwayland_unmanaged_view->map.notify = map_handler;
wl_signal_add(&xwayland_surface->events.map, &xwayland_unmanaged_view->map);
xwayland_unmanaged_view->unmap.notify = unmap_handler;
wl_signal_add(
&xwayland_surface->events.unmap, &xwayland_unmanaged_view->unmap);
xwayland_unmanaged_view->destroy.notify = destroy_handler;
wl_signal_add(
&xwayland_surface->events.destroy, &xwayland_unmanaged_view->destroy);
xwayland_unmanaged_view->request_configure.notify = request_configure_handler;
wl_signal_add(&xwayland_surface->events.request_configure,
&xwayland_unmanaged_view->request_configure);
}
#endif

417
src/xwayland_view.c Normal file
View File

@ -0,0 +1,417 @@
#ifdef HAVE_XWAYLAND
#include <hikari/xwayland_view.h>
#include <assert.h>
#include <stdlib.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_output_damage.h>
#include <wlr/xwayland.h>
#include <hikari/configuration.h>
#include <hikari/geometry.h>
#include <hikari/output.h>
#include <hikari/render_data.h>
#include <hikari/server.h>
#include <hikari/sheet.h>
#include <hikari/view.h>
#include <hikari/workspace.h>
static uint32_t
resize(struct hikari_view *view, int width, int height)
{
struct hikari_xwayland_view *xwayland_view =
(struct hikari_xwayland_view *)view;
struct wlr_box *geometry = hikari_view_geometry(view);
struct hikari_output *output = view->output;
wlr_xwayland_surface_configure(xwayland_view->surface,
output->geometry.x + geometry->x,
output->geometry.y + geometry->y,
width,
height);
return 0;
}
static void
move(struct hikari_view *view, int x, int y)
{
struct hikari_xwayland_view *xwayland_view =
(struct hikari_xwayland_view *)view;
struct wlr_box *geometry = hikari_view_geometry(view);
struct hikari_output *output = view->output;
wlr_xwayland_surface_configure(xwayland_view->surface,
output->geometry.x + x,
output->geometry.y + y,
geometry->width,
geometry->height);
}
static bool
was_updated(struct hikari_xwayland_view *xwayland_view)
{
struct hikari_view *view = (struct hikari_view *)xwayland_view;
struct wlr_xwayland_surface *surface = xwayland_view->surface;
struct wlr_box *pending_geometry = &view->pending_operation.geometry;
return hikari_view_is_dirty(view) &&
(surface->width == pending_geometry->width ||
surface->height == pending_geometry->height);
}
static bool
was_moved(struct wlr_xwayland_surface *surface,
struct wlr_box *geometry,
struct hikari_output *output)
{
return !((output->geometry.x + surface->x == geometry->x) &&
(output->geometry.y + surface->y == geometry->y));
}
static void
commit_handler(struct wl_listener *listener, void *data)
{
struct hikari_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, commit);
struct hikari_view *view = (struct hikari_view *)xwayland_view;
struct wlr_box *geometry = hikari_view_geometry(view);
struct hikari_output *output = view->output;
struct wlr_xwayland_surface *surface = xwayland_view->surface;
if (was_updated(xwayland_view)) {
hikari_view_commit_pending_operation(view, geometry);
geometry = hikari_view_geometry(view);
wlr_xwayland_surface_configure(surface,
output->geometry.x + geometry->x,
output->geometry.y + geometry->y,
geometry->width,
geometry->height);
} else if (was_moved(surface, geometry, output)) {
hikari_view_damage_whole(view);
hikari_indicator_damage(&hikari_server.indicator, view);
geometry->x = surface->x - output->geometry.x;
geometry->y = surface->y - output->geometry.y;
hikari_view_damage_whole(view);
} else {
pixman_region32_t damage;
pixman_region32_init(&damage);
wlr_surface_get_effective_damage(surface->surface, &damage);
pixman_region32_translate(&damage, geometry->x, geometry->y);
wlr_output_damage_add(output->damage, &damage);
pixman_region32_fini(&damage);
wlr_output_schedule_frame(output->output);
}
}
static void
set_title_handler(struct wl_listener *listener, void *data)
{
struct hikari_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, set_title);
struct hikari_view *view = (struct hikari_view *)xwayland_view;
hikari_view_set_title(view, xwayland_view->surface->title);
}
static void
first_map(struct hikari_xwayland_view *xwayland_view)
{
struct hikari_view *view = (struct hikari_view *)xwayland_view;
struct hikari_output *output = hikari_server.workspace->output;
view->border = HIKARI_BORDER_INACTIVE;
struct hikari_sheet *sheet;
struct hikari_group *group;
int x;
int y;
bool focus;
hikari_configuration_resolve_view_autoconf(&hikari_configuration,
xwayland_view->surface->class,
view,
&sheet,
&group,
&x,
&y,
&focus);
if (x == -1) {
x = hikari_server.cursor->x - output->geometry.x;
}
if (y == -1) {
y = hikari_server.cursor->y - output->geometry.y;
}
view->geometry.width = xwayland_view->surface->width;
view->geometry.height = xwayland_view->surface->height;
xwayland_view->commit.notify = commit_handler;
wl_signal_add(
&xwayland_view->surface->surface->events.commit, &xwayland_view->commit);
hikari_view_set_title(view, xwayland_view->surface->title);
hikari_view_manage(view, sheet, group);
int screen_width, screen_height;
wlr_output_effective_resolution(
output->output, &screen_width, &screen_height);
hikari_geometry_constrain_position(
&view->geometry, screen_width, screen_height, x, y);
wlr_xwayland_surface_configure(xwayland_view->surface,
output->geometry.x + view->geometry.x,
output->geometry.y + view->geometry.y,
view->geometry.width,
view->geometry.height);
}
static void
map(struct hikari_view *view)
{
#if !defined(NDEBUG)
printf("XWAYLAND MAP %p\n", view);
#endif
struct hikari_xwayland_view *xwayland_view =
(struct hikari_xwayland_view *)view;
view->surface = xwayland_view->surface->surface;
view->surface->data = (struct hikari_view_interface *)view;
/* if (view->sheet == view->sheet->workspace->sheet || */
/* view->sheet == &view->sheet->workspace->sheets[0]) { */
hikari_view_show(view);
hikari_server_cursor_focus();
/* } */
}
static void
map_handler(struct wl_listener *listener, void *data)
{
struct hikari_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, map);
struct hikari_view *view = (struct hikari_view *)xwayland_view;
if (view->sheet == NULL) {
first_map(xwayland_view);
}
map(view);
}
static void
unmap(struct hikari_view *view)
{
#if !defined(NDEBUG)
printf("XWAYLAND UNMAP %p\n", view);
#endif
if (!hikari_view_is_hidden(view)) {
hikari_view_hide(view);
hikari_server_cursor_focus();
}
struct hikari_xwayland_view *xwayland_view =
(struct hikari_xwayland_view *)view;
wl_list_remove(&xwayland_view->commit.link);
view->surface = NULL;
}
static void
unmap_handler(struct wl_listener *listener, void *data)
{
struct hikari_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, unmap);
unmap((struct hikari_view *)xwayland_view);
}
static void
destroy_handler(struct wl_listener *listener, void *data)
{
struct hikari_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, destroy);
#if !defined(NDEBUG)
printf("XWAYLAND DESTROY %p\n", xwayland_view);
#endif
struct hikari_view *view = (struct hikari_view *)xwayland_view;
if (hikari_view_is_mapped(view)) {
unmap(view);
}
hikari_view_fini(&xwayland_view->view);
wl_list_remove(&xwayland_view->map.link);
wl_list_remove(&xwayland_view->unmap.link);
wl_list_remove(&xwayland_view->destroy.link);
wl_list_remove(&xwayland_view->request_configure.link);
wl_list_remove(&xwayland_view->set_title.link);
hikari_free(xwayland_view);
}
static void
request_configure_handler(struct wl_listener *listener, void *data)
{
struct hikari_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, request_configure);
struct wlr_xwayland_surface *xwayland_surface = xwayland_view->surface;
struct wlr_xwayland_surface_configure_event *event = data;
#if !defined(NDEBUG)
printf("XWAYLAND CONFIGURE %p %d %d\n", xwayland_view, event->x, event->y);
#endif
struct wlr_box geometry = {
.x = event->x, .y = event->y, .width = event->width, .height = event->height
};
struct hikari_sheet *sheet = xwayland_view->view.sheet;
int screen_width, screen_height;
if (sheet != NULL) {
wlr_output_effective_resolution(
xwayland_view->view.output->output, &screen_width, &screen_height);
} else {
wlr_output_effective_resolution(
hikari_server.workspace->output->output, &screen_width, &screen_height);
}
hikari_geometry_constrain_position(
&geometry, screen_width, screen_height, event->x, event->y);
wlr_xwayland_surface_configure(xwayland_surface,
geometry.x,
geometry.y,
geometry.width,
geometry.height);
}
static void
activate(struct hikari_view *view, bool active)
{
struct hikari_xwayland_view *xwayland_view =
(struct hikari_xwayland_view *)view;
struct wlr_xwayland_surface *xwayland_surface = xwayland_view->surface;
wlr_xwayland_surface_activate(xwayland_surface, active);
wlr_xwayland_set_seat(hikari_server.xwayland, hikari_server.seat);
}
static void
quit(struct hikari_view *view)
{
struct hikari_xwayland_view *xwayland_view =
(struct hikari_xwayland_view *)view;
wlr_xwayland_surface_close(xwayland_view->surface);
}
static struct wlr_surface *
surface_at(struct hikari_view_interface *view_interface,
double ox,
double oy,
double *sx,
double *sy)
{
struct hikari_view *view = (struct hikari_view *)view_interface;
struct wlr_box *geometry = hikari_view_geometry(view);
double x = ox - geometry->x;
double y = oy - geometry->y;
return wlr_surface_surface_at(view->surface, x, y, sx, sy);
}
static void
focus(struct hikari_view_interface *view_interface)
{
struct hikari_view *view = (struct hikari_view *)view_interface;
hikari_workspace_focus_view(view->sheet->workspace, view);
}
static void
for_each_surface(struct hikari_view_interface *view_interface,
void (*func)(struct wlr_surface *, int, int, void *),
void *data)
{
struct hikari_view *view = (struct hikari_view *)view_interface;
wlr_surface_for_each_surface(view->surface, func, data);
}
static void
hide(struct hikari_view *view)
{}
static void
show(struct hikari_view *view)
{}
void
hikari_xwayland_view_init(struct hikari_xwayland_view *xwayland_view,
struct wlr_xwayland_surface *xwayland_surface,
struct hikari_workspace *workspace)
{
hikari_view_init(&xwayland_view->view, HIKARI_XWAYLAND_VIEW, workspace);
xwayland_view->view.view_interface.surface_at = surface_at;
xwayland_view->view.view_interface.focus = focus;
xwayland_view->view.view_interface.for_each_surface = for_each_surface;
wlr_xwayland_surface_ping(xwayland_surface);
#if !defined(NDEBUG)
printf("XWAYLAND NEW %p\n", xwayland_view);
#endif
xwayland_view->surface = xwayland_surface;
xwayland_view->map.notify = map_handler;
wl_signal_add(&xwayland_surface->events.map, &xwayland_view->map);
xwayland_view->unmap.notify = unmap_handler;
wl_signal_add(&xwayland_surface->events.unmap, &xwayland_view->unmap);
xwayland_view->destroy.notify = destroy_handler;
wl_signal_add(&xwayland_surface->events.destroy, &xwayland_view->destroy);
xwayland_view->request_configure.notify = request_configure_handler;
wl_signal_add(&xwayland_surface->events.request_configure,
&xwayland_view->request_configure);
xwayland_view->set_title.notify = set_title_handler;
wl_signal_add(&xwayland_surface->events.set_title, &xwayland_view->set_title);
xwayland_view->view.activate = activate;
xwayland_view->view.resize = resize;
xwayland_view->view.move = move;
xwayland_view->view.quit = quit;
xwayland_view->view.hide = hide;
xwayland_view->view.show = show;
}
#endif