AtlatestRepositorysigil-wm

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

1/* SPDX-License-Identifier: BSD-3-Clause
2 * Native-owner refresh, detached copy for Scheme. Enumerate DRM resources,
3 * including connectors for which wlroots has never created an output. */
4#define INVENTORY_CONNECTORS 256
5#define INVENTORY_MODES 128
6struct inventory_record {
7 int64_t word[16];
8 char name[256],make[256],model[256],serial[256];
9 int64_t modes[INVENTORY_MODES][4];
10};
11struct inventory_snapshot {
12 int64_t version,count,truncated,errors;
13 struct inventory_record records[INVENTORY_CONNECTORS];
14};
15static pthread_mutex_t inventory_mutex=PTHREAD_MUTEX_INITIALIZER;
16static struct inventory_snapshot inventory={.version=1},inventory_pending;
17static void inventory_string(char *target,const char *value) {
18 snprintf(target,256,"%s",value ? value : "");
20static struct inventory_record *inventory_append(void) {
21 if(inventory_pending.count==INVENTORY_CONNECTORS) {
22 inventory_pending.truncated=1; return NULL;
23 }
24 return &inventory_pending.records[inventory_pending.count++];
26static void inventory_output(struct inventory_record *record,struct output *output) {
27 struct wlr_output *native=output->native;
28 record->word[0]=output->id; record->word[1]=1;
29 record->word[2]=output->configured_enabled; record->word[3]=native->enabled;
30 record->word[4]=output->x; record->word[5]=output->y;
31 record->word[6]=lround(native->scale*1000); record->word[7]=native->transform;
32 record->word[8]=native->width; record->word[9]=native->height;
33 record->word[10]=native->refresh; record->word[11]=-1;
34 inventory_string(record->name,native->name); inventory_string(record->make,native->make);
35 inventory_string(record->model,native->model); inventory_string(record->serial,native->serial);
36 struct wlr_output_mode *mode;
37 unsigned count=0;
38 wl_list_for_each(mode,&native->modes,link) {
39 if(count==INVENTORY_MODES) { inventory_pending.truncated=1; break; }
40 if(mode==native->current_mode) record->word[11]=count;
41 record->modes[count][0]=mode->width; record->modes[count][1]=mode->height;
42 record->modes[count][2]=mode->refresh; record->modes[count][3]=count;
43 count++;
44 }
45 record->word[12]=count;
47struct inventory_context { struct server *server; };
48static void inventory_backend(struct wlr_backend *backend,void *data) {
49 if(wlr_backend_is_multi(backend)) { wlr_multi_for_each_backend(backend,inventory_backend,data); return; }
50 if(!wlr_backend_is_drm(backend)) return;
51 struct server *s=((struct inventory_context *)data)->server;
52 int fd=wlr_backend_get_drm_fd(backend);
53 drmModeRes *resources=fd>=0 ? drmModeGetResources(fd) : NULL;
54 if(!resources) { inventory_pending.errors++; return; }
55 struct stat device={0};
56 if(fstat(fd,&device)!=0) inventory_pending.errors++;
57 for(int i=0;i<resources->count_connectors;i++) {
58 drmModeConnector *connector=drmModeGetConnectorCurrent(fd,resources->connectors[i]);
59 if(!connector) { inventory_pending.errors++; continue; }
60 struct inventory_record *record=inventory_append();
61 if(!record) { drmModeFreeConnector(connector); break; }
62 record->word[1]=connector->connection==DRM_MODE_CONNECTED;
63 record->word[6]=1000; record->word[11]=-1;
64 record->word[13]=connector->connector_id; record->word[14]=device.st_rdev;
65 snprintf(record->name,sizeof(record->name),"%s-%u",
66 drmModeGetConnectorTypeName(connector->connector_type),connector->connector_type_id);
67 struct output *output;
68 bool found=false;
69 wl_list_for_each(output,&s->outputs,link) {
70 if(output->native->backend==backend && wlr_output_is_drm(output->native) &&
71 wlr_drm_connector_get_id(output->native)==connector->connector_id) {
72 inventory_output(record,output); found=true; break;
73 }
74 }
75 if(!found) {
76 unsigned count=connector->count_modes>INVENTORY_MODES ? INVENTORY_MODES : (unsigned)connector->count_modes;
77 if(connector->count_modes>INVENTORY_MODES) inventory_pending.truncated=1;
78 record->word[12]=count;
79 for(unsigned j=0;j<count;j++) {
80 drmModeModeInfo *mode=&connector->modes[j];
81 double refresh=mode->htotal && mode->vtotal ?
82 (double)mode->clock*1000000.0/(mode->htotal*mode->vtotal) : 0;
83 if(mode->flags&DRM_MODE_FLAG_INTERLACE) refresh*=2;
84 if(mode->flags&DRM_MODE_FLAG_DBLSCAN) refresh/=2;
85 if(mode->vscan>1) refresh/=mode->vscan;
86 record->modes[j][0]=mode->hdisplay; record->modes[j][1]=mode->vdisplay;
87 record->modes[j][2]=lround(refresh); record->modes[j][3]=j;
88 }
89 }
90 drmModeFreeConnector(connector);
91 }
92 drmModeFreeResources(resources);
94static void inventory_refresh(void *data) {
95 struct server *s=data;
96 s->inventory_idle=NULL;
97 memset(&inventory_pending,0,sizeof(inventory_pending)); inventory_pending.version=1;
98 struct inventory_context context={s};
99 inventory_backend(s->backend,&context);
100 struct output *output;
101 wl_list_for_each(output,&s->outputs,link) {
102 if(wlr_output_is_drm(output->native)) continue;
103 struct inventory_record *record=inventory_append();
104 if(!record) break;
105 inventory_output(record,output);
106 }
107 pthread_mutex_lock(&inventory_mutex);
108 memcpy(&inventory,&inventory_pending,sizeof(inventory));
109 pthread_mutex_unlock(&inventory_mutex);
111static void inventory_schedule(struct server *s) {
112 if(!s->stopping && !s->inventory_idle)
113 s->inventory_idle=wl_event_loop_add_idle(wl_display_get_event_loop(s->display),inventory_refresh,s);
115int wm_inventory_size(void) { return sizeof(inventory); }
116int wm_inventory_copy(void *buffer,int capacity) {
117 if(!buffer || capacity<(int)sizeof(inventory)) return 0;
118 pthread_mutex_lock(&inventory_mutex);
119 memcpy(buffer,&inventory,sizeof(inventory));
120 pthread_mutex_unlock(&inventory_mutex);
121 return 1;