mirror of
https://cagebreak.project-repo.co/cagebreak.git
synced 2026-08-21 13:04:18 +02:00
Release 1.1.0
- Unify commands and actions. See Issue 4 in Bugs.md
This commit is contained in:
parent
0566029eeb
commit
40e1313a12
16 changed files with 982 additions and 410 deletions
24
Bugs.md
24
Bugs.md
|
|
@ -55,3 +55,27 @@ Steps to reproduce:
|
|||
```
|
||||
(EE) failed to read Wayland events: Broken pipe
|
||||
```
|
||||
|
||||
### Issue 4
|
||||
|
||||
github issue number: #1
|
||||
Fixed: 1.1.0
|
||||
|
||||
This issue is code duplication in `parse.c`.
|
||||
|
||||
Github issue text:
|
||||
|
||||
```
|
||||
As of right now, the actions which can be run in the config file and the
|
||||
actions which can be run as a keybinding are parsed separately in `parse.c`.
|
||||
This leads to a lot of code duplication. Furthermore, unifying these
|
||||
functionalities would enable a more versatile configuration. For instance, it
|
||||
would enable the user to write `hsplit` into the configuration file to split
|
||||
the output on startup and workspace 2 to set the default workspace to
|
||||
workspace 2. Therefore, this change would simplify the code base, while at
|
||||
the same time increasing the feature set.
|
||||
|
||||
PS: As a side effect, this would allow quirky statements such as
|
||||
`bind dbind r hsplit` which would bind the d key to binding the r key to
|
||||
split the output...
|
||||
```
|
||||
|
|
|
|||
36
README.md
36
README.md
|
|
@ -1,7 +1,7 @@
|
|||
# Cagebreak: A Wayland Tiling Compositor Inspired by Ratpoison
|
||||
|
||||
This is Cagebreak, a Wayland tiling compositor. The goal of this project is to
|
||||
provide a successor to ratpoison for wayland users. However, this is
|
||||
provide a successor to ratpoison for Wayland users. However, this is
|
||||
no reimplementation of ratpoison. Should you like to know if a feature
|
||||
will be implemented, open an issue or get in touch with the development team.
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ git tag -v version
|
|||
git push --tags origin master
|
||||
```
|
||||
|
||||
and a log message roughly describing the features is added in the commit.
|
||||
and a log message roughly describing the features added in the commit.
|
||||
|
||||
In the past, our git history did not always reflect this scheme.
|
||||
|
||||
|
|
@ -94,8 +94,9 @@ Release checklist
|
|||
* [ ] Cursory testing
|
||||
* [ ] libfuzzer testing
|
||||
* [ ] Version Number
|
||||
* [ ] -v flag
|
||||
* [ ] meson.build
|
||||
* [ ] git tag
|
||||
* [ ] man pages
|
||||
* [ ] Relevant Documentation
|
||||
* [ ] New features documented
|
||||
* [ ] man page
|
||||
|
|
@ -131,7 +132,7 @@ The full public keys can be found in `keys/` along with any revocation certifica
|
|||
Cagebreak offers reproducible builds given the exact library versions specified
|
||||
in `meson.build`. Should a version mismatch occur, a warning will be emitted. We have
|
||||
decided on this compromise to allow flexibility and security. In general we will
|
||||
adapt the versions to the packages available under archlinux at the time of
|
||||
adapt the versions to the packages available under arch linux at the time of
|
||||
release.
|
||||
|
||||
#### Reproducible Build Instructions
|
||||
|
|
@ -147,6 +148,11 @@ ninja -C build
|
|||
|
||||
For every release after 1.0.5, hashes will be provided.
|
||||
|
||||
1.1.0
|
||||
|
||||
* sha 256: fc393e225c549f893b9e21e8b904e546d5857bac1d905b3d26334c8f8a1cda11
|
||||
* sha 512: 8b94b1069e767202bcab087cb592eadc42f0453d17ee119d48760be00bc66278cf0fa60bb09308d30cb551df6a7a3e26e2ab8b29c04f0e953cc6906542cd2d6f
|
||||
|
||||
1.0.6
|
||||
|
||||
* sha 256: 712ae9a8f17a9e589e108f0d503da203cc5eaf1c4a6ca6efb5b4c83b432ce0b8
|
||||
|
|
@ -163,12 +169,28 @@ will be named after their release version.
|
|||
|
||||
Along with the project source code, a fuzzing framework based on `libfuzzer` is
|
||||
supplied. This allows for the testing of the parsing code responsible for reading
|
||||
the `cagebreak` configuration file. When the `libfuzzer` is available (please
|
||||
the `cagebreak` configuration file. When `libfuzzer` is available (please
|
||||
use the `clang` compiler to enable it), building the fuzz-testing software can
|
||||
be enabled by passing `-Dfuzz=true` to meson. This generates a `build/fuzz/fuzz-parse`
|
||||
binary according to the `libfuzzer` specifications. Further documentation on
|
||||
how to run this binary can be found [here](https://llvm.org/docs/LibFuzzer.html).
|
||||
|
||||
Here is an example workflow:
|
||||
|
||||
```
|
||||
rm -rf build
|
||||
CC=clang meson build -Dfuzz=true -Db_sanitize=address,undefined -Db_lundef=false
|
||||
ninja -C build/
|
||||
mkdir build/fuzz_corpus
|
||||
cp examples/config build/fuzz_corpus/
|
||||
WLR_BACKENDS=headless ./build/fuzz/fuzz-parse -jobs=12 -max_len=50000 -close_fd_mask=3 build/fuzz_corpus/
|
||||
```
|
||||
|
||||
You may want to tweak `-jobs` or add other options depending on your own setup.
|
||||
We have found code path discovery to increase rapidly when the fuzzer is supplied
|
||||
with an initial config file. We are working on improving our fuzzing coverage to
|
||||
find bugs in other areas of the code.
|
||||
|
||||
## Bugs
|
||||
|
||||
For any bug, please [create an
|
||||
|
|
@ -184,6 +206,10 @@ independent of github, in case this service is unavailable.
|
|||
|
||||
Adds basic tiling window manager functionality to cage.
|
||||
|
||||
### Release 1.1.0
|
||||
|
||||
Unifies commands and actions. See Issue 4 in Bugs.md.
|
||||
|
||||
## License
|
||||
|
||||
Please see [LICENSE](https://github.com/project-repo/cagebreak/blob/master/LICENSE)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include <getopt.h>
|
||||
#include <pango.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -533,5 +536,10 @@ end:
|
|||
with a proper wl_display. */
|
||||
wl_display_destroy(server.wl_display);
|
||||
wlr_output_layout_destroy(server.output_layout);
|
||||
|
||||
pango_cairo_font_map_set_default(NULL);
|
||||
cairo_debug_reset_static_data();
|
||||
FcFini();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,29 @@
|
|||
/* This file is used by the fuzzer in order to prevent executing shell commands.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <time.h>
|
||||
|
||||
struct tm *(*orig_localtime)(const time_t *timep);
|
||||
#include "../output.h"
|
||||
#include <cairo.h>
|
||||
#include <cairo/cairo.h>
|
||||
#include <stdlib.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
|
||||
int
|
||||
execl(const char *pathname, const char *arg, ...) {
|
||||
return 0;
|
||||
fork() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
wlr_texture_get_size(struct wlr_texture *texture, int *width, int *height) {
|
||||
if(width != NULL) {
|
||||
*width = 0;
|
||||
}
|
||||
|
||||
if(height != NULL) {
|
||||
*height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_image_surface_create(cairo_format_t fmt, int width, int height) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,75 +1,412 @@
|
|||
#define _POSIX_C_SOURCE 200812L
|
||||
#define FUZZING
|
||||
/*
|
||||
* Cagebreak: A Wayland tiling compositor.
|
||||
*
|
||||
* Copyright (C) 2018-2020 Jente Hidskes
|
||||
*
|
||||
* See the LICENSE file accompanying this file.
|
||||
*/
|
||||
|
||||
#include "../keybinding.h"
|
||||
#include "../parse.h"
|
||||
#include "../seat.h"
|
||||
#include "../server.h"
|
||||
#include <signal.h>
|
||||
#define _POSIX_C_SOURCE 200812L
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include <pango.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_data_device.h>
|
||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||
#include <wlr/types/wlr_idle.h>
|
||||
#include <wlr/types/wlr_idle_inhibit_v1.h>
|
||||
#include <wlr/types/wlr_output_damage.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_screencopy_v1.h>
|
||||
#include <wlr/types/wlr_server_decoration.h>
|
||||
#if CG_HAS_XWAYLAND
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#endif
|
||||
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
||||
#include <wlr/types/wlr_xdg_output_v1.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/log.h>
|
||||
#if CG_HAS_XWAYLAND
|
||||
#include <wlr/xwayland.h>
|
||||
#endif
|
||||
|
||||
#include "idle_inhibit_v1.h"
|
||||
#include "keybinding.h"
|
||||
#include "message.h"
|
||||
#include "output.h"
|
||||
#include "parse.h"
|
||||
#include "seat.h"
|
||||
#include "server.h"
|
||||
#include "view.h"
|
||||
#include "workspace.h"
|
||||
#include "xdg_shell.h"
|
||||
#if CG_HAS_XWAYLAND
|
||||
#include "xwayland.h"
|
||||
#endif
|
||||
|
||||
#ifndef WAIT_ANY
|
||||
#define WAIT_ANY -1
|
||||
#endif
|
||||
|
||||
void
|
||||
set_sig_handler(int sig) {
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SIG_IGN; // handle signal by ignoring
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
if(sigaction(SIGCHLD, &sa, 0) == -1) {
|
||||
perror(0);
|
||||
exit(1);
|
||||
static bool
|
||||
drop_permissions(void) {
|
||||
if(getuid() != geteuid() || getgid() != getegid()) {
|
||||
if(setuid(getuid()) != 0 || setgid(getgid()) != 0) {
|
||||
wlr_log(WLR_ERROR, "Unable to drop root, refusing to start");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(setuid(0) != -1) {
|
||||
wlr_log(WLR_ERROR, "Unable to drop root (we shouldn't be able to "
|
||||
"restore it after setuid), refusing to start");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct cg_server server;
|
||||
static bool
|
||||
parse_args(struct cg_server *server, int argc, char *argv[]) {
|
||||
server->output_transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
#ifdef DEBUG
|
||||
server->debug_damage_tracking = false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
struct cg_server server = {0};
|
||||
struct wlr_xwayland *xwayland = NULL;
|
||||
#if CG_HAS_XWAYLAND
|
||||
struct wlr_xcursor_manager *xcursor_manager = NULL;
|
||||
#endif
|
||||
|
||||
void
|
||||
cleanup() {
|
||||
server.running = false;
|
||||
#if CG_HAS_XWAYLAND
|
||||
if(xwayland != NULL) {
|
||||
wlr_xwayland_destroy(xwayland);
|
||||
}
|
||||
if(xcursor_manager != NULL) {
|
||||
wlr_xcursor_manager_destroy(xcursor_manager);
|
||||
}
|
||||
#endif
|
||||
wl_display_destroy_clients(server.wl_display);
|
||||
|
||||
for(unsigned int i = 0; server.modes[i] != NULL; ++i) {
|
||||
free(server.modes[i]);
|
||||
}
|
||||
free(server.modes);
|
||||
|
||||
keybinding_list_free(server.keybindings);
|
||||
|
||||
seat_destroy(server.seat);
|
||||
/* This function is not null-safe, but we only ever get here
|
||||
with a proper wl_display. */
|
||||
wl_display_destroy(server.wl_display);
|
||||
wlr_output_layout_destroy(server.output_layout);
|
||||
}
|
||||
|
||||
int
|
||||
LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||
set_sig_handler(SIGCHLD);
|
||||
struct wl_event_loop *event_loop = NULL;
|
||||
struct wlr_backend *backend = NULL;
|
||||
struct wlr_renderer *renderer = NULL;
|
||||
struct wlr_compositor *compositor = NULL;
|
||||
struct wlr_data_device_manager *data_device_manager = NULL;
|
||||
struct wlr_server_decoration_manager *server_decoration_manager = NULL;
|
||||
struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager = NULL;
|
||||
struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager = NULL;
|
||||
struct wlr_screencopy_manager_v1 *screencopy_manager = NULL;
|
||||
struct wlr_xdg_output_manager_v1 *output_manager = NULL;
|
||||
struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL;
|
||||
struct wlr_xdg_shell *xdg_shell = NULL;
|
||||
int ret = 0;
|
||||
|
||||
server.wl_display = NULL;
|
||||
server.event_loop = NULL;
|
||||
if(!parse_args(&server, *argc, *argv)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
server.seat = malloc(sizeof(struct cg_seat));
|
||||
server.seat->mode = 0;
|
||||
server.seat->default_mode = 0;
|
||||
#ifdef DEBUG
|
||||
wlr_log_init(WLR_DEBUG, NULL);
|
||||
#else
|
||||
wlr_log_init(WLR_ERROR, NULL);
|
||||
#endif
|
||||
|
||||
server.idle = NULL;
|
||||
server.idle_inhibit_v1 = NULL;
|
||||
/* new_idle_inhibitor_v1 */
|
||||
wl_list_init(&server.inhibitors);
|
||||
/* Wayland requires XDG_RUNTIME_DIR to be set. */
|
||||
if(!getenv("XDG_RUNTIME_DIR")) {
|
||||
wlr_log(WLR_ERROR, "XDG_RUNTIME_DIR is not set in the environment");
|
||||
return 1;
|
||||
}
|
||||
|
||||
server.output_layout = NULL;
|
||||
wl_list_init(&server.outputs);
|
||||
server.curr_output = NULL;
|
||||
|
||||
/* new_output */
|
||||
|
||||
/* xdg_toplevel_decoration */
|
||||
/* new_xdg_shell_surface */
|
||||
/* new_xwayland_surface */
|
||||
server.keybindings = keybinding_list_init();
|
||||
server.output_transform = 0;
|
||||
server.wl_display = wl_display_create();
|
||||
if(!server.wl_display) {
|
||||
wlr_log(WLR_ERROR, "Cannot allocate a Wayland display");
|
||||
return 1;
|
||||
}
|
||||
|
||||
server.running = true;
|
||||
server.modes = malloc(sizeof(char *));
|
||||
server.modes[0] = NULL;
|
||||
|
||||
server.modes = malloc(4 * sizeof(char *));
|
||||
server.modes[0] = strdup("top");
|
||||
server.modes[1] = strdup("root");
|
||||
server.modes[2] = strdup("resize");
|
||||
server.modes[3] = NULL;
|
||||
|
||||
server.nws = 1;
|
||||
server.message_timeout = 0;
|
||||
server.message_timeout = 2;
|
||||
|
||||
event_loop = wl_display_get_event_loop(server.wl_display);
|
||||
server.event_loop = event_loop;
|
||||
|
||||
backend = wlr_backend_autocreate(server.wl_display, NULL);
|
||||
if(!backend) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the wlroots backend");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
server.backend = backend;
|
||||
|
||||
if(!drop_permissions()) {
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
server.keybindings = keybinding_list_init();
|
||||
if(server.keybindings == NULL || server.keybindings->keybindings == NULL) {
|
||||
wlr_log(WLR_ERROR, "Unable to allocate keybindings");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
renderer = wlr_backend_get_renderer(backend);
|
||||
wlr_renderer_init_wl_display(renderer, server.wl_display);
|
||||
|
||||
server.bg_color = malloc(4 * sizeof(float));
|
||||
server.bg_color[0] = 0;
|
||||
server.bg_color[1] = 0;
|
||||
server.bg_color[2] = 0;
|
||||
server.bg_color[3] = 1;
|
||||
wl_list_init(&server.outputs);
|
||||
|
||||
server.output_layout = wlr_output_layout_create();
|
||||
if(!server.output_layout) {
|
||||
wlr_log(WLR_ERROR, "Unable to create output layout");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
compositor = wlr_compositor_create(server.wl_display, renderer);
|
||||
if(!compositor) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the wlroots compositor");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
data_device_manager = wlr_data_device_manager_create(server.wl_display);
|
||||
if(!data_device_manager) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the data device manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Configure a listener to be notified when new outputs are
|
||||
* available on the backend. We use this only to detect the
|
||||
* first output and ignore subsequent outputs. */
|
||||
server.new_output.notify = handle_new_output;
|
||||
wl_signal_add(&backend->events.new_output, &server.new_output);
|
||||
|
||||
server.seat = seat_create(&server, backend);
|
||||
if(!server.seat) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the seat");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
server.idle = wlr_idle_create(server.wl_display);
|
||||
if(!server.idle) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the idle tracker");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
server.idle_inhibit_v1 = wlr_idle_inhibit_v1_create(server.wl_display);
|
||||
if(!server.idle_inhibit_v1) {
|
||||
wlr_log(WLR_ERROR, "Cannot create the idle inhibitor");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
server.new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1_new;
|
||||
wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor,
|
||||
&server.new_idle_inhibitor_v1);
|
||||
wl_list_init(&server.inhibitors);
|
||||
|
||||
xdg_shell = wlr_xdg_shell_create(server.wl_display);
|
||||
if(!xdg_shell) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the XDG shell interface");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
server.new_xdg_shell_surface.notify = handle_xdg_shell_surface_new;
|
||||
wl_signal_add(&xdg_shell->events.new_surface,
|
||||
&server.new_xdg_shell_surface);
|
||||
|
||||
xdg_decoration_manager =
|
||||
wlr_xdg_decoration_manager_v1_create(server.wl_display);
|
||||
if(!xdg_decoration_manager) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the XDG decoration manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
wl_signal_add(&xdg_decoration_manager->events.new_toplevel_decoration,
|
||||
&server.xdg_toplevel_decoration);
|
||||
server.xdg_toplevel_decoration.notify = handle_xdg_toplevel_decoration;
|
||||
|
||||
server_decoration_manager =
|
||||
wlr_server_decoration_manager_create(server.wl_display);
|
||||
if(!server_decoration_manager) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the server decoration manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
wlr_server_decoration_manager_set_default_mode(
|
||||
server_decoration_manager, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
|
||||
|
||||
export_dmabuf_manager =
|
||||
wlr_export_dmabuf_manager_v1_create(server.wl_display);
|
||||
if(!export_dmabuf_manager) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the export DMABUF manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
screencopy_manager = wlr_screencopy_manager_v1_create(server.wl_display);
|
||||
if(!screencopy_manager) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the screencopy manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
output_manager = wlr_xdg_output_manager_v1_create(server.wl_display,
|
||||
server.output_layout);
|
||||
if(!output_manager) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the output manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
gamma_control_manager =
|
||||
wlr_gamma_control_manager_v1_create(server.wl_display);
|
||||
if(!gamma_control_manager) {
|
||||
wlr_log(WLR_ERROR, "Unable to create the gamma control manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if CG_HAS_XWAYLAND
|
||||
xwayland = wlr_xwayland_create(server.wl_display, compositor, true);
|
||||
if(!xwayland) {
|
||||
wlr_log(WLR_ERROR, "Cannot create XWayland server");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
server.new_xwayland_surface.notify = handle_xwayland_surface_new;
|
||||
wl_signal_add(&xwayland->events.new_surface, &server.new_xwayland_surface);
|
||||
|
||||
xcursor_manager = wlr_xcursor_manager_create(DEFAULT_XCURSOR, XCURSOR_SIZE);
|
||||
if(!xcursor_manager) {
|
||||
wlr_log(WLR_ERROR, "Cannot create XWayland XCursor manager");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(setenv("DISPLAY", xwayland->display_name, true) < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Unable to set DISPLAY for XWayland.",
|
||||
"Clients may not be able to connect");
|
||||
} else {
|
||||
wlr_log(WLR_DEBUG, "XWayland is running on display %s",
|
||||
xwayland->display_name);
|
||||
}
|
||||
|
||||
if(wlr_xcursor_manager_load(xcursor_manager, 1)) {
|
||||
wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme");
|
||||
}
|
||||
struct wlr_xcursor *xcursor =
|
||||
wlr_xcursor_manager_get_xcursor(xcursor_manager, DEFAULT_XCURSOR, 1);
|
||||
if(xcursor) {
|
||||
struct wlr_xcursor_image *image = xcursor->images[0];
|
||||
wlr_xwayland_set_cursor(xwayland, image->buffer, image->width * 4,
|
||||
image->width, image->height, image->hotspot_x,
|
||||
image->hotspot_y);
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *socket = wl_display_add_socket_auto(server.wl_display);
|
||||
if(!socket) {
|
||||
wlr_log_errno(WLR_ERROR, "Unable to open Wayland socket");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(!wlr_backend_start(backend)) {
|
||||
wlr_log(WLR_ERROR, "Unable to start the wlroots backend");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(setenv("WAYLAND_DISPLAY", socket, true) < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "Unable to set WAYLAND_DISPLAY.",
|
||||
"Clients may not be able to connect");
|
||||
} else {
|
||||
wlr_log(WLR_DEBUG,
|
||||
"Cagebreak " CG_VERSION " is running on Wayland display %s",
|
||||
socket);
|
||||
}
|
||||
|
||||
#if CG_HAS_XWAYLAND
|
||||
wlr_xwayland_set_seat(xwayland, server.seat->seat);
|
||||
#endif
|
||||
|
||||
/* Place the cursor to the topl left of the output layout. */
|
||||
wlr_cursor_warp(server.seat->cursor, NULL, 0, 0);
|
||||
atexit(cleanup);
|
||||
return 0;
|
||||
end:
|
||||
cleanup();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Parse config file. Lines longer than "max_line_size" are ignored */
|
||||
int
|
||||
set_configuration(struct cg_server *server, char *content) {
|
||||
char *line;
|
||||
for(unsigned int line_num = 1;
|
||||
(line = strtok_r(NULL, "\n", &content)) != NULL; ++line_num) {
|
||||
line[strcspn(line, "\n")] = '\0';
|
||||
if(*line != '\0' && *line != '#') {
|
||||
if(parse_rc_line(server, line) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -78,9 +415,33 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||
char *str = malloc(size * sizeof(char) + 1);
|
||||
strncpy(str, (char *)data, size);
|
||||
str[size] = 0;
|
||||
parse_rc_line(&server, str);
|
||||
set_configuration(&server, str);
|
||||
free(str);
|
||||
keybinding_list_free(server.keybindings);
|
||||
server.keybindings = keybinding_list_init();
|
||||
run_action(KEYBINDING_WORKSPACES, &server,
|
||||
(union keybinding_params){.i = 1});
|
||||
run_action(KEYBINDING_LAYOUT_FULLSCREEN, &server,
|
||||
(union keybinding_params){.c = NULL});
|
||||
wl_display_flush_clients(server.wl_display);
|
||||
wl_display_destroy_clients(server.wl_display);
|
||||
struct cg_output *output;
|
||||
wl_list_for_each(output, &server.outputs, link) {
|
||||
message_clear(output);
|
||||
struct cg_view *view;
|
||||
wl_list_for_each(view, &(*output->workspaces)->views, link) {
|
||||
view_unmap(view);
|
||||
view_destroy(view);
|
||||
}
|
||||
wl_list_for_each(view, &(*output->workspaces)->unmanaged_views, link) {
|
||||
view_unmap(view);
|
||||
view_destroy(view);
|
||||
}
|
||||
}
|
||||
for(unsigned int i = 3; server.modes[i] != NULL; ++i) {
|
||||
free(server.modes[i]);
|
||||
}
|
||||
server.modes[3] = NULL;
|
||||
server.modes = realloc(server.modes, 4 * sizeof(char *));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ endif
|
|||
|
||||
override_lib = shared_library('execl_override',
|
||||
[ 'execl_override.c' ],
|
||||
dependencies: [ pixman,cairo,pango,pangocairo ],
|
||||
install: false
|
||||
)
|
||||
|
||||
|
|
|
|||
180
keybinding.c
180
keybinding.c
|
|
@ -54,12 +54,19 @@ find_keybinding(const struct keybinding_list *list,
|
|||
}
|
||||
|
||||
void
|
||||
keybinding_free(struct keybinding *keybinding) {
|
||||
keybinding_free(struct keybinding *keybinding, bool recursive) {
|
||||
switch(keybinding->action) {
|
||||
case KEYBINDING_DEFINEMODE:
|
||||
case KEYBINDING_RUN_COMMAND:
|
||||
if(keybinding->data.c != NULL) {
|
||||
free(keybinding->data.c);
|
||||
}
|
||||
break;
|
||||
case KEYBINDING_DEFINEKEY:
|
||||
if(keybinding->data.kb != NULL && recursive) {
|
||||
keybinding_free(keybinding->data.kb, true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -79,7 +86,7 @@ keybinding_list_push(struct keybinding_list *list,
|
|||
* exist*/
|
||||
struct keybinding **found_keybinding = find_keybinding(list, keybinding);
|
||||
if(found_keybinding != NULL) {
|
||||
keybinding_free(*found_keybinding);
|
||||
keybinding_free(*found_keybinding, true);
|
||||
*found_keybinding = keybinding;
|
||||
wlr_log(WLR_DEBUG, "A keybinding was found twice in the config file.");
|
||||
} else {
|
||||
|
|
@ -101,7 +108,7 @@ keybinding_list_init() {
|
|||
void
|
||||
keybinding_list_free(struct keybinding_list *list) {
|
||||
for(unsigned int i = 0; i < list->length; ++i) {
|
||||
keybinding_free(list->keybindings[i]);
|
||||
keybinding_free(list->keybindings[i], true);
|
||||
}
|
||||
free(list->keybindings);
|
||||
free(list);
|
||||
|
|
@ -248,10 +255,27 @@ is_between_strict(int a, int b, int x) {
|
|||
return a < x && x < b;
|
||||
}
|
||||
|
||||
int
|
||||
get_compl_coord(struct cg_tile *tile, int *(*get_coord)(struct cg_tile *tile)) {
|
||||
return tile->tile.x + tile->tile.y - *get_coord(tile);
|
||||
}
|
||||
|
||||
int
|
||||
get_compl_dim(struct cg_tile *tile, int *(*get_dim)(struct cg_tile *tile)) {
|
||||
return tile->tile.width + tile->tile.height - *get_dim(tile);
|
||||
}
|
||||
|
||||
bool
|
||||
resize_allowed(struct cg_tile *tile, struct cg_tile *parent, int coord_offset,
|
||||
int dim_offset, int *(*get_coord)(struct cg_tile *tile),
|
||||
int *(*get_dim)(struct cg_tile *tile)) {
|
||||
intervalls_intersect(int x1, int x2, int y1, int y2) {
|
||||
return y2 > x1 && y1 < x2;
|
||||
}
|
||||
|
||||
bool
|
||||
resize_allowed(struct cg_tile *tile, const struct cg_tile *parent,
|
||||
int coord_offset, int dim_offset,
|
||||
int *(*get_coord)(struct cg_tile *tile),
|
||||
int *(*get_dim)(struct cg_tile *tile), struct cg_tile *orig) {
|
||||
|
||||
if(coord_offset == 0 && dim_offset == 0) {
|
||||
return true;
|
||||
} else if(*get_dim(tile) - coord_offset + dim_offset <= 0) {
|
||||
|
|
@ -260,17 +284,25 @@ resize_allowed(struct cg_tile *tile, struct cg_tile *parent, int coord_offset,
|
|||
|
||||
for(struct cg_tile *it = tile->next; it != tile && it != NULL;
|
||||
it = it->next) {
|
||||
if(it == parent) {
|
||||
if(it == parent || it == orig) {
|
||||
continue;
|
||||
}
|
||||
if(it->tile.x == tile->tile.x + tile->tile.width) {
|
||||
if(!resize_allowed(it, tile, dim_offset, -dim_offset, get_coord,
|
||||
get_dim)) {
|
||||
return false;
|
||||
}
|
||||
} else if(it->tile.x + it->tile.width == tile->tile.x) {
|
||||
if(!resize_allowed(it, tile, 0, coord_offset, get_coord, get_dim)) {
|
||||
return false;
|
||||
if(intervalls_intersect(
|
||||
get_compl_coord(tile, get_coord),
|
||||
get_compl_coord(tile, get_coord) + get_compl_dim(tile, get_dim),
|
||||
get_compl_coord(it, get_coord),
|
||||
get_compl_coord(it, get_coord) + get_compl_dim(it, get_dim))) {
|
||||
if(*get_coord(it) == *get_coord(tile) + *get_dim(tile)) {
|
||||
if(!resize_allowed(it, tile, dim_offset + coord_offset,
|
||||
-dim_offset - coord_offset, get_coord,
|
||||
get_dim, orig)) {
|
||||
return false;
|
||||
}
|
||||
} else if(*get_coord(it) + *get_dim(it) == *get_coord(tile)) {
|
||||
if(!resize_allowed(it, tile, 0, coord_offset, get_coord,
|
||||
get_dim, orig)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -280,20 +312,27 @@ resize_allowed(struct cg_tile *tile, struct cg_tile *parent, int coord_offset,
|
|||
void
|
||||
resize(struct cg_tile *tile, const struct cg_tile *parent, int coord_offset,
|
||||
int dim_offset, int *(*get_coord)(struct cg_tile *tile),
|
||||
int *(*get_dim)(struct cg_tile *tile)) {
|
||||
int *(*get_dim)(struct cg_tile *tile), struct cg_tile *orig) {
|
||||
if(coord_offset == 0 && dim_offset == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(struct cg_tile *it = tile->next; it != tile && it != NULL;
|
||||
it = it->next) {
|
||||
if(it == parent) {
|
||||
if(it == parent || it == orig) {
|
||||
continue;
|
||||
}
|
||||
if(*get_coord(it) == *get_coord(tile) + *get_dim(tile)) {
|
||||
resize(it, tile, dim_offset, -dim_offset, get_coord, get_dim);
|
||||
} else if(*get_coord(it) + *get_dim(it) == *get_coord(tile)) {
|
||||
resize(it, tile, 0, coord_offset, get_coord, get_dim);
|
||||
if(intervalls_intersect(
|
||||
get_compl_coord(tile, get_coord),
|
||||
get_compl_coord(tile, get_coord) + get_compl_dim(tile, get_dim),
|
||||
get_compl_coord(it, get_coord),
|
||||
get_compl_coord(it, get_coord) + get_compl_dim(it, get_dim))) {
|
||||
if(*get_coord(it) == *get_coord(tile) + *get_dim(tile)) {
|
||||
resize(it, tile, dim_offset + coord_offset,
|
||||
-dim_offset - coord_offset, get_coord, get_dim, orig);
|
||||
} else if(*get_coord(it) + *get_dim(it) == *get_coord(tile)) {
|
||||
resize(it, tile, 0, coord_offset, get_coord, get_dim, orig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,26 +374,26 @@ bool
|
|||
resize_allowed_horizontal(struct cg_tile *tile, struct cg_tile *parent,
|
||||
int x_offset, int width_offset) {
|
||||
return resize_allowed(tile, parent, x_offset, width_offset, get_x,
|
||||
get_width);
|
||||
get_width, tile);
|
||||
}
|
||||
|
||||
bool
|
||||
resize_allowed_vertical(struct cg_tile *tile, struct cg_tile *parent,
|
||||
int y_offset, int height_offset) {
|
||||
return resize_allowed(tile, parent, y_offset, height_offset, get_y,
|
||||
get_height);
|
||||
get_height, tile);
|
||||
}
|
||||
|
||||
void
|
||||
resize_horizontal(struct cg_tile *tile, struct cg_tile *parent, int x_offset,
|
||||
int width_offset) {
|
||||
resize(tile, parent, x_offset, width_offset, get_x, get_width);
|
||||
resize(tile, parent, x_offset, width_offset, get_x, get_width, tile);
|
||||
}
|
||||
|
||||
void
|
||||
resize_vertical(struct cg_tile *tile, struct cg_tile *parent, int y_offset,
|
||||
int height_offset) {
|
||||
resize(tile, parent, y_offset, height_offset, get_y, get_height);
|
||||
resize(tile, parent, y_offset, height_offset, get_y, get_height, tile);
|
||||
}
|
||||
|
||||
/* hpixs: positiv -> right, negative -> left; vpixs: positiv -> down, negative
|
||||
|
|
@ -608,9 +647,9 @@ keybinding_cycle_tiles(struct cg_server *server, bool reverse) {
|
|||
|
||||
int
|
||||
keybinding_switch_ws(struct cg_server *server, uint32_t ws) {
|
||||
if(ws > server->nws) {
|
||||
if(ws >= server->nws) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Requested workspace %u, but only have %u workspaces.", ws,
|
||||
"Requested workspace %u, but only have %u workspaces.", ws + 1,
|
||||
server->nws);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -634,6 +673,7 @@ keybinding_show_time(struct cg_server *server) {
|
|||
msg[strcspn(msg, "\n")] = '\0'; /* Remove the newline */
|
||||
|
||||
message_printf(server->curr_output, "%s", msg);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -670,6 +710,80 @@ keybinding_move_view_to_next_output(struct cg_server *server) {
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
keybinding_set_nws(struct cg_server *server, int nws) {
|
||||
struct cg_output *output;
|
||||
wl_list_for_each(output, &server->outputs, link) {
|
||||
for(unsigned int i = nws; i < server->nws; ++i) {
|
||||
struct cg_view *view, *tmp;
|
||||
wl_list_for_each_safe(view, tmp, &output->workspaces[i]->views,
|
||||
link) {
|
||||
wl_list_remove(&view->link);
|
||||
wl_list_insert(&output->workspaces[nws - 1]->views,
|
||||
&view->link);
|
||||
view->workspace = output->workspaces[nws - 1];
|
||||
}
|
||||
wl_list_for_each_safe(
|
||||
view, tmp, &output->workspaces[i]->unmanaged_views, link) {
|
||||
wl_list_remove(&view->link);
|
||||
wl_list_insert(&output->workspaces[nws - 1]->unmanaged_views,
|
||||
&view->link);
|
||||
view->workspace = output->workspaces[nws - 1];
|
||||
}
|
||||
workspace_free(output->workspaces[i]);
|
||||
}
|
||||
struct cg_workspace **new_workspaces =
|
||||
realloc(output->workspaces, nws * sizeof(struct cg_workspace *));
|
||||
if(new_workspaces == NULL) {
|
||||
wlr_log(WLR_ERROR, "Error reallocating memory for workspaces.");
|
||||
return;
|
||||
}
|
||||
output->workspaces = new_workspaces;
|
||||
for(int i = server->nws; i < nws; ++i) {
|
||||
output->workspaces[i] = full_screen_workspace(output);
|
||||
wl_list_init(&output->workspaces[i]->views);
|
||||
wl_list_init(&output->workspaces[i]->unmanaged_views);
|
||||
}
|
||||
|
||||
if(output->curr_workspace >= nws) {
|
||||
output->curr_workspace = nws - 1;
|
||||
}
|
||||
}
|
||||
server->nws = nws;
|
||||
seat_set_focus(
|
||||
server->seat,
|
||||
server->curr_output->workspaces[server->curr_output->curr_workspace]
|
||||
->focused_tile->view);
|
||||
}
|
||||
|
||||
void
|
||||
keybinding_definemode(struct cg_server *server, char *mode) {
|
||||
int length = 0;
|
||||
while(server->modes[length++] != NULL)
|
||||
;
|
||||
char **tmp = realloc(server->modes, (length + 1) * sizeof(char *));
|
||||
if(tmp == NULL) {
|
||||
wlr_log(WLR_ERROR, "Could not allocate memory for storing modes.");
|
||||
return;
|
||||
}
|
||||
server->modes = tmp;
|
||||
server->modes[length] = NULL;
|
||||
|
||||
server->modes[length - 1] = strdup(mode);
|
||||
}
|
||||
|
||||
void
|
||||
keybinding_definekey(struct cg_server *server, struct keybinding *kb) {
|
||||
keybinding_list_push(server->keybindings, kb);
|
||||
}
|
||||
|
||||
void
|
||||
keybinding_set_background(struct cg_server *server, float *bg) {
|
||||
server->bg_color[0] = bg[0];
|
||||
server->bg_color[1] = bg[1];
|
||||
server->bg_color[2] = bg[2];
|
||||
}
|
||||
|
||||
void
|
||||
keybinding_move_view_to_workspace(struct cg_server *server, uint32_t ws) {
|
||||
struct cg_view *view =
|
||||
|
|
@ -808,6 +922,18 @@ run_action(enum keybinding_action action, struct cg_server *server,
|
|||
keybinding_move_view_to_next_output(server);
|
||||
break;
|
||||
}
|
||||
case KEYBINDING_DEFINEKEY:
|
||||
keybinding_definekey(server, data.kb);
|
||||
break;
|
||||
case KEYBINDING_BACKGROUND:
|
||||
keybinding_set_background(server, data.color);
|
||||
break;
|
||||
case KEYBINDING_DEFINEMODE:
|
||||
keybinding_definemode(server, data.c);
|
||||
break;
|
||||
case KEYBINDING_WORKSPACES:
|
||||
keybinding_set_nws(server, data.i);
|
||||
break;
|
||||
default: {
|
||||
wlr_log(WLR_ERROR,
|
||||
"run_action was called with a value not present in \"enum "
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ enum keybinding_action {
|
|||
KEYBINDING_FOCUS_RIGHT,
|
||||
KEYBINDING_FOCUS_TOP,
|
||||
KEYBINDING_FOCUS_BOTTOM,
|
||||
|
||||
KEYBINDING_DEFINEKEY, // data.kb is the keybinding definition
|
||||
KEYBINDING_BACKGROUND, // data.color is the background color
|
||||
KEYBINDING_DEFINEMODE, // data.c is the mode name
|
||||
KEYBINDING_WORKSPACES, // data.i is the number of workspaces
|
||||
};
|
||||
|
||||
union keybinding_params {
|
||||
|
|
@ -50,6 +55,8 @@ union keybinding_params {
|
|||
uint32_t u;
|
||||
int32_t i;
|
||||
bool b;
|
||||
float color[3];
|
||||
struct keybinding *kb;
|
||||
};
|
||||
|
||||
struct keybinding {
|
||||
|
|
@ -82,5 +89,7 @@ keybinding_list_init();
|
|||
int
|
||||
run_action(enum keybinding_action action, struct cg_server *server,
|
||||
union keybinding_params data);
|
||||
void
|
||||
keybinding_free(struct keybinding *keybinding, bool recursive);
|
||||
|
||||
#endif /* end of include guard KEYBINDINGS_H */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
% CAGEBREAK-CONFIG(1) Version 1.0 | Cagebreak Manual
|
||||
% CAGEBREAK-CONFIG(1) Version 1.1 | Cagebreak Manual
|
||||
|
||||
# NAME
|
||||
|
||||
|
|
@ -18,19 +18,23 @@ by prepending a line with the # symbol.
|
|||
|
||||
## COMMANDS
|
||||
|
||||
**abort**
|
||||
|
||||
> Return to the default mode without running any command
|
||||
|
||||
**background - Set background color**
|
||||
|
||||
> Set the background color. This command expects three floating point numbers
|
||||
> between 0 and 1, specifying the r,g and b values respectively.
|
||||
> between 0 and 1, specifying the r, g and b values respectively.
|
||||
> (e.g. "background 1.0 0.0 0.0" sets to background color to red)
|
||||
> There is no support for specifying a background image.
|
||||
|
||||
**bind - Bind key to action in command mode**
|
||||
**bind - Bind key to command in root mode**
|
||||
|
||||
> This command requires a key (see **KEY DEFINITIONS**) and an action (see **ACTIONS**) as an argument.
|
||||
> This command requires a key (see **KEY DEFINITIONS**) and a command (see **COMMANDS**) as an argument.
|
||||
> Subsequently, pressing this key while in command mode executes the
|
||||
> supplied action. `bind <key> <keybinding>` is equivalent to
|
||||
> `definekey root <key> <action>`
|
||||
> supplied action. `bind <key> <command>` is equivalent to
|
||||
>> `definekey root <key> <command>`
|
||||
|
||||
**definekey - Bind key to action in arbitrary mode**
|
||||
|
||||
|
|
@ -38,13 +42,13 @@ by prepending a line with the # symbol.
|
|||
> difference that the mode in which the keybinding is activated is
|
||||
> specified by the user. A call to this function is to be structured as follows:
|
||||
>
|
||||
>> `definekey <mode> <key> <action>`
|
||||
>> `definekey <mode> <key> <command>`
|
||||
|
||||
**definemode**
|
||||
|
||||
> This command requires a single argument; the name of the mode to be defined.
|
||||
> Subsequent to a call to this function, the defined mode may be used along with
|
||||
> the definekey command to create a custom keymapping. Synopsis:
|
||||
> the definekey command to create a custom key mapping. Synopsis:
|
||||
>
|
||||
>> `definemode <mode>`
|
||||
|
||||
|
|
@ -53,90 +57,9 @@ by prepending a line with the # symbol.
|
|||
> Defines the key with which the current mode can be changed to "root".
|
||||
> `escape <key>` is equivalent to `definekey top <key> switch_mode root`
|
||||
|
||||
**exec**
|
||||
**exchangedown**
|
||||
|
||||
> Executes the supplied shell command using *`sh -c "<command>"`*. Synopsis:
|
||||
>
|
||||
>> `exec <command>`
|
||||
|
||||
**workspaces**
|
||||
|
||||
> Requires a single integer larger than 1 and less than 30 as an argument. Sets the number of
|
||||
> workspaces to the supplied number
|
||||
|
||||
# ACTIONS
|
||||
|
||||
**vsplit**
|
||||
|
||||
> Split current tile vertically
|
||||
|
||||
**hsplit**
|
||||
|
||||
> Split current tile horizontally
|
||||
|
||||
**quit**
|
||||
|
||||
> Exit cagebreak
|
||||
|
||||
**focus**
|
||||
|
||||
> Focus next tile
|
||||
|
||||
**focusprev**
|
||||
|
||||
> Focus previous tile
|
||||
|
||||
**next**
|
||||
|
||||
> Focus next window in current tile
|
||||
|
||||
**prev**
|
||||
|
||||
> Focus previous window in current tile
|
||||
|
||||
**only**
|
||||
|
||||
> Remove all splits and make the current window fill the entire screen
|
||||
|
||||
**abort**
|
||||
|
||||
> Return to the default mode without running any action
|
||||
|
||||
**time**
|
||||
|
||||
> Display time
|
||||
|
||||
**nextscreen**
|
||||
|
||||
> Focus the next screen
|
||||
|
||||
**prevscreen**
|
||||
|
||||
> Focus the previous screen
|
||||
|
||||
**resizeleft**
|
||||
|
||||
> Resize the current tile towards the left
|
||||
|
||||
**resizeright**
|
||||
|
||||
> Resize the current tile towards the right
|
||||
|
||||
**resizedown**
|
||||
|
||||
> Resize the current tile towards the bottom
|
||||
|
||||
**resizeup**
|
||||
|
||||
> Resize the current tile towards the top
|
||||
|
||||
**workspace <n>**
|
||||
|
||||
> Change to the n-th workspace
|
||||
|
||||
**movetoworkspace <n>**
|
||||
|
||||
> Move the currently focused window to the n-th workspace
|
||||
> Exchange the current window with the window in the tile to the bottom
|
||||
|
||||
**exchangeleft**
|
||||
|
||||
|
|
@ -150,14 +73,28 @@ by prepending a line with the # symbol.
|
|||
|
||||
> Exchange the current window with the window in the tile to the top
|
||||
|
||||
**exchangedown**
|
||||
**exec**
|
||||
|
||||
> Exchange the current window with the window in the tile to the bottom
|
||||
> Executes the supplied shell command using *`sh -c "<command>"`*. Synopsis:
|
||||
>
|
||||
>> `exec <command>`
|
||||
|
||||
**focus**
|
||||
|
||||
> Focus next tile
|
||||
|
||||
**focusdown**
|
||||
|
||||
> Focus the tile to the bottom
|
||||
|
||||
**focusleft**
|
||||
|
||||
> Focus the tile to the left
|
||||
|
||||
**focusprev**
|
||||
|
||||
> Focus previous tile
|
||||
|
||||
**focusright**
|
||||
|
||||
> Focus the tile to the right
|
||||
|
|
@ -166,26 +103,87 @@ by prepending a line with the # symbol.
|
|||
|
||||
> Focus the tile to the top
|
||||
|
||||
**focusdown**
|
||||
**hsplit**
|
||||
|
||||
> Focus the tile to the bottom
|
||||
|
||||
**movetonextscreen**
|
||||
|
||||
> Move the current window to the next screen
|
||||
|
||||
**switchvt <n>**
|
||||
|
||||
> Switch to tty n
|
||||
> Split current tile horizontally
|
||||
|
||||
**mode <mode>**
|
||||
|
||||
> Enter mode "`<mode>`". After a keybinding is processed, return to default mode
|
||||
|
||||
**movetonextscreen**
|
||||
|
||||
> Move the current window to the next screen
|
||||
|
||||
**movetoworkspace <n>**
|
||||
|
||||
> Move the currently focused window to the n-th workspace
|
||||
|
||||
**next**
|
||||
|
||||
> Focus next window in current tile
|
||||
|
||||
**nextscreen**
|
||||
|
||||
> Focus the next screen
|
||||
|
||||
**only**
|
||||
|
||||
> Remove all splits and make the current window fill the entire screen
|
||||
|
||||
**prev**
|
||||
|
||||
> Focus previous window in current tile
|
||||
|
||||
**prevscreen**
|
||||
|
||||
> Focus the previous screen
|
||||
|
||||
**quit**
|
||||
|
||||
> Exit cagebreak
|
||||
|
||||
**resizedown**
|
||||
|
||||
> Resize the current tile towards the bottom
|
||||
|
||||
**resizeleft**
|
||||
|
||||
> Resize the current tile towards the left
|
||||
|
||||
**resizeright**
|
||||
|
||||
> Resize the current tile towards the right
|
||||
|
||||
**resizeup**
|
||||
|
||||
> Resize the current tile towards the top
|
||||
|
||||
**setmode <mode>**
|
||||
|
||||
> Set the default mode to `<mode>`
|
||||
|
||||
**switchvt <n>**
|
||||
|
||||
> Switch to tty n
|
||||
|
||||
**time**
|
||||
|
||||
> Display time
|
||||
|
||||
**vsplit**
|
||||
|
||||
> Split current tile vertically
|
||||
|
||||
**workspace <n>**
|
||||
|
||||
> Change to the n-th workspace
|
||||
|
||||
**workspaces**
|
||||
|
||||
> Requires a single integer larger than 1 and less than 30 as an argument. Sets the number of
|
||||
> workspaces to the supplied number
|
||||
|
||||
# MODES
|
||||
|
||||
By default, three modes are defined:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
% CAGEBREAK(1) Version 1.0 | Cagebreak Manual
|
||||
% CAGEBREAK(1) Version 1.1 | Cagebreak Manual
|
||||
|
||||
# NAME
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
project('cagebreak', 'c',
|
||||
version: '1.0.6',
|
||||
version: '1.1.0',
|
||||
license: 'MIT',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
|
|
@ -165,7 +165,6 @@ endforeach
|
|||
foreach header : cagebreak_header_strings
|
||||
cagebreak_headers += files(header)
|
||||
endforeach
|
||||
|
||||
cagebreak_dependencies_dict = {
|
||||
'server_protos': server_protos,
|
||||
'wayland_server': wayland_server,
|
||||
|
|
@ -182,7 +181,7 @@ cagebreak_dependencies_dict = {
|
|||
}
|
||||
|
||||
reproducible_build_versions = {
|
||||
'server_protos': '1.0.6',
|
||||
'server_protos': '-1',
|
||||
'wayland_server': '1.18.0',
|
||||
'wayland_client': '1.18.0',
|
||||
'wayland_cursor': '1.18.0',
|
||||
|
|
|
|||
|
|
@ -45,7 +45,13 @@ create_message_texture(const char *string, const struct cg_output *output) {
|
|||
// Therefore, we cannot use cairo_create(NULL).
|
||||
cairo_surface_t *dummy_surface =
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
|
||||
// This occurs when we are fuzzing. In that case, do nothing
|
||||
if(dummy_surface == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cairo_t *c = cairo_create(dummy_surface);
|
||||
|
||||
cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST);
|
||||
cairo_font_options_t *fo = cairo_font_options_create();
|
||||
cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
|
||||
|
|
|
|||
2
pango.c
2
pango.c
|
|
@ -1,4 +1,4 @@
|
|||
#include "cairo.h"
|
||||
#include <cairo.h>
|
||||
#include <cairo/cairo.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <stdarg.h>
|
||||
|
|
|
|||
540
parse.c
540
parse.c
|
|
@ -10,167 +10,6 @@
|
|||
#include "server.h"
|
||||
#include "workspace.h"
|
||||
|
||||
int
|
||||
parse_action(struct cg_server *server, struct keybinding *keybinding,
|
||||
char **saveptr) {
|
||||
char *action = strtok_r(NULL, " ", saveptr);
|
||||
if(action == NULL) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
"Not enough parameters to \"bind\". Expected action to execute");
|
||||
return -1;
|
||||
}
|
||||
keybinding->data = (union keybinding_params){.c = NULL};
|
||||
if(strcmp(action, "vsplit") == 0) {
|
||||
keybinding->action = KEYBINDING_SPLIT_VERTICAL;
|
||||
} else if(strcmp(action, "hsplit") == 0) {
|
||||
keybinding->action = KEYBINDING_SPLIT_HORIZONTAL;
|
||||
} else if(strcmp(action, "quit") == 0) {
|
||||
keybinding->action = KEYBINDING_QUIT;
|
||||
} else if(strcmp(action, "focus") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_TILES;
|
||||
keybinding->data.b = false;
|
||||
} else if(strcmp(action, "focusprev") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_TILES;
|
||||
keybinding->data.b = true;
|
||||
} else if(strcmp(action, "next") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_VIEWS;
|
||||
keybinding->data.b = false;
|
||||
} else if(strcmp(action, "prev") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_VIEWS;
|
||||
keybinding->data.b = true;
|
||||
} else if(strcmp(action, "only") == 0) {
|
||||
keybinding->action = KEYBINDING_LAYOUT_FULLSCREEN;
|
||||
} else if(strcmp(action, "abort") == 0) {
|
||||
keybinding->action = KEYBINDING_NOOP;
|
||||
} else if(strcmp(action, "time") == 0) {
|
||||
keybinding->action = KEYBINDING_SHOW_TIME;
|
||||
} else if(strcmp(action, "nextscreen") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_OUTPUT;
|
||||
keybinding->data.b = false;
|
||||
} else if(strcmp(action, "prevscreen") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_OUTPUT;
|
||||
keybinding->data.b = true;
|
||||
} else if(strcmp(action, "exec") == 0) {
|
||||
keybinding->action = KEYBINDING_RUN_COMMAND;
|
||||
if(*saveptr == NULL) {
|
||||
wlr_log(WLR_ERROR, "Not enough paramaters to \"exec\". Expected "
|
||||
"string to execute.");
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.c = strdup(*saveptr);
|
||||
} else if(strcmp(action, "resizeleft") == 0) {
|
||||
keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL;
|
||||
keybinding->data.i = -10;
|
||||
} else if(strcmp(action, "resizeright") == 0) {
|
||||
keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL;
|
||||
keybinding->data.i = 10;
|
||||
} else if(strcmp(action, "resizedown") == 0) {
|
||||
keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL;
|
||||
keybinding->data.i = 10;
|
||||
} else if(strcmp(action, "resizeup") == 0) {
|
||||
keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL;
|
||||
keybinding->data.i = -10;
|
||||
} else if(strcmp(action, "workspace") == 0) {
|
||||
keybinding->action = KEYBINDING_SWITCH_WORKSPACE;
|
||||
char *nws_str = strtok_r(NULL, " ", saveptr);
|
||||
if(nws_str == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected argument for \"workspace\" action, got none.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
long ws = strtol(nws_str, NULL, 10);
|
||||
if(!(1 <= ws && ws <= server->nws)) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Requested binding for workspace %li, but have %u", ws,
|
||||
server->nws);
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.u = ws - 1;
|
||||
} else if(strcmp(action, "movetoworkspace") == 0) {
|
||||
keybinding->action = KEYBINDING_MOVE_VIEW_TO_WORKSPACE;
|
||||
char *nws_str = strtok_r(NULL, " ", saveptr);
|
||||
if(nws_str == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected argument for \"workspace\" action, got none.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
long ws = strtol(nws_str, NULL, 10);
|
||||
if(!(1 <= ws && ws <= server->nws)) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
"Requested binding for moving to workspace %li, but have %u",
|
||||
ws, server->nws);
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.u = ws - 1;
|
||||
} else if(strcmp(action, "exchangeleft") == 0) {
|
||||
keybinding->action = KEYBINDING_SWAP_LEFT;
|
||||
} else if(strcmp(action, "exchangeright") == 0) {
|
||||
keybinding->action = KEYBINDING_SWAP_RIGHT;
|
||||
} else if(strcmp(action, "exchangeup") == 0) {
|
||||
keybinding->action = KEYBINDING_SWAP_TOP;
|
||||
} else if(strcmp(action, "exchangedown") == 0) {
|
||||
keybinding->action = KEYBINDING_SWAP_BOTTOM;
|
||||
} else if(strcmp(action, "focusleft") == 0) {
|
||||
keybinding->action = KEYBINDING_FOCUS_LEFT;
|
||||
} else if(strcmp(action, "focusright") == 0) {
|
||||
keybinding->action = KEYBINDING_FOCUS_RIGHT;
|
||||
} else if(strcmp(action, "focusup") == 0) {
|
||||
keybinding->action = KEYBINDING_FOCUS_TOP;
|
||||
} else if(strcmp(action, "focusdown") == 0) {
|
||||
keybinding->action = KEYBINDING_FOCUS_BOTTOM;
|
||||
} else if(strcmp(action, "movetonextscreen") == 0) {
|
||||
keybinding->action = KEYBINDING_MOVE_VIEW_TO_NEXT_OUTPUT;
|
||||
} else if(strcmp(action, "switchvt") == 0) {
|
||||
keybinding->action = KEYBINDING_CHANGE_TTY;
|
||||
char *ntty = strtok_r(NULL, " ", saveptr);
|
||||
if(ntty == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected argument for \"switchvt\" command, got none.");
|
||||
return -1;
|
||||
}
|
||||
long tty = strtol(ntty, NULL, 10);
|
||||
keybinding->data.u = tty;
|
||||
} else if(strcmp(action, "mode") == 0) {
|
||||
keybinding->action = KEYBINDING_SWITCH_MODE;
|
||||
char *mode = strtok_r(NULL, " ", saveptr);
|
||||
if(mode == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected mode after \"switch_mode\". Got nothing.");
|
||||
return -1;
|
||||
}
|
||||
int mode_idx = get_mode_index_from_name(server->modes, mode);
|
||||
if(mode_idx == -1) {
|
||||
wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_mode", mode);
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.u = (unsigned int)mode_idx;
|
||||
} else if(strcmp(action, "setmode") == 0) {
|
||||
keybinding->action = KEYBINDING_SWITCH_DEFAULT_MODE;
|
||||
char *mode = strtok_r(NULL, " ", saveptr);
|
||||
if(mode == NULL) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
"Expected mode after \"switch_default_mode\". Got nothing.");
|
||||
return -1;
|
||||
}
|
||||
int mode_idx = get_mode_index_from_name(server->modes, mode);
|
||||
if(mode_idx == -1) {
|
||||
wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_default_mode",
|
||||
mode);
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.u = (unsigned int)mode_idx;
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "Error, unsupported action \"%s\".", action);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parses a key definition (e.g. "S-Tab") and sets key and modifiers in
|
||||
* keybinding respectivly */
|
||||
int
|
||||
|
|
@ -218,6 +57,10 @@ parse_key(struct keybinding *keybinding, const char *key_def) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
parse_command(struct cg_server *server, struct keybinding *keybinding,
|
||||
char *saveptr);
|
||||
|
||||
/* Parse a keybinding definition and return it if successful, else return NULL
|
||||
*/
|
||||
struct keybinding *
|
||||
|
|
@ -229,188 +72,341 @@ parse_keybinding(struct cg_server *server, char **saveptr) {
|
|||
free(keybinding);
|
||||
return NULL;
|
||||
}
|
||||
if(parse_action(server, keybinding, saveptr) != 0) {
|
||||
if(parse_command(server, keybinding, *saveptr) != 0) {
|
||||
free(keybinding);
|
||||
return NULL;
|
||||
}
|
||||
return keybinding;
|
||||
}
|
||||
|
||||
int
|
||||
parse_bind(struct cg_server *server, struct keybinding_list *list,
|
||||
char **saveptr) {
|
||||
struct keybinding *
|
||||
parse_bind(struct cg_server *server, char **saveptr) {
|
||||
struct keybinding *keybinding = parse_keybinding(server, saveptr);
|
||||
if(keybinding == NULL) {
|
||||
wlr_log(WLR_ERROR, "Could not parse keybinding for \"bind\".");
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
keybinding->mode = 1;
|
||||
keybinding_list_push(list, keybinding);
|
||||
return 0;
|
||||
return keybinding;
|
||||
}
|
||||
|
||||
int
|
||||
parse_definekey(struct cg_server *server, struct keybinding_list *list,
|
||||
char **saveptr) {
|
||||
struct keybinding *
|
||||
parse_definekey(struct cg_server *server, char **saveptr) {
|
||||
char *mode = strtok_r(NULL, " ", saveptr);
|
||||
if(mode == NULL) {
|
||||
wlr_log(WLR_ERROR, "Too few arguments to \"definekey\". Expected mode");
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
int mode_idx = get_mode_index_from_name(server->modes, mode);
|
||||
if(mode_idx == -1) {
|
||||
wlr_log(WLR_ERROR, "Unknown mode \"%s\"", mode);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
struct keybinding *keybinding = parse_keybinding(server, saveptr);
|
||||
if(keybinding == NULL) {
|
||||
wlr_log(WLR_ERROR, "Could not parse keybinding for \"definekey\"");
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
keybinding->mode = mode_idx;
|
||||
keybinding_list_push(list, keybinding);
|
||||
return 0;
|
||||
return keybinding;
|
||||
}
|
||||
|
||||
int
|
||||
parse_and_run_exec(char **saveptr) {
|
||||
return run_action(KEYBINDING_RUN_COMMAND, NULL,
|
||||
(union keybinding_params){.c = *saveptr});
|
||||
}
|
||||
|
||||
int
|
||||
parse_background(struct cg_server *server, char **saveptr) {
|
||||
parse_background(struct cg_server *server, float *color, char **saveptr) {
|
||||
/* Read rgb numbers */
|
||||
for(unsigned int i = 0; i < 3; ++i) {
|
||||
char *nstr = strtok_r(NULL, " ", saveptr);
|
||||
if(nstr == NULL) {
|
||||
char *nstr = strtok_r(NULL, " \n", saveptr);
|
||||
int nstrlen;
|
||||
if(nstr == NULL || (nstrlen = strlen(nstr)) == 0) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected three space-separated numbers (rgb) for "
|
||||
"background color setting. Got %d.",
|
||||
i);
|
||||
return -1;
|
||||
}
|
||||
if(nstr[nstrlen - 1] == '\n') {
|
||||
nstr[nstrlen - 1] = '\0';
|
||||
--nstrlen;
|
||||
}
|
||||
char *endptr = NULL;
|
||||
float nval = strtof(nstr, &endptr);
|
||||
if(endptr == nstr) {
|
||||
if(endptr != nstr + nstrlen) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
"Could not parse number \"%s\" für background color setting.",
|
||||
"Could not parse number \"%s\" for background color setting.",
|
||||
nstr);
|
||||
return -1;
|
||||
}
|
||||
server->bg_color[i] = nval;
|
||||
if(nval < 0 || nval > 1) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected a number between 0 and 1 for setting of "
|
||||
"background color. Got %f.",
|
||||
nval);
|
||||
return -1;
|
||||
}
|
||||
color[i] = nval;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
parse_escape(struct keybinding_list *list, char **saveptr) {
|
||||
struct keybinding *
|
||||
parse_escape(char **saveptr) {
|
||||
struct keybinding *keybinding = malloc(sizeof(struct keybinding));
|
||||
char *key = strtok_r(NULL, " ", saveptr);
|
||||
if(parse_key(keybinding, key) != 0) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Could not parse key definition \"%s\" for \"escape\"", key);
|
||||
free(keybinding);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
keybinding->mode = 0; //"top" mode
|
||||
keybinding->action = KEYBINDING_SWITCH_MODE;
|
||||
keybinding->data.u = 1; //"root" mode
|
||||
keybinding_list_push(list, keybinding);
|
||||
return 0;
|
||||
return keybinding;
|
||||
}
|
||||
|
||||
int
|
||||
parse_definemode(char ***modes, char **saveptr) {
|
||||
int length = 0;
|
||||
while((*modes)[length++] != NULL)
|
||||
;
|
||||
char **tmp = realloc(*modes, (length + 1) * sizeof(char *));
|
||||
if(tmp == NULL) {
|
||||
wlr_log(WLR_ERROR, "Could not allocate memory for storing modes.");
|
||||
return -1;
|
||||
}
|
||||
*modes = tmp;
|
||||
(*modes)[length] = NULL;
|
||||
|
||||
char *
|
||||
parse_definemode(char **saveptr) {
|
||||
char *mode = strtok_r(NULL, " ", saveptr);
|
||||
if(mode == NULL) {
|
||||
wlr_log(WLR_ERROR, "Expected mode to succeed \"definemode\" keyword.");
|
||||
return NULL;
|
||||
}
|
||||
return strdup(mode);
|
||||
}
|
||||
|
||||
int
|
||||
parse_workspaces(char **saveptr) {
|
||||
char *nws_str = strtok_r(NULL, " ", saveptr);
|
||||
if(nws_str == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected argument for \"workspaces\" command, got none.");
|
||||
return -1;
|
||||
}
|
||||
long nws = strtol(nws_str, NULL, 10);
|
||||
if(!(1 <= nws && nws <= 30)) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"More than 30 workspaces are not supported. Received %li", nws);
|
||||
return -1;
|
||||
}
|
||||
return nws;
|
||||
}
|
||||
|
||||
int
|
||||
parse_command(struct cg_server *server, struct keybinding *keybinding,
|
||||
char *saveptr) {
|
||||
char *action = strtok_r(NULL, " ", &saveptr);
|
||||
if(action == NULL) {
|
||||
wlr_log(WLR_ERROR, "Expected an action to parse, got none.");
|
||||
return -1;
|
||||
}
|
||||
keybinding->data = (union keybinding_params){.c = NULL};
|
||||
if(strcmp(action, "vsplit") == 0) {
|
||||
keybinding->action = KEYBINDING_SPLIT_VERTICAL;
|
||||
} else if(strcmp(action, "hsplit") == 0) {
|
||||
keybinding->action = KEYBINDING_SPLIT_HORIZONTAL;
|
||||
} else if(strcmp(action, "quit") == 0) {
|
||||
keybinding->action = KEYBINDING_QUIT;
|
||||
} else if(strcmp(action, "focus") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_TILES;
|
||||
keybinding->data.b = false;
|
||||
} else if(strcmp(action, "focusprev") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_TILES;
|
||||
keybinding->data.b = true;
|
||||
} else if(strcmp(action, "next") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_VIEWS;
|
||||
keybinding->data.b = false;
|
||||
} else if(strcmp(action, "prev") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_VIEWS;
|
||||
keybinding->data.b = true;
|
||||
} else if(strcmp(action, "only") == 0) {
|
||||
keybinding->action = KEYBINDING_LAYOUT_FULLSCREEN;
|
||||
} else if(strcmp(action, "abort") == 0) {
|
||||
keybinding->action = KEYBINDING_NOOP;
|
||||
} else if(strcmp(action, "time") == 0) {
|
||||
keybinding->action = KEYBINDING_SHOW_TIME;
|
||||
} else if(strcmp(action, "nextscreen") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_OUTPUT;
|
||||
keybinding->data.b = false;
|
||||
} else if(strcmp(action, "prevscreen") == 0) {
|
||||
keybinding->action = KEYBINDING_CYCLE_OUTPUT;
|
||||
keybinding->data.b = true;
|
||||
} else if(strcmp(action, "exec") == 0) {
|
||||
keybinding->action = KEYBINDING_RUN_COMMAND;
|
||||
if(saveptr == NULL) {
|
||||
wlr_log(WLR_ERROR, "Not enough paramaters to \"exec\". Expected "
|
||||
"string to execute.");
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.c = strdup(saveptr);
|
||||
} else if(strcmp(action, "resizeleft") == 0) {
|
||||
keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL;
|
||||
keybinding->data.i = -10;
|
||||
} else if(strcmp(action, "resizeright") == 0) {
|
||||
keybinding->action = KEYBINDING_RESIZE_TILE_HORIZONTAL;
|
||||
keybinding->data.i = 10;
|
||||
} else if(strcmp(action, "resizedown") == 0) {
|
||||
keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL;
|
||||
keybinding->data.i = 10;
|
||||
} else if(strcmp(action, "resizeup") == 0) {
|
||||
keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL;
|
||||
keybinding->data.i = -10;
|
||||
} else if(strcmp(action, "workspace") == 0) {
|
||||
keybinding->action = KEYBINDING_SWITCH_WORKSPACE;
|
||||
char *nws_str = strtok_r(NULL, " ", &saveptr);
|
||||
if(nws_str == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected argument for \"workspace\" action, got none.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
long ws = strtol(nws_str, NULL, 10);
|
||||
if(ws < 1) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Workspace number must be a integer number larger or equal "
|
||||
"to 1. Got %ld",
|
||||
ws);
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.u = ws - 1;
|
||||
} else if(strcmp(action, "movetoworkspace") == 0) {
|
||||
keybinding->action = KEYBINDING_MOVE_VIEW_TO_WORKSPACE;
|
||||
char *nws_str = strtok_r(NULL, " ", &saveptr);
|
||||
if(nws_str == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected argument for \"workspace\" action, got none.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
long ws = strtol(nws_str, NULL, 10);
|
||||
if(ws < 1) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Workspace number must be an integer larger or equal to 1. "
|
||||
"Got %ld",
|
||||
ws);
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.u = ws - 1;
|
||||
} else if(strcmp(action, "exchangeleft") == 0) {
|
||||
keybinding->action = KEYBINDING_SWAP_LEFT;
|
||||
} else if(strcmp(action, "exchangeright") == 0) {
|
||||
keybinding->action = KEYBINDING_SWAP_RIGHT;
|
||||
} else if(strcmp(action, "exchangeup") == 0) {
|
||||
keybinding->action = KEYBINDING_SWAP_TOP;
|
||||
} else if(strcmp(action, "exchangedown") == 0) {
|
||||
keybinding->action = KEYBINDING_SWAP_BOTTOM;
|
||||
} else if(strcmp(action, "focusleft") == 0) {
|
||||
keybinding->action = KEYBINDING_FOCUS_LEFT;
|
||||
} else if(strcmp(action, "focusright") == 0) {
|
||||
keybinding->action = KEYBINDING_FOCUS_RIGHT;
|
||||
} else if(strcmp(action, "focusup") == 0) {
|
||||
keybinding->action = KEYBINDING_FOCUS_TOP;
|
||||
} else if(strcmp(action, "focusdown") == 0) {
|
||||
keybinding->action = KEYBINDING_FOCUS_BOTTOM;
|
||||
} else if(strcmp(action, "movetonextscreen") == 0) {
|
||||
keybinding->action = KEYBINDING_MOVE_VIEW_TO_NEXT_OUTPUT;
|
||||
} else if(strcmp(action, "switchvt") == 0) {
|
||||
keybinding->action = KEYBINDING_CHANGE_TTY;
|
||||
char *ntty = strtok_r(NULL, " ", &saveptr);
|
||||
if(ntty == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected argument for \"switchvt\" command, got none.");
|
||||
return -1;
|
||||
}
|
||||
long tty = strtol(ntty, NULL, 10);
|
||||
keybinding->data.u = tty;
|
||||
} else if(strcmp(action, "mode") == 0) {
|
||||
keybinding->action = KEYBINDING_SWITCH_MODE;
|
||||
char *mode = strtok_r(NULL, " ", &saveptr);
|
||||
if(mode == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected mode after \"switch_mode\". Got nothing.");
|
||||
return -1;
|
||||
}
|
||||
int mode_idx = get_mode_index_from_name(server->modes, mode);
|
||||
if(mode_idx == -1) {
|
||||
wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_mode", mode);
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.u = (unsigned int)mode_idx;
|
||||
} else if(strcmp(action, "setmode") == 0) {
|
||||
keybinding->action = KEYBINDING_SWITCH_DEFAULT_MODE;
|
||||
char *mode = strtok_r(NULL, " ", &saveptr);
|
||||
if(mode == NULL) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
"Expected mode after \"switch_default_mode\". Got nothing.");
|
||||
return -1;
|
||||
}
|
||||
int mode_idx = get_mode_index_from_name(server->modes, mode);
|
||||
if(mode_idx == -1) {
|
||||
wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_default_mode",
|
||||
mode);
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.u = (unsigned int)mode_idx;
|
||||
} else if(strcmp(action, "bind") == 0) {
|
||||
keybinding->action = KEYBINDING_DEFINEKEY;
|
||||
keybinding->data.kb = parse_bind(server, &saveptr);
|
||||
if(keybinding->data.kb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(action, "definekey") == 0) {
|
||||
keybinding->action = KEYBINDING_DEFINEKEY;
|
||||
keybinding->data.kb = parse_definekey(server, &saveptr);
|
||||
if(keybinding->data.kb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(action, "background") == 0) {
|
||||
keybinding->action = KEYBINDING_BACKGROUND;
|
||||
if(parse_background(server, keybinding->data.color, &saveptr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(action, "escape") == 0) {
|
||||
keybinding->action = KEYBINDING_DEFINEKEY;
|
||||
keybinding->data.kb = parse_escape(&saveptr);
|
||||
if(keybinding->data.kb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(action, "definemode") == 0) {
|
||||
keybinding->action = KEYBINDING_DEFINEMODE;
|
||||
keybinding->data.c = parse_definemode(&saveptr);
|
||||
if(keybinding->data.c == NULL) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(action, "workspaces") == 0) {
|
||||
keybinding->action = KEYBINDING_WORKSPACES;
|
||||
keybinding->data.i = parse_workspaces(&saveptr);
|
||||
if(keybinding->data.i < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "Error, unsupported action \"%s\".", action);
|
||||
return -1;
|
||||
}
|
||||
(*modes)[length - 1] = strdup(mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
parse_rc_line(struct cg_server *server, char *line) {
|
||||
char *saveptr = NULL; // Used internally by strtok_r
|
||||
char *command = strtok_r(line, " ", &saveptr);
|
||||
if(command == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if(strcmp(command, "bind") == 0) {
|
||||
if(parse_bind(server, server->keybindings, &saveptr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(command, "definekey") == 0) {
|
||||
if(parse_definekey(server, server->keybindings, &saveptr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(command, "background") == 0) {
|
||||
if(parse_background(server, &saveptr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(command, "escape") == 0) {
|
||||
if(parse_escape(server->keybindings, &saveptr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(command, "definemode") == 0) {
|
||||
if(parse_definemode(&server->modes, &saveptr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(command, "exec") == 0) {
|
||||
if(parse_and_run_exec(&saveptr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(command, "workspaces") == 0) {
|
||||
char *nws_str = strtok_r(NULL, " ", &saveptr);
|
||||
if(nws_str == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected argument for \"workspaces\" command, got none.");
|
||||
return -1;
|
||||
}
|
||||
long nws = strtol(nws_str, NULL, 10);
|
||||
if(!(1 <= nws && nws <= 30)) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"More than 30 workspaces are not supported. Received %li",
|
||||
nws);
|
||||
return -1;
|
||||
}
|
||||
struct cg_output *output;
|
||||
wl_list_for_each(output, &server->outputs, link) {
|
||||
for(unsigned int i = nws; i < server->nws; ++i) {
|
||||
free(output->workspaces[i]);
|
||||
}
|
||||
struct cg_workspace **new_workspaces = realloc(
|
||||
output->workspaces, nws * sizeof(struct cg_workspace *));
|
||||
if(new_workspaces == NULL) {
|
||||
wlr_log(WLR_ERROR, "Error reallocating memory for workspaces.");
|
||||
return -1;
|
||||
}
|
||||
output->workspaces = new_workspaces;
|
||||
for(unsigned int i = server->nws; i < nws; ++i) {
|
||||
output->workspaces[i] = full_screen_workspace(output);
|
||||
wl_list_init(&output->workspaces[i]->views);
|
||||
wl_list_init(&output->workspaces[i]->unmanaged_views);
|
||||
}
|
||||
}
|
||||
server->nws = nws;
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "Unsupported command \"%s\" in config file",
|
||||
command);
|
||||
char *saveptr = strdup(line); // Used internally by strtok_r
|
||||
|
||||
struct keybinding *keybinding = malloc(sizeof(struct keybinding));
|
||||
if(keybinding == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Failed to allocate memory for temporary keybinding struct.");
|
||||
free(keybinding);
|
||||
free(saveptr);
|
||||
return -1;
|
||||
}
|
||||
if(parse_command(server, keybinding, saveptr) != 0) {
|
||||
wlr_log(WLR_ERROR, "Error parsing config file.");
|
||||
free(keybinding);
|
||||
free(saveptr);
|
||||
return -1;
|
||||
}
|
||||
run_action(keybinding->action, server, keybinding->data);
|
||||
keybinding_free(keybinding, false);
|
||||
free(saveptr);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
BIN
signatures/1.0.6.sig
Normal file
BIN
signatures/1.0.6.sig
Normal file
Binary file not shown.
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue