wio

a wayland wm stylised after plan9 rio - forked from git.sr.ht/~srcmpwn/wio
git clone git://src.gearsix.net/wio
Log | Files | Refs | Atom | Submodules | README | LICENSE

commit 93bd79df9ab2bc366c2d500b8707161c4039a366
parent 9f73b84c7e61910c923a1644f4d09836e9f9360e
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu, 25 Apr 2019 13:17:45 -0400

Implement "new" menu option

Diffstat:
Acontrib/alacritty.yml | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/server.h | 13+++++++++++--
Minput.c | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mmain.c | 25++++++++++++++++++++++++-
Moutput.c | 45+++++++++++++++++++++++----------------------
Mview.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); }