diff --git a/cagebreak.c b/cagebreak.c index 4437331..7ebf905 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -369,6 +370,7 @@ main(int argc, char *argv[]) { server.event_loop = event_loop; backend = wlr_backend_autocreate(server.wl_display); + server.headless_backend=wlr_headless_backend_create(server.wl_display); if(!backend) { wlr_log(WLR_ERROR, "Unable to create the wlroots backend"); ret = 1; diff --git a/keybinding.c b/keybinding.c index eaf2ae7..61aceeb 100644 --- a/keybinding.c +++ b/keybinding.c @@ -249,8 +249,7 @@ swap_tile(struct cg_tile *tile, "{\"event_name\":\"swap_tile\",\"tile_id\":%d,\"swap_" "tile_id\":%d,\"workspace\":%d,\"output\":\"%s\",\"output_id\":%d}", tile->id, swap_tile->id, tile->workspace->num + 1, - tile->workspace->output->wlr_output->name, - output_get_num(tile->workspace->output)); + tile->workspace->output->name, output_get_num(tile->workspace->output)); } void @@ -400,8 +399,7 @@ resize(struct cg_tile *tile, const struct cg_tile *parent, int coord_offset, "\"workspace\":%d,\"output\":\"%s\",\"output_id\":%d}", tile->id, old_x, old_y, old_height, old_width, tile->tile.x, tile->tile.y, tile->tile.height, tile->tile.width, - tile->workspace->num + 1, - tile->workspace->output->wlr_output->name, + tile->workspace->num + 1, tile->workspace->output->name, output_get_num(tile->workspace->output)); } @@ -456,18 +454,18 @@ resize_vertical(struct cg_tile *tile, struct cg_tile *parent, int y_offset, void resize_tile(struct cg_server *server, int hpixs, int vpixs) { struct cg_output *output = server->curr_output; - struct wlr_box output_box; - wlr_output_layout_get_box(output->server->output_layout, output->wlr_output, - &output_box); struct cg_tile *focused = output->workspaces[output->curr_workspace]->focused_tile; /* First do the horizontal adjustment */ - if(hpixs != 0 && focused->tile.width < output_box.width && - is_between_strict(0, output_box.width, focused->tile.width + hpixs)) { + if(hpixs != 0 && + focused->tile.width < output_get_layout_box(output).width && + is_between_strict(0, output_get_layout_box(output).width, + focused->tile.width + hpixs)) { int x_offset = 0; /* In case we are on the total right, move the left edge of the tile */ - if(focused->tile.x + focused->tile.width == output_box.width) { + if(focused->tile.x + focused->tile.width == + output_get_layout_box(output).width) { x_offset = -hpixs; } bool resize_allowed = @@ -477,10 +475,13 @@ resize_tile(struct cg_server *server, int hpixs, int vpixs) { } } /* Repeat for vertical */ - if(vpixs != 0 && focused->tile.height < output_box.height && - is_between_strict(0, output_box.height, focused->tile.height + vpixs)) { + if(vpixs != 0 && + focused->tile.height < output_get_layout_box(output).height && + is_between_strict(0, output_get_layout_box(output).height, + focused->tile.height + vpixs)) { int y_offset = 0; - if(focused->tile.y + focused->tile.height == output_box.height) { + if(focused->tile.y + focused->tile.height == + output_get_layout_box(output).height) { y_offset = -vpixs; } bool resize_allowed = @@ -501,7 +502,7 @@ keybinding_workspace_fullscreen(struct cg_server *server) { "\"workspace\":%d,\"output\":\"%s\",\"output_id\":%d}", output->workspaces[output->curr_workspace]->focused_tile->id, output->workspaces[output->curr_workspace]->num + 1, - output->wlr_output->name, output_get_num(output)); + output->name, output_get_num(output)); } // Switch to a differerent virtual terminal @@ -595,8 +596,8 @@ keybinding_split_output(struct cg_output *output, bool vertical) { "{\"event_name\":\"split\",\"tile_id\":%d,\"new_tile_id\":%d," "\"workspace\":%d,\"output\":\"%s\",\"output_id\":%d,\"vertical\":%d}", curr_workspace->focused_tile->id, new_tile->id, curr_workspace->num + 1, - curr_workspace->output->wlr_output->name, - output_get_num(curr_workspace->output), vertical); + curr_workspace->output->name, output_get_num(curr_workspace->output), + vertical); } static void @@ -614,8 +615,7 @@ keybinding_close_view(struct cg_view *view) { outp->server, "{\"event_name\":\"close\",\"view_id\":%d,\"view_pid\":%d,\"tile_id\":" "%d,\"workspace\":%d,\"output\":\"%s\",\"output_id\":%d}", - view_id, view_pid, tile_id, ws + 1, outp->wlr_output->name, - output_get_num(outp)); + view_id, view_pid, tile_id, ws + 1, outp->name, output_get_num(outp)); } static void @@ -670,8 +670,8 @@ keybinding_cycle_outputs(struct cg_server *server, bool reverse, "{\"event_name\":\"cycle_outputs\",\"old_output\":\"%s\",\"old_" "output_id\":%d," "\"new_output\":\"%s\",\"new_output_id\":%d,\"reverse\":%d}", - old_output->wlr_output->name, output_get_num(old_output), - output->wlr_output->name, output_get_num(output), reverse); + old_output->name, output_get_num(old_output), output->name, + output_get_num(output), reverse); } } @@ -721,7 +721,7 @@ keybinding_cycle_views(struct cg_server *server, bool reverse, bool ipc) { curr_id, curr_pid, next_view == NULL ? -1 : (int)next_view->id, next_view == NULL ? -1 : (int)next_view->impl->get_pid(next_view), next_view->tile->id, curr_workspace->num + 1, - curr_workspace->output->wlr_output->name, + curr_workspace->output->name, output_get_num(curr_workspace->output)); } } @@ -744,7 +744,7 @@ keybinding_focus_tile(struct cg_server *server, uint32_t tile_id) { "{\"event_name\":\"focus_tile\",\"old_tile_id\":%d,\"new_tile_" "id\":%d,\"workspace\":%d,\"output\":\"%s\",\"output_id\":%d}", old_tile->id, workspace->focused_tile->id, workspace->num + 1, - output->wlr_output->name, output_get_num(output)); + output->name, output_get_num(output)); break; } } @@ -778,8 +778,7 @@ keybinding_switch_ws(struct cg_server *server, uint32_t ws) { ipc_send_event(output->server, "{\"event_name\":\"switch_ws\",\"old_workspace\":%d," "\"new_workspace\":%d,\"output\":\"%s\",\"output_id\":%d}", - old_ws + 1, ws + 1, output->wlr_output->name, - output_get_num(output)); + old_ws + 1, ws + 1, output->name, output_get_num(output)); return 0; } @@ -1019,19 +1018,17 @@ print_output(struct cg_output *outp) { struct dyn_str outp_str; outp_str.len = 0; outp_str.cur_pos = 0; - uint32_t nmemb = 8; - struct wlr_box outp_box; - wlr_output_layout_get_box(outp->server->output_layout, outp->wlr_output, - &outp_box); + uint32_t nmemb = 9; outp_str.str_arr = calloc(nmemb, sizeof(char *)); - print_str(&outp_str, "\"%s\": {\n", outp->wlr_output->name); + print_str(&outp_str, "\"%s\": {\n", outp->name); print_str(&outp_str, "\"priority\": %d,\n", outp->priority); - print_str(&outp_str, "\"coords\": {\"x\":%d,\"y\":%d},\n", outp_box.x, - outp_box.y); + print_str(&outp_str, "\"coords\": {\"x\":%d,\"y\":%d},\n", + output_get_layout_box(outp).x, output_get_layout_box(outp).y); print_str(&outp_str, "\"size\": {\"width\":%d,\"height\":%d},\n", outp->wlr_output->width, outp->wlr_output->height); print_str(&outp_str, "\"refresh_rate\": %f,\n", (float)outp->wlr_output->refresh / 1000.0); + print_str(&outp_str, "\"permanent\": %d,\n", outp->role == OUTPUT_ROLE_PERMANENT); print_str(&outp_str, "\"curr_workspace\": %d,\n", outp->curr_workspace + 1); char *workspaces_str = print_workspaces(outp); if(workspaces_str != NULL) { @@ -1202,8 +1199,7 @@ keybinding_dump(struct cg_server *server) { } print_str(&str, "\"views_curr_id\":%d,\n", curr_view_id); print_str(&str, "\"tiles_curr_id\":%d,\n", curr_tile_id); - print_str(&str, "\"curr_output\":\"%s\",\n", - server->curr_output->wlr_output->name); + print_str(&str, "\"curr_output\":\"%s\",\n", server->curr_output->name); print_str(&str, "\"default_mode\":\"%s\",\n", get_mode_name(server->modes, server->seat->default_mode)); print_modes(&str, server->modes); @@ -1298,9 +1294,8 @@ keybinding_move_view_to_cycle_output(struct cg_server *server, bool reverse) { "{\"event_name\":\"move_view_to_cycle_output\",\"view_id\":%d,\"view_" "pid\":%d,\"old_output\":\"%s\",\"old_output_id\":%d,\"new_output\":\"%" "s\",\"new_output_id\":%d,\"old_tile_id\":%d,\"new_tile_id\":%d}", - id, pid, old_outp->wlr_output->name, output_get_num(old_outp), - server->curr_output->wlr_output->name, - output_get_num(server->curr_output), + id, pid, old_outp->name, output_get_num(old_outp), + server->curr_output->name, output_get_num(server->curr_output), old_outp->workspaces[old_outp->curr_workspace]->focused_tile->id, server->curr_output->workspaces[server->curr_output->curr_workspace] ->focused_tile->id); @@ -1422,8 +1417,8 @@ keybinding_switch_output(struct cg_server *server, int output) { "{\"event_name\":\"switch_output\",\"old_output\":" "\"%s\",\"old_output_id\":%d,\"new_output\":\"%s\"," "\"new_output_id\":%d}", - old_outp->wlr_output->name, output_get_num(old_outp), - it->wlr_output->name, output_get_num(it)); + old_outp->name, output_get_num(old_outp), it->name, + output_get_num(it)); return; } ++count; @@ -1469,8 +1464,7 @@ keybinding_move_view_to_output(struct cg_server *server, int output_num) { server, "{\"event_name\":\"move_view_to_output\",\"view_id\":%d,\"old_" "output\":\"%s\",\"new_output\":\"%s\"}", - view_id, old_outp->wlr_output->name, - server->curr_output->wlr_output->name); + view_id, old_outp->name, server->curr_output->name); } void @@ -1505,7 +1499,7 @@ keybinding_move_view_to_workspace(struct cg_server *server, uint32_t ws) { "\"old_workspace\":%d,\"new_workspace\":%d," "\"output\":\"%s\",\"output_id\":%d,\"view_pid\":%d}", view == NULL ? -1 : (int)view->id, old_ws + 1, ws + 1, - server->curr_output->wlr_output->name, + server->curr_output->name, output_get_num(server->curr_output), view == NULL ? 0 : view->impl->get_pid(view)); } @@ -1554,17 +1548,18 @@ keybinding_configure_output(struct cg_server *server, struct cg_output *output, *tmp_output; wl_list_for_each_safe(output, tmp_output, &server->outputs, link) { - if(strcmp(config->output_name, output->wlr_output->name) == 0) { + if(strcmp(config->output_name, output->name) == 0) { + int output_num=output_get_num(output); output_configure(server, output); - ipc_send_event(output->server, + ipc_send_event(server, "{\"event_name\":\"configure_output\",\"output\":\"%" "s\",\"output_id\":%d}", - cfg->output_name, output_get_num(output)); + cfg->output_name, output_num); return; } } wl_list_for_each_safe(output, tmp_output, &server->disabled_outputs, link) { - if(strcmp(config->output_name, output->wlr_output->name) == 0) { + if(strcmp(config->output_name, output->name) == 0) { output_configure(server, output); ipc_send_event( output->server, diff --git a/libinput.c b/libinput.c index e980060..6a87b06 100644 --- a/libinput.c +++ b/libinput.c @@ -219,7 +219,7 @@ output_by_name_or_id(const char *name_or_id, struct cg_server *server) { char identifier[128]; output_get_identifier(identifier, sizeof(identifier), output); if(strcasecmp(identifier, name_or_id) == 0 || - strcasecmp(output->wlr_output->name, name_or_id) == 0) { + strcasecmp(output->name, name_or_id) == 0) { return output; } } diff --git a/man/cagebreak-config.5.md b/man/cagebreak-config.5.md index f894d04..3a56cfb 100644 --- a/man/cagebreak-config.5.md +++ b/man/cagebreak-config.5.md @@ -271,7 +271,7 @@ message *only* Remove all splits and make current window fill the entire screen -*output [[pos res x rate [scale ]] | enable | disable | prio | rotate ]* +*output [[pos res x rate [scale ]] | enable | disable | [permanent|peripheral] | prio | rotate ]* Configure output "" - - and are the position of the monitor in pixels. The top-left monitor should have the coordinates 0 0. @@ -281,6 +281,15 @@ message - enable and disable enable or disable . Note that if is the only enabled output, *output disable* has no effect. + - permanent sets to persist even on disconnect. Thus when + the physical monitor is disconnected, the output is nevertheless + maintained and operates identically to the attached monitor. On reconnect, + the monitor operates as though it was never disconnected. Setting the + output role to peripheral when the monitor is disconnected, immediately + destroys the output, as if the monitor were disconnected. + - peripheral sets the role of to peripheral, meaning that on + disconnecting the respective monitor, all views will be moved to another + available output. The default role is peripheral. - prio is used to set the priority of an output. If nothing else is set, outputs are added as they request to be added and have a numerical priority of -1. Using prio it is possible diff --git a/message.c b/message.c index 74b1d0a..c502ced 100644 --- a/message.c +++ b/message.c @@ -236,17 +236,18 @@ message_set_output(struct cg_output *output, const char *string, wlr_scene_buffer_create(&scene_output->scene->tree, &buf->base); wlr_scene_node_raise_to_top(&message->message->node); wlr_scene_node_set_enabled(&message->message->node, true); - struct wlr_box outp_box; - wlr_output_layout_get_box(output->server->output_layout, output->wlr_output, - &outp_box); wlr_scene_buffer_set_dest_size(message->message, width, height); - wlr_scene_node_set_position(&message->message->node, - message->position->x + outp_box.x, - message->position->y + outp_box.y); + wlr_scene_node_set_position( + &message->message->node, + message->position->x + output_get_layout_box(output).x, + message->position->y + output_get_layout_box(output).y); } void message_printf(struct cg_output *output, const char *fmt, ...) { + if(output->destroyed) { + return; + } va_list ap; va_start(ap, fmt); char *buffer = malloc_vsprintf_va_list(fmt, ap); @@ -262,11 +263,7 @@ message_printf(struct cg_output *output, const char *fmt, ...) { free(buffer); return; } - struct wlr_box output_box; - wlr_output_layout_get_box(output->server->output_layout, output->wlr_output, - &output_box); - - box->x = output_box.width; + box->x = output_get_layout_box(output).width; box->y = 0; box->width = 0; box->height = 0; @@ -282,6 +279,10 @@ message_printf(struct cg_output *output, const char *fmt, ...) { void message_printf_pos(struct cg_output *output, struct wlr_box *position, const enum cg_message_align align, const char *fmt, ...) { + if(output->destroyed) { + free(position); + return; + } uint16_t buf_len = 256; char *buffer = (char *)malloc(buf_len * sizeof(char)); va_list ap; diff --git a/output.c b/output.c index 506f5bd..881d9e4 100644 --- a/output.c +++ b/output.c @@ -14,6 +14,7 @@ #if WLR_HAS_X11_BACKEND #include #endif +#include #include #include #include @@ -103,7 +104,7 @@ output_get_num(const struct cg_output *output) { struct cg_output *it; int count = 1; wl_list_for_each(it, &output->server->outputs, link) { - if(strcmp(output->wlr_output->name, it->wlr_output->name) == 0) { + if(strcmp(output->name, it->name) == 0) { return count; } ++count; @@ -111,34 +112,54 @@ output_get_num(const struct cg_output *output) { return -1; } +struct wlr_box +output_get_layout_box(struct cg_output *output) { + if(!output->destroyed) { + wlr_output_layout_get_box(output->server->output_layout, + output->wlr_output, &output->layout_box); + } + return output->layout_box; +} + static void output_destroy(struct cg_output *output) { struct cg_server *server = output->server; - char *outp_name = strdup(output->wlr_output->name); + char *outp_name = strdup(output->name); int outp_num = output_get_num(output); - wl_list_remove(&output->destroy.link); - wl_list_remove(&output->mode.link); - wl_list_remove(&output->commit.link); - wl_list_remove(&output->frame.link); - - output_clear(output); - - /*Important: due to unfortunate events, "workspace" and "output->workspace" - * have nothing in common. The former is the workspace of a single output, - * whereas the latter is the workspace of the outputs.*/ - for(unsigned int i = 0; i < server->nws; ++i) { - workspace_free(output->workspaces[i]); + if(output->destroyed == false) { + wl_list_remove(&output->destroy.link); + wl_list_remove(&output->mode.link); + wl_list_remove(&output->commit.link); + wl_list_remove(&output->frame.link); } - free(output->workspaces); + output->destroyed = true; + enum output_role role = output->role; + if(role == OUTPUT_ROLE_PERMANENT) { + wlr_output_layout_get_box(server->output_layout, output->wlr_output, + &output->layout_box); + wlr_output_layout_remove(server->output_layout, output->wlr_output); + output->wlr_output=wlr_headless_add_output(server->headless_backend,output->layout_box.width,output->layout_box.height); + wlr_output_layout_add(server->output_layout, output->wlr_output, output->layout_box.x, + output->layout_box.y); - free(output); + } else { + output_clear(output); + + for(unsigned int i = 0; i < server->nws; ++i) { + workspace_free(output->workspaces[i]); + } + free(output->workspaces); + free(output->name); + + free(output); + } if(outp_name != NULL) { ipc_send_event(server, "{\"event_name\":\"destroy_output\",\"output\":\"%s\"," - "\"output_id\":%d}", - outp_name, outp_num); + "\"output_id\":%d,\"permanent\":%d}", + outp_name, outp_num, role == OUTPUT_ROLE_PERMANENT); free(outp_name); } else { wlr_log(WLR_ERROR, @@ -258,6 +279,15 @@ output_apply_config(struct cg_server *server, struct cg_output *output, struct cg_output_config *config) { struct wlr_output *wlr_output = output->wlr_output; + if(config->role != OUTPUT_ROLE_DEFAULT) { + output->role = config->role; + if((output->role == OUTPUT_ROLE_PERIPHERAL)&&(output->destroyed == true)) { + output_destroy(output); + wlr_output_destroy(wlr_output); + return; + } + } + if(output->wlr_output->enabled) { wlr_output_layout_remove(server->output_layout, wlr_output); } @@ -292,6 +322,13 @@ output_apply_config(struct cg_server *server, struct cg_output *output, } } else { wlr_output_layout_add_auto(server->output_layout, wlr_output); + // The following two lines make sure that the output is "manually" managed, + // so that its position doesn't change anymore in the future. + wlr_output_layout_get_box(server->output_layout, output->wlr_output, + &output->layout_box); + wlr_output_layout_move(server->output_layout, output->wlr_output, output->layout_box.x, + output->layout_box.y); + struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output); @@ -325,9 +362,11 @@ output_apply_config(struct cg_server *server, struct cg_output *output, output->bg = wlr_scene_rect_create( &scene_output->scene->tree, output->wlr_output->width, output->wlr_output->height, server->bg_color); - struct wlr_box box; - wlr_output_layout_get_box(server->output_layout, output->wlr_output, &box); - wlr_scene_node_set_position(&output->bg->node, box.x, box.y); + wlr_output_layout_get_box(server->output_layout, output->wlr_output, + &output->layout_box); + wlr_scene_node_set_position(&output->bg->node, + output_get_layout_box(output).x, + output_get_layout_box(output).y); wlr_scene_node_lower_to_bottom(&output->bg->node); } @@ -340,6 +379,7 @@ empty_output_config(void) { } cfg->status = OUTPUT_DEFAULT; + cfg->role = OUTPUT_ROLE_DEFAULT; cfg->pos.x = -1; cfg->pos.y = -1; cfg->pos.width = -1; @@ -363,6 +403,11 @@ merge_output_configs(struct cg_output_config *cfg1, } else { out_cfg->status = cfg1->status; } + if(cfg1->role == out_cfg->role) { + out_cfg->role = cfg2->role; + } else { + out_cfg->role = cfg1->role; + } if(cfg1->pos.x == out_cfg->pos.x) { out_cfg->pos.x = cfg2->pos.x; out_cfg->pos.y = cfg2->pos.y; @@ -411,7 +456,7 @@ output_configure(struct cg_server *server, struct cg_output *output) { struct cg_output_config *tot_config = empty_output_config(); struct cg_output_config *config; wl_list_for_each(config, &server->output_config, link) { - if(strcmp(config->output_name, output->wlr_output->name) == 0) { + if(strcmp(config->output_name, output->name) == 0) { if(tot_config == NULL) { return; } @@ -484,7 +529,7 @@ output_make_workspace_fullscreen(struct cg_output *output, int ws) { } workspace_free_tiles(output->workspaces[ws]); - if(full_screen_workspace_tiles(server->output_layout, output->wlr_output, + if(full_screen_workspace_tiles(server->output_layout, output->workspaces[ws], &server->tiles_curr_id) != 0) { wlr_log(WLR_ERROR, "Failed to allocate space for fullscreen workspace"); @@ -516,58 +561,88 @@ handle_new_output(struct wl_listener *listener, void *data) { return; } - struct cg_output *output = calloc(1, sizeof(struct cg_output)); + struct cg_output *ito; + bool reinit = false; + struct cg_output *output = NULL; + wl_list_for_each(ito, &server->outputs, link) { + if((strcmp(ito->name, wlr_output->name) == 0) && (ito->destroyed)) { + reinit = true; + output = ito; + } + } + if(reinit) { + wlr_output_layout_remove(server->output_layout, output->wlr_output); + wlr_output_destroy(output->wlr_output); + } else { + output = calloc(1, sizeof(struct cg_output)); + } if(!output) { wlr_log(WLR_ERROR, "Failed to allocate output"); return; } output->wlr_output = wlr_output; - output->server = server; - output->last_scanned_out_view = NULL; + output->destroyed = false; - struct cg_output_priorities *it; - int prio = -1; - wl_list_for_each(it, &server->output_priorities, link) { - if(strcmp(output->wlr_output->name, it->ident) == 0) { - prio = it->priority; + if(!reinit) { + output->server = server; + output->last_scanned_out_view = NULL; + output->name = strdup(wlr_output->name); + + struct cg_output_priorities *it; + int prio = -1; + wl_list_for_each(it, &server->output_priorities, link) { + if(strcmp(output->name, it->ident) == 0) { + prio = it->priority; + } } - } - output->priority = prio; - wlr_output_set_transform(wlr_output, WL_OUTPUT_TRANSFORM_NORMAL); - output->workspaces = NULL; + output->priority = prio; + wlr_output_set_transform(wlr_output, WL_OUTPUT_TRANSFORM_NORMAL); + output->workspaces = NULL; - wl_list_init(&output->messages); + wl_list_init(&output->messages); - if(!wlr_xcursor_manager_load(server->seat->xcursor_manager, - wlr_output->scale)) { - wlr_log(WLR_ERROR, - "Cannot load XCursor theme for output '%s' with scale %f", - wlr_output->name, wlr_output->scale); - } - - output_insert(server, output); - output_configure(server, output); - - output->workspaces = malloc(server->nws * sizeof(struct cg_workspace *)); - for(unsigned int i = 0; i < server->nws; ++i) { - output->workspaces[i] = full_screen_workspace(output); - if(!output->workspaces[i]) { - wlr_log(WLR_ERROR, "Failed to allocate workspaces for output"); - return; + if(!wlr_xcursor_manager_load(server->seat->xcursor_manager, + wlr_output->scale)) { + wlr_log(WLR_ERROR, + "Cannot load XCursor theme for output '%s' with scale %f", + output->name, wlr_output->scale); } - output->workspaces[i]->num = i; - wl_list_init(&output->workspaces[i]->views); - wl_list_init(&output->workspaces[i]->unmanaged_views); + + output_insert(server, output); + output_configure(server, output); + wlr_output_layout_get_box(server->output_layout, output->wlr_output, + &output->layout_box); + + output->workspaces = + malloc(server->nws * sizeof(struct cg_workspace *)); + for(unsigned int i = 0; i < server->nws; ++i) { + output->workspaces[i] = full_screen_workspace(output); + if(!output->workspaces[i]) { + wlr_log(WLR_ERROR, "Failed to allocate workspaces for output"); + return; + } + output->workspaces[i]->num = i; + wl_list_init(&output->workspaces[i]->views); + wl_list_init(&output->workspaces[i]->unmanaged_views); + } + + wlr_scene_node_raise_to_top(&output->workspaces[0]->scene->node); + workspace_focus(output, 0); + + /* We are the first output. Set the current output to this one. */ + if(server->curr_output == NULL) { + server->curr_output = output; + } + } else { + wlr_output_layout_add(server->output_layout, wlr_output, + output_get_layout_box(output).x, + output_get_layout_box(output).y); + output_configure(server, output); + wlr_output_layout_get_box(server->output_layout, output->wlr_output, + &output->layout_box); } - wlr_scene_node_raise_to_top(&output->workspaces[0]->scene->node); - workspace_focus(output, 0); - - /* We are the first output. Set the current output to this one. */ - if(server->curr_output == NULL) { - server->curr_output = output; - } wlr_xcursor_manager_set_cursor_image(server->seat->xcursor_manager, DEFAULT_XCURSOR, server->seat->cursor); wlr_cursor_warp(server->seat->cursor, NULL, 0, 0); @@ -580,11 +655,12 @@ handle_new_output(struct wl_listener *listener, void *data) { wl_signal_add(&wlr_output->events.commit, &output->commit); output->mode.notify = handle_output_mode; wl_signal_add(&wlr_output->events.mode, &output->mode); + ipc_send_event(server, "{\"event_name\":\"new_output\",\"output\":\"%s\",\"output_" - "id\":%d,\"priority\":%d}", - output->wlr_output->name, output_get_num(output), - output->priority); + "id\":%d,\"priority\":%d,\"restart\":%d}", + output->name, output_get_num(output), output->priority, + reinit); } #if CG_HAS_FANALYZE #pragma GCC diagnostic pop diff --git a/output.h b/output.h index 90cd615..5df3af8 100644 --- a/output.h +++ b/output.h @@ -12,6 +12,12 @@ struct cg_view; struct wlr_output; struct wlr_surface; +enum output_role { + OUTPUT_ROLE_PERIPHERAL, + OUTPUT_ROLE_PERMANENT, + OUTPUT_ROLE_DEFAULT +}; + struct cg_output { struct cg_server *server; struct wlr_output *wlr_output; @@ -23,9 +29,13 @@ struct cg_output { struct wl_listener frame; struct cg_workspace **workspaces; struct wl_list messages; + struct wlr_box layout_box; int curr_workspace; int priority; struct cg_view *last_scanned_out_view; + enum output_role role; + bool destroyed; + char *name; struct wl_list link; // cg_server::outputs }; @@ -40,6 +50,7 @@ enum output_status { OUTPUT_ENABLE, OUTPUT_DISABLE, OUTPUT_DEFAULT }; struct cg_output_config { enum output_status status; + enum output_role role; struct wlr_box pos; char *output_name; float refresh_rate; @@ -53,7 +64,8 @@ typedef void (*cg_surface_iterator_func_t)(struct cg_output *output, struct wlr_surface *surface, struct wlr_box *box, void *user_data); - +struct wlr_box +output_get_layout_box(struct cg_output *output); void handle_new_output(struct wl_listener *listener, void *data); void diff --git a/parse.c b/parse.c index c163b3a..28e218e 100644 --- a/parse.c +++ b/parse.c @@ -543,6 +543,10 @@ parse_output_config_keyword(char *key_str, enum output_status *status) { *status = OUTPUT_DEFAULT; } else if(strcmp(key_str, "enable") == 0) { *status = OUTPUT_ENABLE; + } else if(strcmp(key_str, "permanent") == 0) { + *status = OUTPUT_DEFAULT; + } else if(strcmp(key_str, "peripheral") == 0) { + *status = OUTPUT_DEFAULT; } else if(strcmp(key_str, "disable") == 0) { *status = OUTPUT_DISABLE; } else { @@ -566,6 +570,7 @@ parse_output_config(char **saveptr, char **errstr) { cfg->priority = -1; cfg->scale = -1; cfg->angle = -1; + cfg->role = OUTPUT_ROLE_DEFAULT; char *name = strtok_r(NULL, " ", saveptr); if(name == NULL) { *errstr = @@ -574,8 +579,9 @@ parse_output_config(char **saveptr, char **errstr) { } char *key_str = strtok_r(NULL, " ", saveptr); if(parse_output_config_keyword(key_str, &(cfg->status)) != 0) { - *errstr = log_error("Expected keyword \"pos\", \"prio\", \"enable\" or " - "\"disable\" in output configuration for output %s", + *errstr = log_error("Expected keyword \"pos\", \"prio\", \"enable\", " + "\"disable\", \"permanent\" or \"peripheral\" in " + "output configuration for output %s", name); goto error; } @@ -622,6 +628,18 @@ parse_output_config(char **saveptr, char **errstr) { return cfg; } + if(strcmp(key_str, "peripheral") == 0) { + cfg->output_name = strdup(name); + cfg->role = OUTPUT_ROLE_PERIPHERAL; + return cfg; + } + + if(strcmp(key_str, "permanent") == 0) { + cfg->output_name = strdup(name); + cfg->role = OUTPUT_ROLE_PERMANENT; + return cfg; + } + cfg->pos.x = parse_uint(saveptr, " "); if(cfg->pos.x < 0) { *errstr = log_error( diff --git a/seat.c b/seat.c index 1c88f49..ee78e24 100644 --- a/seat.c +++ b/seat.c @@ -95,7 +95,7 @@ new_touch(struct cg_seat *seat, struct cg_input_device *input_device) { if(wlr_touch->output_name != NULL) { struct cg_output *output; wl_list_for_each(output, &seat->server->outputs, link) { - if(strcmp(wlr_touch->output_name, output->wlr_output->name) == 0) { + if(strcmp(wlr_touch->output_name, output->name) == 0) { wlr_cursor_map_input_to_output(seat->cursor, device, output->wlr_output); break; @@ -133,8 +133,7 @@ new_pointer(struct cg_seat *seat, struct cg_input_device *input_device) { if(wlr_pointer->output_name != NULL) { struct cg_output *output; wl_list_for_each(output, &seat->server->outputs, link) { - if(strcmp(wlr_pointer->output_name, output->wlr_output->name) == - 0) { + if(strcmp(wlr_pointer->output_name, output->name) == 0) { wlr_cursor_map_input_to_output(seat->cursor, device, output->wlr_output); break; @@ -755,7 +754,7 @@ process_cursor_motion(struct cg_seat *seat, uint32_t time) { "\"%s\",\"old_output_id\":%d," "\"old_tile\":%d,\"new_output\":\"%s\",\"new_output_" "id\":%d,\"new_tile\":%d}", - seat->cursor_tile->workspace->output->wlr_output->name, + seat->cursor_tile->workspace->output->name, output_get_num(seat->cursor_tile->workspace->output), seat->cursor_tile->id, c_outp->name, output_get_num(cg_outp), c_tile->id); @@ -1095,9 +1094,8 @@ seat_set_focus(struct cg_seat *seat, struct cg_view *view) { wlr_scene_node_raise_to_top(&view->scene_tree->node); process_cursor_motion(seat, -1); - struct wlr_box box; - wlr_output_layout_get_box(server->output_layout, - view->workspace->output->wlr_output, &box); - wlr_scene_node_set_position(&view->workspace->output->bg->node, box.x, - box.y); + wlr_scene_node_set_position( + &view->workspace->output->bg->node, + output_get_layout_box(view->workspace->output).x, + output_get_layout_box(view->workspace->output).y); } diff --git a/server.c b/server.c index c50f528..1bfb3b7 100644 --- a/server.c +++ b/server.c @@ -43,8 +43,7 @@ server_show_info(struct cg_server *server) { return NULL; } output_str_tmp = output_str; - output_str = malloc_vsprintf("%s\t * %s\n", output_str, - output->wlr_output->name); + output_str = malloc_vsprintf("%s\t * %s\n", output_str, output->name); free(output_str_tmp); } char *input_str = strdup(""), *input_str_tmp; diff --git a/server.h b/server.h index 9f6eca6..96c3380 100644 --- a/server.h +++ b/server.h @@ -37,6 +37,7 @@ struct cg_server { struct cg_output *curr_output; struct wl_listener new_output; struct wl_list output_priorities; + struct wlr_backend *headless_backend; struct wlr_renderer *renderer; struct wlr_allocator *allocator; diff --git a/view.c b/view.c index 99e2e7c..425a6e1 100644 --- a/view.c +++ b/view.c @@ -81,11 +81,10 @@ void view_maximize(struct cg_view *view, struct cg_tile *tile) { view->ox = tile->tile.x; view->oy = tile->tile.y; - struct wlr_box box; - wlr_output_layout_get_box(view->server->output_layout, - view->workspace->output->wlr_output, &box); - wlr_scene_node_set_position(&view->scene_tree->node, view->ox + box.x, - view->oy + box.y); + wlr_scene_node_set_position( + &view->scene_tree->node, + view->ox + output_get_layout_box(view->workspace->output).x, + output_get_layout_box(view->oy + view->workspace->output).y); view->impl->maximize(view, tile->tile.width, tile->tile.height); view->tile = tile; wlr_scene_node_raise_to_top(&view->scene_tree->node); @@ -97,7 +96,7 @@ view_unmap(struct cg_view *view) { uint32_t id = view->id; uint32_t tile_id = 0; uint32_t ws = view->workspace->num; - char *output_name = view->workspace->output->wlr_output->name; + char *output_name = view->workspace->output->name; int output_id = output_get_num(view->workspace->output); pid_t pid = view->impl->get_pid(view); /* If the view is not mapped, do nothing */ @@ -171,11 +170,10 @@ view_map(struct cg_view *view, struct wlr_surface *surface, their own (x,y) coordinates in handle_wayland_surface_map. */ if(view->type == CG_XWAYLAND_VIEW && !xwayland_view_should_manage(view)) { wl_list_insert(&ws->unmanaged_views, &view->link); - struct wlr_box box; - wlr_output_layout_get_box(view->server->output_layout, - view->workspace->output->wlr_output, &box); - wlr_scene_node_set_position(&view->scene_tree->node, view->ox + box.x, - view->oy + box.y); + wlr_scene_node_set_position( + &view->scene_tree->node, + view->ox + output_get_layout_box(view->workspace->output).x, + view->oy + output_get_layout_box(view->workspace->output).y); } else #endif { @@ -193,8 +191,8 @@ view_map(struct cg_view *view, struct wlr_surface *surface, "{\"event_name\":\"view_map\",\"view_id\":%d,\"tile_id\":%d," "\"workspace\":%d,\"output\":\"%s\",\"output_id\":%d,\"view_pid\":%d}", view->id, tile_id, view->workspace->num + 1, - view->workspace->output->wlr_output->name, - output_get_num(view->workspace->output), view->impl->get_pid(view)); + view->workspace->output->name, output_get_num(view->workspace->output), + view->impl->get_pid(view)); } void diff --git a/workspace.c b/workspace.c index 1dff244..a3ad991 100644 --- a/workspace.c +++ b/workspace.c @@ -35,7 +35,6 @@ workspace_tile_update_view(struct cg_tile *tile, struct cg_view *view) { #endif int full_screen_workspace_tiles(struct wlr_output_layout *layout, - struct wlr_output *output, struct cg_workspace *workspace, uint32_t *tiles_curr_id) { workspace->focused_tile = calloc(1, sizeof(struct cg_tile)); @@ -47,10 +46,10 @@ full_screen_workspace_tiles(struct wlr_output_layout *layout, workspace->focused_tile->prev = workspace->focused_tile; workspace->focused_tile->tile.x = 0; workspace->focused_tile->tile.y = 0; - struct wlr_box output_box; - wlr_output_layout_get_box(layout, output, &output_box); - workspace->focused_tile->tile.width = output_box.width; - workspace->focused_tile->tile.height = output_box.height; + workspace->focused_tile->tile.width = + output_get_layout_box(workspace->output).width; + workspace->focused_tile->tile.height = + output_get_layout_box(workspace->output).height; workspace_tile_update_view(workspace->focused_tile, NULL); workspace->focused_tile->id = *tiles_curr_id; ++(*tiles_curr_id); @@ -72,16 +71,15 @@ full_screen_workspace(struct cg_output *output) { free(workspace); return NULL; } + workspace->output = output; workspace->server = output->server; workspace->num = -1; workspace->scene = wlr_scene_tree_create(&scene_output->scene->tree); - if(full_screen_workspace_tiles(output->server->output_layout, - output->wlr_output, workspace, + if(full_screen_workspace_tiles(output->server->output_layout, workspace, &output->server->tiles_curr_id) != 0) { free(workspace); return NULL; } - workspace->output = output; return workspace; } @@ -107,7 +105,8 @@ workspace_free_tiles(struct cg_workspace *workspace) { workspace->focused_tile) { workspace->output->server->seat->cursor_tile = NULL; } - if(workspace->focused_tile == workspace->server->seat->cursor_tile) { + if(workspace->output->server->running && + workspace->focused_tile == workspace->server->seat->cursor_tile) { workspace->server->seat->cursor_tile = NULL; } struct cg_tile *next = workspace->focused_tile->next; diff --git a/workspace.h b/workspace.h index b669cec..f7e68ca 100644 --- a/workspace.h +++ b/workspace.h @@ -33,7 +33,6 @@ struct cg_workspace * full_screen_workspace(struct cg_output *output); int full_screen_workspace_tiles(struct wlr_output_layout *layout, - struct wlr_output *output, struct cg_workspace *workspace, uint32_t *tiles_curr_id); void diff --git a/xdg_shell.c b/xdg_shell.c index afa3352..41af699 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -74,12 +74,12 @@ popup_unconstrain(struct cg_view *view, struct wlr_xdg_popup *popup) { struct wlr_box *popup_box = &popup->current.geometry; struct wlr_output_layout *output_layout = view->server->output_layout; - struct wlr_box view_output_box; - wlr_output_layout_get_box( - output_layout, view->workspace->output->wlr_output, &view_output_box); struct wlr_output *wlr_output = wlr_output_layout_output_at( - output_layout, view_output_box.x + view->ox + popup_box->x, - view_output_box.y + view->oy + popup_box->y); + output_layout, + output_get_layout_box(view->workspace->output).x + view->ox + + popup_box->x, + output_get_layout_box(view->workspace->output).y + view->oy + + popup_box->y); struct wlr_box output_box; wlr_output_layout_get_box(output_layout, wlr_output, &output_box); diff --git a/xwayland.c b/xwayland.c index ece9e5a..43f8382 100644 --- a/xwayland.c +++ b/xwayland.c @@ -93,13 +93,11 @@ maximize(struct cg_view *view, int width, int height) { } } - struct wlr_box output_box; - wlr_output_layout_get_box(view->server->output_layout, - view->server->curr_output->wlr_output, - &output_box); - wlr_xwayland_surface_configure(xwayland_view->xwayland_surface, - view->ox + output_box.x, - view->oy + output_box.y, width, height); + wlr_xwayland_surface_configure( + xwayland_view->xwayland_surface, + view->ox + output_get_layout_box(view->server->curr_output).x, + view->oy + output_get_layout_box(view->server->curr_output).y, width, + height); wlr_xwayland_surface_set_maximized(xwayland_view->xwayland_surface, true); } @@ -135,12 +133,10 @@ handle_xwayland_surface_map(struct wl_listener *listener, void *_data) { wl_container_of(listener, xwayland_view, map); struct cg_view *view = &xwayland_view->view; if(!xwayland_view_should_manage(view)) { - struct wlr_output_layout *output_layout = view->server->output_layout; - struct wlr_box output_box; - wlr_output_layout_get_box( - output_layout, view->server->curr_output->wlr_output, &output_box); - view->ox = xwayland_view->xwayland_surface->x - output_box.x; - view->oy = xwayland_view->xwayland_surface->y - output_box.y; + view->ox = xwayland_view->xwayland_surface->x - + view->server->curr_output->layout_box.x; + view->oy = xwayland_view->xwayland_surface->y - + view->server->curr_output->layout_box.y; } view_map(view, xwayland_view->xwayland_surface->surface,