Commit c15fc8a82f5e3d8ad28f1d46156473ff80cd2475 Parent: d4ae291eac1e78e2cd6dfa79a52ee0995957757e Author: mcol <mcol@posteo.net> Date: 2021-02-04 21:55:20 +0000 Committer: mcol <mcol@posteo.net> Committed: 2021-02-04 21:55:20 +0000 Add scratchpad windows
wimp.conf Modified
@@ -85,6 +85,9 @@ # The line after 'exec' is executed by /bin/sh bind Return exec gnome-terminal +# And replace with 'exec' with 'scratchpad' and its window will be sticky +bind Ctrl e scratchpad footclient mutt + # These two actions can be used to mark and go to set positions. Each one, once # pressed, waits for the next key press and uses that as the 'mark', e.g. # hitting 'mod + m' then 'a' will save the current position, then hitting 'mod
src/types.h Modified
@@ -106,8 +106,10 @@ struct wlr_box grab_geobox; uint32_t resize_edges; double zoom_min, zoom_max; - bool vt_switching; + + struct wl_list scratchpads; + pid_t scratchpad_waiting; }; extern struct wimp wimp; @@ -122,6 +124,7 @@ struct wl_listener request_resize_listener; struct wl_listener request_fullscreen_listener; double x, y; + bool is_scratchpad; }; struct output { @@ -208,4 +211,13 @@ LEFT = 1 << 3, }; +struct scratchpad { + struct wl_list link; + char *command; + int id; + pid_t pid; + struct view *view; + bool is_mapped; +}; + #endif
src/shell.c Modified
@@ -5,6 +5,19 @@ #include "types.h" +static struct scratchpad *scratchpad_from_view(struct view *view) { + struct scratchpad *scratchpad; + + wl_list_for_each(scratchpad, &wimp.scratchpads, link) { + if (view == scratchpad->view) { + return scratchpad; + } + } + + return NULL; +} + + void unmap_view(struct view *view) { wl_signal_emit(&view->surface->events.unmap, view); } @@ -31,10 +44,19 @@ wlr_xdg_toplevel_set_activated(previous, false); } struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat); - /* Move the view to the front */ - wl_list_remove(&view->link); - wl_list_insert(&wimp.current_desk->views, &view->link); - /* Activate the new surface */ + + if (view->is_scratchpad) { + struct scratchpad *scratchpad; + wl_list_for_each(scratchpad, &wimp.scratchpads, link) { + if (scratchpad->view == view) { + scratchpad->is_mapped = true; + } + } + } else { + wl_list_remove(&view->link); + wl_list_insert(&wimp.current_desk->views, &view->link); + } + wlr_xdg_toplevel_set_activated(view->surface, true); wlr_seat_keyboard_notify_enter( seat, view->surface->surface, keyboard->keycodes, @@ -122,17 +144,33 @@ static void on_map(struct wl_listener *listener, void *data) { struct view *view = wl_container_of(listener, view, map_listener); - if (wimp.can_steal_focus) + + if (view->is_scratchpad) { + struct scratchpad *scratchpad = scratchpad_from_view(view); + scratchpad->is_mapped = true; + } + + if (wimp.can_steal_focus) { focus_view(view, view->surface->surface); + } } static void on_unmap(struct wl_listener *listener, void *data) { struct view *view = wl_container_of(listener, view, unmap_listener); - if (wimp.can_steal_focus) { + + if (view->is_scratchpad) { + struct scratchpad *scratchpad = scratchpad_from_view(view); + scratchpad->is_mapped = false; + } else { wl_list_remove(&view->link); wl_list_insert(wimp.current_desk->views.prev, &view->link); - struct view *next_view = wl_container_of(wimp.current_desk->views.next, view, link); - focus_view(next_view, next_view->surface->surface); + } + + if (wimp.can_steal_focus) { + if (!wl_list_empty(&wimp.current_desk->views)) { + struct view *next_view = wl_container_of(wimp.current_desk->views.next, view, link); + focus_view(next_view, next_view->surface->surface); + } } } @@ -142,7 +180,15 @@ if (wimp.current_desk->fullscreened == view->surface) { wimp.current_desk->fullscreened = NULL; } - wl_list_remove(&view->link); + + if (view->is_scratchpad) { + struct scratchpad *scratchpad = scratchpad_from_view(view); + scratchpad->is_mapped = false; + scratchpad->view = NULL; + } else { + wl_list_remove(&view->link); + } + free(view); } @@ -215,6 +261,23 @@ view->request_fullscreen_listener.notify = on_request_fullscreen; wl_signal_add(&toplevel->events.request_fullscreen, &view->request_fullscreen_listener); + if (wimp.scratchpad_waiting) { + pid_t pid; + wl_client_get_credentials(surface->client->client, &pid, NULL, NULL); + struct scratchpad *scratchpad; + wl_list_for_each(scratchpad, &wimp.scratchpads, link) { + if (scratchpad->pid == pid) { + scratchpad->view = view; + view->is_scratchpad = true; + view->x = 50; + view->y = 50; + map_view(view); + return; + } + } + } + + view->is_scratchpad = false; view->x = wimp.current_desk->border_width; view->y = wimp.current_desk->border_width; wl_list_insert(&wimp.current_desk->views, &view->link);
src/output.c Modified
@@ -140,7 +140,7 @@ // paint clients struct view *view; - struct view *focussed = wl_container_of(wimp.current_desk->views.next, focussed, link); + struct wlr_surface *focussed = wimp.seat->keyboard_state.focused_surface; int border_width = wimp.current_desk->border_width; wl_list_for_each_reverse(view, &desk->views, link) { rdata.x = view->x - ox / zoom; @@ -154,14 +154,27 @@ } rdata.x = view->x + ox; rdata.y = view->y + oy; - rdata.is_focussed = (view == focussed); + rdata.is_focussed = (view->surface->surface == focussed); rdata.bordered = view->surface->surface; wlr_xdg_surface_for_each_surface(view->surface, render_surface, &rdata); } + rdata.zoom = 1; + + struct scratchpad *scratchpad; + wl_list_for_each(scratchpad, &wimp.scratchpads, link) { + if (scratchpad->is_mapped) { + view = scratchpad->view; + rdata.x = view->x; + rdata.y = view->y; + rdata.is_focussed = (view->surface->surface == focussed); + rdata.bordered = view->surface->surface; + wlr_xdg_surface_for_each_surface(view->surface, render_surface, &rdata); + } + } + rdata.bordered = NULL; rdata.is_focussed = false; - rdata.zoom = 1; // paint top and overlay layers wl_list_for_each(lview, &output->layer_views[ZWLR_LAYER_SHELL_V1_LAYER_TOP], link) {
src/main.c Modified
@@ -37,6 +37,7 @@ .mark_indicator.box.height = 25, .mark_indicator.box.x = 0, .mark_indicator.box.y = 0, + .scratchpad_waiting = false, }; @@ -116,6 +117,14 @@ free(output); }; + struct scratchpad *scratchpad, *tscratchpad; + wl_list_for_each_safe(scratchpad, tscratchpad, &wimp.scratchpads, link) { + wl_list_remove(&scratchpad->link); + free(scratchpad->view); + free(scratchpad->command); + free(scratchpad); + }; + struct keyboard *keyboard, *tkeyboard; wl_list_for_each_safe(keyboard, tkeyboard, &wimp.keyboards, link) { wl_list_remove(&keyboard->link); @@ -182,6 +191,7 @@ wl_list_init(&wimp.key_bindings); wl_list_init(&wimp.mouse_bindings); wl_list_init(&wimp.marks); + wl_list_init(&wimp.scratchpads); // configure locate_config();
src/cursor.c Modified
@@ -75,6 +75,24 @@ } } + // scratchpads + struct scratchpad *scratchpad; + wl_list_for_each(scratchpad, &wimp.scratchpads, link) { + if (scratchpad->is_mapped) { + view = scratchpad->view; + tsurface = wlr_xdg_surface_surface_at( + view->surface, x - view->x, y - view->y, &tsx, &tsy + ); + if (tsurface) { + *sx = tsx; + *sy = tsy; + *surface = tsurface; + *is_layer = false; + return view; + } + } + } + // clients double zx = x / wimp.current_desk->zoom; double zy = y / wimp.current_desk->zoom;
src/config.c Modified
@@ -138,6 +138,26 @@ } +static int scratchpad_id = 0; + + +static void scratchpad_handler(struct binding *kb, char *data) { + if (!data) { + return; + } + struct scratchpad *scratchpad = calloc(1, sizeof(struct scratchpad)); + wl_list_insert(wimp.scratchpads.prev, &scratchpad->link); + scratchpad->command = strdup(data); + scratchpad->id = scratchpad_id; + scratchpad->view = NULL; + scratchpad->is_mapped = false; + + kb->data = calloc(1, sizeof(int)); + *(int *)(kb->data) = scratchpad_id; + scratchpad_id++; +} + + static struct { const char *name; const action action; @@ -160,6 +180,7 @@ { "maximize", &maximize, NULL }, { "reload_config", &reload_config, NULL }, { "send_to_desk", &send_to_desk, &str_handler }, + { "scratchpad", &scratchpad, &scratchpad_handler }, };
src/action.h Modified
@@ -26,5 +26,6 @@ void maximize(void *data); void reload_config(void *data); void send_to_desk(void *data); +void scratchpad(void *data); #endif
src/action.c Modified
@@ -23,7 +23,7 @@ exit(EXIT_FAILURE); } } else if (pid < 0) { - wlr_log(WLR_ERROR, "Failed to execute: %s", data); + wlr_log(WLR_ERROR, "Failed to fork for exec command."); } else { wlr_log(WLR_DEBUG, "Executing: %s", data); } @@ -400,3 +400,37 @@ unfullscreen(); view_to_desk(view, index); } + + +void scratchpad(void *data) { + int id = *(int *)data; + struct scratchpad *scratchpad; + + wl_list_for_each(scratchpad, &wimp.scratchpads, link) { + if (scratchpad->id == id) { + break; + } + } + + if (scratchpad->view) { + if (scratchpad->is_mapped) { + unmap_view(scratchpad->view); + } else { + map_view(scratchpad->view); + } + return; + } + + wimp.scratchpad_waiting = true; + + scratchpad->pid = fork(); + if (scratchpad->pid == 0) { + execl("/bin/sh", "/bin/sh", "-c", scratchpad->command, (void *)NULL); + exit(EXIT_FAILURE); + } else if (scratchpad->pid < 0) { + wlr_log(WLR_ERROR, "Failed to fork for scratchpad."); + wimp.scratchpad_waiting = false; + } else { + wlr_log(WLR_DEBUG, "Launching scratchpad: %s", scratchpad->command); + } +}