commit 93bd79df9ab2bc366c2d500b8707161c4039a366
parent 9f73b84c7e61910c923a1644f4d09836e9f9360e
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 25 Apr 2019 13:17:45 -0400
Implement "new" menu option
Diffstat:
A | contrib/alacritty.yml | | | 163 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | include/server.h | | | 13 | +++++++++++-- |
M | input.c | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
M | main.c | | | 25 | ++++++++++++++++++++++++- |
M | output.c | | | 45 | +++++++++++++++++++++++---------------------- |
M | view.c | | | 29 | +++++++++++++++++++++++++---- |
6 files changed, 337 insertions(+), 38 deletions(-)
diff --git a/contrib/alacritty.yml b/contrib/alacritty.yml
@@ -0,0 +1,163 @@
+env:
+ TERM: xterm-256color
+window:
+ dimensions:
+ columns: 80
+ lines: 24
+ padding:
+ x: 2
+ y: 2
+ decorations: none
+scrolling:
+ history: 10000
+ multiplier: 3
+ faux_multiplier: 3
+ auto_scroll: false
+tabspaces: 8
+draw_bold_text_with_bright_colors: true
+font:
+ normal:
+ family: DejaVu Sans Mono
+ bold:
+ family: monospace
+ italic:
+ family: monospace
+ size: 12.0
+ offset:
+ x: 0
+ y: 0
+ glyph_offset:
+ x: 0
+ y: 0
+colors:
+ primary:
+ background: '0xfdffea'
+ foreground: '0x020400'
+ cursor:
+ text: '0x000000'
+ cursor: '0x424440'
+ normal:
+ black: '0x0b141a'
+ red: '0xff4053'
+ green: '0x11ab00'
+ yellow: '0xbf8c00'
+ blue: '0x0099ff'
+ magenta: '0x9854ff'
+ cyan: '0x00a5ab'
+ white: '0xffffff'
+ bright:
+ black: '0x0b141a'
+ red: '0xff4053'
+ green: '0x11ab00'
+ yellow: '0xbf8c00'
+ blue: '0x0099ff'
+ magenta: '0x9854ff'
+ cyan: '0x00a5ab'
+ white: '0xffffff'
+
+key_bindings:
+ - { key: V, mods: Control|Shift, action: Paste }
+ - { key: C, mods: Control|Shift, action: Copy }
+ - { key: Paste, action: Paste }
+ - { key: Copy, action: Copy }
+ - { key: Q, mods: Command, action: Quit }
+ - { key: W, mods: Command, action: Quit }
+ - { key: Insert, mods: Shift, action: PasteSelection }
+ - { key: Key0, mods: Control, action: ResetFontSize }
+ - { key: Equals, mods: Control, action: IncreaseFontSize }
+ - { key: Subtract, mods: Control, action: DecreaseFontSize }
+ - { key: Home, chars: "\x1bOH", mode: AppCursor }
+ - { key: Home, chars: "\x1b[H", mode: ~AppCursor }
+ - { key: End, chars: "\x1bOF", mode: AppCursor }
+ - { key: End, chars: "\x1b[F", mode: ~AppCursor }
+ - { key: PageUp, mods: Shift, chars: "\x1b[5;2~" }
+ - { key: PageUp, mods: Control, chars: "\x1b[5;5~" }
+ - { key: PageUp, chars: "\x1b[5~" }
+ - { key: PageDown, mods: Shift, chars: "\x1b[6;2~" }
+ - { key: PageDown, mods: Control, chars: "\x1b[6;5~" }
+ - { key: PageDown, chars: "\x1b[6~" }
+ - { key: Tab, mods: Shift, chars: "\x1b[Z" }
+ - { key: Back, chars: "\x7f" }
+ - { key: Back, mods: Alt, chars: "\x1b\x7f" }
+ - { key: Insert, chars: "\x1b[2~" }
+ - { key: Delete, chars: "\x1b[3~" }
+ - { key: Left, mods: Shift, chars: "\x1b[1;2D" }
+ - { key: Left, mods: Control, chars: "\x1b[1;5D" }
+ - { key: Left, mods: Alt, chars: "\x1b[1;3D" }
+ - { key: Left, chars: "\x1b[D", mode: ~AppCursor }
+ - { key: Left, chars: "\x1bOD", mode: AppCursor }
+ - { key: Right, mods: Shift, chars: "\x1b[1;2C" }
+ - { key: Right, mods: Control, chars: "\x1b[1;5C" }
+ - { key: Right, mods: Alt, chars: "\x1b[1;3C" }
+ - { key: Right, chars: "\x1b[C", mode: ~AppCursor }
+ - { key: Right, chars: "\x1bOC", mode: AppCursor }
+ - { key: Up, mods: Shift, chars: "\x1b[1;2A" }
+ - { key: Up, mods: Control, chars: "\x1b[1;5A" }
+ - { key: Up, mods: Alt, chars: "\x1b[1;3A" }
+ - { key: Up, chars: "\x1b[A", mode: ~AppCursor }
+ - { key: Up, chars: "\x1bOA", mode: AppCursor }
+ - { key: Down, mods: Shift, chars: "\x1b[1;2B" }
+ - { key: Down, mods: Control, chars: "\x1b[1;5B" }
+ - { key: Down, mods: Alt, chars: "\x1b[1;3B" }
+ - { key: Down, chars: "\x1b[B", mode: ~AppCursor }
+ - { key: Down, chars: "\x1bOB", mode: AppCursor }
+ - { key: F1, chars: "\x1bOP" }
+ - { key: F2, chars: "\x1bOQ" }
+ - { key: F3, chars: "\x1bOR" }
+ - { key: F4, chars: "\x1bOS" }
+ - { key: F5, chars: "\x1b[15~" }
+ - { key: F6, chars: "\x1b[17~" }
+ - { key: F7, chars: "\x1b[18~" }
+ - { key: F8, chars: "\x1b[19~" }
+ - { key: F9, chars: "\x1b[20~" }
+ - { key: F10, chars: "\x1b[21~" }
+ - { key: F11, chars: "\x1b[23~" }
+ - { key: F12, chars: "\x1b[24~" }
+ - { key: F1, mods: Shift, chars: "\x1b[1;2P" }
+ - { key: F2, mods: Shift, chars: "\x1b[1;2Q" }
+ - { key: F3, mods: Shift, chars: "\x1b[1;2R" }
+ - { key: F4, mods: Shift, chars: "\x1b[1;2S" }
+ - { key: F5, mods: Shift, chars: "\x1b[15;2~" }
+ - { key: F6, mods: Shift, chars: "\x1b[17;2~" }
+ - { key: F7, mods: Shift, chars: "\x1b[18;2~" }
+ - { key: F8, mods: Shift, chars: "\x1b[19;2~" }
+ - { key: F9, mods: Shift, chars: "\x1b[20;2~" }
+ - { key: F10, mods: Shift, chars: "\x1b[21;2~" }
+ - { key: F11, mods: Shift, chars: "\x1b[23;2~" }
+ - { key: F12, mods: Shift, chars: "\x1b[24;2~" }
+ - { key: F1, mods: Control, chars: "\x1b[1;5P" }
+ - { key: F2, mods: Control, chars: "\x1b[1;5Q" }
+ - { key: F3, mods: Control, chars: "\x1b[1;5R" }
+ - { key: F4, mods: Control, chars: "\x1b[1;5S" }
+ - { key: F5, mods: Control, chars: "\x1b[15;5~" }
+ - { key: F6, mods: Control, chars: "\x1b[17;5~" }
+ - { key: F7, mods: Control, chars: "\x1b[18;5~" }
+ - { key: F8, mods: Control, chars: "\x1b[19;5~" }
+ - { key: F9, mods: Control, chars: "\x1b[20;5~" }
+ - { key: F10, mods: Control, chars: "\x1b[21;5~" }
+ - { key: F11, mods: Control, chars: "\x1b[23;5~" }
+ - { key: F12, mods: Control, chars: "\x1b[24;5~" }
+ - { key: F1, mods: Alt, chars: "\x1b[1;6P" }
+ - { key: F2, mods: Alt, chars: "\x1b[1;6Q" }
+ - { key: F3, mods: Alt, chars: "\x1b[1;6R" }
+ - { key: F4, mods: Alt, chars: "\x1b[1;6S" }
+ - { key: F5, mods: Alt, chars: "\x1b[15;6~" }
+ - { key: F6, mods: Alt, chars: "\x1b[17;6~" }
+ - { key: F7, mods: Alt, chars: "\x1b[18;6~" }
+ - { key: F8, mods: Alt, chars: "\x1b[19;6~" }
+ - { key: F9, mods: Alt, chars: "\x1b[20;6~" }
+ - { key: F10, mods: Alt, chars: "\x1b[21;6~" }
+ - { key: F11, mods: Alt, chars: "\x1b[23;6~" }
+ - { key: F12, mods: Alt, chars: "\x1b[24;6~" }
+ - { key: F1, mods: Super, chars: "\x1b[1;3P" }
+ - { key: F2, mods: Super, chars: "\x1b[1;3Q" }
+ - { key: F3, mods: Super, chars: "\x1b[1;3R" }
+ - { key: F4, mods: Super, chars: "\x1b[1;3S" }
+ - { key: F5, mods: Super, chars: "\x1b[15;3~" }
+ - { key: F6, mods: Super, chars: "\x1b[17;3~" }
+ - { key: F7, mods: Super, chars: "\x1b[18;3~" }
+ - { key: F8, mods: Super, chars: "\x1b[19;3~" }
+ - { key: F9, mods: Super, chars: "\x1b[20;3~" }
+ - { key: F10, mods: Super, chars: "\x1b[21;3~" }
+ - { key: F11, mods: Super, chars: "\x1b[23;3~" }
+ - { key: F12, mods: Super, chars: "\x1b[24;3~" }
diff --git a/include/server.h b/include/server.h
@@ -1,8 +1,10 @@
#ifndef _WIO_SERVER_H
#define _WIO_SERVER_H
+#include <signal.h>
#include <wayland-server.h>
#include <wlr/backend.h>
#include <wlr/render/wlr_renderer.h>
+#include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_keyboard.h>
@@ -31,6 +33,8 @@ enum wio_input_state {
struct wio_server {
struct wl_display *wl_display;
+ const char *cage, *term;
+
struct wlr_backend *backend;
struct wlr_cursor *cursor;
struct wlr_output_layout *output_layout;
@@ -44,6 +48,7 @@ struct wio_server {
struct wl_list pointers;
struct wl_list keyboards;
struct wl_list views;
+ struct wl_list new_views;
struct wl_listener new_output;
struct wl_listener new_input;
@@ -67,8 +72,6 @@ struct wio_server {
struct {
int sx, sy;
struct wio_view *view;
- struct wlr_surface *cursor;
- int hotspot_x, hotspot_y;
} interactive;
enum wio_input_state input_state;
@@ -93,6 +96,12 @@ struct wio_keyboard {
struct wl_listener key;
};
+struct wio_new_view {
+ pid_t pid;
+ struct wlr_box box;
+ struct wl_list link;
+};
+
void server_new_output(struct wl_listener *listener, void *data);
void server_new_input(struct wl_listener *listener, void *data);
void server_cursor_motion(struct wl_listener *listener, void *data);
diff --git a/input.c b/input.c
@@ -1,11 +1,16 @@
+#define _POSIX_C_SOURCE 200811L
+#include <signal.h>
#include <stdlib.h>
+#include <sys/wait.h>
#include <linux/input-event-codes.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_pointer.h>
+#include <wlr/util/log.h>
#include <xkbcommon/xkbcommon.h>
+#include <unistd.h>
#include "server.h"
#include "view.h"
@@ -100,10 +105,12 @@ static void process_cursor_motion(struct wio_server *server, uint32_t time) {
"grabbing", server->cursor);
break;
case INPUT_STATE_RESIZE_START:
+ case INPUT_STATE_NEW_START:
wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
"top_left_corner", server->cursor);
break;
case INPUT_STATE_RESIZE_END:
+ case INPUT_STATE_NEW_END:
wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
"bottom_right_corner", server->cursor);
break;
@@ -146,6 +153,11 @@ static void menu_handle_button(
struct wio_server *server, struct wlr_event_pointer_button *event) {
server->menu.x = server->menu.y = -1;
switch (server->menu.selected) {
+ case 0:
+ server->input_state = INPUT_STATE_NEW_START;
+ wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
+ "top_left_corner", server->cursor);
+ break;
case 1:
server->input_state = INPUT_STATE_RESIZE_SELECT;
wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
@@ -182,12 +194,74 @@ static void view_begin_interactive(struct wio_view *view,
static void view_end_interactive(struct wio_server *server) {
server->input_state = INPUT_STATE_NONE;
server->interactive.view = NULL;
- if (server->interactive.cursor) {
- wlr_cursor_set_surface(server->cursor, server->interactive.cursor,
- server->interactive.hotspot_x, server->interactive.hotspot_y);
- } else {
- wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
- "left_ptr", server->cursor);
+ // TODO: Restore previous pointer?
+ wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
+ "left_ptr", server->cursor);
+}
+
+static void new_view(struct wio_server *server) {
+ int x1 = server->interactive.sx, x2 = server->cursor->x;
+ int y1 = server->interactive.sy, y2 = server->cursor->y;
+ if (x2 < x1) {
+ int _ = x1;
+ x1 = x2;
+ x2 = _;
+ }
+ if (y2 < y1) {
+ int _ = y1;
+ y1 = y2;
+ y2 = _;
+ }
+ struct wio_new_view *view = calloc(1, sizeof(struct wio_new_view));
+ view->box.x = x1 + window_border;
+ view->box.y = y1 + window_border;
+ view->box.width = x2 - x1;
+ view->box.height = y2 - y1;
+ int fd[2];
+ if (pipe(fd) != 0) {
+ wlr_log(WLR_ERROR, "Unable to create pipe for fork");
+ return;
+ }
+ char cmd[1024];
+ if (snprintf(cmd, sizeof(cmd), "%s -- %s",
+ server->cage, server->term) >= (int)sizeof(cmd)) {
+ fprintf(stderr, "New view command truncated\n");
+ return;
+ }
+ pid_t pid, child;
+ if ((pid = fork()) == 0) {
+ setsid();
+ sigset_t set;
+ sigemptyset(&set);
+ sigprocmask(SIG_SETMASK, &set, NULL);
+ close(fd[0]);
+ if ((child = fork()) == 0) {
+ close(fd[1]);
+ execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL);
+ _exit(0);
+ }
+ ssize_t s = 0;
+ while ((size_t)s < sizeof(pid_t)) {
+ s += write(fd[1], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
+ }
+ close(fd[1]);
+ _exit(0); // Close child process
+ } else if (pid < 0) {
+ close(fd[0]);
+ close(fd[1]);
+ wlr_log(WLR_ERROR, "fork failed");
+ return;
+ }
+ close(fd[1]); // close write
+ ssize_t s = 0;
+ while ((size_t)s < sizeof(pid_t)) {
+ s += read(fd[0], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
+ }
+ close(fd[0]);
+ waitpid(pid, NULL, 0);
+ if (child > 0) {
+ view->pid = child;
+ wl_list_insert(&server->new_views, &view->link);
}
}
@@ -220,6 +294,17 @@ static void handle_button_internal(
}
}
break;
+ case INPUT_STATE_NEW_START:
+ if (event->state == WLR_BUTTON_PRESSED) {
+ server->interactive.sx = server->cursor->x;
+ server->interactive.sy = server->cursor->y;
+ server->input_state = INPUT_STATE_NEW_END;
+ }
+ break;
+ case INPUT_STATE_NEW_END:
+ new_view(server);
+ view_end_interactive(server);
+ break;
case INPUT_STATE_RESIZE_SELECT:
if (event->state == WLR_BUTTON_PRESSED) {
double sx, sy;
@@ -349,8 +434,5 @@ void seat_request_cursor(struct wl_listener *listener, void *data) {
&& server->input_state == INPUT_STATE_NONE) {
wlr_cursor_set_surface(server->cursor, event->surface,
event->hotspot_x, event->hotspot_y);
- server->interactive.cursor = event->surface;
- server->interactive.hotspot_x = event->hotspot_x;
- server->interactive.hotspot_y = event->hotspot_y;
}
}
diff --git a/main.c b/main.c
@@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200112L
#include <cairo/cairo.h>
+#include <getopt.h>
#include <stdlib.h>
#include <time.h>
#include <wayland-server.h>
@@ -73,9 +74,29 @@ static void gen_menu_textures(struct wio_server *server) {
int main(int argc, char **argv) {
struct wio_server server = { 0 };
-
+ server.cage = "cage -d";
+ server.term = "alacritty";
wlr_log_init(WLR_DEBUG, NULL);
+ int c;
+ while ((c = getopt(argc, argv, "c:t:h")) != -1) {
+ switch (c) {
+ case 'c':
+ server.cage = optarg;
+ break;
+ case 't':
+ server.term = optarg;
+ break;
+ case 'h':
+ printf("Usage: %s [-t terminal command] [-c cage command]\n",
+ argv[0]);
+ break;
+ default:
+ fprintf(stderr, "Unrecognized option %c\n", c);
+ return 1;
+ }
+ }
+
server.wl_display = wl_display_create();
server.backend = wlr_backend_autocreate(server.wl_display, NULL);
server.renderer = wlr_backend_get_renderer(server.backend);
@@ -134,6 +155,8 @@ int main(int argc, char **argv) {
wl_signal_add(&server.xdg_shell->events.new_surface,
&server.new_xdg_surface);
+ wl_list_init(&server.new_views);
+
server.menu.x = server.menu.y = -1;
gen_menu_textures(&server);
server.input_state = INPUT_STATE_NONE;
diff --git a/output.c b/output.c
@@ -69,8 +69,8 @@ static void render_menu(struct wio_output *output) {
text_height += border * 2 - margin;
double ox = 0, oy = 0;
- //wlr_output_layout_output_coords(
- // view->server->output_layout, output->wlr_output, &ox, &oy);
+ wlr_output_layout_output_coords(
+ server->output_layout, output->wlr_output, &ox, &oy);
ox += server->menu.x, oy += server->menu.y;
int scale = output->wlr_output->scale;
@@ -98,6 +98,7 @@ static void render_menu(struct wio_output *output) {
wlr_render_rect(renderer, &bg_box, menu_border,
output->wlr_output->transform_matrix);
+ server->menu.selected = -1;
ox += margin;
oy += margin;
for (size_t i = 0; i < ntextures; ++i) {
@@ -137,7 +138,7 @@ static void render_view_border(struct wlr_renderer *renderer,
struct wio_output *output, struct wio_view *view,
int x, int y, int width, int height) {
float color[4];
- if (view->xdg_surface->toplevel->current.activated) {
+ if (!view || view->xdg_surface->toplevel->current.activated) {
memcpy(color, active_border, sizeof(color));
} else {
memcpy(color, inactive_border, sizeof(color));
@@ -208,25 +209,25 @@ static void output_frame(struct wl_listener *listener, void *data) {
view->xdg_surface->surface->current.height);
wlr_xdg_surface_for_each_surface(view->xdg_surface,
render_surface, &rdata);
- if (server->interactive.view == view) {
- switch (server->input_state) {
- case INPUT_STATE_MOVE:
- render_view_border(renderer, output, view,
- server->cursor->x - server->interactive.sx,
- server->cursor->y - server->interactive.sy,
- view->xdg_surface->surface->current.width,
- view->xdg_surface->surface->current.height);
- break;
- case INPUT_STATE_RESIZE_END:
- render_view_border(renderer, output, view,
- server->interactive.sx, server->interactive.sy,
- server->cursor->x - server->interactive.sx,
- server->cursor->y - server->interactive.sy);
- break;
- default:
- break;
- }
- }
+ }
+ switch (server->input_state) {
+ case INPUT_STATE_MOVE:;
+ struct wio_view *view = server->interactive.view;
+ render_view_border(renderer, output, view,
+ server->cursor->x - server->interactive.sx,
+ server->cursor->y - server->interactive.sy,
+ view->xdg_surface->surface->current.width,
+ view->xdg_surface->surface->current.height);
+ break;
+ case INPUT_STATE_NEW_END:
+ case INPUT_STATE_RESIZE_END:
+ render_view_border(renderer, output, NULL,
+ server->interactive.sx, server->interactive.sy,
+ server->cursor->x - server->interactive.sx,
+ server->cursor->y - server->interactive.sy);
+ break;
+ default:
+ break;
}
if (server->menu.x != -1 && server->menu.y != -1) {
diff --git a/view.c b/view.c
@@ -15,10 +15,12 @@ static void xdg_surface_map(struct wl_listener *listener, void *data) {
server->output_layout, server->cursor->x, server->cursor->y);
struct wlr_output_layout_output *layout = wlr_output_layout_get(
server->output_layout, output);
- view->x = layout->x +
- (output->width / 2 - view->xdg_surface->surface->current.width / 2);
- view->y = layout->y +
- (output->height / 2 - view->xdg_surface->surface->current.height / 2);
+ if (view->x == -1 || view->y == -1) {
+ view->x = layout->x +
+ (output->width / 2 - view->xdg_surface->surface->current.width / 2);
+ view->y = layout->y +
+ (output->height / 2 - view->xdg_surface->surface->current.height / 2);
+ }
}
static void xdg_surface_destroy(struct wl_listener *listener, void *data) {
@@ -38,6 +40,7 @@ void server_new_xdg_surface(struct wl_listener *listener, void *data) {
struct wio_view *view = calloc(1, sizeof(struct wio_view));
view->server = server;
view->xdg_surface = xdg_surface;
+ view->x = view->y = -1;
view->destroy.notify = xdg_surface_destroy;
wl_signal_add(&xdg_surface->events.destroy, &view->destroy);
@@ -47,6 +50,24 @@ void server_new_xdg_surface(struct wl_listener *listener, void *data) {
wlr_xdg_toplevel_set_tiled(view->xdg_surface,
WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
+ struct wl_client *client = wl_resource_get_client(xdg_surface->resource);
+ wl_client_get_credentials(client, &pid, &uid, &gid);
+ struct wio_new_view *new_view;
+ wl_list_for_each(new_view, &server->new_views, link) {
+ if (new_view->pid != pid) {
+ continue;
+ }
+ view->x = new_view->box.x;
+ view->y = new_view->box.y;
+ wlr_xdg_toplevel_set_size(xdg_surface,
+ new_view->box.width, new_view->box.height);
+ wl_list_remove(&new_view->link);
+ break;
+ }
+
wl_list_insert(&server->views, &view->link);
}