xrandr.c 100 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936
  1. /*
  2. * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
  3. * Copyright © 2002 Hewlett Packard Company, Inc.
  4. * Copyright © 2006 Intel Corporation
  5. * Copyright © 2013 NVIDIA Corporation
  6. *
  7. * Permission to use, copy, modify, distribute, and sell this software and its
  8. * documentation for any purpose is hereby granted without fee, provided that
  9. * the above copyright notice appear in all copies and that both that copyright
  10. * notice and this permission notice appear in supporting documentation, and
  11. * that the name of the copyright holders not be used in advertising or
  12. * publicity pertaining to distribution of the software without specific,
  13. * written prior permission. The copyright holders make no representations
  14. * about the suitability of this software for any purpose. It is provided "as
  15. * is" without express or implied warranty.
  16. *
  17. * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  18. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  19. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  20. * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  21. * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  22. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  23. * OF THIS SOFTWARE.
  24. *
  25. * Thanks to Jim Gettys who wrote most of the client side code,
  26. * and part of the server code for randr.
  27. */
  28. #include <stdio.h>
  29. #include <X11/Xlib.h>
  30. #include <X11/Xlibint.h>
  31. #include <X11/Xproto.h>
  32. #include <X11/Xatom.h>
  33. #include <X11/extensions/Xrandr.h>
  34. #include <X11/extensions/Xrender.h> /* we share subpixel information */
  35. #include <strings.h>
  36. #include <string.h>
  37. #include <stdlib.h>
  38. #include <stdint.h>
  39. #include <inttypes.h>
  40. #include <stdarg.h>
  41. #include <math.h>
  42. #ifdef HAVE_CONFIG_H
  43. #include "config.h"
  44. #endif
  45. static char *program_name;
  46. static Display *dpy;
  47. static Window root;
  48. static int screen = -1;
  49. static Bool verbose = False;
  50. static Bool automatic = False;
  51. static Bool properties = False;
  52. static Bool grab_server = True;
  53. static Bool no_primary = False;
  54. static const char *direction[5] = {
  55. "normal",
  56. "left",
  57. "inverted",
  58. "right",
  59. "\n"};
  60. static const char *reflections[5] = {
  61. "normal",
  62. "x",
  63. "y",
  64. "xy",
  65. "\n"};
  66. /* subpixel order */
  67. static const char *order[6] = {
  68. "unknown",
  69. "horizontal rgb",
  70. "horizontal bgr",
  71. "vertical rgb",
  72. "vertical bgr",
  73. "no subpixels"};
  74. static const struct {
  75. const char *string;
  76. unsigned long flag;
  77. } mode_flags[] = {
  78. { "+HSync", RR_HSyncPositive },
  79. { "-HSync", RR_HSyncNegative },
  80. { "+VSync", RR_VSyncPositive },
  81. { "-VSync", RR_VSyncNegative },
  82. { "Interlace", RR_Interlace },
  83. { "DoubleScan", RR_DoubleScan },
  84. { "CSync", RR_CSync },
  85. { "+CSync", RR_CSyncPositive },
  86. { "-CSync", RR_CSyncNegative },
  87. { NULL, 0 }
  88. };
  89. static void
  90. usage(void)
  91. {
  92. printf("usage: %s [options]\n%s", program_name,
  93. " where options are:\n"
  94. " --display <display> or -d <display>\n"
  95. " --help\n"
  96. " -o <normal,inverted,left,right,0,1,2,3>\n"
  97. " or --orientation <normal,inverted,left,right,0,1,2,3>\n"
  98. " -q or --query\n"
  99. " -s <size>/<width>x<height> or --size <size>/<width>x<height>\n"
  100. " -r <rate> or --rate <rate> or --refresh <rate>\n"
  101. " -v or --version\n"
  102. " -x (reflect in x)\n"
  103. " -y (reflect in y)\n"
  104. " --screen <screen>\n"
  105. " --verbose\n"
  106. " --current\n"
  107. " --dryrun\n"
  108. " --nograb\n"
  109. " --prop or --properties\n"
  110. " --fb <width>x<height>\n"
  111. " --fbmm <width>x<height>\n"
  112. " --dpi <dpi>/<output>\n"
  113. " --output <output>\n"
  114. " --auto\n"
  115. " --mode <mode>\n"
  116. " --preferred\n"
  117. " --pos <x>x<y>\n"
  118. " --rate <rate> or --refresh <rate>\n"
  119. " --reflect normal,x,y,xy\n"
  120. " --rotate normal,inverted,left,right\n"
  121. " --left-of <output>\n"
  122. " --right-of <output>\n"
  123. " --above <output>\n"
  124. " --below <output>\n"
  125. " --same-as <output>\n"
  126. " --set <property> <value>\n"
  127. " --scale <x>x<y>\n"
  128. " --scale-from <w>x<h>\n"
  129. " --transform <a>,<b>,<c>,<d>,<e>,<f>,<g>,<h>,<i>\n"
  130. " --off\n"
  131. " --crtc <crtc>\n"
  132. " --panning <w>x<h>[+<x>+<y>[/<track:w>x<h>+<x>+<y>[/<border:l>/<t>/<r>/<b>]]]\n"
  133. " --gamma <r>:<g>:<b>\n"
  134. " --brightness <value>\n"
  135. " --primary\n"
  136. " --noprimary\n"
  137. " --newmode <name> <clock MHz>\n"
  138. " <hdisp> <hsync-start> <hsync-end> <htotal>\n"
  139. " <vdisp> <vsync-start> <vsync-end> <vtotal>\n"
  140. " [flags...]\n"
  141. " Valid flags: +HSync -HSync +VSync -VSync\n"
  142. " +CSync -CSync CSync Interlace DoubleScan\n"
  143. " --rmmode <name>\n"
  144. " --addmode <output> <name>\n"
  145. " --delmode <output> <name>\n"
  146. " --listproviders\n"
  147. " --setprovideroutputsource <prov-xid> <source-xid>\n"
  148. " --setprovideroffloadsink <prov-xid> <sink-xid>\n");
  149. }
  150. static void _X_NORETURN _X_ATTRIBUTE_PRINTF(1,2)
  151. fatal (const char *format, ...)
  152. {
  153. va_list ap;
  154. va_start (ap, format);
  155. fprintf (stderr, "%s: ", program_name);
  156. vfprintf (stderr, format, ap);
  157. va_end (ap);
  158. exit (1);
  159. /*NOTREACHED*/
  160. }
  161. static void _X_ATTRIBUTE_PRINTF(1,2)
  162. warning (const char *format, ...)
  163. {
  164. va_list ap;
  165. va_start (ap, format);
  166. fprintf (stderr, "%s: ", program_name);
  167. vfprintf (stderr, format, ap);
  168. va_end (ap);
  169. }
  170. static void _X_NORETURN _X_ATTRIBUTE_PRINTF(1,2)
  171. argerr (const char *format, ...)
  172. {
  173. va_list ap;
  174. va_start (ap, format);
  175. fprintf (stderr, "%s: ", program_name);
  176. vfprintf (stderr, format, ap);
  177. fprintf (stderr, "Try '%s --help' for more information.\n", program_name);
  178. va_end (ap);
  179. exit (1);
  180. /*NOTREACHED*/
  181. }
  182. /* Because fmin requires C99 suppport */
  183. static inline double dmin (double x, double y)
  184. {
  185. return x < y ? x : y;
  186. }
  187. static const char *
  188. rotation_name (Rotation rotation)
  189. {
  190. int i;
  191. if ((rotation & 0xf) == 0)
  192. return "normal";
  193. for (i = 0; i < 4; i++)
  194. if (rotation & (1 << i))
  195. return direction[i];
  196. return "invalid rotation";
  197. }
  198. static const char *
  199. reflection_name (Rotation rotation)
  200. {
  201. rotation &= (RR_Reflect_X|RR_Reflect_Y);
  202. switch (rotation) {
  203. case 0:
  204. return "none";
  205. case RR_Reflect_X:
  206. return "X axis";
  207. case RR_Reflect_Y:
  208. return "Y axis";
  209. case RR_Reflect_X|RR_Reflect_Y:
  210. return "X and Y axis";
  211. }
  212. return "invalid reflection";
  213. }
  214. static const char *
  215. capability_name (int cap_bit)
  216. {
  217. switch (cap_bit) {
  218. case RR_Capability_SourceOutput:
  219. return "Source Output";
  220. case RR_Capability_SinkOutput:
  221. return "Sink Output";
  222. case RR_Capability_SourceOffload:
  223. return "Source Offload";
  224. case RR_Capability_SinkOffload:
  225. return "Sink Offload";
  226. }
  227. return "invalid capability";
  228. }
  229. typedef enum _relation {
  230. relation_left_of,
  231. relation_right_of,
  232. relation_above,
  233. relation_below,
  234. relation_same_as,
  235. } relation_t;
  236. typedef struct {
  237. int x, y, width, height;
  238. } rectangle_t;
  239. typedef struct {
  240. int x1, y1, x2, y2;
  241. } box_t;
  242. typedef struct {
  243. int x, y;
  244. } point_t;
  245. typedef enum _changes {
  246. changes_none = 0,
  247. changes_crtc = (1 << 0),
  248. changes_mode = (1 << 1),
  249. changes_relation = (1 << 2),
  250. changes_position = (1 << 3),
  251. changes_rotation = (1 << 4),
  252. changes_reflection = (1 << 5),
  253. changes_automatic = (1 << 6),
  254. changes_refresh = (1 << 7),
  255. changes_property = (1 << 8),
  256. changes_transform = (1 << 9),
  257. changes_panning = (1 << 10),
  258. changes_gamma = (1 << 11),
  259. changes_primary = (1 << 12),
  260. } changes_t;
  261. typedef enum _name_kind {
  262. name_none = 0,
  263. name_string = (1 << 0),
  264. name_xid = (1 << 1),
  265. name_index = (1 << 2),
  266. name_preferred = (1 << 3),
  267. } name_kind_t;
  268. typedef struct {
  269. name_kind_t kind;
  270. char *string;
  271. XID xid;
  272. int index;
  273. } name_t;
  274. typedef struct _crtc crtc_t;
  275. typedef struct _output output_t;
  276. typedef struct _transform transform_t;
  277. typedef struct _umode umode_t;
  278. typedef struct _output_prop output_prop_t;
  279. typedef struct _provider provider_t;
  280. struct _transform {
  281. XTransform transform;
  282. const char *filter;
  283. int nparams;
  284. XFixed *params;
  285. };
  286. struct _crtc {
  287. name_t crtc;
  288. Bool changing;
  289. XRRCrtcInfo *crtc_info;
  290. XRRModeInfo *mode_info;
  291. XRRPanning *panning_info;
  292. int x;
  293. int y;
  294. Rotation rotation;
  295. output_t **outputs;
  296. int noutput;
  297. transform_t current_transform, pending_transform;
  298. };
  299. struct _output_prop {
  300. struct _output_prop *next;
  301. char *name;
  302. char *value;
  303. };
  304. struct _output {
  305. struct _output *next;
  306. changes_t changes;
  307. output_prop_t *props;
  308. name_t output;
  309. XRROutputInfo *output_info;
  310. name_t crtc;
  311. crtc_t *crtc_info;
  312. crtc_t *current_crtc_info;
  313. name_t mode;
  314. double refresh;
  315. XRRModeInfo *mode_info;
  316. name_t addmode;
  317. relation_t relation;
  318. char *relative_to;
  319. int x, y;
  320. Rotation rotation;
  321. XRRPanning panning;
  322. Bool automatic;
  323. int scale_from_w, scale_from_h;
  324. transform_t transform;
  325. struct {
  326. float red;
  327. float green;
  328. float blue;
  329. } gamma;
  330. float brightness;
  331. Bool primary;
  332. Bool found;
  333. };
  334. typedef enum _umode_action {
  335. umode_create, umode_destroy, umode_add, umode_delete
  336. } umode_action_t;
  337. struct _umode {
  338. struct _umode *next;
  339. umode_action_t action;
  340. XRRModeInfo mode;
  341. name_t output;
  342. name_t name;
  343. };
  344. struct _provider {
  345. name_t provider;
  346. XRRProviderInfo *info;
  347. };
  348. static const char *connection[3] = {
  349. "connected",
  350. "disconnected",
  351. "unknown connection"};
  352. #define OUTPUT_NAME 1
  353. #define CRTC_OFF 2
  354. #define CRTC_UNSET 3
  355. #define CRTC_INDEX 0x40000000
  356. #define MODE_NAME 1
  357. #define MODE_OFF 2
  358. #define MODE_UNSET 3
  359. #define MODE_PREF 4
  360. #define POS_UNSET -1
  361. static output_t *all_outputs = NULL;
  362. static output_t **all_outputs_tail = &all_outputs;
  363. static crtc_t *crtcs;
  364. static provider_t *providers;
  365. static umode_t *umodes;
  366. static int num_crtcs, num_providers;
  367. static XRRScreenResources *res;
  368. static int fb_width = 0, fb_height = 0;
  369. static int fb_width_mm = 0, fb_height_mm = 0;
  370. static double dpi = 0;
  371. static char *dpi_output_name = NULL;
  372. static Bool dryrun = False;
  373. static int minWidth, maxWidth, minHeight, maxHeight;
  374. static Bool has_1_2 = False;
  375. static Bool has_1_3 = False;
  376. static Bool has_1_4 = False;
  377. static name_t provider_name, output_source_provider_name, offload_sink_provider_name;
  378. static int
  379. mode_height (XRRModeInfo *mode_info, Rotation rotation)
  380. {
  381. switch (rotation & 0xf) {
  382. case RR_Rotate_0:
  383. case RR_Rotate_180:
  384. return mode_info->height;
  385. case RR_Rotate_90:
  386. case RR_Rotate_270:
  387. return mode_info->width;
  388. default:
  389. return 0;
  390. }
  391. }
  392. static int
  393. mode_width (XRRModeInfo *mode_info, Rotation rotation)
  394. {
  395. switch (rotation & 0xf) {
  396. case RR_Rotate_0:
  397. case RR_Rotate_180:
  398. return mode_info->width;
  399. case RR_Rotate_90:
  400. case RR_Rotate_270:
  401. return mode_info->height;
  402. default:
  403. return 0;
  404. }
  405. }
  406. static Bool
  407. transform_point (XTransform *transform, double *xp, double *yp)
  408. {
  409. double vector[3];
  410. double result[3];
  411. int i, j;
  412. double v;
  413. vector[0] = *xp;
  414. vector[1] = *yp;
  415. vector[2] = 1;
  416. for (j = 0; j < 3; j++)
  417. {
  418. v = 0;
  419. for (i = 0; i < 3; i++)
  420. v += (XFixedToDouble (transform->matrix[j][i]) * vector[i]);
  421. result[j] = v;
  422. }
  423. if (!result[2])
  424. return False;
  425. for (j = 0; j < 2; j++) {
  426. vector[j] = result[j] / result[2];
  427. if (vector[j] > 32767 || vector[j] < -32767)
  428. return False;
  429. }
  430. *xp = vector[0];
  431. *yp = vector[1];
  432. return True;
  433. }
  434. static void
  435. path_bounds (XTransform *transform, point_t *points, int npoints, box_t *box)
  436. {
  437. int i;
  438. box_t point;
  439. for (i = 0; i < npoints; i++) {
  440. double x, y;
  441. x = points[i].x;
  442. y = points[i].y;
  443. transform_point (transform, &x, &y);
  444. point.x1 = floor (x);
  445. point.y1 = floor (y);
  446. point.x2 = ceil (x);
  447. point.y2 = ceil (y);
  448. if (i == 0)
  449. *box = point;
  450. else {
  451. if (point.x1 < box->x1) box->x1 = point.x1;
  452. if (point.y1 < box->y1) box->y1 = point.y1;
  453. if (point.x2 > box->x2) box->x2 = point.x2;
  454. if (point.y2 > box->y2) box->y2 = point.y2;
  455. }
  456. }
  457. }
  458. static void
  459. mode_geometry (XRRModeInfo *mode_info, Rotation rotation,
  460. XTransform *transform,
  461. box_t *bounds)
  462. {
  463. point_t rect[4];
  464. int width = mode_width (mode_info, rotation);
  465. int height = mode_height (mode_info, rotation);
  466. rect[0].x = 0;
  467. rect[0].y = 0;
  468. rect[1].x = width;
  469. rect[1].y = 0;
  470. rect[2].x = width;
  471. rect[2].y = height;
  472. rect[3].x = 0;
  473. rect[3].y = height;
  474. path_bounds (transform, rect, 4, bounds);
  475. }
  476. /* v refresh frequency in Hz */
  477. static double
  478. mode_refresh (XRRModeInfo *mode_info)
  479. {
  480. double rate;
  481. double vTotal = mode_info->vTotal;
  482. if (mode_info->modeFlags & RR_DoubleScan) {
  483. /* doublescan doubles the number of lines */
  484. vTotal *= 2;
  485. }
  486. if (mode_info->modeFlags & RR_Interlace) {
  487. /* interlace splits the frame into two fields */
  488. /* the field rate is what is typically reported by monitors */
  489. vTotal /= 2;
  490. }
  491. if (mode_info->hTotal && vTotal)
  492. rate = ((double) mode_info->dotClock /
  493. ((double) mode_info->hTotal * (double) vTotal));
  494. else
  495. rate = 0;
  496. return rate;
  497. }
  498. /* h sync frequency in Hz */
  499. static double
  500. mode_hsync (XRRModeInfo *mode_info)
  501. {
  502. double rate;
  503. if (mode_info->hTotal)
  504. rate = (double) mode_info->dotClock / (double) mode_info->hTotal;
  505. else
  506. rate = 0;
  507. return rate;
  508. }
  509. static void
  510. init_name (name_t *name)
  511. {
  512. name->kind = name_none;
  513. }
  514. static void
  515. set_name_string (name_t *name, char *string)
  516. {
  517. name->kind |= name_string;
  518. name->string = string;
  519. }
  520. static void
  521. set_name_xid (name_t *name, XID xid)
  522. {
  523. name->kind |= name_xid;
  524. name->xid = xid;
  525. }
  526. static void
  527. set_name_index (name_t *name, int idx)
  528. {
  529. name->kind |= name_index;
  530. name->index = idx;
  531. }
  532. static void
  533. set_name_preferred (name_t *name)
  534. {
  535. name->kind |= name_preferred;
  536. }
  537. static void
  538. set_name_all (name_t *name, name_t *old)
  539. {
  540. if (old->kind & name_xid)
  541. name->xid = old->xid;
  542. if (old->kind & name_string)
  543. name->string = old->string;
  544. if (old->kind & name_index)
  545. name->index = old->index;
  546. name->kind |= old->kind;
  547. }
  548. static void
  549. set_name (name_t *name, char *string, name_kind_t valid)
  550. {
  551. unsigned int xid; /* don't make it XID (which is unsigned long):
  552. scanf() takes unsigned int */
  553. int idx;
  554. if ((valid & name_xid) && sscanf (string, "0x%x", &xid) == 1)
  555. set_name_xid (name, xid);
  556. else if ((valid & name_index) && sscanf (string, "%d", &idx) == 1)
  557. set_name_index (name, idx);
  558. else if (valid & name_string)
  559. set_name_string (name, string);
  560. else
  561. argerr ("invalid name '%s'\n", string);
  562. }
  563. static int
  564. print_name (const name_t *name)
  565. {
  566. name_kind_t kind = name->kind;
  567. if ((kind & name_xid)) return printf("XID 0x%x", (unsigned int)name->xid);
  568. else if ((kind & name_string)) return printf("name %s", name->string);
  569. else if ((kind & name_index)) return printf("index %d", name->index);
  570. else return printf("unknown name");
  571. }
  572. static void
  573. init_transform (transform_t *transform)
  574. {
  575. int x;
  576. memset (&transform->transform, '\0', sizeof (transform->transform));
  577. for (x = 0; x < 3; x++)
  578. transform->transform.matrix[x][x] = XDoubleToFixed (1.0);
  579. transform->filter = "";
  580. transform->nparams = 0;
  581. transform->params = NULL;
  582. }
  583. static void
  584. set_transform (transform_t *dest,
  585. XTransform *transform,
  586. const char *filter,
  587. XFixed *params,
  588. int nparams)
  589. {
  590. dest->transform = *transform;
  591. /* note: this string is leaked */
  592. dest->filter = strdup (filter);
  593. dest->nparams = nparams;
  594. dest->params = malloc (nparams * sizeof (XFixed));
  595. memcpy (dest->params, params, nparams * sizeof (XFixed));
  596. }
  597. static void
  598. copy_transform (transform_t *dest, transform_t *src)
  599. {
  600. set_transform (dest, &src->transform,
  601. src->filter, src->params, src->nparams);
  602. }
  603. static Bool
  604. equal_transform (transform_t *a, transform_t *b)
  605. {
  606. if (memcmp (&a->transform, &b->transform, sizeof (XTransform)) != 0)
  607. return False;
  608. if (strcmp (a->filter, b->filter) != 0)
  609. return False;
  610. if (a->nparams != b->nparams)
  611. return False;
  612. if (memcmp (a->params, b->params, a->nparams * sizeof (XFixed)) != 0)
  613. return False;
  614. return True;
  615. }
  616. static output_t *
  617. add_output (void)
  618. {
  619. output_t *output = calloc (1, sizeof (output_t));
  620. if (!output)
  621. fatal ("out of memory\n");
  622. output->next = NULL;
  623. output->found = False;
  624. output->brightness = 1.0;
  625. *all_outputs_tail = output;
  626. all_outputs_tail = &output->next;
  627. return output;
  628. }
  629. static output_t *
  630. find_output (name_t *name)
  631. {
  632. output_t *output;
  633. for (output = all_outputs; output; output = output->next)
  634. {
  635. name_kind_t common = name->kind & output->output.kind;
  636. if ((common & name_xid) && name->xid == output->output.xid)
  637. break;
  638. if ((common & name_string) && !strcmp (name->string, output->output.string))
  639. break;
  640. if ((common & name_index) && name->index == output->output.index)
  641. break;
  642. }
  643. return output;
  644. }
  645. static output_t *
  646. find_output_by_xid (RROutput output)
  647. {
  648. name_t output_name;
  649. init_name (&output_name);
  650. set_name_xid (&output_name, output);
  651. return find_output (&output_name);
  652. }
  653. static output_t *
  654. find_output_by_name (char *name)
  655. {
  656. name_t output_name;
  657. init_name (&output_name);
  658. set_name_string (&output_name, name);
  659. return find_output (&output_name);
  660. }
  661. static crtc_t *
  662. find_crtc (name_t *name)
  663. {
  664. int c;
  665. crtc_t *crtc = NULL;
  666. for (c = 0; c < num_crtcs; c++)
  667. {
  668. name_kind_t common;
  669. crtc = &crtcs[c];
  670. common = name->kind & crtc->crtc.kind;
  671. if ((common & name_xid) && name->xid == crtc->crtc.xid)
  672. break;
  673. if ((common & name_string) && !strcmp (name->string, crtc->crtc.string))
  674. break;
  675. if ((common & name_index) && name->index == crtc->crtc.index)
  676. break;
  677. crtc = NULL;
  678. }
  679. return crtc;
  680. }
  681. static crtc_t *
  682. find_crtc_by_xid (RRCrtc crtc)
  683. {
  684. name_t crtc_name;
  685. init_name (&crtc_name);
  686. set_name_xid (&crtc_name, crtc);
  687. return find_crtc (&crtc_name);
  688. }
  689. static XRRModeInfo *
  690. find_mode (name_t *name, double refresh)
  691. {
  692. int m;
  693. XRRModeInfo *best = NULL;
  694. double bestDist = 0;
  695. for (m = 0; m < res->nmode; m++)
  696. {
  697. XRRModeInfo *mode = &res->modes[m];
  698. if ((name->kind & name_xid) && name->xid == mode->id)
  699. {
  700. best = mode;
  701. break;
  702. }
  703. if ((name->kind & name_string) && !strcmp (name->string, mode->name))
  704. {
  705. double dist;
  706. if (refresh)
  707. dist = fabs (mode_refresh (mode) - refresh);
  708. else
  709. dist = 0;
  710. if (!best || dist < bestDist)
  711. {
  712. bestDist = dist;
  713. best = mode;
  714. }
  715. }
  716. }
  717. return best;
  718. }
  719. static XRRModeInfo *
  720. find_mode_by_xid (RRMode mode)
  721. {
  722. name_t mode_name;
  723. init_name (&mode_name);
  724. set_name_xid (&mode_name, mode);
  725. return find_mode (&mode_name, 0);
  726. }
  727. #if 0
  728. static XRRModeInfo *
  729. find_mode_by_name (char *name)
  730. {
  731. name_t mode_name;
  732. init_name (&mode_name);
  733. set_name_string (&mode_name, name);
  734. return find_mode (&mode_name, 0);
  735. }
  736. #endif
  737. static
  738. XRRModeInfo *
  739. find_mode_for_output (output_t *output, name_t *name)
  740. {
  741. XRROutputInfo *output_info = output->output_info;
  742. int m;
  743. XRRModeInfo *best = NULL;
  744. double bestDist = 0;
  745. for (m = 0; m < output_info->nmode; m++)
  746. {
  747. XRRModeInfo *mode;
  748. mode = find_mode_by_xid (output_info->modes[m]);
  749. if (!mode) continue;
  750. if ((name->kind & name_xid) && name->xid == mode->id)
  751. {
  752. best = mode;
  753. break;
  754. }
  755. if ((name->kind & name_string) && !strcmp (name->string, mode->name))
  756. {
  757. double dist;
  758. /* Stay away from doublescan modes unless refresh rate is specified. */
  759. if (!output->refresh && (mode->modeFlags & RR_DoubleScan))
  760. continue;
  761. if (output->refresh)
  762. dist = fabs (mode_refresh (mode) - output->refresh);
  763. else
  764. dist = 0;
  765. if (!best || dist < bestDist)
  766. {
  767. bestDist = dist;
  768. best = mode;
  769. }
  770. }
  771. }
  772. return best;
  773. }
  774. static XRRModeInfo *
  775. preferred_mode (output_t *output)
  776. {
  777. XRROutputInfo *output_info = output->output_info;
  778. int m;
  779. XRRModeInfo *best;
  780. int bestDist;
  781. best = NULL;
  782. bestDist = 0;
  783. for (m = 0; m < output_info->nmode; m++)
  784. {
  785. XRRModeInfo *mode_info = find_mode_by_xid (output_info->modes[m]);
  786. int dist;
  787. if (m < output_info->npreferred)
  788. dist = 0;
  789. else if (output_info->mm_height)
  790. dist = (1000 * DisplayHeight(dpy, screen) / DisplayHeightMM(dpy, screen) -
  791. 1000 * mode_info->height / output_info->mm_height);
  792. else
  793. dist = DisplayHeight(dpy, screen) - mode_info->height;
  794. if (dist < 0) dist = -dist;
  795. if (!best || dist < bestDist)
  796. {
  797. best = mode_info;
  798. bestDist = dist;
  799. }
  800. }
  801. return best;
  802. }
  803. static Bool
  804. output_can_use_crtc (output_t *output, crtc_t *crtc)
  805. {
  806. XRROutputInfo *output_info = output->output_info;
  807. int c;
  808. for (c = 0; c < output_info->ncrtc; c++)
  809. if (output_info->crtcs[c] == crtc->crtc.xid)
  810. return True;
  811. return False;
  812. }
  813. static Bool
  814. output_can_use_mode (output_t *output, XRRModeInfo *mode)
  815. {
  816. XRROutputInfo *output_info = output->output_info;
  817. int m;
  818. for (m = 0; m < output_info->nmode; m++)
  819. if (output_info->modes[m] == mode->id)
  820. return True;
  821. return False;
  822. }
  823. static Bool
  824. crtc_can_use_rotation (crtc_t *crtc, Rotation rotation)
  825. {
  826. Rotation rotations = crtc->crtc_info->rotations;
  827. Rotation dir = rotation & (RR_Rotate_0|RR_Rotate_90|RR_Rotate_180|RR_Rotate_270);
  828. Rotation reflect = rotation & (RR_Reflect_X|RR_Reflect_Y);
  829. if (((rotations & dir) != 0) && ((rotations & reflect) == reflect))
  830. return True;
  831. return False;
  832. }
  833. #if 0
  834. static Bool
  835. crtc_can_use_transform (crtc_t *crtc, XTransform *transform)
  836. {
  837. int major, minor;
  838. XRRQueryVersion (dpy, &major, &minor);
  839. if (major > 1 || (major == 1 && minor >= 3))
  840. return True;
  841. return False;
  842. }
  843. #endif
  844. /*
  845. * Report only rotations that are supported by all crtcs
  846. */
  847. static Rotation
  848. output_rotations (output_t *output)
  849. {
  850. Bool found = False;
  851. Rotation rotation = RR_Rotate_0;
  852. XRROutputInfo *output_info = output->output_info;
  853. int c;
  854. for (c = 0; c < output_info->ncrtc; c++)
  855. {
  856. crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]);
  857. if (crtc)
  858. {
  859. if (!found) {
  860. rotation = crtc->crtc_info->rotations;
  861. found = True;
  862. } else
  863. rotation &= crtc->crtc_info->rotations;
  864. }
  865. }
  866. return rotation;
  867. }
  868. static Bool
  869. output_can_use_rotation (output_t *output, Rotation rotation)
  870. {
  871. XRROutputInfo *output_info = output->output_info;
  872. int c;
  873. /* make sure all of the crtcs can use this rotation.
  874. * yes, this is not strictly necessary, but it is
  875. * simpler,and we expect most drivers to either
  876. * support rotation everywhere or nowhere
  877. */
  878. for (c = 0; c < output_info->ncrtc; c++)
  879. {
  880. crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[c]);
  881. if (crtc && !crtc_can_use_rotation (crtc, rotation))
  882. return False;
  883. }
  884. return True;
  885. }
  886. static Bool
  887. output_is_primary(output_t *output)
  888. {
  889. if (has_1_3)
  890. return XRRGetOutputPrimary(dpy, root) == output->output.xid;
  891. return False;
  892. }
  893. /* Returns the index of the last value in an array < 0xffff */
  894. static int
  895. find_last_non_clamped(CARD16 array[], int size) {
  896. int i;
  897. for (i = size - 1; i > 0; i--) {
  898. if (array[i] < 0xffff)
  899. return i;
  900. }
  901. return 0;
  902. }
  903. static void
  904. set_gamma_info(output_t *output)
  905. {
  906. XRRCrtcGamma *crtc_gamma;
  907. double i1, v1, i2, v2;
  908. int size, middle, last_best, last_red, last_green, last_blue;
  909. CARD16 *best_array;
  910. if (!output->crtc_info)
  911. return;
  912. size = XRRGetCrtcGammaSize(dpy, output->crtc_info->crtc.xid);
  913. if (!size) {
  914. warning("Failed to get size of gamma for output %s\n", output->output.string);
  915. return;
  916. }
  917. crtc_gamma = XRRGetCrtcGamma(dpy, output->crtc_info->crtc.xid);
  918. if (!crtc_gamma) {
  919. warning("Failed to get gamma for output %s\n", output->output.string);
  920. return;
  921. }
  922. /*
  923. * Here is a bit tricky because gamma is a whole curve for each
  924. * color. So, typically, we need to represent 3 * 256 values as 3 + 1
  925. * values. Therefore, we approximate the gamma curve (v) by supposing
  926. * it always follows the way we set it: a power function (i^g)
  927. * multiplied by a brightness (b).
  928. * v = i^g * b
  929. * so g = (ln(v) - ln(b))/ln(i)
  930. * and b can be found using two points (v1,i1) and (v2, i2):
  931. * b = e^((ln(v2)*ln(i1) - ln(v1)*ln(i2))/ln(i1/i2))
  932. * For the best resolution, we select i2 at the highest place not
  933. * clamped and i1 at i2/2. Note that if i2 = 1 (as in most normal
  934. * cases), then b = v2.
  935. */
  936. last_red = find_last_non_clamped(crtc_gamma->red, size);
  937. last_green = find_last_non_clamped(crtc_gamma->green, size);
  938. last_blue = find_last_non_clamped(crtc_gamma->blue, size);
  939. best_array = crtc_gamma->red;
  940. last_best = last_red;
  941. if (last_green > last_best) {
  942. last_best = last_green;
  943. best_array = crtc_gamma->green;
  944. }
  945. if (last_blue > last_best) {
  946. last_best = last_blue;
  947. best_array = crtc_gamma->blue;
  948. }
  949. if (last_best == 0)
  950. last_best = 1;
  951. middle = last_best / 2;
  952. i1 = (double)(middle + 1) / size;
  953. v1 = (double)(best_array[middle]) / 65535;
  954. i2 = (double)(last_best + 1) / size;
  955. v2 = (double)(best_array[last_best]) / 65535;
  956. if (v2 < 0.0001) { /* The screen is black */
  957. output->brightness = 0;
  958. output->gamma.red = 1;
  959. output->gamma.green = 1;
  960. output->gamma.blue = 1;
  961. } else {
  962. if ((last_best + 1) == size)
  963. output->brightness = v2;
  964. else
  965. output->brightness = exp((log(v2)*log(i1) - log(v1)*log(i2))/log(i1/i2));
  966. output->gamma.red = log((double)(crtc_gamma->red[last_red / 2]) / output->brightness
  967. / 65535) / log((double)((last_red / 2) + 1) / size);
  968. output->gamma.green = log((double)(crtc_gamma->green[last_green / 2]) / output->brightness
  969. / 65535) / log((double)((last_green / 2) + 1) / size);
  970. output->gamma.blue = log((double)(crtc_gamma->blue[last_blue / 2]) / output->brightness
  971. / 65535) / log((double)((last_blue / 2) + 1) / size);
  972. }
  973. XRRFreeGamma(crtc_gamma);
  974. }
  975. static void
  976. set_output_info (output_t *output, RROutput xid, XRROutputInfo *output_info)
  977. {
  978. /* sanity check output info */
  979. if (output_info->connection != RR_Disconnected && !output_info->nmode)
  980. warning ("Output %s is not disconnected but has no modes\n",
  981. output_info->name);
  982. /* set output name and info */
  983. if (!(output->output.kind & name_xid))
  984. set_name_xid (&output->output, xid);
  985. if (!(output->output.kind & name_string))
  986. set_name_string (&output->output, output_info->name);
  987. output->output_info = output_info;
  988. /* set crtc name and info */
  989. if (!(output->changes & changes_crtc))
  990. set_name_xid (&output->crtc, output_info->crtc);
  991. if (output->crtc.kind == name_xid && output->crtc.xid == None)
  992. output->crtc_info = NULL;
  993. else
  994. {
  995. output->crtc_info = find_crtc (&output->crtc);
  996. if (!output->crtc_info)
  997. {
  998. if (output->crtc.kind & name_xid)
  999. fatal ("cannot find crtc 0x%lx\n", output->crtc.xid);
  1000. if (output->crtc.kind & name_index)
  1001. fatal ("cannot find crtc %d\n", output->crtc.index);
  1002. }
  1003. if (!output_can_use_crtc (output, output->crtc_info))
  1004. fatal ("output %s cannot use crtc 0x%lx\n", output->output.string,
  1005. output->crtc_info->crtc.xid);
  1006. }
  1007. /* set mode name and info */
  1008. if (!(output->changes & changes_mode))
  1009. {
  1010. crtc_t *crtc = NULL;
  1011. if (output_info->crtc)
  1012. crtc = find_crtc_by_xid(output_info->crtc);
  1013. if (crtc && crtc->crtc_info)
  1014. set_name_xid (&output->mode, crtc->crtc_info->mode);
  1015. else if (output->crtc_info)
  1016. set_name_xid (&output->mode, output->crtc_info->crtc_info->mode);
  1017. else
  1018. set_name_xid (&output->mode, None);
  1019. if (output->mode.xid)
  1020. {
  1021. output->mode_info = find_mode_by_xid (output->mode.xid);
  1022. if (!output->mode_info)
  1023. fatal ("server did not report mode 0x%lx for output %s\n",
  1024. output->mode.xid, output->output.string);
  1025. }
  1026. else
  1027. output->mode_info = NULL;
  1028. }
  1029. else if (output->mode.kind == name_xid && output->mode.xid == None)
  1030. output->mode_info = NULL;
  1031. else
  1032. {
  1033. if (output->mode.kind == name_preferred)
  1034. output->mode_info = preferred_mode (output);
  1035. else
  1036. output->mode_info = find_mode_for_output (output, &output->mode);
  1037. if (!output->mode_info)
  1038. {
  1039. if (output->mode.kind & name_preferred)
  1040. fatal ("cannot find preferred mode\n");
  1041. if (output->mode.kind & name_string)
  1042. fatal ("cannot find mode %s\n", output->mode.string);
  1043. if (output->mode.kind & name_xid)
  1044. fatal ("cannot find mode 0x%lx\n", output->mode.xid);
  1045. }
  1046. if (!output_can_use_mode (output, output->mode_info))
  1047. fatal ("output %s cannot use mode %s\n", output->output.string,
  1048. output->mode_info->name);
  1049. }
  1050. /* set position */
  1051. if (!(output->changes & changes_position))
  1052. {
  1053. if (output->crtc_info)
  1054. {
  1055. output->x = output->crtc_info->crtc_info->x;
  1056. output->y = output->crtc_info->crtc_info->y;
  1057. }
  1058. else
  1059. {
  1060. output->x = 0;
  1061. output->y = 0;
  1062. }
  1063. }
  1064. /* set rotation */
  1065. if (!(output->changes & changes_rotation))
  1066. {
  1067. output->rotation &= ~0xf;
  1068. if (output->crtc_info)
  1069. output->rotation |= (output->crtc_info->crtc_info->rotation & 0xf);
  1070. else
  1071. output->rotation = RR_Rotate_0;
  1072. }
  1073. if (!(output->changes & changes_reflection))
  1074. {
  1075. output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y);
  1076. if (output->crtc_info)
  1077. output->rotation |= (output->crtc_info->crtc_info->rotation &
  1078. (RR_Reflect_X|RR_Reflect_Y));
  1079. }
  1080. if (!output_can_use_rotation (output, output->rotation))
  1081. fatal ("output %s cannot use rotation \"%s\" reflection \"%s\"\n",
  1082. output->output.string,
  1083. rotation_name (output->rotation),
  1084. reflection_name (output->rotation));
  1085. /* set gamma */
  1086. if (!(output->changes & changes_gamma))
  1087. set_gamma_info(output);
  1088. /* set transformation */
  1089. if (!(output->changes & changes_transform))
  1090. {
  1091. if (output->crtc_info)
  1092. copy_transform (&output->transform, &output->crtc_info->current_transform);
  1093. else
  1094. init_transform (&output->transform);
  1095. } else {
  1096. /* transform was already set for --scale or --transform */
  1097. /* for --scale-from, figure out the mode size and compute the transform
  1098. * for the target framebuffer area */
  1099. if (output->scale_from_w > 0 && output->mode_info) {
  1100. double sx = (double)output->scale_from_w /
  1101. output->mode_info->width;
  1102. double sy = (double)output->scale_from_h /
  1103. output->mode_info->height;
  1104. if (verbose)
  1105. printf("scaling %s by %lfx%lf\n", output->output.string, sx,
  1106. sy);
  1107. init_transform (&output->transform);
  1108. output->transform.transform.matrix[0][0] = XDoubleToFixed (sx);
  1109. output->transform.transform.matrix[1][1] = XDoubleToFixed (sy);
  1110. output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0);
  1111. if (sx != 1 || sy != 1)
  1112. output->transform.filter = "bilinear";
  1113. else
  1114. output->transform.filter = "nearest";
  1115. output->transform.nparams = 0;
  1116. output->transform.params = NULL;
  1117. }
  1118. }
  1119. /* set primary */
  1120. if (!(output->changes & changes_primary))
  1121. output->primary = output_is_primary(output);
  1122. }
  1123. static void
  1124. get_screen (Bool current)
  1125. {
  1126. if (!has_1_2)
  1127. fatal ("Server RandR version before 1.2\n");
  1128. if (res)
  1129. return;
  1130. XRRGetScreenSizeRange (dpy, root, &minWidth, &minHeight,
  1131. &maxWidth, &maxHeight);
  1132. if (current)
  1133. res = XRRGetScreenResourcesCurrent (dpy, root);
  1134. else
  1135. res = XRRGetScreenResources (dpy, root);
  1136. if (!res) fatal ("could not get screen resources");
  1137. }
  1138. static void
  1139. get_crtcs (void)
  1140. {
  1141. int c;
  1142. num_crtcs = res->ncrtc;
  1143. crtcs = calloc (num_crtcs, sizeof (crtc_t));
  1144. if (!crtcs) fatal ("out of memory\n");
  1145. for (c = 0; c < res->ncrtc; c++)
  1146. {
  1147. XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (dpy, res, res->crtcs[c]);
  1148. XRRCrtcTransformAttributes *attr;
  1149. XRRPanning *panning_info = NULL;
  1150. if (has_1_3) {
  1151. XRRPanning zero;
  1152. memset(&zero, 0, sizeof(zero));
  1153. panning_info = XRRGetPanning (dpy, res, res->crtcs[c]);
  1154. zero.timestamp = panning_info->timestamp;
  1155. if (!memcmp(panning_info, &zero, sizeof(zero))) {
  1156. Xfree(panning_info);
  1157. panning_info = NULL;
  1158. }
  1159. }
  1160. set_name_xid (&crtcs[c].crtc, res->crtcs[c]);
  1161. set_name_index (&crtcs[c].crtc, c);
  1162. if (!crtc_info) fatal ("could not get crtc 0x%lx information\n", res->crtcs[c]);
  1163. crtcs[c].crtc_info = crtc_info;
  1164. crtcs[c].panning_info = panning_info;
  1165. if (crtc_info->mode == None)
  1166. {
  1167. crtcs[c].mode_info = NULL;
  1168. crtcs[c].x = 0;
  1169. crtcs[c].y = 0;
  1170. crtcs[c].rotation = RR_Rotate_0;
  1171. }
  1172. if (XRRGetCrtcTransform (dpy, res->crtcs[c], &attr) && attr) {
  1173. set_transform (&crtcs[c].current_transform,
  1174. &attr->currentTransform,
  1175. attr->currentFilter,
  1176. attr->currentParams,
  1177. attr->currentNparams);
  1178. XFree (attr);
  1179. }
  1180. else
  1181. {
  1182. init_transform (&crtcs[c].current_transform);
  1183. }
  1184. copy_transform (&crtcs[c].pending_transform, &crtcs[c].current_transform);
  1185. }
  1186. }
  1187. static void
  1188. crtc_add_output (crtc_t *crtc, output_t *output)
  1189. {
  1190. if (crtc->outputs)
  1191. crtc->outputs = realloc (crtc->outputs, (crtc->noutput + 1) * sizeof (output_t *));
  1192. else
  1193. {
  1194. crtc->outputs = malloc (sizeof (output_t *));
  1195. crtc->x = output->x;
  1196. crtc->y = output->y;
  1197. crtc->rotation = output->rotation;
  1198. crtc->mode_info = output->mode_info;
  1199. copy_transform (&crtc->pending_transform, &output->transform);
  1200. }
  1201. if (!crtc->outputs) fatal ("out of memory\n");
  1202. crtc->outputs[crtc->noutput++] = output;
  1203. }
  1204. static void
  1205. set_crtcs (void)
  1206. {
  1207. output_t *output;
  1208. for (output = all_outputs; output; output = output->next)
  1209. {
  1210. if (!output->mode_info) continue;
  1211. crtc_add_output (output->crtc_info, output);
  1212. }
  1213. }
  1214. static void
  1215. set_panning (void)
  1216. {
  1217. output_t *output;
  1218. for (output = all_outputs; output; output = output->next)
  1219. {
  1220. if (! output->crtc_info)
  1221. continue;
  1222. if (! (output->changes & changes_panning))
  1223. continue;
  1224. if (! output->crtc_info->panning_info)
  1225. output->crtc_info->panning_info = malloc (sizeof(XRRPanning));
  1226. memcpy (output->crtc_info->panning_info, &output->panning, sizeof(XRRPanning));
  1227. output->crtc_info->changing = 1;
  1228. }
  1229. }
  1230. static void
  1231. set_gamma(void)
  1232. {
  1233. output_t *output;
  1234. for (output = all_outputs; output; output = output->next) {
  1235. int i, size;
  1236. crtc_t *crtc;
  1237. XRRCrtcGamma *crtc_gamma;
  1238. float gammaRed;
  1239. float gammaGreen;
  1240. float gammaBlue;
  1241. if (!(output->changes & changes_gamma))
  1242. continue;
  1243. if (!output->crtc_info) {
  1244. fatal("Need crtc to set gamma on.\n");
  1245. continue;
  1246. }
  1247. crtc = output->crtc_info;
  1248. size = XRRGetCrtcGammaSize(dpy, crtc->crtc.xid);
  1249. if (!size) {
  1250. fatal("Gamma size is 0.\n");
  1251. continue;
  1252. }
  1253. /*
  1254. * The gamma-correction lookup table managed through XRR[GS]etCrtcGamma
  1255. * is 2^n in size, where 'n' is the number of significant bits in
  1256. * the X Color. Because an X Color is 16 bits, size cannot be larger
  1257. * than 2^16.
  1258. */
  1259. if (size > 65536) {
  1260. fatal("Gamma correction table is impossibly large.\n");
  1261. continue;
  1262. }
  1263. crtc_gamma = XRRAllocGamma(size);
  1264. if (!crtc_gamma) {
  1265. fatal("Gamma allocation failed.\n");
  1266. continue;
  1267. }
  1268. if (output->gamma.red == 0.0)
  1269. output->gamma.red = 1.0;
  1270. if (output->gamma.green == 0.0)
  1271. output->gamma.green = 1.0;
  1272. if (output->gamma.blue == 0.0)
  1273. output->gamma.blue = 1.0;
  1274. gammaRed = 1.0 / output->gamma.red;
  1275. gammaGreen = 1.0 / output->gamma.green;
  1276. gammaBlue = 1.0 / output->gamma.blue;
  1277. for (i = 0; i < size; i++) {
  1278. if (gammaRed == 1.0 && output->brightness == 1.0)
  1279. crtc_gamma->red[i] = (double)i / (double)(size - 1) * 65535.0;
  1280. else
  1281. crtc_gamma->red[i] = dmin(pow((double)i/(double)(size - 1),
  1282. gammaRed) * output->brightness,
  1283. 1.0) * 65535.0;
  1284. if (gammaGreen == 1.0 && output->brightness == 1.0)
  1285. crtc_gamma->green[i] = (double)i / (double)(size - 1) * 65535.0;
  1286. else
  1287. crtc_gamma->green[i] = dmin(pow((double)i/(double)(size - 1),
  1288. gammaGreen) * output->brightness,
  1289. 1.0) * 65535.0;
  1290. if (gammaBlue == 1.0 && output->brightness == 1.0)
  1291. crtc_gamma->blue[i] = (double)i / (double)(size - 1) * 65535.0;
  1292. else
  1293. crtc_gamma->blue[i] = dmin(pow((double)i/(double)(size - 1),
  1294. gammaBlue) * output->brightness,
  1295. 1.0) * 65535.0;
  1296. }
  1297. XRRSetCrtcGamma(dpy, crtc->crtc.xid, crtc_gamma);
  1298. free(crtc_gamma);
  1299. }
  1300. }
  1301. static void
  1302. set_primary(void)
  1303. {
  1304. output_t *output;
  1305. if (no_primary) {
  1306. XRRSetOutputPrimary(dpy, root, None);
  1307. } else {
  1308. for (output = all_outputs; output; output = output->next) {
  1309. if (!(output->changes & changes_primary))
  1310. continue;
  1311. if (output->primary)
  1312. XRRSetOutputPrimary(dpy, root, output->output.xid);
  1313. }
  1314. }
  1315. }
  1316. static Status
  1317. crtc_disable (crtc_t *crtc)
  1318. {
  1319. if (verbose)
  1320. printf ("crtc %d: disable\n", crtc->crtc.index);
  1321. if (dryrun)
  1322. return RRSetConfigSuccess;
  1323. return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
  1324. 0, 0, None, RR_Rotate_0, NULL, 0);
  1325. }
  1326. static void
  1327. crtc_set_transform (crtc_t *crtc, transform_t *transform)
  1328. {
  1329. int major, minor;
  1330. XRRQueryVersion (dpy, &major, &minor);
  1331. if (major > 1 || (major == 1 && minor >= 3))
  1332. XRRSetCrtcTransform (dpy, crtc->crtc.xid,
  1333. &transform->transform,
  1334. transform->filter,
  1335. transform->params,
  1336. transform->nparams);
  1337. }
  1338. static Status
  1339. crtc_revert (crtc_t *crtc)
  1340. {
  1341. XRRCrtcInfo *crtc_info = crtc->crtc_info;
  1342. if (verbose)
  1343. printf ("crtc %d: revert\n", crtc->crtc.index);
  1344. if (dryrun)
  1345. return RRSetConfigSuccess;
  1346. if (!equal_transform (&crtc->current_transform, &crtc->pending_transform))
  1347. crtc_set_transform (crtc, &crtc->current_transform);
  1348. return XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
  1349. crtc_info->x, crtc_info->y,
  1350. crtc_info->mode, crtc_info->rotation,
  1351. crtc_info->outputs, crtc_info->noutput);
  1352. }
  1353. static Status
  1354. crtc_apply (crtc_t *crtc)
  1355. {
  1356. RROutput *rr_outputs;
  1357. int o;
  1358. Status s;
  1359. RRMode mode = None;
  1360. if (!crtc->changing || !crtc->mode_info)
  1361. return RRSetConfigSuccess;
  1362. rr_outputs = calloc (crtc->noutput, sizeof (RROutput));
  1363. if (!rr_outputs)
  1364. return BadAlloc;
  1365. for (o = 0; o < crtc->noutput; o++)
  1366. rr_outputs[o] = crtc->outputs[o]->output.xid;
  1367. mode = crtc->mode_info->id;
  1368. if (verbose) {
  1369. printf ("crtc %d: %12s %6.2f +%d+%d", crtc->crtc.index,
  1370. crtc->mode_info->name, mode_refresh (crtc->mode_info),
  1371. crtc->x, crtc->y);
  1372. for (o = 0; o < crtc->noutput; o++)
  1373. printf (" \"%s\"", crtc->outputs[o]->output.string);
  1374. printf ("\n");
  1375. }
  1376. if (dryrun)
  1377. s = RRSetConfigSuccess;
  1378. else
  1379. {
  1380. if (!equal_transform (&crtc->current_transform, &crtc->pending_transform))
  1381. crtc_set_transform (crtc, &crtc->pending_transform);
  1382. s = XRRSetCrtcConfig (dpy, res, crtc->crtc.xid, CurrentTime,
  1383. crtc->x, crtc->y, mode, crtc->rotation,
  1384. rr_outputs, crtc->noutput);
  1385. if (s == RRSetConfigSuccess && crtc->panning_info) {
  1386. if (has_1_3)
  1387. s = XRRSetPanning (dpy, res, crtc->crtc.xid, crtc->panning_info);
  1388. else
  1389. fatal ("panning needs RandR 1.3\n");
  1390. }
  1391. }
  1392. free (rr_outputs);
  1393. return s;
  1394. }
  1395. static void
  1396. screen_revert (void)
  1397. {
  1398. if (verbose)
  1399. printf ("screen %d: revert\n", screen);
  1400. if (dryrun)
  1401. return;
  1402. XRRSetScreenSize (dpy, root,
  1403. DisplayWidth (dpy, screen),
  1404. DisplayHeight (dpy, screen),
  1405. DisplayWidthMM (dpy, screen),
  1406. DisplayHeightMM (dpy, screen));
  1407. }
  1408. static void
  1409. screen_apply (void)
  1410. {
  1411. if (fb_width == DisplayWidth (dpy, screen) &&
  1412. fb_height == DisplayHeight (dpy, screen) &&
  1413. fb_width_mm == DisplayWidthMM (dpy, screen) &&
  1414. fb_height_mm == DisplayHeightMM (dpy, screen))
  1415. {
  1416. return;
  1417. }
  1418. if (verbose)
  1419. printf ("screen %d: %dx%d %dx%d mm %6.2fdpi\n", screen,
  1420. fb_width, fb_height, fb_width_mm, fb_height_mm, dpi);
  1421. if (dryrun)
  1422. return;
  1423. XRRSetScreenSize (dpy, root, fb_width, fb_height,
  1424. fb_width_mm, fb_height_mm);
  1425. }
  1426. static void
  1427. revert (void)
  1428. {
  1429. int c;
  1430. /* first disable all crtcs */
  1431. for (c = 0; c < res->ncrtc; c++)
  1432. crtc_disable (&crtcs[c]);
  1433. /* next reset screen size */
  1434. screen_revert ();
  1435. /* now restore all crtcs */
  1436. for (c = 0; c < res->ncrtc; c++)
  1437. crtc_revert (&crtcs[c]);
  1438. }
  1439. /*
  1440. * uh-oh, something bad happened in the middle of changing
  1441. * the configuration. Revert to the previous configuration
  1442. * and bail
  1443. */
  1444. static void _X_NORETURN
  1445. panic (Status s, crtc_t *crtc)
  1446. {
  1447. int c = crtc->crtc.index;
  1448. const char *message;
  1449. switch (s) {
  1450. case RRSetConfigSuccess: message = "succeeded"; break;
  1451. case BadAlloc: message = "out of memory"; break;
  1452. case RRSetConfigFailed: message = "failed"; break;
  1453. case RRSetConfigInvalidConfigTime: message = "invalid config time"; break;
  1454. case RRSetConfigInvalidTime: message = "invalid time"; break;
  1455. default: message = "unknown failure"; break;
  1456. }
  1457. fprintf (stderr, "%s: Configure crtc %d %s\n", program_name, c, message);
  1458. revert ();
  1459. exit (1);
  1460. }
  1461. static void
  1462. apply (void)
  1463. {
  1464. Status s;
  1465. int c;
  1466. /*
  1467. * Hold the server grabbed while messing with
  1468. * the screen so that apps which notice the resize
  1469. * event and ask for xinerama information from the server
  1470. * receive up-to-date information
  1471. */
  1472. if (grab_server)
  1473. XGrabServer (dpy);
  1474. /*
  1475. * Turn off any crtcs which are to be disabled or which are
  1476. * larger than the target size
  1477. */
  1478. for (c = 0; c < res->ncrtc; c++)
  1479. {
  1480. crtc_t *crtc = &crtcs[c];
  1481. XRRCrtcInfo *crtc_info = crtc->crtc_info;
  1482. /* if this crtc is already disabled, skip it */
  1483. if (crtc_info->mode == None)
  1484. continue;
  1485. /*
  1486. * If this crtc is to be left enabled, make
  1487. * sure the old size fits then new screen
  1488. */
  1489. if (crtc->mode_info)
  1490. {
  1491. XRRModeInfo *old_mode = find_mode_by_xid (crtc_info->mode);
  1492. int x, y, w, h;
  1493. box_t bounds;
  1494. if (!old_mode)
  1495. panic (RRSetConfigFailed, crtc);
  1496. /* old position and size information */
  1497. mode_geometry (old_mode, crtc_info->rotation,
  1498. &crtc->current_transform.transform,
  1499. &bounds);
  1500. x = crtc_info->x + bounds.x1;
  1501. y = crtc_info->y + bounds.y1;
  1502. w = bounds.x2 - bounds.x1;
  1503. h = bounds.y2 - bounds.y1;
  1504. /* if it fits, skip it */
  1505. if (x + w <= fb_width && y + h <= fb_height)
  1506. continue;
  1507. crtc->changing = True;
  1508. }
  1509. s = crtc_disable (crtc);
  1510. if (s != RRSetConfigSuccess)
  1511. panic (s, crtc);
  1512. }
  1513. /*
  1514. * Set the screen size
  1515. */
  1516. screen_apply ();
  1517. /*
  1518. * Set crtcs
  1519. */
  1520. for (c = 0; c < res->ncrtc; c++)
  1521. {
  1522. crtc_t *crtc = &crtcs[c];
  1523. s = crtc_apply (crtc);
  1524. if (s != RRSetConfigSuccess)
  1525. panic (s, crtc);
  1526. }
  1527. set_primary ();
  1528. /*
  1529. * Release the server grab and let all clients
  1530. * respond to the updated state
  1531. */
  1532. if (grab_server)
  1533. XUngrabServer (dpy);
  1534. }
  1535. /*
  1536. * Use current output state to complete the output list
  1537. */
  1538. static void
  1539. get_outputs (void)
  1540. {
  1541. int o;
  1542. output_t *q;
  1543. for (o = 0; o < res->noutput; o++)
  1544. {
  1545. XRROutputInfo *output_info = XRRGetOutputInfo (dpy, res, res->outputs[o]);
  1546. output_t *output;
  1547. name_t output_name;
  1548. if (!output_info) fatal ("could not get output 0x%lx information\n", res->outputs[o]);
  1549. set_name_xid (&output_name, res->outputs[o]);
  1550. set_name_index (&output_name, o);
  1551. set_name_string (&output_name, output_info->name);
  1552. output = find_output (&output_name);
  1553. if (!output)
  1554. {
  1555. output = add_output ();
  1556. set_name_all (&output->output, &output_name);
  1557. /*
  1558. * When global --automatic mode is set, turn on connected but off
  1559. * outputs, turn off disconnected but on outputs
  1560. */
  1561. if (automatic)
  1562. {
  1563. switch (output_info->connection) {
  1564. case RR_Connected:
  1565. if (!output_info->crtc) {
  1566. output->changes |= changes_automatic;
  1567. output->automatic = True;
  1568. }
  1569. break;
  1570. case RR_Disconnected:
  1571. if (output_info->crtc)
  1572. {
  1573. output->changes |= changes_automatic;
  1574. output->automatic = True;
  1575. }
  1576. break;
  1577. }
  1578. }
  1579. }
  1580. output->found = True;
  1581. /*
  1582. * Automatic mode -- track connection state and enable/disable outputs
  1583. * as necessary
  1584. */
  1585. if (output->automatic)
  1586. {
  1587. switch (output_info->connection) {
  1588. case RR_Connected:
  1589. case RR_UnknownConnection:
  1590. if ((!(output->changes & changes_mode)))
  1591. {
  1592. set_name_preferred (&output->mode);
  1593. output->changes |= changes_mode;
  1594. }
  1595. break;
  1596. case RR_Disconnected:
  1597. if ((!(output->changes & changes_mode)))
  1598. {
  1599. set_name_xid (&output->mode, None);
  1600. set_name_xid (&output->crtc, None);
  1601. output->changes |= changes_mode;
  1602. output->changes |= changes_crtc;
  1603. }
  1604. break;
  1605. }
  1606. }
  1607. set_output_info (output, res->outputs[o], output_info);
  1608. }
  1609. for (q = all_outputs; q; q = q->next)
  1610. {
  1611. if (!q->found)
  1612. {
  1613. fprintf(stderr, "warning: output %s not found; ignoring\n",
  1614. q->output.string);
  1615. }
  1616. }
  1617. }
  1618. static void
  1619. mark_changing_crtcs (void)
  1620. {
  1621. int c;
  1622. for (c = 0; c < num_crtcs; c++)
  1623. {
  1624. crtc_t *crtc = &crtcs[c];
  1625. int o;
  1626. output_t *output;
  1627. /* walk old output list (to catch disables) */
  1628. for (o = 0; o < crtc->crtc_info->noutput; o++)
  1629. {
  1630. output = find_output_by_xid (crtc->crtc_info->outputs[o]);
  1631. if (!output) fatal ("cannot find output 0x%lx\n",
  1632. crtc->crtc_info->outputs[o]);
  1633. if (output->changes)
  1634. crtc->changing = True;
  1635. }
  1636. /* walk new output list */
  1637. for (o = 0; o < crtc->noutput; o++)
  1638. {
  1639. output = crtc->outputs[o];
  1640. if (output->changes)
  1641. crtc->changing = True;
  1642. }
  1643. }
  1644. }
  1645. /*
  1646. * Test whether 'crtc' can be used for 'output'
  1647. */
  1648. static Bool
  1649. check_crtc_for_output (crtc_t *crtc, output_t *output)
  1650. {
  1651. int c;
  1652. int l;
  1653. output_t *other;
  1654. for (c = 0; c < output->output_info->ncrtc; c++)
  1655. if (output->output_info->crtcs[c] == crtc->crtc.xid)
  1656. break;
  1657. if (c == output->output_info->ncrtc)
  1658. return False;
  1659. for (other = all_outputs; other; other = other->next)
  1660. {
  1661. if (other == output)
  1662. continue;
  1663. if (other->mode_info == NULL)
  1664. continue;
  1665. if (other->crtc_info != crtc)
  1666. continue;
  1667. /* see if the output connected to the crtc can clone to this output */
  1668. for (l = 0; l < output->output_info->nclone; l++)
  1669. if (output->output_info->clones[l] == other->output.xid)
  1670. break;
  1671. /* not on the list, can't clone */
  1672. if (l == output->output_info->nclone)
  1673. return False;
  1674. }
  1675. if (crtc->noutput)
  1676. {
  1677. /* make sure the state matches */
  1678. if (crtc->mode_info != output->mode_info)
  1679. return False;
  1680. if (crtc->x != output->x)
  1681. return False;
  1682. if (crtc->y != output->y)
  1683. return False;
  1684. if (crtc->rotation != output->rotation)
  1685. return False;
  1686. if (!equal_transform (&crtc->current_transform, &output->transform))
  1687. return False;
  1688. }
  1689. else if (crtc->crtc_info->noutput)
  1690. {
  1691. /* make sure the state matches the already used state */
  1692. XRRModeInfo *mode = find_mode_by_xid (crtc->crtc_info->mode);
  1693. if (mode != output->mode_info)
  1694. return False;
  1695. if (crtc->crtc_info->x != output->x)
  1696. return False;
  1697. if (crtc->crtc_info->y != output->y)
  1698. return False;
  1699. if (crtc->crtc_info->rotation != output->rotation)
  1700. return False;
  1701. }
  1702. return True;
  1703. }
  1704. static crtc_t *
  1705. find_crtc_for_output (output_t *output)
  1706. {
  1707. int c;
  1708. for (c = 0; c < output->output_info->ncrtc; c++)
  1709. {
  1710. crtc_t *crtc;
  1711. crtc = find_crtc_by_xid (output->output_info->crtcs[c]);
  1712. if (!crtc) fatal ("cannot find crtc 0x%lx\n", output->output_info->crtcs[c]);
  1713. if (check_crtc_for_output (crtc, output))
  1714. return crtc;
  1715. }
  1716. return NULL;
  1717. }
  1718. static void
  1719. set_positions (void)
  1720. {
  1721. output_t *output;
  1722. Bool keep_going;
  1723. Bool any_set;
  1724. int min_x, min_y;
  1725. for (;;)
  1726. {
  1727. any_set = False;
  1728. keep_going = False;
  1729. for (output = all_outputs; output; output = output->next)
  1730. {
  1731. output_t *relation;
  1732. name_t relation_name;
  1733. if (!(output->changes & changes_relation)) continue;
  1734. if (output->mode_info == NULL) continue;
  1735. init_name (&relation_name);
  1736. set_name_string (&relation_name, output->relative_to);
  1737. relation = find_output (&relation_name);
  1738. if (!relation) fatal ("cannot find output \"%s\"\n", output->relative_to);
  1739. if (relation->mode_info == NULL)
  1740. {
  1741. output->x = 0;
  1742. output->y = 0;
  1743. output->changes |= changes_position;
  1744. any_set = True;
  1745. continue;
  1746. }
  1747. /*
  1748. * Make sure the dependent object has been set in place
  1749. */
  1750. if ((relation->changes & changes_relation) &&
  1751. !(relation->changes & changes_position))
  1752. {
  1753. keep_going = True;
  1754. continue;
  1755. }
  1756. switch (output->relation) {
  1757. case relation_left_of:
  1758. output->y = relation->y;
  1759. output->x = relation->x - mode_width (output->mode_info, output->rotation);
  1760. break;
  1761. case relation_right_of:
  1762. output->y = relation->y;
  1763. output->x = relation->x + mode_width (relation->mode_info, relation->rotation);
  1764. break;
  1765. case relation_above:
  1766. output->x = relation->x;
  1767. output->y = relation->y - mode_height (output->mode_info, output->rotation);
  1768. break;
  1769. case relation_below:
  1770. output->x = relation->x;
  1771. output->y = relation->y + mode_height (relation->mode_info, relation->rotation);
  1772. break;
  1773. case relation_same_as:
  1774. output->x = relation->x;
  1775. output->y = relation->y;
  1776. }
  1777. output->changes |= changes_position;
  1778. any_set = True;
  1779. }
  1780. if (!keep_going)
  1781. break;
  1782. if (!any_set)
  1783. fatal ("loop in relative position specifications\n");
  1784. }
  1785. /*
  1786. * Now normalize positions so the upper left corner of all outputs is at 0,0
  1787. */
  1788. min_x = 32768;
  1789. min_y = 32768;
  1790. for (output = all_outputs; output; output = output->next)
  1791. {
  1792. if (output->mode_info == NULL) continue;
  1793. if (output->x < min_x) min_x = output->x;
  1794. if (output->y < min_y) min_y = output->y;
  1795. }
  1796. if (min_x || min_y)
  1797. {
  1798. /* move all outputs */
  1799. for (output = all_outputs; output; output = output->next)
  1800. {
  1801. if (output->mode_info == NULL) continue;
  1802. output->x -= min_x;
  1803. output->y -= min_y;
  1804. output->changes |= changes_position;
  1805. }
  1806. }
  1807. }
  1808. static void
  1809. set_screen_size (void)
  1810. {
  1811. output_t *output;
  1812. Bool fb_specified = fb_width != 0 && fb_height != 0;
  1813. for (output = all_outputs; output; output = output->next)
  1814. {
  1815. XRRModeInfo *mode_info = output->mode_info;
  1816. int x, y, w, h;
  1817. box_t bounds;
  1818. if (!mode_info) continue;
  1819. mode_geometry (mode_info, output->rotation,
  1820. &output->transform.transform,
  1821. &bounds);
  1822. x = output->x + bounds.x1;
  1823. y = output->y + bounds.y1;
  1824. w = bounds.x2 - bounds.x1;
  1825. h = bounds.y2 - bounds.y1;
  1826. /* make sure output fits in specified size */
  1827. if (fb_specified)
  1828. {
  1829. if (x + w > fb_width || y + h > fb_height)
  1830. warning ("specified screen %dx%d not large enough for output %s (%dx%d+%d+%d)\n",
  1831. fb_width, fb_height, output->output.string, w, h, x, y);
  1832. }
  1833. /* fit fb to output */
  1834. else
  1835. {
  1836. XRRPanning *pan;
  1837. if (x + w > fb_width)
  1838. fb_width = x + w;
  1839. if (y + h > fb_height)
  1840. fb_height = y + h;
  1841. if (output->changes & changes_panning)
  1842. pan = &output->panning;
  1843. else
  1844. pan = output->crtc_info ? output->crtc_info->panning_info : NULL;
  1845. if (pan && pan->left + pan->width > fb_width)
  1846. fb_width = pan->left + pan->width;
  1847. if (pan && pan->top + pan->height > fb_height)
  1848. fb_height = pan->top + pan->height;
  1849. }
  1850. }
  1851. if (fb_width > maxWidth || fb_height > maxHeight)
  1852. fatal ("screen cannot be larger than %dx%d (desired size %dx%d)\n",
  1853. maxWidth, maxHeight, fb_width, fb_height);
  1854. if (fb_specified)
  1855. {
  1856. if (fb_width < minWidth || fb_height < minHeight)
  1857. fatal ("screen must be at least %dx%d\n", minWidth, minHeight);
  1858. }
  1859. else
  1860. {
  1861. if (fb_width < minWidth) fb_width = minWidth;
  1862. if (fb_height < minHeight) fb_height = minHeight;
  1863. }
  1864. }
  1865. static void
  1866. disable_outputs (output_t *outputs)
  1867. {
  1868. while (outputs)
  1869. {
  1870. outputs->crtc_info = NULL;
  1871. outputs = outputs->next;
  1872. }
  1873. }
  1874. /*
  1875. * find the best mapping from output to crtc available
  1876. */
  1877. static int
  1878. pick_crtcs_score (output_t *outputs)
  1879. {
  1880. output_t *output;
  1881. int best_score;
  1882. int my_score;
  1883. int score;
  1884. crtc_t *best_crtc;
  1885. int c;
  1886. if (!outputs)
  1887. return 0;
  1888. output = outputs;
  1889. outputs = outputs->next;
  1890. /*
  1891. * Score with this output disabled
  1892. */
  1893. output->crtc_info = NULL;
  1894. best_score = pick_crtcs_score (outputs);
  1895. if (output->mode_info == NULL)
  1896. return best_score;
  1897. best_crtc = NULL;
  1898. /*
  1899. * Now score with this output any valid crtc
  1900. */
  1901. for (c = 0; c < output->output_info->ncrtc; c++)
  1902. {
  1903. crtc_t *crtc;
  1904. crtc = find_crtc_by_xid (output->output_info->crtcs[c]);
  1905. if (!crtc)
  1906. fatal ("cannot find crtc 0x%lx\n", output->output_info->crtcs[c]);
  1907. /* reset crtc allocation for following outputs */
  1908. disable_outputs (outputs);
  1909. if (!check_crtc_for_output (crtc, output))
  1910. continue;
  1911. my_score = 1000;
  1912. /* slight preference for existing connections */
  1913. if (crtc == output->current_crtc_info)
  1914. my_score++;
  1915. output->crtc_info = crtc;
  1916. score = my_score + pick_crtcs_score (outputs);
  1917. if (score > best_score)
  1918. {
  1919. best_crtc = crtc;
  1920. best_score = score;
  1921. }
  1922. }
  1923. if (output->crtc_info != best_crtc)
  1924. output->crtc_info = best_crtc;
  1925. /*
  1926. * Reset other outputs based on this one using the best crtc
  1927. */
  1928. (void) pick_crtcs_score (outputs);
  1929. return best_score;
  1930. }
  1931. /*
  1932. * Pick crtcs for any changing outputs that don't have one
  1933. */
  1934. static void
  1935. pick_crtcs (void)
  1936. {
  1937. output_t *output;
  1938. /*
  1939. * First try to match up newly enabled outputs with spare crtcs
  1940. */
  1941. for (output = all_outputs; output; output = output->next)
  1942. {
  1943. if (output->changes && output->mode_info)
  1944. {
  1945. if (output->crtc_info) {
  1946. if (output->crtc_info->crtc_info->noutput > 0 &&
  1947. (output->crtc_info->crtc_info->noutput > 1 ||
  1948. output != find_output_by_xid (output->crtc_info->crtc_info->outputs[0])))
  1949. break;
  1950. } else {
  1951. output->crtc_info = find_crtc_for_output (output);
  1952. if (!output->crtc_info)
  1953. break;
  1954. }
  1955. }
  1956. }
  1957. /*
  1958. * Everyone is happy
  1959. */
  1960. if (!output)
  1961. return;
  1962. /*
  1963. * When the simple way fails, see if there is a way
  1964. * to swap crtcs around and make things work
  1965. */
  1966. for (output = all_outputs; output; output = output->next)
  1967. output->current_crtc_info = output->crtc_info;
  1968. pick_crtcs_score (all_outputs);
  1969. for (output = all_outputs; output; output = output->next)
  1970. {
  1971. if (output->mode_info && !output->crtc_info)
  1972. fatal ("cannot find crtc for output %s\n", output->output.string);
  1973. if (!output->changes && output->crtc_info != output->current_crtc_info)
  1974. output->changes |= changes_crtc;
  1975. }
  1976. }
  1977. static int
  1978. check_strtol(char *s)
  1979. {
  1980. char *endptr;
  1981. int result = strtol(s, &endptr, 10);
  1982. if (s == endptr)
  1983. argerr ("failed to parse '%s' as a number\n", s);
  1984. return result;
  1985. }
  1986. static double
  1987. check_strtod(char *s)
  1988. {
  1989. char *endptr;
  1990. double result = strtod(s, &endptr);
  1991. if (s == endptr)
  1992. argerr ("failed to parse '%s' as a number\n", s);
  1993. return result;
  1994. }
  1995. static void *
  1996. property_values_from_string(const char *str, const Atom type, const int format,
  1997. int *returned_nitems)
  1998. {
  1999. char *token, *tmp;
  2000. void *returned_bytes = NULL;
  2001. int nitems = 0, bytes_per_item = format / 8;
  2002. if ((type != XA_INTEGER && type != XA_CARDINAL) ||
  2003. (format != 8 && format != 16 && format != 32))
  2004. {
  2005. return NULL;
  2006. }
  2007. tmp = strdup (str);
  2008. for (token = strtok (tmp, ","); token; token = strtok (NULL, ","))
  2009. {
  2010. char *endptr;
  2011. long int val = strtol (token, &endptr, 0);
  2012. if (token == endptr || *endptr != '\0')
  2013. {
  2014. argerr ("failed to parse '%s' as a number\n", token);
  2015. }
  2016. returned_bytes = realloc (returned_bytes, (nitems + 1) * bytes_per_item);
  2017. if (type == XA_INTEGER && format == 8)
  2018. {
  2019. int8_t *ptr = returned_bytes;
  2020. ptr[nitems] = (int8_t) val;
  2021. }
  2022. else if (type == XA_INTEGER && format == 16)
  2023. {
  2024. int16_t *ptr = returned_bytes;
  2025. ptr[nitems] = (int16_t) val;
  2026. }
  2027. else if (type == XA_INTEGER && format == 32)
  2028. {
  2029. int32_t *ptr = returned_bytes;
  2030. ptr[nitems] = (int32_t) val;
  2031. }
  2032. else if (type == XA_CARDINAL && format == 8)
  2033. {
  2034. uint8_t *ptr = returned_bytes;
  2035. ptr[nitems] = (uint8_t) val;
  2036. }
  2037. else if (type == XA_CARDINAL && format == 16)
  2038. {
  2039. uint16_t *ptr = returned_bytes;
  2040. ptr[nitems] = (uint16_t) val;
  2041. }
  2042. else if (type == XA_CARDINAL && format == 32)
  2043. {
  2044. uint32_t *ptr = returned_bytes;
  2045. ptr[nitems] = (uint32_t) val;
  2046. }
  2047. else
  2048. {
  2049. free (tmp);
  2050. free (returned_bytes);
  2051. return NULL;
  2052. }
  2053. nitems++;
  2054. }
  2055. free (tmp);
  2056. *returned_nitems = nitems;
  2057. return returned_bytes;
  2058. }
  2059. static void
  2060. print_output_property_value(int value_format, /* 8, 16, 32 */
  2061. Atom value_type, /* XA_{ATOM,INTEGER,CARDINAL} */
  2062. const void *value_bytes)
  2063. {
  2064. if (value_type == XA_ATOM && value_format == 32)
  2065. {
  2066. const Atom *val = value_bytes;
  2067. char *str = XGetAtomName (dpy, *val);
  2068. if (str != NULL)
  2069. {
  2070. printf ("%s", str);
  2071. XFree (str);
  2072. return;
  2073. }
  2074. }
  2075. if (value_type == XA_INTEGER)
  2076. {
  2077. if (value_format == 8)
  2078. {
  2079. const int8_t *val = value_bytes;
  2080. printf ("%" PRId8, *val);
  2081. return;
  2082. }
  2083. if (value_format == 16)
  2084. {
  2085. const int16_t *val = value_bytes;
  2086. printf ("%" PRId16, *val);
  2087. return;
  2088. }
  2089. if (value_format == 32)
  2090. {
  2091. const int32_t *val = value_bytes;
  2092. printf ("%" PRId32, *val);
  2093. return;
  2094. }
  2095. }
  2096. if (value_type == XA_CARDINAL)
  2097. {
  2098. if (value_format == 8)
  2099. {
  2100. const uint8_t *val = value_bytes;
  2101. printf ("%" PRIu8, *val);
  2102. return;
  2103. }
  2104. if (value_format == 16)
  2105. {
  2106. const uint16_t *val = value_bytes;
  2107. printf ("%" PRIu16, *val);
  2108. return;
  2109. }
  2110. if (value_format == 32)
  2111. {
  2112. const uint32_t *val = value_bytes;
  2113. printf ("%" PRIu32, *val);
  2114. return;
  2115. }
  2116. }
  2117. printf ("?");
  2118. }
  2119. static void
  2120. print_edid(int nitems, const unsigned char *prop)
  2121. {
  2122. int k;
  2123. printf ("\n\t\t");
  2124. for (k = 0; k < nitems; k++)
  2125. {
  2126. if (k != 0 && (k % 16) == 0)
  2127. {
  2128. printf ("\n\t\t");
  2129. }
  2130. printf("%02" PRIx8, prop[k]);
  2131. }
  2132. printf("\n");
  2133. }
  2134. static void
  2135. print_guid(const unsigned char *prop)
  2136. {
  2137. int k;
  2138. printf("{");
  2139. for (k = 0; k < 16; k++)
  2140. {
  2141. printf("%02" PRIX8, prop[k]);
  2142. if (k == 3 || k == 5 || k == 7 || k == 9)
  2143. {
  2144. printf("-");
  2145. }
  2146. }
  2147. printf("}\n");
  2148. }
  2149. static void
  2150. print_output_property(const char *atom_name,
  2151. int value_format,
  2152. Atom value_type,
  2153. int nitems,
  2154. const unsigned char *prop)
  2155. {
  2156. int bytes_per_item = value_format / 8;
  2157. int k;
  2158. /*
  2159. * Check for properties that need special formatting.
  2160. */
  2161. if (strcmp (atom_name, "EDID") == 0 && value_format == 8 &&
  2162. value_type == XA_INTEGER)
  2163. {
  2164. print_edid (nitems, prop);
  2165. return;
  2166. }
  2167. else if (strcmp (atom_name, "GUID") == 0 && value_format == 8 &&
  2168. value_type == XA_INTEGER && nitems == 16)
  2169. {
  2170. print_guid (prop);
  2171. return;
  2172. }
  2173. for (k = 0; k < nitems; k++)
  2174. {
  2175. if (k != 0)
  2176. {
  2177. if ((k % 16) == 0)
  2178. {
  2179. printf ("\n\t\t");
  2180. }
  2181. }
  2182. print_output_property_value (value_format, value_type,
  2183. prop + (k * bytes_per_item));
  2184. printf (" ");
  2185. }
  2186. printf ("\n");
  2187. }
  2188. static void
  2189. get_providers (void)
  2190. {
  2191. XRRProviderResources *pr;
  2192. int i;
  2193. if (!has_1_4 || providers)
  2194. return;
  2195. pr = XRRGetProviderResources(dpy, root);
  2196. num_providers = pr->nproviders;
  2197. providers = calloc (num_providers, sizeof (provider_t));
  2198. if (!providers)
  2199. fatal ("out of memory\n");
  2200. for (i = 0; i < num_providers; i++) {
  2201. provider_t *provider = &providers[i];
  2202. name_t *name = &provider->provider;
  2203. XRRProviderInfo *info = XRRGetProviderInfo(dpy, res, pr->providers[i]);
  2204. provider->info = info;
  2205. set_name_xid (name, pr->providers[i]);
  2206. set_name_index (name, i);
  2207. set_name_string (name, info->name);
  2208. }
  2209. XRRFreeProviderResources(pr);
  2210. }
  2211. static provider_t *
  2212. find_provider (name_t *name)
  2213. {
  2214. int i;
  2215. if ((name->kind & name_xid) && name->xid == 0)
  2216. return NULL;
  2217. for (i = 0; i < num_providers; i++) {
  2218. provider_t *p = &providers[i];
  2219. name_kind_t common = name->kind & p->provider.kind;
  2220. if ((common & name_xid) && name->xid == p->provider.xid)
  2221. return p;
  2222. if ((common & name_string) && !strcmp (name->string, p->provider.string))
  2223. return p;
  2224. if ((common & name_index) && name->index == p->provider.index)
  2225. return p;
  2226. }
  2227. printf ("Could not find provider with ");
  2228. print_name (name);
  2229. printf ("\n");
  2230. exit (1);
  2231. }
  2232. int
  2233. main (int argc, char **argv)
  2234. {
  2235. XRRScreenSize *sizes;
  2236. XRRScreenConfiguration *sc;
  2237. int nsize;
  2238. int nrate;
  2239. short *rates;
  2240. Status status = RRSetConfigFailed;
  2241. int rot = -1;
  2242. int query = False;
  2243. int action_requested = False;
  2244. Rotation current_rotation;
  2245. XEvent event;
  2246. XRRScreenChangeNotifyEvent *sce;
  2247. char *display_name = NULL;
  2248. int i;
  2249. SizeID current_size;
  2250. short current_rate;
  2251. double rate = -1;
  2252. int size = -1;
  2253. int dirind = 0;
  2254. Bool setit = False;
  2255. Bool version = False;
  2256. int event_base, error_base;
  2257. int reflection = 0;
  2258. int width = 0, height = 0;
  2259. Bool have_pixel_size = False;
  2260. int ret = 0;
  2261. output_t *config_output = NULL;
  2262. Bool setit_1_2 = False;
  2263. Bool query_1_2 = False;
  2264. Bool modeit = False;
  2265. Bool propit = False;
  2266. Bool query_1 = False;
  2267. Bool list_providers = False;
  2268. Bool provsetoutsource = False;
  2269. Bool provsetoffsink = False;
  2270. int major, minor;
  2271. Bool current = False;
  2272. Bool toggle_x = False;
  2273. Bool toggle_y = False;
  2274. program_name = argv[0];
  2275. for (i = 1; i < argc; i++) {
  2276. if (!strcmp ("-display", argv[i]) || !strcmp ("--display", argv[i]) ||
  2277. !strcmp ("-d", argv[i])) {
  2278. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2279. display_name = argv[i];
  2280. continue;
  2281. }
  2282. if (!strcmp("-help", argv[i]) || !strcmp("--help", argv[i])) {
  2283. usage();
  2284. exit(0);
  2285. }
  2286. if (!strcmp ("--verbose", argv[i])) {
  2287. verbose = True;
  2288. continue;
  2289. }
  2290. if (!strcmp ("--dryrun", argv[i])) {
  2291. dryrun = True;
  2292. verbose = True;
  2293. continue;
  2294. }
  2295. if (!strcmp ("--nograb", argv[i])) {
  2296. grab_server = False;
  2297. continue;
  2298. }
  2299. if (!strcmp("--current", argv[i])) {
  2300. current = True;
  2301. continue;
  2302. }
  2303. if (!strcmp ("-s", argv[i]) || !strcmp ("--size", argv[i])) {
  2304. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2305. if (sscanf (argv[i], "%dx%d", &width, &height) == 2) {
  2306. have_pixel_size = True;
  2307. } else {
  2308. size = check_strtol(argv[i]);
  2309. if (size < 0) argerr ("--size argument must be nonnegative\n");
  2310. }
  2311. setit = True;
  2312. action_requested = True;
  2313. continue;
  2314. }
  2315. if (!strcmp ("-r", argv[i]) ||
  2316. !strcmp ("--rate", argv[i]) ||
  2317. !strcmp ("--refresh", argv[i]))
  2318. {
  2319. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2320. rate = check_strtod(argv[i]);
  2321. setit = True;
  2322. if (config_output)
  2323. {
  2324. config_output->refresh = rate;
  2325. config_output->changes |= changes_refresh;
  2326. setit_1_2 = True;
  2327. }
  2328. action_requested = True;
  2329. continue;
  2330. }
  2331. if (!strcmp ("-v", argv[i]) || !strcmp ("--version", argv[i])) {
  2332. version = True;
  2333. action_requested = True;
  2334. continue;
  2335. }
  2336. if (!strcmp ("-x", argv[i])) {
  2337. toggle_x = True;
  2338. setit = True;
  2339. action_requested = True;
  2340. continue;
  2341. }
  2342. if (!strcmp ("-y", argv[i])) {
  2343. toggle_y = True;
  2344. setit = True;
  2345. action_requested = True;
  2346. continue;
  2347. }
  2348. if (!strcmp ("--screen", argv[i])) {
  2349. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2350. screen = check_strtol(argv[i]);
  2351. if (screen < 0) argerr ("--screen argument must be nonnegative\n");
  2352. continue;
  2353. }
  2354. if (!strcmp ("-q", argv[i]) || !strcmp ("--query", argv[i])) {
  2355. query = True;
  2356. continue;
  2357. }
  2358. if (!strcmp ("-o", argv[i]) || !strcmp ("--orientation", argv[i])) {
  2359. char *endptr;
  2360. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2361. dirind = strtol(argv[i], &endptr, 10);
  2362. if (argv[i] == endptr) {
  2363. for (dirind = 0; dirind < 4; dirind++) {
  2364. if (strcmp (direction[dirind], argv[i]) == 0) break;
  2365. }
  2366. }
  2367. if ((dirind < 0) || (dirind > 3))
  2368. argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
  2369. rot = dirind;
  2370. setit = True;
  2371. action_requested = True;
  2372. continue;
  2373. }
  2374. if (!strcmp ("--prop", argv[i]) ||
  2375. !strcmp ("--props", argv[i]) ||
  2376. !strcmp ("--madprops", argv[i]) ||
  2377. !strcmp ("--properties", argv[i]))
  2378. {
  2379. query_1_2 = True;
  2380. properties = True;
  2381. action_requested = True;
  2382. continue;
  2383. }
  2384. if (!strcmp ("--output", argv[i])) {
  2385. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2386. config_output = find_output_by_name (argv[i]);
  2387. if (!config_output) {
  2388. config_output = add_output ();
  2389. set_name (&config_output->output, argv[i], name_string|name_xid);
  2390. }
  2391. setit_1_2 = True;
  2392. action_requested = True;
  2393. continue;
  2394. }
  2395. if (!strcmp ("--crtc", argv[i])) {
  2396. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2397. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2398. set_name (&config_output->crtc, argv[i], name_xid|name_index);
  2399. config_output->changes |= changes_crtc;
  2400. continue;
  2401. }
  2402. if (!strcmp ("--mode", argv[i])) {
  2403. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2404. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2405. set_name (&config_output->mode, argv[i], name_string|name_xid);
  2406. config_output->changes |= changes_mode;
  2407. continue;
  2408. }
  2409. if (!strcmp ("--preferred", argv[i])) {
  2410. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2411. set_name_preferred (&config_output->mode);
  2412. config_output->changes |= changes_mode;
  2413. continue;
  2414. }
  2415. if (!strcmp ("--pos", argv[i])) {
  2416. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2417. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2418. if (sscanf (argv[i], "%dx%d",
  2419. &config_output->x, &config_output->y) != 2)
  2420. argerr ("failed to parse '%s' as a position\n", argv[i]);
  2421. config_output->changes |= changes_position;
  2422. continue;
  2423. }
  2424. if (!strcmp ("--rotation", argv[i]) || !strcmp ("--rotate", argv[i])) {
  2425. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2426. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2427. for (dirind = 0; dirind < 4; dirind++) {
  2428. if (strcmp (direction[dirind], argv[i]) == 0) break;
  2429. }
  2430. if (dirind == 4)
  2431. argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
  2432. config_output->rotation &= ~0xf;
  2433. config_output->rotation |= 1 << dirind;
  2434. config_output->changes |= changes_rotation;
  2435. continue;
  2436. }
  2437. if (!strcmp ("--reflect", argv[i]) || !strcmp ("--reflection", argv[i])) {
  2438. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2439. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2440. for (dirind = 0; dirind < 4; dirind++) {
  2441. if (strcmp (reflections[dirind], argv[i]) == 0) break;
  2442. }
  2443. if (dirind == 4)
  2444. argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
  2445. config_output->rotation &= ~(RR_Reflect_X|RR_Reflect_Y);
  2446. config_output->rotation |= dirind * RR_Reflect_X;
  2447. config_output->changes |= changes_reflection;
  2448. continue;
  2449. }
  2450. if (!strcmp ("--left-of", argv[i])) {
  2451. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2452. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2453. config_output->relation = relation_left_of;
  2454. config_output->relative_to = argv[i];
  2455. config_output->changes |= changes_relation;
  2456. continue;
  2457. }
  2458. if (!strcmp ("--right-of", argv[i])) {
  2459. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2460. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2461. config_output->relation = relation_right_of;
  2462. config_output->relative_to = argv[i];
  2463. config_output->changes |= changes_relation;
  2464. continue;
  2465. }
  2466. if (!strcmp ("--above", argv[i])) {
  2467. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2468. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2469. config_output->relation = relation_above;
  2470. config_output->relative_to = argv[i];
  2471. config_output->changes |= changes_relation;
  2472. continue;
  2473. }
  2474. if (!strcmp ("--below", argv[i])) {
  2475. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2476. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2477. config_output->relation = relation_below;
  2478. config_output->relative_to = argv[i];
  2479. config_output->changes |= changes_relation;
  2480. continue;
  2481. }
  2482. if (!strcmp ("--same-as", argv[i])) {
  2483. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2484. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2485. config_output->relation = relation_same_as;
  2486. config_output->relative_to = argv[i];
  2487. config_output->changes |= changes_relation;
  2488. continue;
  2489. }
  2490. if (!strcmp ("--panning", argv[i])) {
  2491. XRRPanning *pan;
  2492. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2493. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2494. pan = &config_output->panning;
  2495. switch (sscanf (argv[i], "%dx%d+%d+%d/%dx%d+%d+%d/%d/%d/%d/%d",
  2496. &pan->width, &pan->height, &pan->left, &pan->top,
  2497. &pan->track_width, &pan->track_height,
  2498. &pan->track_left, &pan->track_top,
  2499. &pan->border_left, &pan->border_top,
  2500. &pan->border_right, &pan->border_bottom)) {
  2501. case 2:
  2502. pan->left = pan->top = 0;
  2503. /* fall through */
  2504. case 4:
  2505. pan->track_left = pan->track_top =
  2506. pan->track_width = pan->track_height = 0;
  2507. /* fall through */
  2508. case 8:
  2509. pan->border_left = pan->border_top =
  2510. pan->border_right = pan->border_bottom = 0;
  2511. /* fall through */
  2512. case 12:
  2513. break;
  2514. default:
  2515. argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
  2516. }
  2517. config_output->changes |= changes_panning;
  2518. continue;
  2519. }
  2520. if (!strcmp ("--gamma", argv[i])) {
  2521. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2522. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2523. if (sscanf(argv[i], "%f:%f:%f", &config_output->gamma.red,
  2524. &config_output->gamma.green, &config_output->gamma.blue) != 3)
  2525. argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
  2526. config_output->changes |= changes_gamma;
  2527. setit_1_2 = True;
  2528. continue;
  2529. }
  2530. if (!strcmp ("--brightness", argv[i])) {
  2531. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2532. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2533. if (sscanf(argv[i], "%f", &config_output->brightness) != 1)
  2534. argerr ("%s: invalid argument '%s'\n", argv[i-1], argv[i]);
  2535. config_output->changes |= changes_gamma;
  2536. setit_1_2 = True;
  2537. continue;
  2538. }
  2539. if (!strcmp ("--primary", argv[i])) {
  2540. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2541. config_output->changes |= changes_primary;
  2542. config_output->primary = True;
  2543. setit_1_2 = True;
  2544. continue;
  2545. }
  2546. if (!strcmp ("--noprimary", argv[i])) {
  2547. no_primary = True;
  2548. setit_1_2 = True;
  2549. continue;
  2550. }
  2551. if (!strcmp ("--set", argv[i])) {
  2552. output_prop_t *prop;
  2553. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2554. if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]);
  2555. prop = malloc (sizeof (output_prop_t));
  2556. prop->next = config_output->props;
  2557. config_output->props = prop;
  2558. prop->name = argv[++i];
  2559. prop->value = argv[++i];
  2560. propit = True;
  2561. config_output->changes |= changes_property;
  2562. setit_1_2 = True;
  2563. continue;
  2564. }
  2565. if (!strcmp ("--scale", argv[i]))
  2566. {
  2567. double sx, sy;
  2568. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2569. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2570. if (sscanf (argv[i], "%lfx%lf", &sx, &sy) != 2)
  2571. argerr ("failed to parse '%s' as a scaling factor\n", argv[i]);
  2572. init_transform (&config_output->transform);
  2573. config_output->transform.transform.matrix[0][0] = XDoubleToFixed (sx);
  2574. config_output->transform.transform.matrix[1][1] = XDoubleToFixed (sy);
  2575. config_output->transform.transform.matrix[2][2] = XDoubleToFixed (1.0);
  2576. if (sx != 1 || sy != 1)
  2577. config_output->transform.filter = "bilinear";
  2578. else
  2579. config_output->transform.filter = "nearest";
  2580. config_output->transform.nparams = 0;
  2581. config_output->transform.params = NULL;
  2582. config_output->changes |= changes_transform;
  2583. continue;
  2584. }
  2585. if (!strcmp ("--scale-from", argv[i]))
  2586. {
  2587. int w, h;
  2588. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2589. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2590. if (sscanf (argv[i], "%dx%d", &w, &h) != 2)
  2591. argerr ("failed to parse '%s' as a scale-from size\n", argv[i]);
  2592. if (w <=0 || h <= 0)
  2593. argerr ("--scale-from dimensions must be nonnegative\n");
  2594. config_output->scale_from_w = w;
  2595. config_output->scale_from_h = h;
  2596. config_output->changes |= changes_transform;
  2597. continue;
  2598. }
  2599. if (!strcmp ("--transform", argv[i])) {
  2600. double transform[3][3];
  2601. int k, l;
  2602. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2603. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2604. init_transform (&config_output->transform);
  2605. if (strcmp (argv[i], "none") != 0)
  2606. {
  2607. if (sscanf(argv[i], "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",
  2608. &transform[0][0],&transform[0][1],&transform[0][2],
  2609. &transform[1][0],&transform[1][1],&transform[1][2],
  2610. &transform[2][0],&transform[2][1],&transform[2][2])
  2611. != 9)
  2612. argerr ("failed to parse '%s' as a transformation\n", argv[i]);
  2613. init_transform (&config_output->transform);
  2614. for (k = 0; k < 3; k++)
  2615. for (l = 0; l < 3; l++) {
  2616. config_output->transform.transform.matrix[k][l] = XDoubleToFixed (transform[k][l]);
  2617. }
  2618. config_output->transform.filter = "bilinear";
  2619. config_output->transform.nparams = 0;
  2620. config_output->transform.params = NULL;
  2621. }
  2622. config_output->changes |= changes_transform;
  2623. continue;
  2624. }
  2625. if (!strcmp ("--off", argv[i])) {
  2626. if (!config_output) argerr ("%s must be used after --output\n", argv[i]);
  2627. set_name_xid (&config_output->mode, None);
  2628. set_name_xid (&config_output->crtc, None);
  2629. config_output->changes |= changes_mode;
  2630. continue;
  2631. }
  2632. if (!strcmp ("--fb", argv[i])) {
  2633. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2634. if (sscanf (argv[i], "%dx%d",
  2635. &fb_width, &fb_height) != 2)
  2636. argerr ("failed to parse '%s' as a framebuffer size\n", argv[i]);
  2637. setit_1_2 = True;
  2638. action_requested = True;
  2639. continue;
  2640. }
  2641. if (!strcmp ("--fbmm", argv[i])) {
  2642. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2643. if (sscanf (argv[i], "%dx%d",
  2644. &fb_width_mm, &fb_height_mm) != 2)
  2645. argerr ("failed to parse '%s' as a physical size\n", argv[i]);
  2646. setit_1_2 = True;
  2647. action_requested = True;
  2648. continue;
  2649. }
  2650. if (!strcmp ("--dpi", argv[i])) {
  2651. char *strtod_error;
  2652. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2653. dpi = strtod(argv[i], &strtod_error);
  2654. if (argv[i] == strtod_error)
  2655. {
  2656. dpi = 0.0;
  2657. dpi_output_name = argv[i];
  2658. }
  2659. setit_1_2 = True;
  2660. action_requested = True;
  2661. continue;
  2662. }
  2663. if (!strcmp ("--auto", argv[i])) {
  2664. if (config_output)
  2665. {
  2666. config_output->automatic = True;
  2667. config_output->changes |= changes_automatic;
  2668. }
  2669. else
  2670. automatic = True;
  2671. setit_1_2 = True;
  2672. action_requested = True;
  2673. continue;
  2674. }
  2675. if (!strcmp ("--q12", argv[i]))
  2676. {
  2677. query_1_2 = True;
  2678. continue;
  2679. }
  2680. if (!strcmp ("--q1", argv[i]))
  2681. {
  2682. query_1 = True;
  2683. continue;
  2684. }
  2685. if (!strcmp ("--newmode", argv[i]))
  2686. {
  2687. umode_t *m = calloc (1, sizeof (umode_t));
  2688. double clock;
  2689. ++i;
  2690. if (i + 9 >= argc)
  2691. argerr ("failed to parse '%s' as a mode specification\n", argv[i]);
  2692. m->mode.name = argv[i];
  2693. m->mode.nameLength = strlen (argv[i]);
  2694. i++;
  2695. clock = check_strtod(argv[i++]);
  2696. m->mode.dotClock = clock * 1e6;
  2697. m->mode.width = check_strtol(argv[i++]);
  2698. m->mode.hSyncStart = check_strtol(argv[i++]);
  2699. m->mode.hSyncEnd = check_strtol(argv[i++]);
  2700. m->mode.hTotal = check_strtol(argv[i++]);
  2701. m->mode.height = check_strtol(argv[i++]);
  2702. m->mode.vSyncStart = check_strtol(argv[i++]);
  2703. m->mode.vSyncEnd = check_strtol(argv[i++]);
  2704. m->mode.vTotal = check_strtol(argv[i++]);
  2705. m->mode.modeFlags = 0;
  2706. while (i < argc) {
  2707. int f;
  2708. for (f = 0; mode_flags[f].string; f++)
  2709. if (!strcasecmp (mode_flags[f].string, argv[i]))
  2710. break;
  2711. if (!mode_flags[f].string)
  2712. break;
  2713. m->mode.modeFlags |= mode_flags[f].flag;
  2714. i++;
  2715. }
  2716. m->next = umodes;
  2717. m->action = umode_create;
  2718. umodes = m;
  2719. modeit = True;
  2720. action_requested = True;
  2721. continue;
  2722. }
  2723. if (!strcmp ("--rmmode", argv[i]))
  2724. {
  2725. umode_t *m = calloc (1, sizeof (umode_t));
  2726. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2727. set_name (&m->name, argv[i], name_string|name_xid);
  2728. m->action = umode_destroy;
  2729. m->next = umodes;
  2730. umodes = m;
  2731. modeit = True;
  2732. action_requested = True;
  2733. continue;
  2734. }
  2735. if (!strcmp ("--addmode", argv[i]))
  2736. {
  2737. umode_t *m = calloc (1, sizeof (umode_t));
  2738. if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]);
  2739. set_name (&m->output, argv[++i], name_string|name_xid);
  2740. set_name (&m->name, argv[++i], name_string|name_xid);
  2741. m->action = umode_add;
  2742. m->next = umodes;
  2743. umodes = m;
  2744. modeit = True;
  2745. action_requested = True;
  2746. continue;
  2747. }
  2748. if (!strcmp ("--delmode", argv[i]))
  2749. {
  2750. umode_t *m = calloc (1, sizeof (umode_t));
  2751. if (i+2 >= argc) argerr ("%s requires two arguments\n", argv[i]);
  2752. set_name (&m->output, argv[++i], name_string|name_xid);
  2753. set_name (&m->name, argv[++i], name_string|name_xid);
  2754. m->action = umode_delete;
  2755. m->next = umodes;
  2756. umodes = m;
  2757. modeit = True;
  2758. action_requested = True;
  2759. continue;
  2760. }
  2761. if (!strcmp ("--listproviders", argv[i]))
  2762. {
  2763. list_providers = True;
  2764. action_requested = True;
  2765. continue;
  2766. }
  2767. if (!strcmp("--setprovideroutputsource", argv[i]))
  2768. {
  2769. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2770. set_name (&provider_name, argv[i], name_string|name_xid|name_index);
  2771. if (++i>=argc)
  2772. set_name_xid (&output_source_provider_name, 0);
  2773. else
  2774. set_name (&output_source_provider_name, argv[i], name_string|name_xid|name_index);
  2775. action_requested = True;
  2776. provsetoutsource = True;
  2777. continue;
  2778. }
  2779. if (!strcmp("--setprovideroffloadsink", argv[i]))
  2780. {
  2781. if (++i >= argc) argerr ("%s requires an argument\n", argv[i-1]);
  2782. set_name (&provider_name, argv[i], name_string|name_xid|name_index);
  2783. if (++i>=argc)
  2784. set_name_xid (&offload_sink_provider_name, 0);
  2785. else
  2786. set_name (&offload_sink_provider_name, argv[i], name_string|name_xid|name_index);
  2787. action_requested = True;
  2788. provsetoffsink = True;
  2789. continue;
  2790. }
  2791. argerr ("unrecognized option '%s'\n", argv[i]);
  2792. }
  2793. if (!action_requested)
  2794. query = True;
  2795. if (verbose)
  2796. {
  2797. query = True;
  2798. if (setit && !setit_1_2)
  2799. query_1 = True;
  2800. }
  2801. if (version)
  2802. printf("xrandr program version " VERSION "\n");
  2803. dpy = XOpenDisplay (display_name);
  2804. if (dpy == NULL) {
  2805. fprintf (stderr, "Can't open display %s\n", XDisplayName(display_name));
  2806. exit (1);
  2807. }
  2808. if (screen < 0)
  2809. screen = DefaultScreen (dpy);
  2810. if (screen >= ScreenCount (dpy)) {
  2811. fprintf (stderr, "Invalid screen number %d (display has %d)\n",
  2812. screen, ScreenCount (dpy));
  2813. exit (1);
  2814. }
  2815. root = RootWindow (dpy, screen);
  2816. if (!XRRQueryExtension (dpy, &event_base, &error_base) ||
  2817. !XRRQueryVersion (dpy, &major, &minor))
  2818. {
  2819. fprintf (stderr, "RandR extension missing\n");
  2820. exit (1);
  2821. }
  2822. if (major > 1 || (major == 1 && minor >= 2))
  2823. has_1_2 = True;
  2824. if (major > 1 || (major == 1 && minor >= 3))
  2825. has_1_3 = True;
  2826. if (major > 1 || (major == 1 && minor >= 4))
  2827. has_1_4 = True;
  2828. if (has_1_2 && modeit)
  2829. {
  2830. umode_t *m;
  2831. get_screen (current);
  2832. get_crtcs();
  2833. get_outputs();
  2834. for (m = umodes; m; m = m->next)
  2835. {
  2836. XRRModeInfo *e;
  2837. output_t *o;
  2838. switch (m->action) {
  2839. case umode_create:
  2840. XRRCreateMode (dpy, root, &m->mode);
  2841. break;
  2842. case umode_destroy:
  2843. e = find_mode (&m->name, 0);
  2844. if (!e)
  2845. fatal ("cannot find mode \"%s\"\n", m->name.string);
  2846. XRRDestroyMode (dpy, e->id);
  2847. break;
  2848. case umode_add:
  2849. o = find_output (&m->output);
  2850. if (!o)
  2851. fatal ("cannot find output \"%s\"\n", m->output.string);
  2852. e = find_mode (&m->name, 0);
  2853. if (!e)
  2854. fatal ("cannot find mode \"%s\"\n", m->name.string);
  2855. XRRAddOutputMode (dpy, o->output.xid, e->id);
  2856. break;
  2857. case umode_delete:
  2858. o = find_output (&m->output);
  2859. if (!o)
  2860. fatal ("cannot find output \"%s\"\n", m->output.string);
  2861. e = find_mode (&m->name, 0);
  2862. if (!e)
  2863. fatal ("cannot find mode \"%s\"\n", m->name.string);
  2864. XRRDeleteOutputMode (dpy, o->output.xid, e->id);
  2865. break;
  2866. }
  2867. }
  2868. if (!setit_1_2)
  2869. {
  2870. XSync (dpy, False);
  2871. exit (0);
  2872. }
  2873. }
  2874. if (has_1_2 && propit)
  2875. {
  2876. output_t *output;
  2877. get_screen (current);
  2878. get_crtcs();
  2879. get_outputs();
  2880. for (output = all_outputs; output; output = output->next)
  2881. {
  2882. output_prop_t *prop;
  2883. for (prop = output->props; prop; prop = prop->next)
  2884. {
  2885. Atom name = XInternAtom (dpy, prop->name, False);
  2886. Atom type;
  2887. int format = 0;
  2888. unsigned char *data, *malloced_data = NULL;
  2889. int nelements;
  2890. int int_value;
  2891. unsigned long ulong_value;
  2892. unsigned char *prop_data;
  2893. int actual_format;
  2894. unsigned long nitems, bytes_after;
  2895. Atom actual_type;
  2896. XRRPropertyInfo *propinfo;
  2897. type = AnyPropertyType;
  2898. if (XRRGetOutputProperty (dpy, output->output.xid, name,
  2899. 0, 100, False, False,
  2900. AnyPropertyType,
  2901. &actual_type, &actual_format,
  2902. &nitems, &bytes_after, &prop_data) == Success &&
  2903. (propinfo = XRRQueryOutputProperty(dpy, output->output.xid,
  2904. name)))
  2905. {
  2906. type = actual_type;
  2907. format = actual_format;
  2908. }
  2909. malloced_data = property_values_from_string
  2910. (prop->value, type, actual_format, &nelements);
  2911. if (malloced_data)
  2912. {
  2913. data = malloced_data;
  2914. type = actual_type;
  2915. format = actual_format;
  2916. }
  2917. else if (type == AnyPropertyType &&
  2918. (sscanf (prop->value, "%d", &int_value) == 1 ||
  2919. sscanf (prop->value, "0x%x", &int_value) == 1))
  2920. {
  2921. type = XA_INTEGER;
  2922. ulong_value = int_value;
  2923. data = (unsigned char *) &ulong_value;
  2924. nelements = 1;
  2925. format = 32;
  2926. }
  2927. else if (type == XA_ATOM)
  2928. {
  2929. ulong_value = XInternAtom (dpy, prop->value, False);
  2930. data = (unsigned char *) &ulong_value;
  2931. nelements = 1;
  2932. }
  2933. else if (type == XA_STRING || type == AnyPropertyType)
  2934. {
  2935. type = XA_STRING;
  2936. data = (unsigned char *) prop->value;
  2937. nelements = strlen (prop->value);
  2938. format = 8;
  2939. }
  2940. else
  2941. continue;
  2942. XRRChangeOutputProperty (dpy, output->output.xid,
  2943. name, type, format, PropModeReplace,
  2944. data, nelements);
  2945. free (malloced_data);
  2946. }
  2947. }
  2948. if (!setit_1_2)
  2949. {
  2950. XSync (dpy, False);
  2951. exit (0);
  2952. }
  2953. }
  2954. if (provsetoutsource)
  2955. {
  2956. provider_t *provider, *source;
  2957. if (!has_1_4)
  2958. fatal ("--setprovideroutputsource requires RandR 1.4\n");
  2959. get_screen (current);
  2960. get_providers ();
  2961. provider = find_provider (&provider_name);
  2962. source = find_provider(&output_source_provider_name);
  2963. XRRSetProviderOutputSource(dpy, provider->provider.xid, source ? source->provider.xid : 0);
  2964. }
  2965. if (provsetoffsink)
  2966. {
  2967. provider_t *provider, *sink;
  2968. if (!has_1_4)
  2969. fatal ("--setprovideroffloadsink requires RandR 1.4\n");
  2970. get_screen (current);
  2971. get_providers ();
  2972. provider = find_provider (&provider_name);
  2973. sink = find_provider(&offload_sink_provider_name);
  2974. XRRSetProviderOffloadSink(dpy, provider->provider.xid, sink ? sink->provider.xid : 0);
  2975. }
  2976. if (setit_1_2)
  2977. {
  2978. get_screen (current);
  2979. get_crtcs ();
  2980. get_outputs ();
  2981. set_positions ();
  2982. set_screen_size ();
  2983. pick_crtcs ();
  2984. /*
  2985. * Assign outputs to crtcs
  2986. */
  2987. set_crtcs ();
  2988. /*
  2989. * Mark changing crtcs
  2990. */
  2991. mark_changing_crtcs ();
  2992. /*
  2993. * If an output was specified to track dpi, use it
  2994. */
  2995. if (dpi_output_name)
  2996. {
  2997. output_t *dpi_output = find_output_by_name (dpi_output_name);
  2998. XRROutputInfo *output_info;
  2999. XRRModeInfo *mode_info;
  3000. if (!dpi_output)
  3001. fatal ("Cannot find output %s\n", dpi_output_name);
  3002. output_info = dpi_output->output_info;
  3003. mode_info = dpi_output->mode_info;
  3004. if (output_info && mode_info && output_info->mm_height)
  3005. {
  3006. /*
  3007. * When this output covers the whole screen, just use
  3008. * the known physical size
  3009. */
  3010. if (fb_width == mode_info->width &&
  3011. fb_height == mode_info->height)
  3012. {
  3013. fb_width_mm = output_info->mm_width;
  3014. fb_height_mm = output_info->mm_height;
  3015. }
  3016. else
  3017. {
  3018. dpi = (25.4 * mode_info->height) / output_info->mm_height;
  3019. }
  3020. }
  3021. }
  3022. /*
  3023. * Compute physical screen size
  3024. */
  3025. if (fb_width_mm == 0 || fb_height_mm == 0)
  3026. {
  3027. if (fb_width != DisplayWidth (dpy, screen) ||
  3028. fb_height != DisplayHeight (dpy, screen) || dpi != 0.0)
  3029. {
  3030. if (dpi <= 0)
  3031. dpi = (25.4 * DisplayHeight (dpy, screen)) / DisplayHeightMM(dpy, screen);
  3032. fb_width_mm = (25.4 * fb_width) / dpi;
  3033. fb_height_mm = (25.4 * fb_height) / dpi;
  3034. }
  3035. else
  3036. {
  3037. fb_width_mm = DisplayWidthMM (dpy, screen);
  3038. fb_height_mm = DisplayHeightMM (dpy, screen);
  3039. }
  3040. }
  3041. /*
  3042. * Set panning
  3043. */
  3044. set_panning ();
  3045. /*
  3046. * Set gamma on crtc's that belong to the outputs.
  3047. */
  3048. set_gamma ();
  3049. /*
  3050. * Now apply all of the changes
  3051. */
  3052. apply ();
  3053. XSync (dpy, False);
  3054. exit (0);
  3055. }
  3056. if (query_1_2 || (query && has_1_2 && !query_1))
  3057. {
  3058. output_t *output;
  3059. int m;
  3060. #define ModeShown 0x80000000
  3061. get_screen (current);
  3062. get_crtcs ();
  3063. get_outputs ();
  3064. printf ("Screen %d: minimum %d x %d, current %d x %d, maximum %d x %d\n",
  3065. screen, minWidth, minHeight,
  3066. DisplayWidth (dpy, screen), DisplayHeight(dpy, screen),
  3067. maxWidth, maxHeight);
  3068. for (output = all_outputs; output; output = output->next)
  3069. {
  3070. XRROutputInfo *output_info = output->output_info;
  3071. crtc_t *cur_crtc = output->crtc_info;
  3072. XRRCrtcInfo *crtc_info = cur_crtc ? cur_crtc->crtc_info : NULL;
  3073. XRRModeInfo *cur_mode = output->mode_info;
  3074. Atom *props;
  3075. int j, nprop;
  3076. Bool *mode_shown;
  3077. Rotation rotations = output_rotations (output);
  3078. printf ("%s %s", output_info->name, connection[output_info->connection]);
  3079. if (output->primary) {
  3080. printf(" primary");
  3081. }
  3082. if (cur_mode)
  3083. {
  3084. if (crtc_info) {
  3085. printf (" %dx%d+%d+%d",
  3086. crtc_info->width, crtc_info->height,
  3087. crtc_info->x, crtc_info->y);
  3088. } else {
  3089. printf (" %dx%d+%d+%d",
  3090. cur_mode->width, cur_mode->height, output->x,
  3091. output->y);
  3092. }
  3093. if (verbose)
  3094. printf (" (0x%x)", (int)cur_mode->id);
  3095. if (output->rotation != RR_Rotate_0 || verbose)
  3096. {
  3097. printf (" %s",
  3098. rotation_name (output->rotation));
  3099. if (output->rotation & (RR_Reflect_X|RR_Reflect_Y))
  3100. printf (" %s", reflection_name (output->rotation));
  3101. }
  3102. }
  3103. if (rotations != RR_Rotate_0 || verbose)
  3104. {
  3105. Bool first = True;
  3106. printf (" (");
  3107. for (i = 0; i < 4; i ++) {
  3108. if ((rotations >> i) & 1) {
  3109. if (!first) printf (" "); first = False;
  3110. printf("%s", direction[i]);
  3111. }
  3112. }
  3113. if (rotations & RR_Reflect_X)
  3114. {
  3115. if (!first) printf (" "); first = False;
  3116. printf ("x axis");
  3117. }
  3118. if (rotations & RR_Reflect_Y)
  3119. {
  3120. if (!first) printf (" ");
  3121. printf ("y axis");
  3122. }
  3123. printf (")");
  3124. }
  3125. if (cur_mode)
  3126. {
  3127. printf (" %dmm x %dmm",
  3128. (int)output_info->mm_width, (int)output_info->mm_height);
  3129. }
  3130. if (cur_crtc && cur_crtc->panning_info &&
  3131. cur_crtc->panning_info->width > 0)
  3132. {
  3133. XRRPanning *pan = cur_crtc->panning_info;
  3134. printf (" panning %dx%d+%d+%d",
  3135. pan->width, pan->height, pan->left, pan->top);
  3136. if ((pan->track_width != 0 &&
  3137. (pan->track_left != pan->left ||
  3138. pan->track_width != pan->width ||
  3139. pan->border_left != 0 ||
  3140. pan->border_right != 0)) ||
  3141. (pan->track_height != 0 &&
  3142. (pan->track_top != pan->top ||
  3143. pan->track_height != pan->height ||
  3144. pan->border_top != 0 ||
  3145. pan->border_bottom != 0)))
  3146. printf (" tracking %dx%d+%d+%d border %d/%d/%d/%d",
  3147. pan->track_width, pan->track_height,
  3148. pan->track_left, pan->track_top,
  3149. pan->border_left, pan->border_top,
  3150. pan->border_right, pan->border_bottom);
  3151. }
  3152. printf ("\n");
  3153. if (verbose)
  3154. {
  3155. printf ("\tIdentifier: 0x%x\n", (int)output->output.xid);
  3156. printf ("\tTimestamp: %d\n", (int)output_info->timestamp);
  3157. printf ("\tSubpixel: %s\n", order[output_info->subpixel_order]);
  3158. if (output->gamma.red != 0.0 && output->gamma.green != 0.0 && output->gamma.blue != 0.0) {
  3159. printf ("\tGamma: %#.2g:%#.2g:%#.2g\n",
  3160. output->gamma.red, output->gamma.green, output->gamma.blue);
  3161. printf ("\tBrightness: %#.2g\n", output->brightness);
  3162. }
  3163. printf ("\tClones: ");
  3164. for (j = 0; j < output_info->nclone; j++)
  3165. {
  3166. output_t *clone = find_output_by_xid (output_info->clones[j]);
  3167. if (clone) printf (" %s", clone->output.string);
  3168. }
  3169. printf ("\n");
  3170. if (output->crtc_info)
  3171. printf ("\tCRTC: %d\n", output->crtc_info->crtc.index);
  3172. printf ("\tCRTCs: ");
  3173. for (j = 0; j < output_info->ncrtc; j++)
  3174. {
  3175. crtc_t *crtc = find_crtc_by_xid (output_info->crtcs[j]);
  3176. if (crtc)
  3177. printf (" %d", crtc->crtc.index);
  3178. }
  3179. printf ("\n");
  3180. if (output->crtc_info && output->crtc_info->panning_info) {
  3181. XRRPanning *pan = output->crtc_info->panning_info;
  3182. printf ("\tPanning: %dx%d+%d+%d\n",
  3183. pan->width, pan->height, pan->left, pan->top);
  3184. printf ("\tTracking: %dx%d+%d+%d\n",
  3185. pan->track_width, pan->track_height,
  3186. pan->track_left, pan->track_top);
  3187. printf ("\tBorder: %d/%d/%d/%d\n",
  3188. pan->border_left, pan->border_top,
  3189. pan->border_right, pan->border_bottom);
  3190. }
  3191. }
  3192. if (verbose)
  3193. {
  3194. int x, y;
  3195. printf ("\tTransform: ");
  3196. for (y = 0; y < 3; y++)
  3197. {
  3198. for (x = 0; x < 3; x++)
  3199. printf (" %f", XFixedToDouble (output->transform.transform.matrix[y][x]));
  3200. if (y < 2)
  3201. printf ("\n\t ");
  3202. }
  3203. if (output->transform.filter)
  3204. printf ("\n\t filter: %s", output->transform.filter);
  3205. printf ("\n");
  3206. }
  3207. if (verbose || properties)
  3208. {
  3209. props = XRRListOutputProperties (dpy, output->output.xid,
  3210. &nprop);
  3211. for (j = 0; j < nprop; j++) {
  3212. unsigned char *prop;
  3213. int actual_format;
  3214. unsigned long nitems, bytes_after;
  3215. Atom actual_type;
  3216. XRRPropertyInfo *propinfo;
  3217. char *atom_name = XGetAtomName (dpy, props[j]);
  3218. int k;
  3219. XRRGetOutputProperty (dpy, output->output.xid, props[j],
  3220. 0, 100, False, False,
  3221. AnyPropertyType,
  3222. &actual_type, &actual_format,
  3223. &nitems, &bytes_after, &prop);
  3224. propinfo = XRRQueryOutputProperty(dpy, output->output.xid,
  3225. props[j]);
  3226. printf ("\t%s: ", atom_name);
  3227. print_output_property(atom_name, actual_format,
  3228. actual_type, nitems, prop);
  3229. if (propinfo->range && propinfo->num_values > 0)
  3230. {
  3231. printf ("\t\trange%s: ",
  3232. (propinfo->num_values == 2) ? "" : "s");
  3233. for (k = 0; k < propinfo->num_values / 2; k++)
  3234. {
  3235. printf ("(");
  3236. print_output_property_value (32, actual_type,
  3237. (unsigned char *) &(propinfo->values[k * 2]));
  3238. printf (", ");
  3239. print_output_property_value (32, actual_type,
  3240. (unsigned char *) &(propinfo->values[k * 2 + 1]));
  3241. printf (")");
  3242. if (k < propinfo->num_values / 2 - 1)
  3243. printf (", ");
  3244. }
  3245. printf ("\n");
  3246. }
  3247. if (!propinfo->range && propinfo->num_values > 0)
  3248. {
  3249. printf ("\t\tsupported: ");
  3250. for (k = 0; k < propinfo->num_values; k++)
  3251. {
  3252. print_output_property_value (32, actual_type,
  3253. (unsigned char *) &(propinfo->values[k]));
  3254. if (k < propinfo->num_values - 1)
  3255. printf (", ");
  3256. }
  3257. printf ("\n");
  3258. }
  3259. free(propinfo);
  3260. }
  3261. }
  3262. if (verbose)
  3263. {
  3264. for (j = 0; j < output_info->nmode; j++)
  3265. {
  3266. XRRModeInfo *mode = find_mode_by_xid (output_info->modes[j]);
  3267. int f;
  3268. printf (" %s (0x%x) %6.3fMHz",
  3269. mode->name, (int)mode->id,
  3270. (double)mode->dotClock / 1000000.0);
  3271. for (f = 0; mode_flags[f].flag; f++)
  3272. if (mode->modeFlags & mode_flags[f].flag)
  3273. printf (" %s", mode_flags[f].string);
  3274. if (mode == output->mode_info)
  3275. printf (" *current");
  3276. if (j < output_info->npreferred)
  3277. printf (" +preferred");
  3278. printf ("\n");
  3279. printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.2fKHz\n",
  3280. mode->width, mode->hSyncStart, mode->hSyncEnd,
  3281. mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000);
  3282. printf (" v: height %4d start %4d end %4d total %4d clock %6.2fHz\n",
  3283. mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal,
  3284. mode_refresh (mode));
  3285. mode->modeFlags |= ModeShown;
  3286. }
  3287. }
  3288. else
  3289. {
  3290. mode_shown = calloc (output_info->nmode, sizeof (Bool));
  3291. if (!mode_shown) fatal ("out of memory\n");
  3292. for (j = 0; j < output_info->nmode; j++)
  3293. {
  3294. XRRModeInfo *jmode, *kmode;
  3295. int k;
  3296. if (mode_shown[j]) continue;
  3297. jmode = find_mode_by_xid (output_info->modes[j]);
  3298. printf (" ");
  3299. printf (" %-12s", jmode->name);
  3300. for (k = j; k < output_info->nmode; k++)
  3301. {
  3302. if (mode_shown[k]) continue;
  3303. kmode = find_mode_by_xid (output_info->modes[k]);
  3304. if (strcmp (jmode->name, kmode->name) != 0) continue;
  3305. mode_shown[k] = True;
  3306. kmode->modeFlags |= ModeShown;
  3307. printf (" %6.2f", mode_refresh (kmode));
  3308. if (kmode == output->mode_info)
  3309. printf ("*");
  3310. else
  3311. printf (" ");
  3312. if (k < output_info->npreferred)
  3313. printf ("+");
  3314. else
  3315. printf (" ");
  3316. }
  3317. printf ("\n");
  3318. }
  3319. free (mode_shown);
  3320. }
  3321. }
  3322. for (m = 0; m < res->nmode; m++)
  3323. {
  3324. XRRModeInfo *mode = &res->modes[m];
  3325. if (!(mode->modeFlags & ModeShown))
  3326. {
  3327. printf (" %s (0x%x) %6.3fMHz\n",
  3328. mode->name, (int)mode->id,
  3329. (double)mode->dotClock / 1000000.0);
  3330. printf (" h: width %4d start %4d end %4d total %4d skew %4d clock %6.2fKHz\n",
  3331. mode->width, mode->hSyncStart, mode->hSyncEnd,
  3332. mode->hTotal, mode->hSkew, mode_hsync (mode) / 1000);
  3333. printf (" v: height %4d start %4d end %4d total %4d clock %6.2fHz\n",
  3334. mode->height, mode->vSyncStart, mode->vSyncEnd, mode->vTotal,
  3335. mode_refresh (mode));
  3336. }
  3337. }
  3338. exit (0);
  3339. }
  3340. if (list_providers) {
  3341. int k;
  3342. if (!has_1_4) {
  3343. printf ("RandR 1.4 not supported\n");
  3344. exit (0);
  3345. }
  3346. get_screen (current);
  3347. get_providers ();
  3348. if (providers) {
  3349. int j;
  3350. printf("Providers: number : %d\n", num_providers);
  3351. for (j = 0; j < num_providers; j++) {
  3352. provider_t *provider = &providers[j];
  3353. XRRProviderInfo *info = provider->info;
  3354. printf("Provider %d: id: 0x%x cap: 0x%x", j, (int)provider->provider.xid, info->capabilities);
  3355. for (k = 0; k < 4; k++)
  3356. if (info->capabilities & (1 << k))
  3357. printf(", %s", capability_name(1<<k));
  3358. printf(" crtcs: %d outputs: %d associated providers: %d name:%s\n", info->ncrtcs, info->noutputs, info->nassociatedproviders, info->name);
  3359. }
  3360. }
  3361. }
  3362. sc = XRRGetScreenInfo (dpy, root);
  3363. if (sc == NULL)
  3364. exit (1);
  3365. current_size = XRRConfigCurrentConfiguration (sc, &current_rotation);
  3366. sizes = XRRConfigSizes(sc, &nsize);
  3367. if (have_pixel_size) {
  3368. for (size = 0; size < nsize; size++)
  3369. {
  3370. if (sizes[size].width == width && sizes[size].height == height)
  3371. break;
  3372. }
  3373. if (size >= nsize) {
  3374. fprintf (stderr,
  3375. "Size %dx%d not found in available modes\n", width, height);
  3376. exit (1);
  3377. }
  3378. }
  3379. else if (size < 0)
  3380. size = current_size;
  3381. else if (size >= nsize) {
  3382. fprintf (stderr,
  3383. "Size index %d is too large, there are only %d sizes\n",
  3384. size, nsize);
  3385. exit (1);
  3386. }
  3387. if (rot < 0)
  3388. {
  3389. for (rot = 0; rot < 4; rot++)
  3390. if (1 << rot == (current_rotation & 0xf))
  3391. break;
  3392. }
  3393. current_rate = XRRConfigCurrentRate (sc);
  3394. if (rate < 0)
  3395. {
  3396. if (size == current_size)
  3397. rate = current_rate;
  3398. else
  3399. rate = 0;
  3400. }
  3401. else
  3402. {
  3403. rates = XRRConfigRates (sc, size, &nrate);
  3404. for (i = 0; i < nrate; i++)
  3405. if (rate == rates[i])
  3406. break;
  3407. if (i == nrate) {
  3408. fprintf (stderr, "Rate %.2f Hz not available for this size\n", rate);
  3409. exit (1);
  3410. }
  3411. }
  3412. if (version) {
  3413. int major_version, minor_version;
  3414. XRRQueryVersion (dpy, &major_version, &minor_version);
  3415. printf("Server reports RandR version %d.%d\n",
  3416. major_version, minor_version);
  3417. }
  3418. if (query || query_1) {
  3419. printf(" SZ: Pixels Physical Refresh\n");
  3420. for (i = 0; i < nsize; i++) {
  3421. int j;
  3422. printf ("%c%-2d %5d x %-5d (%4dmm x%4dmm )",
  3423. i == current_size ? '*' : ' ',
  3424. i, sizes[i].width, sizes[i].height,
  3425. sizes[i].mwidth, sizes[i].mheight);
  3426. rates = XRRConfigRates (sc, i, &nrate);
  3427. if (nrate) printf (" ");
  3428. for (j = 0; j < nrate; j++)
  3429. printf ("%c%-4d",
  3430. i == current_size && rates[j] == current_rate ? '*' : ' ',
  3431. rates[j]);
  3432. printf ("\n");
  3433. }
  3434. }
  3435. {
  3436. Rotation rotations = XRRConfigRotations(sc, &current_rotation);
  3437. if (toggle_x && !(current_rotation & RR_Reflect_X)) reflection |= RR_Reflect_X;
  3438. if (toggle_y && !(current_rotation & RR_Reflect_Y)) reflection |= RR_Reflect_Y;
  3439. if (query) {
  3440. printf("Current rotation - %s\n",
  3441. rotation_name (current_rotation));
  3442. printf("Current reflection - %s\n",
  3443. reflection_name (current_rotation));
  3444. printf ("Rotations possible - ");
  3445. for (i = 0; i < 4; i ++) {
  3446. if ((rotations >> i) & 1) printf("%s ", direction[i]);
  3447. }
  3448. printf ("\n");
  3449. printf ("Reflections possible - ");
  3450. if (rotations & (RR_Reflect_X|RR_Reflect_Y))
  3451. {
  3452. if (rotations & RR_Reflect_X) printf ("X Axis ");
  3453. if (rotations & RR_Reflect_Y) printf ("Y Axis");
  3454. }
  3455. else
  3456. printf ("none");
  3457. printf ("\n");
  3458. }
  3459. }
  3460. if (verbose) {
  3461. printf("Setting size to %d, rotation to %s\n", size, direction[rot]);
  3462. printf ("Setting reflection on ");
  3463. if (reflection)
  3464. {
  3465. if (reflection & RR_Reflect_X) printf ("X Axis ");
  3466. if (reflection & RR_Reflect_Y) printf ("Y Axis");
  3467. }
  3468. else
  3469. printf ("neither axis");
  3470. printf ("\n");
  3471. }
  3472. /* we should test configureNotify on the root window */
  3473. XSelectInput (dpy, root, StructureNotifyMask);
  3474. if (setit && !dryrun) XRRSelectInput (dpy, root,
  3475. RRScreenChangeNotifyMask);
  3476. if (setit && !dryrun) {
  3477. Rotation rotation = 1 << rot;
  3478. status = XRRSetScreenConfigAndRate (dpy, sc, root, (SizeID) size,
  3479. (Rotation) (rotation | reflection),
  3480. rate, CurrentTime);
  3481. }
  3482. if (setit && !dryrun && status == RRSetConfigFailed) {
  3483. printf ("Failed to change the screen configuration!\n");
  3484. ret = 1;
  3485. }
  3486. if (verbose && setit && !dryrun && size != current_size) {
  3487. if (status == RRSetConfigSuccess)
  3488. {
  3489. Bool seen_screen = False;
  3490. while (!seen_screen) {
  3491. int spo;
  3492. XNextEvent(dpy, (XEvent *) &event);
  3493. printf ("Event received, type = %d\n", event.type);
  3494. /* update Xlib's knowledge of the event */
  3495. XRRUpdateConfiguration (&event);
  3496. if (event.type == ConfigureNotify)
  3497. printf("Received ConfigureNotify Event!\n");
  3498. switch (event.type - event_base) {
  3499. case RRScreenChangeNotify:
  3500. sce = (XRRScreenChangeNotifyEvent *) &event;
  3501. printf("Got a screen change notify event!\n");
  3502. printf(" window = %d\n root = %d\n size_index = %d\n rotation %d\n",
  3503. (int) sce->window, (int) sce->root,
  3504. sce->size_index, sce->rotation);
  3505. printf(" timestamp = %ld, config_timestamp = %ld\n",
  3506. sce->timestamp, sce->config_timestamp);
  3507. printf(" Rotation = %x\n", sce->rotation);
  3508. printf(" %d X %d pixels, %d X %d mm\n",
  3509. sce->width, sce->height, sce->mwidth, sce->mheight);
  3510. printf("Display width %d, height %d\n",
  3511. DisplayWidth(dpy, screen), DisplayHeight(dpy, screen));
  3512. printf("Display widthmm %d, heightmm %d\n",
  3513. DisplayWidthMM(dpy, screen), DisplayHeightMM(dpy, screen));
  3514. spo = sce->subpixel_order;
  3515. if ((spo < 0) || (spo > 5))
  3516. printf ("Unknown subpixel order, value = %d\n", spo);
  3517. else printf ("new Subpixel rendering model is %s\n", order[spo]);
  3518. seen_screen = True;
  3519. break;
  3520. default:
  3521. if (event.type != ConfigureNotify)
  3522. printf("unknown event received, type = %d!\n", event.type);
  3523. }
  3524. }
  3525. }
  3526. }
  3527. XRRFreeScreenConfigInfo(sc);
  3528. return(ret);
  3529. }