AtlatestRepositorysigil-wm
1
/* SPDX-License-Identifier: BSD-3-Clause2
* Whole-backend testing, commit and rollback for explicit output settings. */3
static struct wlr_output_configuration_v1 *output_configuration(struct server *s,bool logical) {4
struct wlr_output_configuration_v1 *configuration=wlr_output_configuration_v1_create();5
if(!configuration) return NULL;6
struct output *output;7
wl_list_for_each(output,&s->outputs,link) {8
struct wlr_output_configuration_head_v1 *head=9
wlr_output_configuration_head_v1_create(configuration,output->native);10
if(!head) { wlr_output_configuration_v1_destroy(configuration); return NULL; }11
head->state.x=output->x; head->state.y=output->y;12
if(logical) head->state.enabled=output->configured_enabled;13
}14
return configuration;15
}16
static void publish_output_state(struct output *output) {17
int width=0,height=0,index=0,current=-1;18
struct wlr_output_mode *mode;19
wl_list_for_each(mode,&output->native->modes,link) {20
if(mode==output->native->current_mode) current=index;21
index++;22
}23
if(output->configured_enabled) wlr_output_effective_resolution(output->native,&width,&height);24
EVENT(6,output->id,output->x,output->y,width,height,25
(int64_t)(output->native->scale*1000),output->configured_enabled,output->native->transform,26
output->native->width,output->native->height,output->native->enabled,output->native->refresh,current,27
output->native->adaptive_sync_status==WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED);28
}29
static void finish_backend_states(struct wlr_backend_output_state *states,size_t count) {30
if(!states) return;31
for(size_t index=0;index<count;index++) wlr_output_state_finish(&states[index].base);32
free(states);33
}34
static void place_output_state(struct server *s,struct output *output,int x,int y) {35
struct wlr_output_layout_output *previous=wlr_output_layout_get(s->layout,output->native);36
/* Keep the last frame until policy moves the scene into the new region. */37
if(previous && output->configured_enabled && (previous->x!=x || previous->y!=y) &&38
!s->scene_update_deadline)39
s->scene_update_deadline=now_ms()+200;40
output->x=x; output->y=y;41
if(!output->configured_enabled) {42
wlr_output_layout_remove(s->layout,output->native);43
return;44
}45
struct wlr_output_layout_output *layout=wlr_output_layout_add(s->layout,output->native,x,y);46
wlr_scene_output_layout_add_output(s->scene_layout,layout,output->scene);47
}48
static bool output_configuration_commit_mode(struct server *s,struct wlr_output_configuration_v1 *configuration,49
const uint64_t *selected,const bool *enabled,size_t selected_count,bool apply,bool per_output,int *rollback) {50
size_t count=0,previous_count=0;51
struct wlr_backend_output_state *states=wlr_output_configuration_v1_build_state(configuration,&count);52
struct wlr_output_configuration_v1 *previous=NULL;53
struct wlr_backend_output_state *previous_states=NULL;54
bool success=false;55
if(apply) {56
previous=output_configuration(s,false);57
if(previous) previous_states=wlr_output_configuration_v1_build_state(previous,&previous_count);58
if(previous_states) {59
success=output_atomic_commit(s,states,count,true,per_output);60
if(!success && s->output_commit_attempted) {61
bool restored=output_atomic_commit(s,previous_states,previous_count,true,false);62
*rollback=restored ? 1 : 2;63
if(!restored) {64
struct output *output;65
wl_list_for_each(output,&s->outputs,link) {66
output->configured_enabled=output->native->enabled;67
output->configuration_generation++;68
place_output_state(s,output,output->x,output->y);69
}70
}71
} else if(success) {72
struct wlr_output_configuration_head_v1 *head;73
wl_list_for_each(head,&configuration->heads,link) {74
struct output *output=head->state.output->data;75
size_t chosen=selected_count;76
for(size_t index=0;index<selected_count;index++)77
if(selected[index]==output->id) chosen=index;78
if(chosen==selected_count) continue;79
output->configured_enabled=enabled[chosen];80
output->configuration_generation++;81
place_output_state(s,output,head->state.x,head->state.y);82
if(s->lock_state) lock_configure(output);83
}84
}85
invalidate_scoped_pixels(s,0);86
struct output *output;87
wl_list_for_each(output,&s->outputs,link) publish_output_state(output);88
}89
}90
if(!apply) success=output_atomic_commit(s,states,count,false,false);91
finish_backend_states(states,count);92
finish_backend_states(previous_states,previous_count);93
if(previous) wlr_output_configuration_v1_destroy(previous);94
return success;95
}96
static bool output_configuration_commit(struct server *s,struct wlr_output_configuration_v1 *configuration,97
const uint64_t *selected,const bool *enabled,size_t selected_count,bool apply,int *rollback) {98
return output_configuration_commit_mode(s,configuration,selected,enabled,selected_count,apply,false,rollback);99
}100
static bool output_configuration_settings(struct server *s,struct wlr_output_configuration_v1 *configuration,101
const int64_t *words,size_t count,uint64_t *selected,bool *enabled,size_t *selected_count) {102
if(count<1 || words[0]<1 || words[0]>64 || count!=1+(size_t)words[0]*12) return false;103
*selected_count=words[0];104
for(size_t index=0;index<*selected_count;index++) {105
const int64_t *record=words+1+index*12;106
struct output *output=find_output(s,record[0]);107
if(!output || record[1]<0 || record[1]>1 || record[2]<-32768 || record[2]>32768 ||108
record[3]<-32768 || record[3]>32768 || record[4]<250 || record[4]>8000 ||109
record[5]<0 || record[5]>7 || record[6]<-1 || record[9]<0 || record[9]>1000000 ||110
record[10]<0 || record[10]>1 || record[11]<0 || record[11]>1) return false;111
for(size_t previous=0;previous<index;previous++) if(selected[previous]==output->id) return false;112
selected[index]=output->id;113
enabled[index]=record[1]!=0;114
struct wlr_output_configuration_head_v1 *head;115
bool found=false;116
wl_list_for_each(head,&configuration->heads,link) {117
if(head->state.output!=output->native) continue;118
found=true;119
head->state.enabled=record[1] && record[11]; head->state.x=record[2]; head->state.y=record[3];120
head->state.scale=record[4]/1000.0f; head->state.transform=record[5];121
head->state.adaptive_sync_enabled=record[10];122
head->state.mode=NULL;123
if(record[6]>=0) {124
int64_t mode_index=0;125
struct wlr_output_mode *mode;126
wl_list_for_each(mode,&output->native->modes,link)127
if(mode_index++==record[6]) { head->state.mode=mode; break; }128
if(!head->state.mode) return false;129
} else {130
if(record[1] && (record[7]<1 || record[7]>16384 || record[8]<1 || record[8]>16384)) return false;131
head->state.custom_mode.width=record[7]; head->state.custom_mode.height=record[8];132
head->state.custom_mode.refresh=record[9];133
}134
}135
if(!found) return false;136
}137
return true;138
}139
static void output_batch_now(struct server *s,uint64_t token,const int64_t *words,size_t count) {140
bool success=false;141
int rollback=0;142
uint64_t selected[64];143
bool enabled[64];144
size_t selected_count=0;145
struct wlr_output_configuration_v1 *configuration=output_configuration(s,false);146
if(configuration && count>1 && (words[0]==0 || words[0]==1) &&147
output_configuration_settings(s,configuration,words+1,count-1,selected,enabled,&selected_count))148
success=output_configuration_commit(s,configuration,selected,enabled,selected_count,words[0]==0,&rollback);149
if(configuration) wlr_output_configuration_v1_destroy(configuration);150
if(success && words[0]==0) s->output_revision++;151
publish_output_management(s);152
EVENT(24,token,10,success,rollback);153
}