256 lines
4.8 KiB
Text
256 lines
4.8 KiB
Text
@code_type c .c
|
|
@comment_type /* %s */
|
|
|
|
@title wmaffle
|
|
|
|
@s Introduction
|
|
|
|
This is the source code for wmaffle.
|
|
It parses it's arguments and prints either help / info text, or runs the window manager.
|
|
|
|
Here's an overview:
|
|
|
|
--- wmaffle.c
|
|
@{copyright notice}
|
|
@{c headers}
|
|
@{posix headers}
|
|
@{defines}
|
|
|
|
char *argv0;
|
|
|
|
@{function definitions}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
argv0 = argv[0];
|
|
|
|
@{variables local to main}
|
|
@{parse arguments}
|
|
|
|
@{open ipc connection}
|
|
@{setup signal handlers}
|
|
}
|
|
---
|
|
|
|
Note that this is version NaV (not a version).
|
|
|
|
--- defines
|
|
#define VERSION_STRING "NaV"
|
|
---
|
|
|
|
@s Copyright
|
|
|
|
This project is licensed under the Mozilla Public License Version 2.0. Please read LICENSE for more details.
|
|
|
|
--- copyright notice
|
|
/* Copyright (c), Niclas Meyer <niclas@countingsort.com>
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
---
|
|
|
|
@s Helper function
|
|
|
|
`die` prints an error message and then exist unsuccessfully.
|
|
|
|
--- function definitions
|
|
static void
|
|
die(char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
---
|
|
|
|
Note that this requires the `stdarg.h` header.
|
|
|
|
--- c headers
|
|
#include <stdarg.h>
|
|
---
|
|
|
|
@s Parse arguments
|
|
|
|
There are only two arguments and two of them are rather straight forward.
|
|
I use getopt for this, since it's quite good and allows us to extract the config argument easily.
|
|
|
|
This requires `getopt.h`.
|
|
|
|
--- posix headers
|
|
#include <getopt.h>
|
|
#include <limits.h>
|
|
---
|
|
|
|
That one we save in a local variable in main.
|
|
|
|
--- variables local to main
|
|
char config_path[PATH_MAX];
|
|
int option;
|
|
---
|
|
|
|
--- parse arguments
|
|
config_path[0] = '\0'; // Used to check if config was already set
|
|
|
|
while ((option = getopt(argc, argv, "hvc:")) != -1) {
|
|
switch (option) {
|
|
case 'h':
|
|
printf("Usage: %s [-h|-v|-c <config_path>]\n", argv0);
|
|
exit(EXIT_SUCCESS);
|
|
break;
|
|
case 'v':
|
|
printf("v" VERSION_STRING "\n");
|
|
exit(EXIT_SUCCESS);
|
|
break;
|
|
case 'c':
|
|
strncpy(config_path, optarg, sizeof(config_path));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!config_path[0]) {
|
|
@{get default config path}
|
|
}
|
|
---
|
|
|
|
We also need `string.h`, `stdio.h`, and `stdlib.h`.
|
|
|
|
--- c headers +=
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
---
|
|
|
|
@s Config default path
|
|
|
|
I can clearly see how a user doesn't specify a config path.
|
|
|
|
This was a design decision to make, whether to load a default config. I decided to go with it.
|
|
|
|
It loads `"${XDG_CONFIG_HOME:-$HOME/.config}/wmaffle/wmafflerc"`.
|
|
|
|
---get default config path
|
|
char *config_home = getenv("XDG_CONFIG_HOME");
|
|
|
|
if (config_home) {
|
|
snprintf(
|
|
config_path,
|
|
sizeof(config_path),
|
|
"%s/%s",
|
|
config_home,
|
|
"wmafflw/wmafflerc"
|
|
);
|
|
} else {
|
|
snprintf(
|
|
config_path,
|
|
sizeof(config_path),
|
|
"%s/%s",
|
|
getenv("HOME"),
|
|
".config/wmaffle/wmafflerc"
|
|
);
|
|
}
|
|
---
|
|
|
|
@s Open IPC connection
|
|
|
|
Pretty straight forward, we open a `AF_UNIX` socket and that's it.
|
|
|
|
We need both a sockaddr and a file descriptor.
|
|
|
|
--- variables local to main +=
|
|
struct sockaddr_un sock_addr;
|
|
int sock_fd;
|
|
char *sock_path;
|
|
---
|
|
|
|
This requires the following headers.
|
|
|
|
--- posix headers +=
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
---
|
|
|
|
Opening the server is pretty straight forward.
|
|
|
|
--- open ipc connection
|
|
memset(&sock_addr, 0, sizeof(sock_addr));
|
|
|
|
@{get socket path}
|
|
|
|
unlink(sock_addr.sun_path);
|
|
sock_addr.sun_family = AF_UNIX;
|
|
|
|
if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
|
die("%s: failed to create socket\n", argv0);
|
|
}
|
|
|
|
if (bind(sock_fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) {
|
|
die("%s: failed to bind socket\n", argv0);
|
|
}
|
|
|
|
if (listen(sock_fd, 1) < 0) {
|
|
die("%s: failed to listen to socket\n", argv0);
|
|
}
|
|
---
|
|
|
|
This requires this header file.
|
|
|
|
--- posix headers +=
|
|
#include <unistd.h>
|
|
---
|
|
|
|
@s Get socket path
|
|
|
|
We default to `/tmp/wmaffle.sock` if `WMAFFLE_SOCKET` isn't set.
|
|
|
|
--- get socket path
|
|
sock_path = getenv("WMAFFLE_SOCKET");
|
|
|
|
if (sock_path) {
|
|
strncpy(sock_addr.sun_path, sock_path, sizeof(sock_addr.sun_path));
|
|
} else {
|
|
strncpy(sock_addr.sun_path, "/tmp/wmaffle.sock", sizeof(sock_addr.sun_path));
|
|
}
|
|
---
|
|
|
|
@s Setup signal handlers
|
|
|
|
We don't want out window manager to just exit on us, so we need to setup signal handler.
|
|
|
|
Here is it:
|
|
|
|
--- function definitions +=
|
|
static void
|
|
sig_handler(int sig)
|
|
{
|
|
if (sig == SIGCHLD) {
|
|
signal(sig, sig_handler);
|
|
while (waitpid(-1, 0, WNOHANG) > 0) {
|
|
// EMPTY
|
|
}
|
|
} else if (sig == SIGINT || sig == SIGHUP || sig == SIGTERM) {
|
|
// TODO: Set about to quit to 1
|
|
}
|
|
}
|
|
---
|
|
|
|
Now we only need to register it.
|
|
|
|
--- setup signal handlers
|
|
signal(SIGINT, sig_handler);
|
|
signal(SIGHUP, sig_handler);
|
|
signal(SIGTERM, sig_handler);
|
|
signal(SIGCHLD, sig_handler);
|
|
signal(SIGPIPE, SIG_IGN);
|
|
---
|
|
|
|
Which of course requires this.
|
|
|
|
--- posix headers +=
|
|
#include <signal.h>
|
|
#include <sys/wait.h>
|
|
---
|