AtlatestRepositorysigil-wm
1
/* SPDX-License-Identifier: BSD-3-Clause */2
#include <errno.h>3
#include <poll.h>4
#include <signal.h>5
#include <stdbool.h>6
#include <stdint.h>7
#include <stdio.h>8
#include <stdlib.h>9
#include <string.h>10
#include <sys/wait.h>11
#include <time.h>12
#include <unistd.h>13
#include "api.h"15
static pid_t child;16
static void cleanup(void) {17
if (child > 0) { kill(child, SIGKILL); waitpid(child, NULL, 0); }18
}19
static void require(bool ok, const char *message) {20
if (ok) return;21
fprintf(stderr, "popup constraints: %s\n", message);22
exit(2);23
}24
static void send_words(int64_t *words, size_t count) {25
struct wm_message command = {0};26
require(count <= 16, "command size");27
memcpy(command.word, words, count * sizeof(*words));28
require(wm_send(&command) == 1, "command refused");29
}30
#define SEND(...) send_words((int64_t[]){__VA_ARGS__}, sizeof((int64_t[]){__VA_ARGS__}) / sizeof(int64_t))31
static double seconds(void) {32
struct timespec now;33
clock_gettime(CLOCK_MONOTONIC, &now);34
return now.tv_sec + now.tv_nsec / 1e9;35
}36
int main(int argc, char **argv) {37
require(argc == 3, "usage: popup-constraints toplevel|layer 0|1");38
int selected = atoi(argv[2]);39
require(selected == 0 || selected == 1, "output selection");40
atexit(cleanup);41
setvbuf(stdout, NULL, _IOLBF, 0);42
require(wm_options(32, 2000) == 1 && wm_start() == 1, "start");43
int outputs = 0, configured = 0, result = 2;44
int64_t chosen = 0;45
bool running = true, layer_configured = false;46
int64_t admitted_popup = 0;47
double deadline = seconds() + 20;48
while (running && seconds() < deadline) {49
struct pollfd fd = {.fd = wm_event_fd(), .events = POLLIN};50
require(poll(&fd, 1, 50) >= 0 || errno == EINTR, "event poll");51
struct wm_message event;52
while (wm_next(&event)) {53
int64_t *w = event.word;54
switch (w[0]) {55
case 2: {56
if (outputs == selected) chosen = w[1];57
int64_t output[] = {w[1], 1, 100 + outputs * 640, 60, 1000, 0, -1, 640, 480, 60000};58
require(wm_submit(2, ++outputs, output, 10) == 1, "output configuration");59
break;60
}61
case 24:62
require(w[3] == 1, "output rejected");63
if (++configured == 2) {64
require(outputs == 2 && chosen, "two outputs");65
SEND(25, chosen);66
require(setenv("WAYLAND_DISPLAY", wm_socket(), 1) == 0, "socket name");67
child = fork();68
require(child >= 0, "fork");69
if (!child) { execl("build/popup-client", "popup-client", argv[1], NULL); _exit(127); }70
}71
break;72
case 14: SEND(2, w[1], 150, 150); break;73
case 19:74
if (w[14] && !layer_configured) {75
layer_configured = true;76
SEND(24, w[1], chosen, 150, 150);77
}78
break;79
case 11: {80
int64_t plan[] = {1, 1, w[1], 200, w[1], 580 + selected * 640, 350, 150, 150, 1, 1, 0, 0, 0};81
require(wm_submit(1, 10, plan, 14) == 1, "parent placement");82
break;83
}84
case 80:85
if (admitted_popup != w[1]) {86
admitted_popup = w[1];87
SEND(20, w[1], w[3], w[4], w[5], w[6]);88
}89
break;90
case 13: {91
int status;92
require(child > 0 && waitpid(child, &status, 0) == child, "client wait");93
child = 0;94
result = WIFEXITED(status) ? WEXITSTATUS(status) : 2;95
SEND(1);96
break;97
}98
case 7: require(w[2] == 0, "native failure"); running = false; break;99
case 23: require(false, "plan rejected"); break;100
case 98: require(false, "command rejected"); break;101
}102
}103
}104
require(!running, "timeout waiting for client");105
require(wm_join() == 1, "join");106
require(wm_stat(1) == 0 && wm_stat(2) == 0 && wm_stat(3) == 0 && wm_stat(7) == 0, "retained resources");107
printf("POPUP_CONSTRAINTS=%s role=%s output=%d\n", result == 0 ? "PASS" : "FAIL", argv[1], selected);108
return result;109
}