diff --git a/cagebreak.c b/cagebreak.c index 838078f..38261ec 100644 --- a/cagebreak.c +++ b/cagebreak.c @@ -53,6 +53,7 @@ #include "seat.h" #include "server.h" #include "xdg_shell.h" +#include "workspace.h" #if CG_HAS_XWAYLAND #include "xwayland.h" #endif @@ -273,6 +274,7 @@ main(int argc, char *argv[]) { wl_list_init(&server.input_config); wl_list_init(&server.output_config); + wl_list_init(&server.output_priorities); server.modes = malloc(4 * sizeof(char *)); if(!server.modes) { @@ -576,11 +578,15 @@ main(int argc, char *argv[]) { } { - + struct wl_list tmp_list; + wl_list_init(&tmp_list); + wl_list_insert_list(&tmp_list,&server.outputs); + wl_list_init(&server.outputs); struct cg_output *output, *output_tmp; - wl_list_for_each_safe(output, output_tmp, &server.outputs, link) { + wl_list_for_each_safe(output, output_tmp, &tmp_list, link) { output_configure(&server, output); } + server.curr_output=wl_container_of(server.outputs.next,server.curr_output,link); } /* Place the cursor to the top left of the output layout. */ diff --git a/keybinding.c b/keybinding.c index f7761cd..721188f 100644 --- a/keybinding.c +++ b/keybinding.c @@ -593,23 +593,8 @@ into_process(const char *command) { } void -keybinding_cycle_outputs(struct cg_server *server, bool reverse) { - if(reverse) { - server->curr_output = wl_container_of(server->curr_output->link.prev, - server->curr_output, link); - } else { - server->curr_output = wl_container_of(server->curr_output->link.next, - server->curr_output, link); - } - if(&server->curr_output->link == &server->outputs) { - if(reverse) { - server->curr_output = wl_container_of( - server->curr_output->link.prev, server->curr_output, link); - } else { - server->curr_output = wl_container_of( - server->curr_output->link.next, server->curr_output, link); - } - } +set_output(struct cg_server *server, struct cg_output *output) { + server->curr_output = output; seat_set_focus( server->seat, server->curr_output->workspaces[server->curr_output->curr_workspace] @@ -617,6 +602,28 @@ keybinding_cycle_outputs(struct cg_server *server, bool reverse) { message_printf(server->curr_output, "Current Output"); } +void +keybinding_cycle_outputs(struct cg_server *server, bool reverse) { + struct cg_output *output=NULL; + if(reverse) { + output = wl_container_of(server->curr_output->link.prev, + server->curr_output, link); + } else { + output = wl_container_of(server->curr_output->link.next, + server->curr_output, link); + } + if(&output->link == &server->outputs) { + if(reverse) { + output = wl_container_of( + output->link.prev, output, link); + } else { + output = wl_container_of( + output->link.next, output, link); + } + } + set_output(server,output); +} + /* Cycle through views, whereby the workspace does not change */ void keybinding_cycle_views(struct cg_server *server, bool reverse) { @@ -718,7 +725,7 @@ keybinding_show_info(struct cg_server *server) { } void -keybinding_move_view_to_next_output(struct cg_server *server) { +keybinding_move_view_to_cycle_output(struct cg_server *server, bool reverse) { if(wl_list_length(&server->outputs) <= 1) { return; } @@ -736,7 +743,7 @@ keybinding_move_view_to_next_output(struct cg_server *server) { seat_set_focus(server->seat, NULL); } } - keybinding_cycle_outputs(server, false); + keybinding_cycle_outputs(server, reverse); if(view != NULL) { wl_list_insert(&server->curr_output ->workspaces[server->curr_output->curr_workspace] @@ -831,6 +838,49 @@ keybinding_set_background(struct cg_server *server, float *bg) { server->bg_color[2] = bg[2]; } +void +keybinding_switch_output(struct cg_server *server, int output) { + struct cg_output *it; + int count=1; + wl_list_for_each(it,&server->outputs,link) { + if(count==output) { + set_output(server,it); + return; + } + ++count; + } + message_printf(server->curr_output,"Output %d does not exist",output); + return; +} + +void +keybinding_move_view_to_output(struct cg_server *server, int output_num) { + struct cg_view *view = + server->curr_output->workspaces[server->curr_output->curr_workspace] + ->focused_tile->view; + if(view != NULL) { + wl_list_remove(&view->link); + server->curr_output->workspaces[server->curr_output->curr_workspace] + ->focused_tile->view = NULL; + keybinding_cycle_views(server, false); + if(server->curr_output->workspaces[server->curr_output->curr_workspace] + ->focused_tile->view == NULL) { + seat_set_focus(server->seat, NULL); + } + } + keybinding_switch_output(server, output_num); + if(view != NULL) { + struct cg_workspace *ws = + server->curr_output + ->workspaces[server->curr_output->curr_workspace]; + view->workspace = ws; + wl_list_insert(&ws->views, &view->link); + ws->focused_tile->view = view; + view_maximize(view, ws->focused_tile); + seat_set_focus(server->seat, view); + } +} + void keybinding_move_view_to_workspace(struct cg_server *server, uint32_t ws) { struct cg_view *view = @@ -859,6 +909,22 @@ keybinding_move_view_to_workspace(struct cg_server *server, uint32_t ws) { } } +void +merge_config(struct cg_output_config *config_new, struct cg_output_config *config_old) { + if(config_new->status==OUTPUT_DEFAULT) { + config_new->status=config_old->status; + } + if(config_new->pos.x == -1) { + config_new->pos=config_old->pos; + } + if(config_new->refresh_rate==0) { + config_new->refresh_rate=config_old->refresh_rate; + } + if(config_new->priority==-1) { + config_new->priority=config_old->priority; + } +} + void keybinding_configure_output(struct cg_server *server, struct cg_output_config *cfg) { @@ -877,6 +943,7 @@ keybinding_configure_output(struct cg_server *server, wl_list_for_each_safe(it, tmp, &server->output_config, link) { if(strcmp(config->output_name, it->output_name) == 0) { wl_list_remove(&it->link); + merge_config(config, it); free(it->output_name); free(it); } @@ -944,6 +1011,9 @@ run_action(enum keybinding_action action, struct cg_server *server, case KEYBINDING_SWITCH_WORKSPACE: keybinding_switch_ws(server, data.u); break; + case KEYBINDING_SWITCH_OUTPUT: + keybinding_switch_output(server, data.u); + break; case KEYBINDING_SWITCH_MODE: server->seat->mode = data.u; break; @@ -969,6 +1039,10 @@ run_action(enum keybinding_action action, struct cg_server *server, keybinding_move_view_to_workspace(server, data.u); break; } + case KEYBINDING_MOVE_VIEW_TO_OUTPUT: { + keybinding_move_view_to_output(server, data.u); + break; + } case KEYBINDING_SWAP_LEFT: { swap_tile_left( server->curr_output->workspaces[server->curr_output->curr_workspace] @@ -1017,8 +1091,8 @@ run_action(enum keybinding_action action, struct cg_server *server, ->focused_tile); break; } - case KEYBINDING_MOVE_VIEW_TO_NEXT_OUTPUT: { - keybinding_move_view_to_next_output(server); + case KEYBINDING_MOVE_VIEW_TO_CYCLE_OUTPUT: { + keybinding_move_view_to_cycle_output(server,data.b); break; } case KEYBINDING_DEFINEKEY: diff --git a/keybinding.h b/keybinding.h index 4cd0e87..aaae649 100644 --- a/keybinding.h +++ b/keybinding.h @@ -29,6 +29,7 @@ enum keybinding_action { // configuration KEYBINDING_QUIT, KEYBINDING_NOOP, + KEYBINDING_SWITCH_OUTPUT, // data.u is the desired output KEYBINDING_SWITCH_WORKSPACE, // data.u is the desired workspace KEYBINDING_SWITCH_MODE, // data.u is the desired mode KEYBINDING_SWITCH_DEFAULT_MODE, // data.u is the desired mode @@ -37,7 +38,8 @@ enum keybinding_action { KEYBINDING_RESIZE_TILE_VERTICAL, // data.i is the number of pixels to add to // the current height KEYBINDING_MOVE_VIEW_TO_WORKSPACE, // data.u is the desired workspace - KEYBINDING_MOVE_VIEW_TO_NEXT_OUTPUT, + KEYBINDING_MOVE_VIEW_TO_OUTPUT, // data.u is the desired output + KEYBINDING_MOVE_VIEW_TO_CYCLE_OUTPUT, //data.b is 0 if forward, 1 if reverse KEYBINDING_SHOW_TIME, KEYBINDING_SHOW_INFO, diff --git a/output.c b/output.c index 8feaec9..9a9a475 100644 --- a/output.c +++ b/output.c @@ -564,6 +564,29 @@ output_set_mode(struct wlr_output *output, int width, int height, wlr_output_set_mode(output, best); } +void +output_insert(struct cg_server *server, struct cg_output *output) { + struct cg_output *it, *prev_it=NULL; + bool first=true; + wl_list_for_each(it,&server->outputs,link) { + if(it->prioritypriority) { + if(first == true) { + wl_list_insert(&server->outputs,&output->link); + } else { + wl_list_insert(it->link.prev,&output->link); + } + return; + } + first=false; + prev_it=it; + } + if(prev_it==NULL) { + wl_list_insert(&server->outputs,&output->link); + } else { + wl_list_insert(&prev_it->link,&output->link); + } +} + void output_configure(struct cg_server *server, struct cg_output *output) { struct wlr_output *wlr_output = output->wlr_output; @@ -577,7 +600,7 @@ output_configure(struct cg_server *server, struct cg_output *output) { wlr_output_layout_remove(server->output_layout, wlr_output); } - if(config == NULL || config->status == OUTPUT_ENABLE) { + if(config == NULL) { wlr_output_layout_add_auto(server->output_layout, wlr_output); struct wlr_output_mode *preferred_mode = @@ -586,23 +609,30 @@ output_configure(struct cg_server *server, struct cg_output *output) { wlr_output_set_mode(wlr_output, preferred_mode); } wl_list_remove(&output->link); - wl_list_insert(&server->outputs, &output->link); + output_insert(server,output); wlr_output_enable(wlr_output, true); wlr_output_commit(wlr_output); - } else if(config->status == OUTPUT_DISABLE) { - output_clear(output); - wl_list_insert(&server->disabled_outputs, &output->link); - wlr_output_enable(wlr_output, false); - wlr_output_commit(wlr_output); } else { - wl_list_remove(&output->link); - wl_list_insert(&server->outputs, &output->link); - output_set_mode(wlr_output, config->pos.width, config->pos.height, - config->refresh_rate); - wlr_output_layout_add(server->output_layout, wlr_output, config->pos.x, - config->pos.y); - wlr_output_enable(wlr_output, true); - wlr_output_commit(wlr_output); + if(config->status == OUTPUT_DISABLE) { + output_clear(output); + wl_list_insert(&server->disabled_outputs, &output->link); + wlr_output_enable(wlr_output, false); + wlr_output_commit(wlr_output); + } else { + wl_list_remove(&output->link); + if(config->priority != -1) { + output->priority=config->priority; + } + if(config->pos.x != -1) { + output_set_mode(wlr_output, config->pos.width, config->pos.height, + config->refresh_rate); + wlr_output_layout_add(server->output_layout, wlr_output, config->pos.x, + config->pos.y); + } + output_insert(server,output); + wlr_output_enable(wlr_output, true); + wlr_output_commit(wlr_output); + } } } @@ -626,17 +656,14 @@ handle_new_output(struct wl_listener *listener, void *data) { output->damage = wlr_output_damage_create(wlr_output); output->last_scanned_out_view = NULL; - output->mode.notify = handle_output_mode; - wl_signal_add(&wlr_output->events.mode, &output->mode); - output->commit.notify = handle_output_commit; - wl_signal_add(&wlr_output->events.commit, &output->commit); - output->destroy.notify = handle_output_destroy; - wl_signal_add(&wlr_output->events.destroy, &output->destroy); - output->damage_frame.notify = handle_output_damage_frame; - wl_signal_add(&output->damage->events.frame, &output->damage_frame); - output->damage_destroy.notify = handle_output_damage_destroy; - wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); - + 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; + } + } + output->priority=prio; wlr_output_set_transform(wlr_output, server->output_transform); output->workspaces = NULL; @@ -650,7 +677,7 @@ handle_new_output(struct wl_listener *listener, void *data) { wlr_output->name, wlr_output->scale); } - wl_list_insert(&server->outputs, &output->link); + output_insert(server,output); output_configure(server, output); wlr_output_damage_add_whole(output->damage); @@ -672,6 +699,17 @@ handle_new_output(struct wl_listener *listener, void *data) { wlr_xcursor_manager_set_cursor_image(server->seat->xcursor_manager, DEFAULT_XCURSOR, server->seat->cursor); wlr_cursor_warp(server->seat->cursor, NULL, 0, 0); + + output->mode.notify = handle_output_mode; + wl_signal_add(&wlr_output->events.mode, &output->mode); + output->commit.notify = handle_output_commit; + wl_signal_add(&wlr_output->events.commit, &output->commit); + output->destroy.notify = handle_output_destroy; + wl_signal_add(&wlr_output->events.destroy, &output->destroy); + output->damage_frame.notify = handle_output_damage_frame; + wl_signal_add(&output->damage->events.frame, &output->damage_frame); + output->damage_destroy.notify = handle_output_damage_destroy; + wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); } #if CG_HAS_FANALYZE #pragma GCC diagnostic pop diff --git a/output.h b/output.h index 42cb629..796d0f4 100644 --- a/output.h +++ b/output.h @@ -23,11 +23,18 @@ struct cg_output { struct cg_workspace **workspaces; struct wl_list messages; int curr_workspace; + int priority; struct cg_view *last_scanned_out_view; struct wl_list link; // cg_server::outputs }; +struct cg_output_priorities { + char *ident; + int priority; + struct wl_list link; +}; + enum output_status { OUTPUT_ENABLE, OUTPUT_DISABLE, OUTPUT_DEFAULT }; struct cg_output_config { @@ -35,6 +42,7 @@ struct cg_output_config { struct wlr_box pos; char *output_name; float refresh_rate; + int priority; struct wl_list link; // cg_server::output_config }; diff --git a/parse.c b/parse.c index 4bbf72d..7042a78 100644 --- a/parse.c +++ b/parse.c @@ -503,6 +503,8 @@ parse_output_config_keyword(char *key_str, enum output_status *status) { } if(strcmp(key_str, "pos") == 0) { *status = OUTPUT_DEFAULT; + } else if(strcmp(key_str, "prio") == 0) { + *status = OUTPUT_DEFAULT; } else if(strcmp(key_str, "enable") == 0) { *status = OUTPUT_ENABLE; } else if(strcmp(key_str, "disable") == 0) { @@ -521,6 +523,11 @@ parse_output_config(char **saveptr, char **errstr) { log_error("Failed to allocate memory for output configuration"); goto error; } + cfg->status=OUTPUT_DEFAULT; + cfg->pos.x=-1; + cfg->output_name=NULL; + cfg->refresh_rate=0; + cfg->priority=-1; char *name = strtok_r(NULL, " ", saveptr); if(name == NULL) { *errstr = @@ -529,7 +536,7 @@ 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\", \"enable\" or " + *errstr = log_error("Expected keyword \"pos\", \"prio\", \"enable\" or " "\"disable\" in output configuration for output %s", name); goto error; @@ -539,6 +546,16 @@ parse_output_config(char **saveptr, char **errstr) { return cfg; } + if(strcmp(key_str, "prio") == 0) { + cfg->priority=parse_uint(saveptr, " "); + if(cfg->priority<0) { + *errstr = log_error( "Error parsing priority of output configuration for output %s", name); + goto error; + } + cfg->output_name = strdup(name); + return cfg; + } + cfg->pos.x = parse_uint(saveptr, " "); if(cfg->pos.x < 0) { *errstr = log_error( @@ -669,6 +686,23 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } else if(strcmp(action, "resizeup") == 0) { keybinding->action = KEYBINDING_RESIZE_TILE_VERTICAL; keybinding->data.i = -10; + } else if(strcmp(action, "screen") == 0) { + keybinding->action = KEYBINDING_SWITCH_OUTPUT; + char *noutp_str = strtok_r(NULL, " ", &saveptr); + if(noutp_str == NULL) { + *errstr = log_error( + "Expected argument for \"output\" action, got none."); + return -1; + } + + long outp = strtol(noutp_str, NULL, 10); + if(outp < 1) { + *errstr = log_error("Workspace number must be an integer number " + "larger or equal to 1. Got %ld", + outp); + return -1; + } + keybinding->data.u = outp; } else if(strcmp(action, "workspace") == 0) { keybinding->action = KEYBINDING_SWITCH_WORKSPACE; char *nws_str = strtok_r(NULL, " ", &saveptr); @@ -686,12 +720,29 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, return -1; } keybinding->data.u = ws - 1; + } else if(strcmp(action, "movetoscreen") == 0) { + keybinding->action = KEYBINDING_MOVE_VIEW_TO_OUTPUT; + char *noutp_str = strtok_r(NULL, " ", &saveptr); + if(noutp_str == NULL) { + *errstr = log_error( + "Expected argument for \"movetoscreen\" action, got none."); + return -1; + } + + long outp = strtol(noutp_str, NULL, 10); + if(outp < 1) { + *errstr = log_error("Output number must be an integer larger or " + "equal to 1. Got %ld", + outp); + return -1; + } + keybinding->data.u = outp; } else if(strcmp(action, "movetoworkspace") == 0) { keybinding->action = KEYBINDING_MOVE_VIEW_TO_WORKSPACE; char *nws_str = strtok_r(NULL, " ", &saveptr); if(nws_str == NULL) { *errstr = log_error( - "Expected argument for \"workspace\" action, got none."); + "Expected argument for \"movetoworkspace\" action, got none."); return -1; } @@ -720,7 +771,11 @@ parse_command(struct cg_server *server, struct keybinding *keybinding, } else if(strcmp(action, "focusdown") == 0) { keybinding->action = KEYBINDING_FOCUS_BOTTOM; } else if(strcmp(action, "movetonextscreen") == 0) { - keybinding->action = KEYBINDING_MOVE_VIEW_TO_NEXT_OUTPUT; + keybinding->action = KEYBINDING_MOVE_VIEW_TO_CYCLE_OUTPUT; + keybinding->data.b=false; + } else if(strcmp(action, "movetoprevscreen") == 0) { + keybinding->action = KEYBINDING_MOVE_VIEW_TO_CYCLE_OUTPUT; + keybinding->data.b=true; } else if(strcmp(action, "switchvt") == 0) { keybinding->action = KEYBINDING_CHANGE_TTY; char *ntty = strtok_r(NULL, " ", &saveptr); diff --git a/server.h b/server.h index 9ee21e1..54fbc17 100644 --- a/server.h +++ b/server.h @@ -32,6 +32,7 @@ struct cg_server { struct wl_list outputs; struct cg_output *curr_output; struct wl_listener new_output; + struct wl_list output_priorities; struct wl_listener xdg_toplevel_decoration; struct wl_listener new_xdg_shell_surface;