/* * The RandR documentation is catastrophically bad. It contains * blantant proofreading errors (if indeed it was proofread at all) * and leaves at least two of the types it uses completely * undocumented. I had to go under the hood, looking at the * implementation, to figure out what they were. * * This file contains comments calling out some of the worst of the * problems. */ #include #include "ext.h" #include "sets.h" #include "fmt-util.h" #include "fmt-core.h" static SETVALS SETofRRSELECTMASK[] = { { 0x0001, "ScreenChangeNotify" }, { 0x0002, "CrtcChangeNotify" }, { 0x0004, "OutputChangeNotify" }, { 0x0008, "OutputPropertyNotify" }, { 0, 0 } }; static SETVALS SETofROTATION[] = { { 0x0001, "Rotate_0" }, { 0x0002, "Rotate_90" }, { 0x0004, "Rotate_180" }, { 0x0008, "Rotate_270" }, { 0x0010, "Reflect_X" }, { 0x0020, "Reflect_Y" }, { 0, 0 } }; static void print_randr_configstatus(FILE *o, unsigned int v) { print_choice(o,v,4,0,"Success",1,"InvalidConfigTime",2,"InvalidTime",3,"Failed"); } /* * The RANDR documentation doesn't document this. It is, at least, * nice enough to point to Xrandr as the source of it - in this case. */ static void print_randr_subpixel_order(FILE *o, unsigned int v) { print_choice(o,v,6, 0, "Unknown", 1, "HorizontalRGB", 2, "HorizontalBGR", 3, "VerticalRGB", 4, "VerticalBGR", 5, "None"); } static void print_randr_rotation(FILE *o, const char *tag, unsigned int v) { print_set(o,tag," ",v,SETofROTATION); } static void print_randr_connection(FILE *o, unsigned int v) { print_choice(o,v,3, 0, "Connected", 1, "Disconnected", 2, "UnknownConnection"); } /* * Print an array of MODEINFOs followed by their names, such as occurs * in, for example, the response to GetScreenResources. * * The RANDR protocol document does not describe how mode name strings * are packed into the "mode names" portion of the protocol. I am * guessing, since it seems like an obvious alternative and seems to * match what I see on the wire, that the name strings appear tightly * packed in the mode names area, in the same order as their MODEINFOs * appear in the body of the request. */ static void print_modeinfo_vector(FLOW *f, FILE *o, int x, int nm, int nn) { int nx; int i; unsigned int mf; int nl; int nnp; nnp = pad(nn); nx = x + (32 * nm); for (i=0;i nn) { fprintf(o,"*** Name truncated: length %d > available %d\n",nl,nn); print_text_blk(f,o,nx,nn," Name: "," "); nx += nn; nn = 0; } else { print_text_blk(f,o,nx,nl," Name: "," "); nx += nl; nn -= nl; } x += 32; } if (nn > 0) { print_text_blk(f,o,nx,nn," Leftover: "," "); } EXACTLENGTH(nx+nn+nnp); if (nnp) get_unused(f,nx+nn,nnp); } /* * RANDR documentation sprinkles TRANSFORM around but does not document * it AT ALL(!!). Going under the hood, it appears to be an * xRenderTransform on the wire (but something different in the API, * for, of course, completely unexplained reasons). * * The element type is yet another completely undocumented type, Fixed, * in the API. The RandR code gets this from the Render include * files, which simply typedefs it to INT32. The Render documentation * says it's a 32-bit fixed-point value with 16 bits of integer * portion and 16 bits of fraction. I'm assuming it's just "divide * signed integer by 65536". */ static void print_randr_transform(FILE *o, FLOW *f, int x) { fprintf(o," [%g %g %g %g %g %g %g %g %g]", get4s(f,x) / 65536.0, get4s(f,x+ 4) / 65536.0, get4s(f,x+ 8) / 65536.0, get4s(f,x+12) / 65536.0, get4s(f,x+16) / 65536.0, get4s(f,x+20) / 65536.0, get4s(f,x+24) / 65536.0, get4s(f,x+28) / 65536.0, get4s(f,x+32) / 65536.0 ); } static int match_randr(const char *name, int len) { return((len==5)&&!bcmp(name,"RANDR",5)); } static void xtoc_randr_QueryVersion(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { unsigned int vmaj; unsigned int vmin; if (! f) return; rep_hdr(f,o,"RANDR QueryVersion"); EXACTLENGTH(32); // randrproto.txt says 1 byte but CARD32. // Appears to really be 4-byte CARD32. get_unused(f,1,1); vmaj = get4u(f,8); vmin = get4u(f,12); fprintf(o," Server version: %u.%u\n",vmaj,vmin); get_unused(f,16,16); } static void request_randr__obsolete(FLOW *f, FILE *o) { req_hdr_min(f,o,"RANDR 0.0-only request",4); print_raw_data(o,f); abort_packet_print(); } static void request_randr__unimp(FLOW *f, FILE *o) { req_hdr_min(f,o,"Unimplemented RANDR request",4); print_raw_data(o,f); abort_packet_print(); } static void request_randr_QueryVersion(FLOW *f, FILE *o) { req_hdr_exact(f,o,"RANDR QueryVersion",12); fprintf(o," Client version: %u.%u\n",get4u(f,4),get4u(f,8)); expect_reply(f->conn,&xtoc_randr_QueryVersion,0); } static void xtoc_randr_SetScreenConfig(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { if (! f) return; rep_hdr(f,o,"RANDR SetScreenConfig"); EXACTLENGTH(32); fprintf(o," Status: "); print_randr_configstatus(o,get1u(f,1)); fprintf(o,"\n"); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,8)); fprintf(o,"\n"); fprintf(o," Configuration timestamp: "); print_timestamp(o,get4u(f,12)); fprintf(o,"\n"); fprintf(o," Root window: "XID_FMT"\n",get4u(f,16)); fprintf(o," Subpixel order: "); print_randr_subpixel_order(o,get2u(f,20)); fprintf(o,"\n"); get_unused(f,22,10); } static void request_randr_SetScreenConfig(FLOW *f, FILE *o) { req_hdr_exact(f,o,"RANDR SetScreenConfig",24); fprintf(o," Window: "XID_FMT"\n",get4u(f,4)); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,8)); fprintf(o,"\n"); fprintf(o," Configuration timestamp: "); print_timestamp(o,get4u(f,12)); fprintf(o,"\n"); fprintf(o," Size index: %u\n",get2u(f,16)); print_randr_rotation(o," Rotation: ",get2u(f,18)); fprintf(o," 1.1 Refresh rate: %d\n",get2u(f,20)); get_unused(f,22,2); expect_reply(f->conn,&xtoc_randr_SetScreenConfig,0); } static void request_randr_SelectInput(FLOW *f, FILE *o) { req_hdr_exact(f,o,"RANDR SelectInput",12); fprintf(o," Window: "XID_FMT"\n",get4u(f,4)); print_set(o," Events: "," ",get2u(f,8),SETofRRSELECTMASK); get_unused(f,10,2); } static void xtoc_randr_GetScreenInfo(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { int n; int m; int i; int j; int x; if (! f) return; rep_hdr(f,o,"RANDR GetScreenInfo"); MINLENGTH(32); print_randr_rotation(o," Rotation: ",get1u(f,1)); fprintf(o," Window: "XID_FMT"\n",get4u(f,8)); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,12)); fprintf(o,"\n"); fprintf(o," Configuration timestamp: "); print_timestamp(o,get4u(f,16)); fprintf(o,"\n"); n = get2u(f,20); fprintf(o," Size index: %u\n",get2u(f,22)); print_randr_rotation(o," Rotation: ",get2u(f,24)); fprintf(o," Rate: %u\n",get2u(f,26)); fprintf(o," Rate info length: %u\n",get2u(f,28)); get_unused(f,30,2); MINLENGTH(32+(8*n)); x = 32 + (8 * n); for (i=0;iconn,&xtoc_randr_GetScreenInfo,0); } static void xtoc_randr_GetScreenSizeRange(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { if (! f) return; rep_hdr(f,o,"RANDR GetScreenSizeRange"); EXACTLENGTH(32); get_unused(f,1,1); fprintf(o," Size range: [%d..%d] x [%d..%d]\n",get2u(f,8),get2u(f,12),get2u(f,10),get2u(f,14)); get_unused(f,16,16); } static void request_randr_GetScreenSizeRange(FLOW *f, FILE *o) { req_hdr_exact(f,o,"RANDR GetScreenSizeRange",8); fprintf(o," Window: "XID_FMT"\n",get4u(f,4)); expect_reply(f->conn,&xtoc_randr_GetScreenSizeRange,0); } static void request_randr_SetScreenSize(FLOW *f, FILE *o) { req_hdr_exact(f,o,"RANDR SetScreenSize",20); fprintf(o," Window: "XID_FMT"\n",get4u(f,4)); fprintf(o," Size: %ux%u pixels, %ux%u mm\n",get2u(f,8),get2u(f,10),get4u(f,12),get4u(f,16)); } // See the comment on print_modeinfo_vector. static void xtoc_randr_GetScreenResources(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { unsigned int nc; unsigned int no; unsigned int nm; unsigned int nb; int x; int i; if (! f) return; rep_hdr(f,o,"RANDR GetScreenResources"); MINLENGTH(32); get_unused(f,1,1); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,8)); fprintf(o,"\n"); fprintf(o," Configuration timestamp: "); print_timestamp(o,get4u(f,12)); fprintf(o,"\n"); nc = get2u(f,16); no = get2u(f,18); nm = get2u(f,20); nb = get2u(f,22); MINLENGTH(32+(4*nc)+(4*no)+(32*nm)+nb); get_unused(f,24,8); x = 32; for (i=0;iconn,&xtoc_randr_GetScreenResources,0); } static void xtoc_randr_GetOutputInfo(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { int nc; int nm; int np; int no; int nn; int x; int i; if (! f) return; rep_hdr(f,o,"RANDR GetOutputInfo"); MINLENGTH(36); fprintf(o," Status: "); print_randr_configstatus(o,get1u(f,1)); fprintf(o,"\n"); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,8)); fprintf(o,"\n"); fprintf(o," Current CRTC: "XID_FMT"\n",get4u(f,12)); fprintf(o," Size: %ux%u mm\n",get4u(f,16),get4u(f,20)); fprintf(o," Connection: "); print_randr_connection(o,get1u(f,24)); fprintf(o,"\n"); fprintf(o," Subpixel order: "); print_randr_subpixel_order(o,get1u(f,25)); fprintf(o,"\n"); nc = get2u(f,26); nm = get2u(f,28); np = get2u(f,30); no = get2u(f,32); nn = get2u(f,34); MINLENGTH(36+(4*nc)+(4*nm)+(4*no)+nn); x = 36; for (i=0;iconn,&xtoc_randr_GetOutputInfo,0); } static void xtoc_randr_GetCrtcInfo(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { int nc; int np; int x; int i; if (! f) return; rep_hdr(f,o,"RANDR GetCrtcInfo"); MINLENGTH(32); fprintf(o," Status: "); print_randr_configstatus(o,get1u(f,1)); fprintf(o,"\n"); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,8)); fprintf(o,"\n"); fprintf(o," Size: %ux%u+%d+%d\n",get2u(f,16),get2u(f,18),get2s(f,12),get2s(f,14)); fprintf(o," Mode: "XID_FMT"\n",get4u(f,20)); print_randr_rotation(o," Current rotation: ",get2u(f,24)); print_randr_rotation(o," Possible rotation: ",get2u(f,26)); nc = get2u(f,28); np = get2u(f,30); EXACTLENGTH(32+(4*nc)+(4*np)); x = 32; for (i=0;iconn,&xtoc_randr_GetCrtcInfo,0); } static void xtoc_randr_SetCrtcConfig(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { if (! f) return; rep_hdr(f,o,"RANDR SetCrtcConfig"); EXACTLENGTH(32); fprintf(o," Status: "); print_randr_configstatus(o,get1u(f,1)); fprintf(o,"\n"); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,8)); fprintf(o,"\n"); get_unused(f,12,20); } static void request_randr_SetCrtcConfig(FLOW *f, FILE *o) { int no; int i; req_hdr_min(f,o,"RANDR SetCrtcConfig",28); fprintf(o," Crtc: "XID_FMT"\n",get4u(f,4)); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,8)); fprintf(o,"\n"); fprintf(o," Configuration timestamp: "); print_timestamp(o,get4u(f,12)); fprintf(o,"\n"); fprintf(o," Loc: %+d%+d\n",get2s(f,16),get2s(f,18)); fprintf(o," Mode: "XID_FMT"\n",get4u(f,20)); print_randr_rotation(o," Rotation: ",get2u(f,24)); get_unused(f,26,2); no = (f->ibfill - 28) >> 2; for (i=0;iconn,&xtoc_randr_SetCrtcConfig,0); } static void xtoc_randr_GetCrtcGammaSize(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { if (! f) return; rep_hdr(f,o,"RANDR GetCrtcGammaSize"); EXACTLENGTH(32); get_unused(f,1,1); fprintf(o," Size: %u\n",get2u(f,8)); get_unused(f,10,22); } static void request_randr_GetCrtcGammaSize(FLOW *f, FILE *o) { req_hdr_exact(f,o,"RANDR GetCrtcGammaSize",8); fprintf(o," Crtc: "XID_FMT"\n",get4u(f,4)); expect_reply(f->conn,&xtoc_randr_GetCrtcGammaSize,0); } static void xtoc_randr_GetCrtcGamma(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { int n; int i; int xr; int xg; int xb; if (! f) return; rep_hdr(f,o,"RANDR GetCrtcGamma"); MINLENGTH(32); get_unused(f,1,1); n = get2u(f,8); get_unused(f,10,22); EXACTLENGTH(32+(6*n)+((n&1)?2:0)); xr = 32; xg = xr + (2 * n); xb = xg + (2 * n); for (i=0;iconn,&xtoc_randr_GetCrtcGamma,0); } // See the comment on print_modeinfo_vector. static void xtoc_randr_GetScreenResourcesCurrent(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { int nc; int no; int nm; int nb; int i; int x; if (! f) return; rep_hdr(f,o,"RANDR GetScreenResourcesCurrent"); MINLENGTH(32); get_unused(f,1,1); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,8)); fprintf(o,"\n"); fprintf(o," Configuration timestamp: "); print_timestamp(o,get4u(f,12)); fprintf(o,"\n"); nc = get2u(f,16); no = get2u(f,18); nm = get2u(f,20); nb = get2u(f,22); get_unused(f,24,8); MINLENGTH(32+(4*nc)+(4*no)+(32*nm)+nb); x = 32; for (i=0;iconn,&xtoc_randr_GetScreenResourcesCurrent,0); } static void xtoc_randr_GetCrtcTransform(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { int pn; int pf; int cn; int cf; int x; if (! f) return; rep_hdr(f,o,"RANDR GetCrtcTransform"); MINLENGTH(96); get_unused(f,1,1); fprintf(o," Pending transform: "); print_randr_transform(o,f,8); fprintf(o,"\n"); // What does "has transforms" mean? RandR doc is silent. fprintf(o," Has transforms: "); print_bool(o,get1u(f,44)); fprintf(o,"\n"); get_unused(f,45,3); fprintf(o," Current transform: "); print_randr_transform(o,f,48); fprintf(o,"\n"); get_unused(f,84,4); pn = get2u(f,88); pf = get2u(f,90); cn = get2u(f,92); cf = get2u(f,94); EXACTLENGTH(96+pn+pad(pn)+(pf<<2)+cn+pad(cn)+(cf<<2)); x = 96; print_padded_text_blk(f,o,x,pn," Pending name: "," "); x += pn + pad(pn); print_bin_blk(f,o,x,pf<<2," Pending params: "," "); x += pf << 2; print_padded_text_blk(f,o,x,cn," Current name: "," "); x += cn + pad(cn); print_bin_blk(f,o,x,cf<<2," Current params: "," "); } static void request_randr_GetCrtcTransform(FLOW *f, FILE *o) { req_hdr_exact(f,o,"RANDR GetCrtcTransform",8); fprintf(o," Window: "XID_FMT"\n",get4u(f,4)); expect_reply(f->conn,&xtoc_randr_GetCrtcTransform,0); } static void xtoc_randr_GetPanning(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { if (! f) return; rep_hdr(f,o,"RANDR GetPanning"); EXACTLENGTH(36); fprintf(o," Status: "); print_randr_configstatus(o,get1u(f,1)); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,8)); fprintf(o,"\n"); fprintf(o," Area: L=%u T=%u W=%u H=%u\n",get2u(f,12),get2u(f,14),get2u(f,16),get2u(f,18)); fprintf(o," Track: L=%u T=%u W=%u H=%u\n",get2u(f,20),get2u(f,22),get2u(f,24),get2u(f,26)); fprintf(o," Border: L=%u T=%u W=%u H=%u\n",get2u(f,28),get2u(f,30),get2u(f,32),get2u(f,34)); } static void request_randr_GetPanning(FLOW *f, FILE *o) { req_hdr_exact(f,o,"RANDR GetPanning",8); fprintf(o," Crtc: "XID_FMT"\n",get4u(f,4)); expect_reply(f->conn,&xtoc_randr_GetPanning,0); } /* * RANDR documentation documents this response as being only 28 bytes * long(!!). */ static void xtoc_randr_GetOutputPrimary(FLOW *f, FILE *o, void *pv __attribute__((__unused__))) { if (! f) return; rep_hdr(f,o,"RANDR GetOutputPrimary"); EXACTLENGTH(32); get_unused(f,1,1); fprintf(o," Output: "XID_FMT"\n",get4u(f,8)); get_unused(f,12,20); } static void request_randr_GetOutputPrimary(FLOW *f, FILE *o) { req_hdr_exact(f,o,"RANDR GetOutputPrimary",8); fprintf(o," Window: "XID_FMT"\n",get4u(f,4)); expect_reply(f->conn,&xtoc_randr_GetOutputPrimary,0); } static void (*reqimpl[])(FLOW *, FILE *) = { &request_randr_QueryVersion, &request_randr__obsolete, &request_randr_SetScreenConfig, &request_randr__obsolete, &request_randr_SelectInput, &request_randr_GetScreenInfo, &request_randr_GetScreenSizeRange, &request_randr_SetScreenSize, &request_randr_GetScreenResources, &request_randr_GetOutputInfo, &request_randr__unimp,//&request_randr_ListOutputProperties, &request_randr__unimp,//&request_randr_QueryOutputProperty, &request_randr__unimp,//&request_randr_ConfigureOutputProperty, &request_randr__unimp,//&request_randr_ChangeOutputProperty, &request_randr__unimp,//&request_randr_DeleteOutputProperty, &request_randr__unimp,//&request_randr_GetOutputProperty, &request_randr__unimp,//&request_randr_CreateMode, &request_randr__unimp,//&request_randr_DestroyMode, &request_randr__unimp,//&request_randr_AddOutputMode, &request_randr__unimp,//&request_randr_DeleteOutputMode, &request_randr_GetCrtcInfo, &request_randr_SetCrtcConfig, &request_randr_GetCrtcGammaSize, &request_randr_GetCrtcGamma, &request_randr__unimp,//&request_randr_SetCrtcGamma, &request_randr_GetScreenResourcesCurrent, &request_randr__unimp,//&request_randr_SetCrtcTransform, &request_randr_GetCrtcTransform, &request_randr_GetPanning, &request_randr__unimp,//&request_randr_SetPanning, &request_randr__unimp,//&request_randr_SetOutputPrimary, &request_randr_GetOutputPrimary }; #define REQ_N (sizeof(reqimpl)/sizeof(reqimpl[0])) static void request_randr(FLOW *f, FILE *o) { unsigned int sub; sub = get1u(f,1); if (sub >= REQ_N) { fprintf(o,"Impossible RANDR request %u\n",sub); print_raw_data(o,f); abort_packet_print(); return; } (*reqimpl[sub])(f,o); } static void event_randr_ScreenChangeNotify(FLOW *f, FILE *o) { event_hdr(f,o,"RANDR ScreenChangeNotify"); print_randr_rotation(o," Rotation: ",get1u(f,1)); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,4)); fprintf(o,"\n"); fprintf(o," Configuration timestamp: "); print_timestamp(o,get4u(f,8)); fprintf(o,"\n"); fprintf(o," Root window: "XID_FMT"\n",get4u(f,12)); fprintf(o," Request window: "XID_FMT"\n",get4u(f,16)); fprintf(o," Size ID: %u\n",get2u(f,20)); fprintf(o," Subpixel order: "); print_randr_subpixel_order(o,get2u(f,22)); fprintf(o,"\n"); fprintf(o," Size: %ux%u pixels, %ux%u mm\n",get2u(f,24),get2u(f,26),get2u(f,28),get2u(f,30)); } static void event_randr_CrtcChangeNotify(FLOW *f, FILE *o) { event_hdr(f,o,"RANDR CrtcChangeNotify"); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,4)); fprintf(o,"\n"); fprintf(o," Request window: "XID_FMT"\n",get4u(f,8)); fprintf(o," CRTC: "XID_FMT"\n",get4u(f,12)); fprintf(o," Mode: %u\n",get4u(f,16)); print_randr_rotation(o," Rotation: ",get2u(f,20)); get_unused(f,22,2); fprintf(o," Geometry: %dx%d+%u+%u\n",get2u(f,28),get2u(f,30),get2s(f,24),get2s(f,26)); } static void event_randr_OutputChangeNotify(FLOW *f, FILE *o) { event_hdr(f,o,"RANDR OutputChangeNotify"); fprintf(o," Timestamp: "); print_timestamp(o,get4u(f,4)); fprintf(o,"\n"); fprintf(o," Configuration timestamp: "); print_timestamp(o,get4u(f,8)); fprintf(o,"\n"); fprintf(o," Request window: "XID_FMT"\n",get4u(f,12)); fprintf(o," Output: "XID_FMT"\n",get4u(f,16)); fprintf(o," CRTC: "XID_FMT"\n",get4u(f,20)); fprintf(o," Mode: "XID_FMT"\n",get4u(f,24)); print_randr_rotation(o," Rotation: ",get2u(f,28)); fprintf(o," Connection: "); print_randr_connection(o,get1u(f,30)); fprintf(o,"\n"); fprintf(o," Subpixel order: "); print_randr_subpixel_order(o,get1u(f,31)); fprintf(o,"\n"); } static void event_randr_OutputPropertyNotify(FLOW *f, FILE *o) { unsigned int state; event_hdr(f,o,"RANDR OutputPropertyNotify"); fprintf(o," Window: "XID_FMT"\n",get4u(f,4)); fprintf(o," Output: "XID_FMT"\n",get4u(f,8)); fprintf(o," Atom: "); print_atom(o,f->conn,get4u(f,12)); fprintf(o,"\n"); fprintf(o," Time: "); print_timestamp(o,get4u(f,16)); fprintf(o,"\n"); fprintf(o," State: "); state = get1u(f,20); switch (state) { case 0: fprintf(o,"NewValue"); break; case 1: fprintf(o,"Deleted"); break; default: fprintf(o,"%u (invalid)",state); break; } fprintf(o,"\n"); get_unused(f,21,11); } static void (*evimpl_sub[])(FLOW *, FILE *) = { &event_randr_CrtcChangeNotify, &event_randr_OutputChangeNotify, &event_randr_OutputPropertyNotify }; #define EV_SUB_N (sizeof(evimpl_sub)/sizeof(evimpl_sub[0])) static void event_randr__subcode(FLOW *f, FILE *o) { unsigned int sub; sub = get1u(f,1); if (sub >= EV_SUB_N) { fprintf(o,"Impossible RANDR event 1.%u",sub); print_raw_data(o,f); abort_packet_print(); return; } (*evimpl_sub[sub])(f,o); } static void (*evimpl[])(FLOW *, FILE *) = { &event_randr_ScreenChangeNotify, &event_randr__subcode }; #define EV_N (sizeof(evimpl)/sizeof(evimpl[0])) static void event_randr(FLOW *f, FILE *o) { unsigned int sub; sub = get1u(f,0); if (sub >= EV_N) { fprintf(o,"Impossible RANDR event %u",sub); print_raw_data(o,f); abort_packet_print(); return; } (*evimpl[sub])(f,o); } static void error_randr(FLOW *f, FILE *o) { fprintf(o,"Impossible RANDR error %u",get1u(f,1)); print_raw_data(o,f); abort_packet_print(); } EXTDEF extdef_randr = { "RANDR", &match_randr, &request_randr, &event_randr, &error_randr };