AtlatestRepositorysigil-wm

sigil-wm / tree / src / coutput-batch.h

1/* SPDX-License-Identifier: BSD-3-Clause
2 * Whole-backend testing, commit and rollback for explicit output settings. */
3static 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;
16static 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);
29static 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);
34static 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);
48static 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;
96static 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);
100static 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;
139static 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);