mirror of
https://cagebreak.project-repo.co/cagebreak.git
synced 2026-08-09 07:09:11 +02:00
Release 1.3.0
- Add IPC
This commit is contained in:
parent
e35da69b87
commit
0c185eef09
14 changed files with 503 additions and 116 deletions
2
Bugs.md
2
Bugs.md
|
|
@ -94,6 +94,6 @@ difficult to reproduce.
|
|||
* github issue number : N/A
|
||||
* Fixed: 1.2.1
|
||||
|
||||
Our fuzzing framework up to and including release 1.2.0 does not the limit line
|
||||
Our fuzzing framework up to and including release 1.2.0 does not limit line
|
||||
lengths. This can crash the fuzzing framework with a segfault due to running
|
||||
out of memory.
|
||||
|
|
|
|||
12
README.md
12
README.md
|
|
@ -139,6 +139,9 @@ Release checklist
|
|||
* [ ] Update signature of the binary
|
||||
* [ ] Signature
|
||||
* [ ] Branching Strategy
|
||||
* [ ] git archive --prefix=cagebreak/ -o release_version.tar.gz tags/version .
|
||||
* [ ] gpg --detach-sign -u keyid release_version.tar.gz
|
||||
* [ ] upload build assets
|
||||
|
||||
### Signing Key
|
||||
|
||||
|
|
@ -180,6 +183,11 @@ ninja -C build
|
|||
|
||||
For every release after 1.0.5, hashes will be provided.
|
||||
|
||||
1.3.0
|
||||
|
||||
* sha 256: aecc5292f56f7250d777110cee1f11a92018a9eb2117d7d37cd51d7d3a5cbae0
|
||||
* sha 512: 1d2d220f44787a97359a32f305e33185f0369551e61a9d7066023bfa43de50849eba5bcbb0083d2dc563ac993b8d51dd733afa0adb2a823ef50ecfee5624bbc0
|
||||
|
||||
1.2.1
|
||||
|
||||
* sha 256: 803f7667dc4997062f9ec95afcdca0cac68c82a7cf057cef83fe1ccfee33b8bc
|
||||
|
|
@ -256,6 +264,10 @@ Unifies commands and actions. See Issue 4 in Bugs.md.
|
|||
|
||||
Adds output configuration as described in the man pages.
|
||||
|
||||
### Release 1.3.0
|
||||
|
||||
Adds IPC as described in the man pages.
|
||||
|
||||
## License
|
||||
|
||||
Please see [LICENSE](https://github.com/project-repo/cagebreak/blob/master/LICENSE)
|
||||
|
|
|
|||
22
cagebreak.c
22
cagebreak.c
|
|
@ -47,6 +47,7 @@
|
|||
#endif
|
||||
|
||||
#include "idle_inhibit_v1.h"
|
||||
#include "ipc_server.h"
|
||||
#include "keybinding.h"
|
||||
#include "message.h"
|
||||
#include "output.h"
|
||||
|
|
@ -189,16 +190,19 @@ set_configuration(struct cg_server *server,
|
|||
config_file_path);
|
||||
return -1;
|
||||
}
|
||||
size_t max_line_size = 256;
|
||||
char line[max_line_size * sizeof(char)];
|
||||
char line[MAX_LINE_SIZE * sizeof(char)];
|
||||
for(unsigned int line_num = 1;
|
||||
fgets(line, max_line_size, config_file) != NULL; ++line_num) {
|
||||
fgets(line, MAX_LINE_SIZE, config_file) != NULL; ++line_num) {
|
||||
line[strcspn(line, "\n")] = '\0';
|
||||
if(*line != '\0' && *line != '#') {
|
||||
if(parse_rc_line(server, line) != 0) {
|
||||
char *errstr;
|
||||
if(parse_rc_line(server, line, &errstr) != 0) {
|
||||
wlr_log(WLR_ERROR, "Error in config file \"%s\", line %d\n",
|
||||
config_file_path, line_num);
|
||||
fclose(config_file);
|
||||
if(errstr != NULL) {
|
||||
free(errstr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -289,7 +293,7 @@ main(int argc, char *argv[]) {
|
|||
if(server.modes[0] == NULL || server.modes[1] == NULL ||
|
||||
server.modes[2] == NULL) {
|
||||
wlr_log(WLR_ERROR, "Error allocating default modes");
|
||||
goto end;
|
||||
return 1;
|
||||
}
|
||||
|
||||
server.nws = 1;
|
||||
|
|
@ -512,6 +516,12 @@ main(int argc, char *argv[]) {
|
|||
wlr_xwayland_set_seat(xwayland, server.seat->seat);
|
||||
#endif
|
||||
|
||||
if(ipc_init(&server) != 0) {
|
||||
wlr_log(WLR_ERROR, "Failed to initialize IPC");
|
||||
ret = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
{ // config_file should only be visible as long as it is valid
|
||||
char *config_file = get_config_file();
|
||||
if(config_file == NULL) {
|
||||
|
|
@ -534,7 +544,7 @@ main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
/* Place the cursor to the topl left of the output layout. */
|
||||
/* Place the cursor to the top left of the output layout. */
|
||||
wlr_cursor_warp(server.seat->cursor, NULL, 0, 0);
|
||||
|
||||
wl_display_run(server.wl_display);
|
||||
|
|
|
|||
|
|
@ -406,7 +406,11 @@ set_configuration(struct cg_server *server, char *content) {
|
|||
(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) {
|
||||
char *errstr;
|
||||
if(parse_rc_line(server, line, &errstr) != 0) {
|
||||
if(errstr != NULL) {
|
||||
free(errstr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
277
ipc_server.c
Normal file
277
ipc_server.c
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Cagebreak: A Wayland tiling compositor.
|
||||
*
|
||||
* Copyright (C) 2020 The Cagebreak Authors
|
||||
* Copyright (C) 2018-2020 Jente Hidskes
|
||||
*
|
||||
* See the LICENSE file accompanying this file.
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
|
||||
#include "ipc_server.h"
|
||||
#include "message.h"
|
||||
#include "parse.h"
|
||||
#include "server.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
static void
|
||||
handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
struct cg_ipc_handle *ipc = wl_container_of(listener, ipc, display_destroy);
|
||||
if(ipc->event_source != NULL) {
|
||||
wl_event_source_remove(ipc->event_source);
|
||||
}
|
||||
close(ipc->socket);
|
||||
unlink(ipc->sockaddr->sun_path);
|
||||
|
||||
struct cg_ipc_client *tmp_client, *client;
|
||||
wl_list_for_each_safe(client, tmp_client, &ipc->client_list, link) {
|
||||
ipc_client_disconnect(client);
|
||||
}
|
||||
|
||||
free(ipc->sockaddr);
|
||||
|
||||
wl_list_remove(&ipc->display_destroy.link);
|
||||
}
|
||||
|
||||
int
|
||||
ipc_init(struct cg_server *server) {
|
||||
struct cg_ipc_handle *ipc = &server->ipc;
|
||||
ipc->socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if(ipc->socket == -1) {
|
||||
wlr_log(WLR_ERROR, "Unable to create IPC socket");
|
||||
return -1;
|
||||
}
|
||||
if(fcntl(ipc->socket, F_SETFD, FD_CLOEXEC) == -1) {
|
||||
wlr_log(WLR_ERROR, "Unable to set CLOEXEC on IPC socket");
|
||||
return -1;
|
||||
}
|
||||
if(fcntl(ipc->socket, F_SETFL, O_NONBLOCK) == -1) {
|
||||
wlr_log(WLR_ERROR, "Unable to set NONBLOCK on IPC socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ipc->sockaddr = malloc(sizeof(struct sockaddr_un));
|
||||
|
||||
if(ipc->sockaddr == NULL) {
|
||||
wlr_log(WLR_ERROR, "Unable to allocate socket address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ipc->sockaddr->sun_family = AF_UNIX;
|
||||
int max_path_size = sizeof(ipc->sockaddr->sun_path);
|
||||
const char *sockdir = getenv("XDG_RUNTIME_DIR");
|
||||
if(sockdir == NULL) {
|
||||
sockdir = "/tmp";
|
||||
}
|
||||
|
||||
if(max_path_size <= snprintf(ipc->sockaddr->sun_path, max_path_size,
|
||||
"%s/cagebreak-ipc.%i.%i.sock", sockdir,
|
||||
getuid(), getpid())) {
|
||||
wlr_log(WLR_ERROR, "Unable to write socket path to "
|
||||
"ipc->sockaddr->sun_path. Path too long");
|
||||
free(ipc->sockaddr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unlink(ipc->sockaddr->sun_path);
|
||||
|
||||
if(bind(ipc->socket, (struct sockaddr *)ipc->sockaddr,
|
||||
sizeof(*ipc->sockaddr)) == -1) {
|
||||
wlr_log(WLR_ERROR, "Unable to bind IPC socket");
|
||||
free(ipc->sockaddr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(listen(ipc->socket, 3) == -1) {
|
||||
wlr_log(WLR_ERROR, "Unable to listen on IPC socket");
|
||||
free(ipc->sockaddr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
setenv("CAGEBREAK_SOCKET", ipc->sockaddr->sun_path, 1);
|
||||
|
||||
wl_list_init(&ipc->client_list);
|
||||
|
||||
ipc->display_destroy.notify = handle_display_destroy;
|
||||
wl_display_add_destroy_listener(server->wl_display, &ipc->display_destroy);
|
||||
|
||||
ipc->event_source =
|
||||
wl_event_loop_add_fd(server->event_loop, ipc->socket, WL_EVENT_READABLE,
|
||||
ipc_handle_connection, server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ipc_handle_connection(int fd, uint32_t mask, void *data) {
|
||||
(void)fd;
|
||||
struct cg_server *server = data;
|
||||
struct cg_ipc_handle *ipc = &server->ipc;
|
||||
if(mask != WL_EVENT_READABLE) {
|
||||
wlr_log(WLR_ERROR, "Expected to receive a WL_EVENT_READABLE");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int client_fd = accept(ipc->socket, NULL, NULL);
|
||||
if(client_fd == -1) {
|
||||
wlr_log(WLR_ERROR, "Unable to accept IPC client connection");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flags;
|
||||
if((flags = fcntl(client_fd, F_GETFD)) == -1 ||
|
||||
fcntl(client_fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
|
||||
wlr_log(WLR_ERROR, "Unable to set CLOEXEC on IPC client socket");
|
||||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
if((flags = fcntl(client_fd, F_GETFL)) == -1 ||
|
||||
fcntl(client_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
wlr_log(WLR_ERROR, "Unable to set NONBLOCK on IPC client socket");
|
||||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cg_ipc_client *client = malloc(sizeof(struct cg_ipc_client));
|
||||
if(!client) {
|
||||
wlr_log(WLR_ERROR, "Unable to allocate ipc client");
|
||||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
// +1 for \n and +1 for \0
|
||||
client->read_buffer = malloc(sizeof(char) * (MAX_LINE_SIZE + 2));
|
||||
client->read_buf_len = 0;
|
||||
client->read_discard = 0;
|
||||
client->server = server;
|
||||
client->fd = client_fd;
|
||||
client->event_source =
|
||||
wl_event_loop_add_fd(server->event_loop, client_fd, WL_EVENT_READABLE,
|
||||
ipc_client_handle_readable, client);
|
||||
client->writable_event_source = NULL;
|
||||
|
||||
client->write_buffer_size = 128;
|
||||
client->write_buffer_len = 0;
|
||||
client->write_buffer = malloc(client->write_buffer_size);
|
||||
if(!client->write_buffer) {
|
||||
wlr_log(WLR_ERROR, "Unable to allocate ipc client write buffer");
|
||||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wl_list_insert(&ipc->client_list, &client->link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
|
||||
struct cg_ipc_client *client = data;
|
||||
|
||||
if(mask & WL_EVENT_ERROR) {
|
||||
wlr_log(WLR_ERROR, "IPC Client socket error, removing client");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(mask & WL_EVENT_HANGUP) {
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_available;
|
||||
if(ioctl(client_fd, FIONREAD, &read_available) < 0) {
|
||||
wlr_log(WLR_ERROR, "Unable to read IPC socket buffer size");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_size = read_available < MAX_LINE_SIZE + 1 - client->read_buf_len
|
||||
? read_available
|
||||
: MAX_LINE_SIZE + 1 - client->read_buf_len;
|
||||
// Append to buffer
|
||||
ssize_t received = recv(
|
||||
client_fd, client->read_buffer + client->read_buf_len, read_size, 0);
|
||||
if(received == -1) {
|
||||
wlr_log(WLR_ERROR, "Unable to receive data from IPC client");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
client->read_buf_len += received;
|
||||
|
||||
ipc_client_handle_command(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ipc_client_disconnect(struct cg_ipc_client *client) {
|
||||
if(client == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Client \"NULL\" was passed to ipc_client_disconnect");
|
||||
return;
|
||||
}
|
||||
|
||||
shutdown(client->fd, SHUT_RDWR);
|
||||
|
||||
wl_event_source_remove(client->event_source);
|
||||
if(client->writable_event_source) {
|
||||
wl_event_source_remove(client->writable_event_source);
|
||||
}
|
||||
wl_list_remove(&client->link);
|
||||
free(client->write_buffer);
|
||||
free(client->read_buffer);
|
||||
close(client->fd);
|
||||
free(client);
|
||||
}
|
||||
|
||||
void
|
||||
ipc_client_handle_command(struct cg_ipc_client *client) {
|
||||
if(client == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Client \"NULL\" was passed to ipc_client_handle_command");
|
||||
return;
|
||||
}
|
||||
client->read_buffer[client->read_buf_len] = '\0';
|
||||
char *nl_pos;
|
||||
uint32_t offset = 0;
|
||||
while((nl_pos = strchr(client->read_buffer + offset, '\n')) != NULL) {
|
||||
if(client->read_discard) {
|
||||
client->read_discard = 0;
|
||||
} else {
|
||||
*nl_pos = '\0';
|
||||
char *line = client->read_buffer + offset;
|
||||
if(*line != '\0' && *line != '#') {
|
||||
message_clear(client->server->curr_output);
|
||||
char *errstr;
|
||||
if(parse_rc_line(client->server, line, &errstr) != 0) {
|
||||
if(errstr != NULL) {
|
||||
message_printf(client->server->curr_output, "%s",
|
||||
errstr);
|
||||
wlr_log(WLR_ERROR, "%s", errstr);
|
||||
free(errstr);
|
||||
}
|
||||
wlr_log(WLR_ERROR, "Error parsing input from IPC socket");
|
||||
}
|
||||
}
|
||||
}
|
||||
offset = (nl_pos - client->read_buffer) + 1;
|
||||
}
|
||||
if(offset == 0) {
|
||||
wlr_log(WLR_ERROR, "Line received was longer that %d, discarding it",
|
||||
MAX_LINE_SIZE);
|
||||
client->read_buf_len = 0;
|
||||
client->read_discard = 1;
|
||||
return;
|
||||
}
|
||||
if(offset < client->read_buf_len) {
|
||||
memmove(client->read_buffer, client->read_buffer + offset,
|
||||
client->read_buf_len - offset);
|
||||
}
|
||||
client->read_buf_len -= offset;
|
||||
}
|
||||
50
ipc_server.h
Normal file
50
ipc_server.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef CG_IPC_SERVER_H
|
||||
#define CG_IPC_SERVER_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
struct cg_server;
|
||||
|
||||
struct cg_ipc_client {
|
||||
struct wl_event_source *event_source;
|
||||
struct wl_event_source *writable_event_source;
|
||||
struct cg_server *server;
|
||||
struct wl_list link;
|
||||
int fd;
|
||||
uint32_t security_policy;
|
||||
size_t write_buffer_len;
|
||||
size_t write_buffer_size;
|
||||
char *write_buffer;
|
||||
// The following is for storing data between event_loop calls
|
||||
uint16_t read_buf_len;
|
||||
uint8_t read_discard; // 1 if the current line is to be discarded
|
||||
char *read_buffer;
|
||||
};
|
||||
|
||||
struct cg_ipc_handle {
|
||||
int socket;
|
||||
struct wl_event_source *event_source;
|
||||
struct wl_list client_list;
|
||||
struct wl_listener display_destroy;
|
||||
struct sockaddr_un *sockaddr;
|
||||
};
|
||||
|
||||
int
|
||||
ipc_init(struct cg_server *server);
|
||||
int
|
||||
ipc_handle_connection(int fd, uint32_t mask, void *data);
|
||||
int
|
||||
ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
|
||||
// int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data);
|
||||
void
|
||||
ipc_client_disconnect(struct cg_ipc_client *client);
|
||||
void
|
||||
ipc_client_handle_command(struct cg_ipc_client *client);
|
||||
// bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t
|
||||
// payload_length);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
% CAGEBREAK-CONFIG(1) Version 1.2.1 | Cagebreak Manual
|
||||
% CAGEBREAK-CONFIG(1) Version 1.3.0 | Cagebreak Manual
|
||||
|
||||
# NAME
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
% CAGEBREAK(1) Version 1.2.1 | Cagebreak Manual
|
||||
% CAGEBREAK(1) Version 1.3.0 | Cagebreak Manual
|
||||
|
||||
# NAME
|
||||
|
||||
|
|
@ -18,10 +18,19 @@ in contrast to the original `ratpoison`, has native support for
|
|||
multi-workspace operation.
|
||||
|
||||
All interactions between the user and `cagebreak` are done via
|
||||
the keyboard. Configuration of this behaviour is specified
|
||||
in the **\$XDG_CONFIG_PATH/cagebreak/config** file (See **cagebreak-config(5)**).
|
||||
the keyboard.
|
||||
|
||||
## OPTIONS
|
||||
Configuration of this behaviour is specified in the
|
||||
**\$XDG_CONFIG_PATH/cagebreak/config** file (See **cagebreak-config(5)**).
|
||||
|
||||
Scripting support is provided through the IPC
|
||||
socket specified in the environment variable **\$CAGEBREAK_SOCKET**.
|
||||
The syntax accepted through this socket is identical to
|
||||
that of the configuration file (see **cagebreak-config(5)**).
|
||||
Errors which occur during interaction over IPC channel
|
||||
are displayed in a message box at the top right of the screen.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
-h
|
||||
|
||||
|
|
@ -37,6 +46,11 @@ in the **\$XDG_CONFIG_PATH/cagebreak/config** file (See **cagebreak-config(5)**)
|
|||
|
||||
# ENVIRONMENT
|
||||
|
||||
`CAGEBREAK_SOCKET`
|
||||
|
||||
: The IPC unix domain socket address accepting
|
||||
commands as specified in **cagebreak-config(5)**
|
||||
|
||||
`XKB_DEFAULT_LAYOUT`
|
||||
|
||||
: The keyboard layout to be used (See **xkeyboard-config(7)**)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
project('cagebreak', 'c',
|
||||
version: '1.2.1',
|
||||
version: '1.3.0',
|
||||
license: 'MIT',
|
||||
default_options: [
|
||||
'c_std=c11',
|
||||
|
|
@ -123,6 +123,7 @@ conf_data.set_quoted('CG_VERSION', version)
|
|||
cagebreak_main_file = [ 'cagebreak.c', ]
|
||||
cagebreak_source_strings = [
|
||||
'idle_inhibit_v1.c',
|
||||
'ipc_server.c',
|
||||
'keybinding.c',
|
||||
'workspace.c',
|
||||
'output.c',
|
||||
|
|
@ -139,6 +140,7 @@ cagebreak_source_strings = [
|
|||
|
||||
cagebreak_header_strings = [
|
||||
'idle_inhibit_v1.h',
|
||||
'ipc_server.h',
|
||||
'keybinding.h',
|
||||
'workspace.h',
|
||||
'output.h',
|
||||
|
|
|
|||
215
parse.c
215
parse.c
|
|
@ -11,12 +11,35 @@
|
|||
#include "server.h"
|
||||
#include "workspace.h"
|
||||
|
||||
char *
|
||||
malloc_vsprintf(const char *fmt, va_list ap) {
|
||||
va_list ap2;
|
||||
va_copy(ap2, ap);
|
||||
int len = vsnprintf(NULL, 0, fmt, ap);
|
||||
char *ret = malloc(sizeof(char) * (len + 1));
|
||||
vsnprintf(ret, len + 1, fmt, ap2);
|
||||
va_end(ap2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
log_error(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
char *ret = malloc_vsprintf(fmt, args);
|
||||
if(ret != NULL) {
|
||||
wlr_log(WLR_ERROR, "%s", ret);
|
||||
}
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* parses a key definition (e.g. "S-Tab") and sets key and modifiers in
|
||||
* keybinding respectivly */
|
||||
int
|
||||
parse_key(struct keybinding *keybinding, const char *key_def) {
|
||||
parse_key(struct keybinding *keybinding, const char *key_def, char **errstr) {
|
||||
if(key_def == NULL) {
|
||||
wlr_log(WLR_ERROR, "Expected key definition, got nothing.");
|
||||
*errstr = log_error("Expected key definition, got nothing.");
|
||||
return -1;
|
||||
}
|
||||
keybinding->modifiers = 0;
|
||||
|
|
@ -44,14 +67,14 @@ parse_key(struct keybinding *keybinding, const char *key_def) {
|
|||
keybinding->modifiers |= WLR_MODIFIER_MOD5;
|
||||
break;
|
||||
default:
|
||||
wlr_log(WLR_ERROR, "Unknown modifier \"%c\"", key_def[0]);
|
||||
*errstr = log_error("Unknown modifier \"%c\"", key_def[0]);
|
||||
return -1;
|
||||
}
|
||||
key_def += 2;
|
||||
}
|
||||
xkb_keysym_t keysym = xkb_keysym_from_name(key_def, XKB_KEYSYM_NO_FLAGS);
|
||||
if(keysym == XKB_KEY_NoSymbol) {
|
||||
wlr_log(WLR_ERROR, "Could not convert key \"%s\" to keysym.", key_def);
|
||||
*errstr = log_error("Could not convert key \"%s\" to keysym.", key_def);
|
||||
return -1;
|
||||
}
|
||||
keybinding->key = keysym;
|
||||
|
|
@ -60,25 +83,25 @@ parse_key(struct keybinding *keybinding, const char *key_def) {
|
|||
|
||||
int
|
||||
parse_command(struct cg_server *server, struct keybinding *keybinding,
|
||||
char *saveptr);
|
||||
char *saveptr, char **errstr);
|
||||
|
||||
/* Parse a keybinding definition and return it if successful, else return NULL
|
||||
*/
|
||||
struct keybinding *
|
||||
parse_keybinding(struct cg_server *server, char **saveptr) {
|
||||
parse_keybinding(struct cg_server *server, char **saveptr, char **errstr) {
|
||||
struct keybinding *keybinding = malloc(sizeof(struct keybinding));
|
||||
if(keybinding == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Failed to allocate memory for keybinding in parse_keybinding");
|
||||
*errstr = log_error(
|
||||
"Failed to allocate memory for keybinding in parse_keybinding");
|
||||
return NULL;
|
||||
}
|
||||
char *key = strtok_r(NULL, " ", saveptr);
|
||||
if(parse_key(keybinding, key) != 0) {
|
||||
if(parse_key(keybinding, key, errstr) != 0) {
|
||||
wlr_log(WLR_ERROR, "Could not parse key definition \"%s\"", key);
|
||||
free(keybinding);
|
||||
return NULL;
|
||||
}
|
||||
if(parse_command(server, keybinding, *saveptr) != 0) {
|
||||
if(parse_command(server, keybinding, *saveptr, errstr) != 0) {
|
||||
free(keybinding);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -86,8 +109,8 @@ parse_keybinding(struct cg_server *server, char **saveptr) {
|
|||
}
|
||||
|
||||
struct keybinding *
|
||||
parse_bind(struct cg_server *server, char **saveptr) {
|
||||
struct keybinding *keybinding = parse_keybinding(server, saveptr);
|
||||
parse_bind(struct cg_server *server, char **saveptr, char **errstr) {
|
||||
struct keybinding *keybinding = parse_keybinding(server, saveptr, errstr);
|
||||
if(keybinding == NULL) {
|
||||
wlr_log(WLR_ERROR, "Could not parse keybinding for \"bind\".");
|
||||
return NULL;
|
||||
|
|
@ -97,18 +120,19 @@ parse_bind(struct cg_server *server, char **saveptr) {
|
|||
}
|
||||
|
||||
struct keybinding *
|
||||
parse_definekey(struct cg_server *server, char **saveptr) {
|
||||
parse_definekey(struct cg_server *server, char **saveptr, char **errstr) {
|
||||
char *mode = strtok_r(NULL, " ", saveptr);
|
||||
if(mode == NULL) {
|
||||
wlr_log(WLR_ERROR, "Too few arguments to \"definekey\". Expected mode");
|
||||
*errstr =
|
||||
log_error("Too few arguments to \"definekey\". Expected mode");
|
||||
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);
|
||||
*errstr = log_error("Unknown mode \"%s\"", mode);
|
||||
return NULL;
|
||||
}
|
||||
struct keybinding *keybinding = parse_keybinding(server, saveptr);
|
||||
struct keybinding *keybinding = parse_keybinding(server, saveptr, errstr);
|
||||
if(keybinding == NULL) {
|
||||
wlr_log(WLR_ERROR, "Could not parse keybinding for \"definekey\"");
|
||||
return NULL;
|
||||
|
|
@ -118,16 +142,16 @@ parse_definekey(struct cg_server *server, char **saveptr) {
|
|||
}
|
||||
|
||||
int
|
||||
parse_background(struct cg_server *server, float *color, char **saveptr) {
|
||||
parse_background(struct cg_server *server, float *color, char **saveptr,
|
||||
char **errstr) {
|
||||
/* Read rgb numbers */
|
||||
for(unsigned int i = 0; i < 3; ++i) {
|
||||
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);
|
||||
*errstr = log_error("Expected three space-separated numbers (rgb) "
|
||||
"for background color setting. Got %d.",
|
||||
i);
|
||||
return -1;
|
||||
}
|
||||
if(nstr[nstrlen - 1] == '\n') {
|
||||
|
|
@ -137,17 +161,15 @@ parse_background(struct cg_server *server, float *color, char **saveptr) {
|
|||
char *endptr = NULL;
|
||||
float nval = strtof(nstr, &endptr);
|
||||
if(endptr != nstr + nstrlen) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
*errstr = log_error(
|
||||
"Could not parse number \"%s\" for background color setting.",
|
||||
nstr);
|
||||
return -1;
|
||||
}
|
||||
if(nval < 0 || nval > 1) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected a number between 0 and 1 for setting of "
|
||||
"background color. Got %f.",
|
||||
nval);
|
||||
*errstr = log_error("Expected a number between 0 and 1 for setting "
|
||||
"of background color. Got %f.",
|
||||
nval);
|
||||
return -1;
|
||||
}
|
||||
color[i] = nval;
|
||||
|
|
@ -156,15 +178,15 @@ parse_background(struct cg_server *server, float *color, char **saveptr) {
|
|||
}
|
||||
|
||||
struct keybinding *
|
||||
parse_escape(char **saveptr) {
|
||||
parse_escape(char **saveptr, char **errstr) {
|
||||
struct keybinding *keybinding = malloc(sizeof(struct keybinding));
|
||||
if(keybinding == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Failed to allocate memory for keybinding in parse_escape");
|
||||
*errstr = log_error(
|
||||
"Failed to allocate memory for keybinding in parse_escape");
|
||||
return NULL;
|
||||
}
|
||||
char *key = strtok_r(NULL, " ", saveptr);
|
||||
if(parse_key(keybinding, key) != 0) {
|
||||
if(parse_key(keybinding, key, errstr) != 0) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Could not parse key definition \"%s\" for \"escape\"", key);
|
||||
free(keybinding);
|
||||
|
|
@ -177,27 +199,27 @@ parse_escape(char **saveptr) {
|
|||
}
|
||||
|
||||
char *
|
||||
parse_definemode(char **saveptr) {
|
||||
parse_definemode(char **saveptr, char **errstr) {
|
||||
char *mode = strtok_r(NULL, " ", saveptr);
|
||||
if(mode == NULL) {
|
||||
wlr_log(WLR_ERROR, "Expected mode to succeed \"definemode\" keyword.");
|
||||
*errstr = log_error("Expected mode to succeed \"definemode\" keyword.");
|
||||
return NULL;
|
||||
}
|
||||
return strdup(mode);
|
||||
}
|
||||
|
||||
int
|
||||
parse_workspaces(char **saveptr) {
|
||||
parse_workspaces(char **saveptr, char **errstr) {
|
||||
char *nws_str = strtok_r(NULL, " ", saveptr);
|
||||
if(nws_str == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected argument for \"workspaces\" command, got none.");
|
||||
*errstr = log_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);
|
||||
*errstr = log_error(
|
||||
"More than 30 workspaces are not supported. Received %li", nws);
|
||||
return -1;
|
||||
}
|
||||
return nws;
|
||||
|
|
@ -240,23 +262,23 @@ parse_float(char **saveptr, const char *delim) {
|
|||
}
|
||||
|
||||
int
|
||||
parse_output_config(struct wl_list *config_list, char **saveptr) {
|
||||
parse_output_config(struct wl_list *config_list, char **saveptr,
|
||||
char **errstr) {
|
||||
struct cg_output_config *cfg = malloc(sizeof(struct cg_output_config));
|
||||
if(cfg == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Failed to allocate memory for output configuration");
|
||||
*errstr =
|
||||
log_error("Failed to allocate memory for output configuration");
|
||||
goto error;
|
||||
}
|
||||
char *name = strtok_r(NULL, " ", saveptr);
|
||||
if(name == NULL) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Expected name of output to be configured, got none");
|
||||
*errstr =
|
||||
log_error("Expected name of output to be configured, got none");
|
||||
goto error;
|
||||
}
|
||||
char *pos_str = strtok_r(NULL, " ", saveptr);
|
||||
if(pos_str == NULL || strcmp(pos_str, "pos") != 0) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
*errstr = log_error(
|
||||
"Expected keyword \"pos\" in output configuration for output %s",
|
||||
name);
|
||||
goto error;
|
||||
|
|
@ -264,8 +286,7 @@ parse_output_config(struct wl_list *config_list, char **saveptr) {
|
|||
|
||||
cfg->pos.x = parse_uint(saveptr, " ");
|
||||
if(cfg->pos.x < 0) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
*errstr = log_error(
|
||||
"Error parsing x coordinate of output configuration for output %s",
|
||||
name);
|
||||
goto error;
|
||||
|
|
@ -273,8 +294,7 @@ parse_output_config(struct wl_list *config_list, char **saveptr) {
|
|||
|
||||
cfg->pos.y = parse_uint(saveptr, " ");
|
||||
if(cfg->pos.y < 0) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
*errstr = log_error(
|
||||
"Error parsing y coordinate of output configuration for output %s",
|
||||
name);
|
||||
goto error;
|
||||
|
|
@ -282,8 +302,7 @@ parse_output_config(struct wl_list *config_list, char **saveptr) {
|
|||
|
||||
char *res_str = strtok_r(NULL, " ", saveptr);
|
||||
if(res_str == NULL || strcmp(res_str, "res") != 0) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
*errstr = log_error(
|
||||
"Expected keyword \"res\" in output configuration for output %s",
|
||||
name);
|
||||
goto error;
|
||||
|
|
@ -291,26 +310,23 @@ parse_output_config(struct wl_list *config_list, char **saveptr) {
|
|||
|
||||
cfg->pos.width = parse_uint(saveptr, "x");
|
||||
if(cfg->pos.width <= 0) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Error parsing width of output configuration for output %s "
|
||||
"(hint: width must be larger than 0)",
|
||||
name);
|
||||
*errstr = log_error("Error parsing width of output configuration for "
|
||||
"output %s (hint: width must be larger than 0)",
|
||||
name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
cfg->pos.height = parse_uint(saveptr, " ");
|
||||
if(cfg->pos.height <= 0) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"Error parsing height of output configuration for output %s "
|
||||
"(hint: height must e larger than 0)",
|
||||
name);
|
||||
*errstr = log_error("Error parsing height of output configuration for "
|
||||
"output %s (hint: height must e larger than 0)",
|
||||
name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
char *rate_str = strtok_r(NULL, " ", saveptr);
|
||||
if(rate_str == NULL || strcmp(rate_str, "rate") != 0) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
*errstr = log_error(
|
||||
"Expected keyword \"rate\" in output configuration for output %s",
|
||||
name);
|
||||
goto error;
|
||||
|
|
@ -318,8 +334,7 @@ parse_output_config(struct wl_list *config_list, char **saveptr) {
|
|||
|
||||
cfg->refresh_rate = parse_float(saveptr, " ");
|
||||
if(cfg->refresh_rate <= 0.0) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
*errstr = log_error(
|
||||
"Error parsing refresh rate of output configuration for output %s",
|
||||
name);
|
||||
goto error;
|
||||
|
|
@ -346,10 +361,10 @@ error:
|
|||
|
||||
int
|
||||
parse_command(struct cg_server *server, struct keybinding *keybinding,
|
||||
char *saveptr) {
|
||||
char *saveptr, char **errstr) {
|
||||
char *action = strtok_r(NULL, " ", &saveptr);
|
||||
if(action == NULL) {
|
||||
wlr_log(WLR_ERROR, "Expected an action to parse, got none.");
|
||||
*errstr = log_error("Expexted an action to parse, got none.");
|
||||
return -1;
|
||||
}
|
||||
keybinding->data = (union keybinding_params){.c = NULL};
|
||||
|
|
@ -386,8 +401,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
|
|||
} 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.");
|
||||
*errstr = log_error("Not enough paramaters to \"exec\". Expected "
|
||||
"string to execute.");
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.c = strdup(saveptr);
|
||||
|
|
@ -407,17 +422,16 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
|
|||
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.");
|
||||
*errstr = log_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);
|
||||
*errstr = log_error("Workspace number must be an integer number "
|
||||
"larger or equal to 1. Got %ld",
|
||||
ws);
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.u = ws - 1;
|
||||
|
|
@ -425,17 +439,16 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
|
|||
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.");
|
||||
*errstr = log_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);
|
||||
*errstr = log_error("Workspace number must be an integer larger or "
|
||||
"equal to 1. Got %ld",
|
||||
ws);
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.u = ws - 1;
|
||||
|
|
@ -461,8 +474,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
|
|||
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.");
|
||||
*errstr = log_error(
|
||||
"Expected argument for \"switchvt\" command, got none.");
|
||||
return -1;
|
||||
}
|
||||
long tty = strtol(ntty, NULL, 10);
|
||||
|
|
@ -471,13 +484,13 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
|
|||
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.");
|
||||
*errstr =
|
||||
log_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);
|
||||
*errstr = log_error("Unknown mode \"%s\" for switch_mode", mode);
|
||||
return -1;
|
||||
}
|
||||
keybinding->data.u = (unsigned int)mode_idx;
|
||||
|
|
@ -485,78 +498,78 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
|
|||
keybinding->action = KEYBINDING_SWITCH_DEFAULT_MODE;
|
||||
char *mode = strtok_r(NULL, " ", &saveptr);
|
||||
if(mode == NULL) {
|
||||
wlr_log(
|
||||
WLR_ERROR,
|
||||
*errstr = log_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);
|
||||
*errstr =
|
||||
log_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);
|
||||
keybinding->data.kb = parse_bind(server, &saveptr, errstr);
|
||||
if(keybinding->data.kb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(action, "definekey") == 0) {
|
||||
keybinding->action = KEYBINDING_DEFINEKEY;
|
||||
keybinding->data.kb = parse_definekey(server, &saveptr);
|
||||
keybinding->data.kb = parse_definekey(server, &saveptr, errstr);
|
||||
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) {
|
||||
if(parse_background(server, keybinding->data.color, &saveptr, errstr) !=
|
||||
0) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(action, "escape") == 0) {
|
||||
keybinding->action = KEYBINDING_DEFINEKEY;
|
||||
keybinding->data.kb = parse_escape(&saveptr);
|
||||
keybinding->data.kb = parse_escape(&saveptr, errstr);
|
||||
if(keybinding->data.kb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(action, "definemode") == 0) {
|
||||
keybinding->action = KEYBINDING_DEFINEMODE;
|
||||
keybinding->data.c = parse_definemode(&saveptr);
|
||||
keybinding->data.c = parse_definemode(&saveptr, errstr);
|
||||
if(keybinding->data.c == NULL) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(action, "workspaces") == 0) {
|
||||
keybinding->action = KEYBINDING_WORKSPACES;
|
||||
keybinding->data.i = parse_workspaces(&saveptr);
|
||||
keybinding->data.i = parse_workspaces(&saveptr, errstr);
|
||||
if(keybinding->data.i < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if(strcmp(action, "output") == 0) {
|
||||
if(parse_output_config(&server->output_config, &saveptr) != 0) {
|
||||
if(parse_output_config(&server->output_config, &saveptr, errstr) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
wlr_log(WLR_ERROR, "Error, unsupported action \"%s\".", action);
|
||||
*errstr = log_error("Error, unsupported action \"%s\".", action);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
parse_rc_line(struct cg_server *server, char *line) {
|
||||
parse_rc_line(struct cg_server *server, char *line, char **errstr) {
|
||||
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.");
|
||||
*errstr = log_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.");
|
||||
if(parse_command(server, keybinding, saveptr, errstr) != 0) {
|
||||
wlr_log(WLR_ERROR, "Error parsing command.");
|
||||
free(keybinding);
|
||||
free(saveptr);
|
||||
return -1;
|
||||
|
|
|
|||
4
parse.h
4
parse.h
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
#define PARSE_H
|
||||
|
||||
#define MAX_LINE_SIZE 256
|
||||
|
||||
struct cg_server;
|
||||
|
||||
int
|
||||
parse_rc_line(struct cg_server *server, char *line);
|
||||
parse_rc_line(struct cg_server *server, char *line, char **errstr);
|
||||
|
||||
#endif /* end of include guard PARSE_H */
|
||||
|
|
|
|||
3
server.h
3
server.h
|
|
@ -2,6 +2,7 @@
|
|||
#define CG_SERVER_H
|
||||
|
||||
#include "config.h"
|
||||
#include "ipc_server.h"
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
||||
|
|
@ -40,6 +41,8 @@ struct cg_server {
|
|||
|
||||
enum wl_output_transform output_transform;
|
||||
|
||||
struct cg_ipc_handle ipc;
|
||||
|
||||
bool running;
|
||||
char **modes;
|
||||
uint16_t nws;
|
||||
|
|
|
|||
BIN
signatures/1.2.1.sig
Normal file
BIN
signatures/1.2.1.sig
Normal file
Binary file not shown.
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue