AtlatestRepositorysigil-wm
1
/* SPDX-License-Identifier: BSD-3-Clause2
* 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 2565
#define INVENTORY_MODES 1286
struct 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
};11
struct inventory_snapshot {12
int64_t version,count,truncated,errors;13
struct inventory_record records[INVENTORY_CONNECTORS];14
};15
static pthread_mutex_t inventory_mutex=PTHREAD_MUTEX_INITIALIZER;16
static struct inventory_snapshot inventory={.version=1},inventory_pending;17
static void inventory_string(char *target,const char *value) {18
snprintf(target,256,"%s",value ? value : "");19
}20
static 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++];25
}26
static 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;46
}47
struct inventory_context { struct server *server; };48
static 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);93
}94
static 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);110
}111
static 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);114
}115
int wm_inventory_size(void) { return sizeof(inventory); }116
int 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;122
}