display_server_x11.cpp 228 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491
  1. /**************************************************************************/
  2. /* display_server_x11.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "display_server_x11.h"
  31. #ifdef X11_ENABLED
  32. #include "x11/detect_prime_x11.h"
  33. #include "x11/key_mapping_x11.h"
  34. #include "core/config/project_settings.h"
  35. #include "core/math/math_funcs.h"
  36. #include "core/string/print_string.h"
  37. #include "core/string/ustring.h"
  38. #include "core/version.h"
  39. #include "drivers/png/png_driver_common.h"
  40. #include "main/main.h"
  41. #include "servers/rendering/dummy/rasterizer_dummy.h"
  42. #if defined(VULKAN_ENABLED)
  43. #include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
  44. #endif
  45. #if defined(GLES3_ENABLED)
  46. #include "drivers/gles3/rasterizer_gles3.h"
  47. #endif
  48. #ifdef ACCESSKIT_ENABLED
  49. #include "drivers/accesskit/accessibility_driver_accesskit.h"
  50. #endif
  51. #include <dlfcn.h>
  52. #include <sys/stat.h>
  53. #include <sys/types.h>
  54. #include <unistd.h>
  55. #include <climits>
  56. #include <cstdio>
  57. #include <cstdlib>
  58. #undef CursorShape
  59. #include <X11/XKBlib.h>
  60. // ICCCM
  61. #define WM_NormalState 1L // window normal state
  62. #define WM_IconicState 3L // window minimized
  63. // EWMH
  64. #define _NET_WM_STATE_REMOVE 0L // remove/unset property
  65. #define _NET_WM_STATE_ADD 1L // add/set property
  66. #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0L
  67. #define _NET_WM_MOVERESIZE_SIZE_TOP 1L
  68. #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2L
  69. #define _NET_WM_MOVERESIZE_SIZE_RIGHT 3L
  70. #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4L
  71. #define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5L
  72. #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6L
  73. #define _NET_WM_MOVERESIZE_SIZE_LEFT 7L
  74. #define _NET_WM_MOVERESIZE_MOVE 8L
  75. // 2.2 is the first release with multitouch
  76. #define XINPUT_CLIENT_VERSION_MAJOR 2
  77. #define XINPUT_CLIENT_VERSION_MINOR 2
  78. #define VALUATOR_ABSX 0
  79. #define VALUATOR_ABSY 1
  80. #define VALUATOR_PRESSURE 2
  81. #define VALUATOR_TILTX 3
  82. #define VALUATOR_TILTY 4
  83. //#define DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
  84. #ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
  85. #define DEBUG_LOG_X11(...) printf(__VA_ARGS__)
  86. #else
  87. #define DEBUG_LOG_X11(...)
  88. #endif
  89. static const double abs_resolution_mult = 10000.0;
  90. static const double abs_resolution_range_mult = 10.0;
  91. // Hints for X11 fullscreen
  92. struct Hints {
  93. unsigned long flags = 0;
  94. unsigned long functions = 0;
  95. unsigned long decorations = 0;
  96. long inputMode = 0;
  97. unsigned long status = 0;
  98. };
  99. static String get_atom_name(Display *p_disp, Atom p_atom) {
  100. char *name = XGetAtomName(p_disp, p_atom);
  101. ERR_FAIL_NULL_V_MSG(name, String(), "Atom is invalid.");
  102. String ret = String::utf8(name);
  103. XFree(name);
  104. return ret;
  105. }
  106. bool DisplayServerX11::has_feature(Feature p_feature) const {
  107. switch (p_feature) {
  108. #ifndef DISABLE_DEPRECATED
  109. case FEATURE_GLOBAL_MENU: {
  110. return (native_menu && native_menu->has_feature(NativeMenu::FEATURE_GLOBAL_MENU));
  111. } break;
  112. #endif
  113. case FEATURE_SUBWINDOWS:
  114. #ifdef TOUCH_ENABLED
  115. case FEATURE_TOUCHSCREEN:
  116. #endif
  117. case FEATURE_MOUSE:
  118. case FEATURE_MOUSE_WARP:
  119. case FEATURE_CLIPBOARD:
  120. case FEATURE_CURSOR_SHAPE:
  121. case FEATURE_CUSTOM_CURSOR_SHAPE:
  122. case FEATURE_IME:
  123. case FEATURE_WINDOW_TRANSPARENCY:
  124. //case FEATURE_HIDPI:
  125. case FEATURE_ICON:
  126. //case FEATURE_NATIVE_ICON:
  127. case FEATURE_SWAP_BUFFERS:
  128. #ifdef DBUS_ENABLED
  129. case FEATURE_KEEP_SCREEN_ON:
  130. #endif
  131. case FEATURE_CLIPBOARD_PRIMARY:
  132. case FEATURE_WINDOW_EMBEDDING:
  133. case FEATURE_WINDOW_DRAG: {
  134. return true;
  135. } break;
  136. //case FEATURE_NATIVE_DIALOG:
  137. //case FEATURE_NATIVE_DIALOG_INPUT:
  138. #ifdef DBUS_ENABLED
  139. case FEATURE_NATIVE_DIALOG_FILE:
  140. case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
  141. case FEATURE_NATIVE_DIALOG_FILE_MIME: {
  142. return (portal_desktop && portal_desktop->is_supported() && portal_desktop->is_file_chooser_supported());
  143. } break;
  144. case FEATURE_NATIVE_COLOR_PICKER: {
  145. return (portal_desktop && portal_desktop->is_supported() && portal_desktop->is_screenshot_supported());
  146. } break;
  147. #endif
  148. case FEATURE_SCREEN_CAPTURE: {
  149. return !xwayland;
  150. } break;
  151. #ifdef SPEECHD_ENABLED
  152. case FEATURE_TEXT_TO_SPEECH: {
  153. return true;
  154. } break;
  155. #endif
  156. #ifdef ACCESSKIT_ENABLED
  157. case FEATURE_ACCESSIBILITY_SCREEN_READER: {
  158. return (accessibility_driver != nullptr);
  159. } break;
  160. #endif
  161. default: {
  162. return false;
  163. }
  164. }
  165. }
  166. String DisplayServerX11::get_name() const {
  167. return "X11";
  168. }
  169. void DisplayServerX11::_update_real_mouse_position(const WindowData &wd) {
  170. Window root_return, child_return;
  171. int root_x, root_y, win_x, win_y;
  172. unsigned int mask_return;
  173. Bool xquerypointer_result = XQueryPointer(x11_display, wd.x11_window, &root_return, &child_return, &root_x, &root_y,
  174. &win_x, &win_y, &mask_return);
  175. if (xquerypointer_result) {
  176. if (win_x > 0 && win_y > 0 && win_x <= wd.size.width && win_y <= wd.size.height) {
  177. last_mouse_pos.x = win_x;
  178. last_mouse_pos.y = win_y;
  179. last_mouse_pos_valid = true;
  180. Input::get_singleton()->set_mouse_position(last_mouse_pos);
  181. }
  182. }
  183. }
  184. bool DisplayServerX11::_refresh_device_info() {
  185. int event_base, error_base;
  186. print_verbose("XInput: Refreshing devices.");
  187. if (!XQueryExtension(x11_display, "XInputExtension", &xi.opcode, &event_base, &error_base)) {
  188. print_verbose("XInput extension not available. Please upgrade your distribution.");
  189. return false;
  190. }
  191. int xi_major_query = XINPUT_CLIENT_VERSION_MAJOR;
  192. int xi_minor_query = XINPUT_CLIENT_VERSION_MINOR;
  193. if (XIQueryVersion(x11_display, &xi_major_query, &xi_minor_query) != Success) {
  194. print_verbose(vformat("XInput 2 not available (server supports %d.%d).", xi_major_query, xi_minor_query));
  195. xi.opcode = 0;
  196. return false;
  197. }
  198. if (xi_major_query < XINPUT_CLIENT_VERSION_MAJOR || (xi_major_query == XINPUT_CLIENT_VERSION_MAJOR && xi_minor_query < XINPUT_CLIENT_VERSION_MINOR)) {
  199. print_verbose(vformat("XInput %d.%d not available (server supports %d.%d). Touch input unavailable.",
  200. XINPUT_CLIENT_VERSION_MAJOR, XINPUT_CLIENT_VERSION_MINOR, xi_major_query, xi_minor_query));
  201. }
  202. xi.absolute_devices.clear();
  203. xi.touch_devices.clear();
  204. xi.pen_inverted_devices.clear();
  205. xi.last_relative_time = 0;
  206. int dev_count;
  207. XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count);
  208. for (int i = 0; i < dev_count; i++) {
  209. XIDeviceInfo *dev = &info[i];
  210. if (!dev->enabled) {
  211. continue;
  212. }
  213. if (!(dev->use == XISlavePointer || dev->use == XIFloatingSlave)) {
  214. continue;
  215. }
  216. bool direct_touch = false;
  217. bool absolute_mode = false;
  218. int resolution_x = 0;
  219. int resolution_y = 0;
  220. double abs_x_min = 0;
  221. double abs_x_max = 0;
  222. double abs_y_min = 0;
  223. double abs_y_max = 0;
  224. double pressure_min = 0;
  225. double pressure_max = 0;
  226. double tilt_x_min = 0;
  227. double tilt_x_max = 0;
  228. double tilt_y_min = 0;
  229. double tilt_y_max = 0;
  230. for (int j = 0; j < dev->num_classes; j++) {
  231. #ifdef TOUCH_ENABLED
  232. if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) {
  233. direct_touch = true;
  234. }
  235. #endif
  236. if (dev->classes[j]->type == XIValuatorClass) {
  237. XIValuatorClassInfo *class_info = (XIValuatorClassInfo *)dev->classes[j];
  238. if (class_info->number == VALUATOR_ABSX && class_info->mode == XIModeAbsolute) {
  239. resolution_x = class_info->resolution;
  240. abs_x_min = class_info->min;
  241. abs_x_max = class_info->max;
  242. absolute_mode = true;
  243. } else if (class_info->number == VALUATOR_ABSY && class_info->mode == XIModeAbsolute) {
  244. resolution_y = class_info->resolution;
  245. abs_y_min = class_info->min;
  246. abs_y_max = class_info->max;
  247. absolute_mode = true;
  248. } else if (class_info->number == VALUATOR_PRESSURE && class_info->mode == XIModeAbsolute) {
  249. pressure_min = class_info->min;
  250. pressure_max = class_info->max;
  251. } else if (class_info->number == VALUATOR_TILTX && class_info->mode == XIModeAbsolute) {
  252. tilt_x_min = class_info->min;
  253. tilt_x_max = class_info->max;
  254. } else if (class_info->number == VALUATOR_TILTY && class_info->mode == XIModeAbsolute) {
  255. tilt_y_min = class_info->min;
  256. tilt_y_max = class_info->max;
  257. }
  258. }
  259. }
  260. if (direct_touch) {
  261. xi.touch_devices.push_back(dev->deviceid);
  262. print_verbose("XInput: Using touch device: " + String(dev->name));
  263. }
  264. if (absolute_mode) {
  265. // If no resolution was reported, use the min/max ranges.
  266. if (resolution_x <= 0) {
  267. resolution_x = (abs_x_max - abs_x_min) * abs_resolution_range_mult;
  268. }
  269. if (resolution_y <= 0) {
  270. resolution_y = (abs_y_max - abs_y_min) * abs_resolution_range_mult;
  271. }
  272. xi.absolute_devices[dev->deviceid] = Vector2(abs_resolution_mult / resolution_x, abs_resolution_mult / resolution_y);
  273. print_verbose("XInput: Absolute pointing device: " + String(dev->name));
  274. }
  275. xi.pressure = 0;
  276. xi.pen_pressure_range[dev->deviceid] = Vector2(pressure_min, pressure_max);
  277. xi.pen_tilt_x_range[dev->deviceid] = Vector2(tilt_x_min, tilt_x_max);
  278. xi.pen_tilt_y_range[dev->deviceid] = Vector2(tilt_y_min, tilt_y_max);
  279. xi.pen_inverted_devices[dev->deviceid] = String(dev->name).findn("eraser") > 0;
  280. }
  281. XIFreeDeviceInfo(info);
  282. #ifdef TOUCH_ENABLED
  283. if (!xi.touch_devices.size()) {
  284. print_verbose("XInput: No touch devices found.");
  285. }
  286. #endif
  287. return true;
  288. }
  289. void DisplayServerX11::_flush_mouse_motion() {
  290. // Block events polling while flushing motion events.
  291. MutexLock mutex_lock(events_mutex);
  292. for (uint32_t event_index = 0; event_index < polled_events.size(); ++event_index) {
  293. XEvent &event = polled_events[event_index];
  294. if (XGetEventData(x11_display, &event.xcookie) && event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
  295. XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
  296. if (event_data->evtype == XI_RawMotion) {
  297. XFreeEventData(x11_display, &event.xcookie);
  298. polled_events.remove_at(event_index--);
  299. continue;
  300. }
  301. XFreeEventData(x11_display, &event.xcookie);
  302. break;
  303. }
  304. }
  305. xi.relative_motion.x = 0;
  306. xi.relative_motion.y = 0;
  307. }
  308. #ifdef SPEECHD_ENABLED
  309. void DisplayServerX11::initialize_tts() const {
  310. const_cast<DisplayServerX11 *>(this)->tts = memnew(TTS_Linux);
  311. }
  312. bool DisplayServerX11::tts_is_speaking() const {
  313. if (unlikely(!tts)) {
  314. initialize_tts();
  315. }
  316. ERR_FAIL_NULL_V(tts, false);
  317. return tts->is_speaking();
  318. }
  319. bool DisplayServerX11::tts_is_paused() const {
  320. if (unlikely(!tts)) {
  321. initialize_tts();
  322. }
  323. ERR_FAIL_NULL_V(tts, false);
  324. return tts->is_paused();
  325. }
  326. TypedArray<Dictionary> DisplayServerX11::tts_get_voices() const {
  327. if (unlikely(!tts)) {
  328. initialize_tts();
  329. }
  330. ERR_FAIL_NULL_V(tts, TypedArray<Dictionary>());
  331. return tts->get_voices();
  332. }
  333. void DisplayServerX11::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
  334. if (unlikely(!tts)) {
  335. initialize_tts();
  336. }
  337. ERR_FAIL_NULL(tts);
  338. tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt);
  339. }
  340. void DisplayServerX11::tts_pause() {
  341. if (unlikely(!tts)) {
  342. initialize_tts();
  343. }
  344. ERR_FAIL_NULL(tts);
  345. tts->pause();
  346. }
  347. void DisplayServerX11::tts_resume() {
  348. if (unlikely(!tts)) {
  349. initialize_tts();
  350. }
  351. ERR_FAIL_NULL(tts);
  352. tts->resume();
  353. }
  354. void DisplayServerX11::tts_stop() {
  355. if (unlikely(!tts)) {
  356. initialize_tts();
  357. }
  358. ERR_FAIL_NULL(tts);
  359. tts->stop();
  360. }
  361. #endif
  362. #ifdef DBUS_ENABLED
  363. bool DisplayServerX11::is_dark_mode_supported() const {
  364. return portal_desktop && portal_desktop->is_supported() && portal_desktop->is_settings_supported();
  365. }
  366. bool DisplayServerX11::is_dark_mode() const {
  367. if (!is_dark_mode_supported()) {
  368. return false;
  369. }
  370. switch (portal_desktop->get_appearance_color_scheme()) {
  371. case 1:
  372. // Prefers dark theme.
  373. return true;
  374. case 2:
  375. // Prefers light theme.
  376. return false;
  377. default:
  378. // Preference unknown.
  379. return false;
  380. }
  381. }
  382. Color DisplayServerX11::get_accent_color() const {
  383. return portal_desktop->get_appearance_accent_color();
  384. }
  385. void DisplayServerX11::set_system_theme_change_callback(const Callable &p_callable) {
  386. portal_desktop->set_system_theme_change_callback(p_callable);
  387. }
  388. Error DisplayServerX11::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback, WindowID p_window_id) {
  389. WindowID window_id = p_window_id;
  390. if (!windows.has(window_id) || windows[window_id].is_popup) {
  391. window_id = MAIN_WINDOW_ID;
  392. }
  393. String xid = vformat("x11:%x", (uint64_t)windows[window_id].x11_window);
  394. return portal_desktop->file_dialog_show(p_window_id, xid, p_title, p_current_directory, String(), p_filename, p_mode, p_filters, TypedArray<Dictionary>(), p_callback, false);
  395. }
  396. Error DisplayServerX11::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, WindowID p_window_id) {
  397. WindowID window_id = p_window_id;
  398. if (!windows.has(window_id) || windows[window_id].is_popup) {
  399. window_id = MAIN_WINDOW_ID;
  400. }
  401. String xid = vformat("x11:%x", (uint64_t)windows[window_id].x11_window);
  402. return portal_desktop->file_dialog_show(p_window_id, xid, p_title, p_current_directory, p_root, p_filename, p_mode, p_filters, p_options, p_callback, true);
  403. }
  404. #endif
  405. void DisplayServerX11::beep() const {
  406. XBell(x11_display, 0);
  407. }
  408. void DisplayServerX11::_mouse_update_mode() {
  409. _THREAD_SAFE_METHOD_
  410. MouseMode wanted_mouse_mode = mouse_mode_override_enabled
  411. ? mouse_mode_override
  412. : mouse_mode_base;
  413. if (wanted_mouse_mode == mouse_mode) {
  414. return;
  415. }
  416. if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
  417. XUngrabPointer(x11_display, CurrentTime);
  418. }
  419. // The only modes that show a cursor are VISIBLE and CONFINED
  420. bool show_cursor = (wanted_mouse_mode == MOUSE_MODE_VISIBLE || wanted_mouse_mode == MOUSE_MODE_CONFINED);
  421. bool previously_shown = (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED);
  422. if (show_cursor && !previously_shown) {
  423. WindowID window_id = get_window_at_screen_position(mouse_get_position());
  424. if (window_id != INVALID_WINDOW_ID && window_mouseover_id != window_id) {
  425. if (window_mouseover_id != INVALID_WINDOW_ID) {
  426. _send_window_event(windows[window_mouseover_id], WINDOW_EVENT_MOUSE_EXIT);
  427. }
  428. window_mouseover_id = window_id;
  429. _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
  430. }
  431. }
  432. for (const KeyValue<WindowID, WindowData> &E : windows) {
  433. if (show_cursor) {
  434. XDefineCursor(x11_display, E.value.x11_window, cursors[current_cursor]); // show cursor
  435. } else {
  436. XDefineCursor(x11_display, E.value.x11_window, null_cursor); // hide cursor
  437. }
  438. }
  439. mouse_mode = wanted_mouse_mode;
  440. if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
  441. //flush pending motion events
  442. _flush_mouse_motion();
  443. WindowID window_id = _get_focused_window_or_popup();
  444. if (!windows.has(window_id)) {
  445. window_id = MAIN_WINDOW_ID;
  446. }
  447. WindowData &window = windows[window_id];
  448. if (XGrabPointer(
  449. x11_display, window.x11_window, True,
  450. ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
  451. GrabModeAsync, GrabModeAsync, window.x11_window, None, CurrentTime) != GrabSuccess) {
  452. ERR_PRINT("NO GRAB");
  453. }
  454. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  455. center.x = window.size.width / 2;
  456. center.y = window.size.height / 2;
  457. XWarpPointer(x11_display, None, window.x11_window,
  458. 0, 0, 0, 0, (int)center.x, (int)center.y);
  459. Input::get_singleton()->set_mouse_position(center);
  460. }
  461. } else {
  462. do_mouse_warp = false;
  463. }
  464. XFlush(x11_display);
  465. }
  466. void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
  467. ERR_FAIL_INDEX(p_mode, MouseMode::MOUSE_MODE_MAX);
  468. if (p_mode == mouse_mode_base) {
  469. return;
  470. }
  471. mouse_mode_base = p_mode;
  472. _mouse_update_mode();
  473. }
  474. DisplayServerX11::MouseMode DisplayServerX11::mouse_get_mode() const {
  475. return mouse_mode;
  476. }
  477. void DisplayServerX11::mouse_set_mode_override(MouseMode p_mode) {
  478. ERR_FAIL_INDEX(p_mode, MouseMode::MOUSE_MODE_MAX);
  479. if (p_mode == mouse_mode_override) {
  480. return;
  481. }
  482. mouse_mode_override = p_mode;
  483. _mouse_update_mode();
  484. }
  485. DisplayServerX11::MouseMode DisplayServerX11::mouse_get_mode_override() const {
  486. return mouse_mode_override;
  487. }
  488. void DisplayServerX11::mouse_set_mode_override_enabled(bool p_override_enabled) {
  489. if (p_override_enabled == mouse_mode_override_enabled) {
  490. return;
  491. }
  492. mouse_mode_override_enabled = p_override_enabled;
  493. _mouse_update_mode();
  494. }
  495. bool DisplayServerX11::mouse_is_mode_override_enabled() const {
  496. return mouse_mode_override_enabled;
  497. }
  498. void DisplayServerX11::warp_mouse(const Point2i &p_position) {
  499. _THREAD_SAFE_METHOD_
  500. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  501. last_mouse_pos = p_position;
  502. } else {
  503. WindowID window_id = _get_focused_window_or_popup();
  504. if (!windows.has(window_id)) {
  505. window_id = MAIN_WINDOW_ID;
  506. }
  507. XWarpPointer(x11_display, None, windows[window_id].x11_window,
  508. 0, 0, 0, 0, (int)p_position.x, (int)p_position.y);
  509. }
  510. }
  511. Point2i DisplayServerX11::mouse_get_position() const {
  512. int number_of_screens = XScreenCount(x11_display);
  513. for (int i = 0; i < number_of_screens; i++) {
  514. Window root, child;
  515. int root_x, root_y, win_x, win_y;
  516. unsigned int mask;
  517. if (XQueryPointer(x11_display, XRootWindow(x11_display, i), &root, &child, &root_x, &root_y, &win_x, &win_y, &mask)) {
  518. XWindowAttributes root_attrs;
  519. XGetWindowAttributes(x11_display, root, &root_attrs);
  520. return Vector2i(root_attrs.x + root_x, root_attrs.y + root_y);
  521. }
  522. }
  523. return Vector2i();
  524. }
  525. BitField<MouseButtonMask> DisplayServerX11::mouse_get_button_state() const {
  526. int number_of_screens = XScreenCount(x11_display);
  527. for (int i = 0; i < number_of_screens; i++) {
  528. Window root, child;
  529. int root_x, root_y, win_x, win_y;
  530. unsigned int mask;
  531. if (XQueryPointer(x11_display, XRootWindow(x11_display, i), &root, &child, &root_x, &root_y, &win_x, &win_y, &mask)) {
  532. BitField<MouseButtonMask> last_button_state = MouseButtonMask::NONE;
  533. if (mask & Button1Mask) {
  534. last_button_state.set_flag(MouseButtonMask::LEFT);
  535. }
  536. if (mask & Button2Mask) {
  537. last_button_state.set_flag(MouseButtonMask::MIDDLE);
  538. }
  539. if (mask & Button3Mask) {
  540. last_button_state.set_flag(MouseButtonMask::RIGHT);
  541. }
  542. if (mask & Button4Mask) {
  543. last_button_state.set_flag(MouseButtonMask::MB_XBUTTON1);
  544. }
  545. if (mask & Button5Mask) {
  546. last_button_state.set_flag(MouseButtonMask::MB_XBUTTON2);
  547. }
  548. return last_button_state;
  549. }
  550. }
  551. return MouseButtonMask::NONE;
  552. }
  553. void DisplayServerX11::clipboard_set(const String &p_text) {
  554. _THREAD_SAFE_METHOD_
  555. {
  556. // The clipboard content can be accessed while polling for events.
  557. MutexLock mutex_lock(events_mutex);
  558. internal_clipboard = p_text;
  559. }
  560. XSetSelectionOwner(x11_display, XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
  561. XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
  562. }
  563. void DisplayServerX11::clipboard_set_primary(const String &p_text) {
  564. _THREAD_SAFE_METHOD_
  565. if (!p_text.is_empty()) {
  566. {
  567. // The clipboard content can be accessed while polling for events.
  568. MutexLock mutex_lock(events_mutex);
  569. internal_clipboard_primary = p_text;
  570. }
  571. XSetSelectionOwner(x11_display, XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
  572. XSetSelectionOwner(x11_display, XInternAtom(x11_display, "PRIMARY", 0), windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
  573. }
  574. }
  575. Bool DisplayServerX11::_predicate_clipboard_selection(Display *display, XEvent *event, XPointer arg) {
  576. if (event->type == SelectionNotify && event->xselection.requestor == *(Window *)arg) {
  577. return True;
  578. } else {
  579. return False;
  580. }
  581. }
  582. Bool DisplayServerX11::_predicate_clipboard_incr(Display *display, XEvent *event, XPointer arg) {
  583. if (event->type == PropertyNotify && event->xproperty.state == PropertyNewValue && event->xproperty.atom == *(Atom *)arg) {
  584. return True;
  585. } else {
  586. return False;
  587. }
  588. }
  589. String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const {
  590. String ret;
  591. Window selection_owner = XGetSelectionOwner(x11_display, p_source);
  592. if (selection_owner == x11_window) {
  593. static const char *target_type = "PRIMARY";
  594. if (p_source != None && get_atom_name(x11_display, p_source) == target_type) {
  595. return internal_clipboard_primary;
  596. } else {
  597. return internal_clipboard;
  598. }
  599. }
  600. if (selection_owner != None) {
  601. // Block events polling while processing selection events.
  602. MutexLock mutex_lock(events_mutex);
  603. Atom selection = XA_PRIMARY;
  604. XConvertSelection(x11_display, p_source, target, selection,
  605. x11_window, CurrentTime);
  606. XFlush(x11_display);
  607. // Blocking wait for predicate to be True and remove the event from the queue.
  608. XEvent event;
  609. XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
  610. // Do not get any data, see how much data is there.
  611. Atom type;
  612. int format, result;
  613. unsigned long len, bytes_left, dummy;
  614. unsigned char *data;
  615. XGetWindowProperty(x11_display, x11_window,
  616. selection, // Tricky..
  617. 0, 0, // offset - len
  618. 0, // Delete 0==FALSE
  619. AnyPropertyType, // flag
  620. &type, // return type
  621. &format, // return format
  622. &len, &bytes_left, // data length
  623. &data);
  624. if (data) {
  625. XFree(data);
  626. }
  627. if (type == XInternAtom(x11_display, "INCR", 0)) {
  628. // Data is going to be received incrementally.
  629. DEBUG_LOG_X11("INCR selection started.\n");
  630. LocalVector<uint8_t> incr_data;
  631. uint32_t data_size = 0;
  632. bool success = false;
  633. // Delete INCR property to notify the owner.
  634. XDeleteProperty(x11_display, x11_window, type);
  635. // Process events from the queue.
  636. bool done = false;
  637. while (!done) {
  638. if (!_wait_for_events()) {
  639. // Error or timeout, abort.
  640. break;
  641. }
  642. // Non-blocking wait for next event and remove it from the queue.
  643. XEvent ev;
  644. while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, (XPointer)&selection)) {
  645. result = XGetWindowProperty(x11_display, x11_window,
  646. selection, // selection type
  647. 0, LONG_MAX, // offset - len
  648. True, // delete property to notify the owner
  649. AnyPropertyType, // flag
  650. &type, // return type
  651. &format, // return format
  652. &len, &bytes_left, // data length
  653. &data);
  654. DEBUG_LOG_X11("PropertyNotify: len=%lu, format=%i\n", len, format);
  655. if (result == Success) {
  656. if (data && (len > 0)) {
  657. uint32_t prev_size = incr_data.size();
  658. if (prev_size == 0) {
  659. // First property contains initial data size.
  660. unsigned long initial_size = *(unsigned long *)data;
  661. incr_data.resize(initial_size);
  662. } else {
  663. // New chunk, resize to be safe and append data.
  664. incr_data.resize(MAX(data_size + len, prev_size));
  665. memcpy(incr_data.ptr() + data_size, data, len);
  666. data_size += len;
  667. }
  668. } else {
  669. // Last chunk, process finished.
  670. done = true;
  671. success = true;
  672. }
  673. } else {
  674. print_verbose("Failed to get selection data chunk.");
  675. done = true;
  676. }
  677. if (data) {
  678. XFree(data);
  679. }
  680. if (done) {
  681. break;
  682. }
  683. }
  684. }
  685. if (success && (data_size > 0)) {
  686. ret.append_utf8((const char *)incr_data.ptr(), data_size);
  687. }
  688. } else if (bytes_left > 0) {
  689. // Data is ready and can be processed all at once.
  690. result = XGetWindowProperty(x11_display, x11_window,
  691. selection, 0, bytes_left, 0,
  692. AnyPropertyType, &type, &format,
  693. &len, &dummy, &data);
  694. if (result == Success) {
  695. ret.append_utf8((const char *)data);
  696. } else {
  697. print_verbose("Failed to get selection data.");
  698. }
  699. if (data) {
  700. XFree(data);
  701. }
  702. }
  703. }
  704. return ret;
  705. }
  706. Atom DisplayServerX11::_clipboard_get_image_target(Atom p_source, Window x11_window) const {
  707. Atom target = XInternAtom(x11_display, "TARGETS", 0);
  708. Atom png = XInternAtom(x11_display, "image/png", 0);
  709. Atom *valid_targets = nullptr;
  710. unsigned long atom_count = 0;
  711. Window selection_owner = XGetSelectionOwner(x11_display, p_source);
  712. if (selection_owner != None && selection_owner != x11_window) {
  713. // Block events polling while processing selection events.
  714. MutexLock mutex_lock(events_mutex);
  715. Atom selection = XA_PRIMARY;
  716. XConvertSelection(x11_display, p_source, target, selection, x11_window, CurrentTime);
  717. XFlush(x11_display);
  718. // Blocking wait for predicate to be True and remove the event from the queue.
  719. XEvent event;
  720. XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
  721. // Do not get any data, see how much data is there.
  722. Atom type;
  723. int format, result;
  724. unsigned long len, bytes_left, dummy;
  725. XGetWindowProperty(x11_display, x11_window,
  726. selection, // Tricky..
  727. 0, 0, // offset - len
  728. 0, // Delete 0==FALSE
  729. XA_ATOM, // flag
  730. &type, // return type
  731. &format, // return format
  732. &len, &bytes_left, // data length
  733. (unsigned char **)&valid_targets);
  734. if (valid_targets) {
  735. XFree(valid_targets);
  736. valid_targets = nullptr;
  737. }
  738. if (type == XA_ATOM && bytes_left > 0) {
  739. // Data is ready and can be processed all at once.
  740. result = XGetWindowProperty(x11_display, x11_window,
  741. selection, 0, bytes_left / 4, 0,
  742. XA_ATOM, &type, &format,
  743. &len, &dummy, (unsigned char **)&valid_targets);
  744. if (result == Success) {
  745. atom_count = len;
  746. } else {
  747. print_verbose("Failed to get selection data.");
  748. return None;
  749. }
  750. } else {
  751. return None;
  752. }
  753. } else {
  754. return None;
  755. }
  756. for (unsigned long i = 0; i < atom_count; i++) {
  757. Atom atom = valid_targets[i];
  758. if (atom == png) {
  759. XFree(valid_targets);
  760. return png;
  761. }
  762. }
  763. XFree(valid_targets);
  764. return None;
  765. }
  766. String DisplayServerX11::_clipboard_get(Atom p_source, Window x11_window) const {
  767. String ret;
  768. Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True);
  769. if (utf8_atom != None) {
  770. ret = _clipboard_get_impl(p_source, x11_window, utf8_atom);
  771. }
  772. if (ret.is_empty()) {
  773. ret = _clipboard_get_impl(p_source, x11_window, XA_STRING);
  774. }
  775. return ret;
  776. }
  777. String DisplayServerX11::clipboard_get() const {
  778. _THREAD_SAFE_METHOD_
  779. String ret;
  780. ret = _clipboard_get(XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window);
  781. if (ret.is_empty()) {
  782. ret = _clipboard_get(XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window);
  783. }
  784. return ret;
  785. }
  786. String DisplayServerX11::clipboard_get_primary() const {
  787. _THREAD_SAFE_METHOD_
  788. String ret;
  789. ret = _clipboard_get(XInternAtom(x11_display, "PRIMARY", 0), windows[MAIN_WINDOW_ID].x11_window);
  790. if (ret.is_empty()) {
  791. ret = _clipboard_get(XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window);
  792. }
  793. return ret;
  794. }
  795. Ref<Image> DisplayServerX11::clipboard_get_image() const {
  796. _THREAD_SAFE_METHOD_
  797. Atom clipboard = XInternAtom(x11_display, "CLIPBOARD", 0);
  798. Window x11_window = windows[MAIN_WINDOW_ID].x11_window;
  799. Ref<Image> ret;
  800. Atom target = _clipboard_get_image_target(clipboard, x11_window);
  801. if (target == None) {
  802. return ret;
  803. }
  804. Window selection_owner = XGetSelectionOwner(x11_display, clipboard);
  805. if (selection_owner != None && selection_owner != x11_window) {
  806. // Block events polling while processing selection events.
  807. MutexLock mutex_lock(events_mutex);
  808. // Identifier for the property the other window
  809. // will send the converted data to.
  810. Atom transfer_prop = XA_PRIMARY;
  811. XConvertSelection(x11_display,
  812. clipboard, // source selection
  813. target, // format to convert to
  814. transfer_prop, // output property
  815. x11_window, CurrentTime);
  816. XFlush(x11_display);
  817. // Blocking wait for predicate to be True and remove the event from the queue.
  818. XEvent event;
  819. XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
  820. // Do not get any data, see how much data is there.
  821. Atom type;
  822. int format, result;
  823. unsigned long len, bytes_left, dummy;
  824. unsigned char *data;
  825. XGetWindowProperty(x11_display, x11_window,
  826. transfer_prop, // Property data is transferred through
  827. 0, 1, // offset, len (4 so we can get the size if INCR is used)
  828. 0, // Delete 0==FALSE
  829. AnyPropertyType, // flag
  830. &type, // return type
  831. &format, // return format
  832. &len, &bytes_left, // data length
  833. &data);
  834. if (type == XInternAtom(x11_display, "INCR", 0)) {
  835. ERR_FAIL_COND_V_MSG(len != 1, ret, "Incremental transfer initial value was not length.");
  836. // Data is going to be received incrementally.
  837. DEBUG_LOG_X11("INCR selection started.\n");
  838. LocalVector<uint8_t> incr_data;
  839. uint32_t data_size = 0;
  840. bool success = false;
  841. // Initial response is the lower bound of the length of the transferred data.
  842. incr_data.resize(*(unsigned long *)data);
  843. XFree(data);
  844. data = nullptr;
  845. // Delete INCR property to notify the owner.
  846. XDeleteProperty(x11_display, x11_window, transfer_prop);
  847. // Process events from the queue.
  848. bool done = false;
  849. while (!done) {
  850. if (!_wait_for_events()) {
  851. // Error or timeout, abort.
  852. break;
  853. }
  854. // Non-blocking wait for next event and remove it from the queue.
  855. XEvent ev;
  856. while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, (XPointer)&transfer_prop)) {
  857. result = XGetWindowProperty(x11_display, x11_window,
  858. transfer_prop, // output property
  859. 0, LONG_MAX, // offset - len
  860. True, // delete property to notify the owner
  861. AnyPropertyType, // flag
  862. &type, // return type
  863. &format, // return format
  864. &len, &bytes_left, // data length
  865. &data);
  866. DEBUG_LOG_X11("PropertyNotify: len=%lu, format=%i\n", len, format);
  867. if (result == Success) {
  868. if (data && (len > 0)) {
  869. uint32_t prev_size = incr_data.size();
  870. // New chunk, resize to be safe and append data.
  871. incr_data.resize(MAX(data_size + len, prev_size));
  872. memcpy(incr_data.ptr() + data_size, data, len);
  873. data_size += len;
  874. } else if (!(format == 0 && len == 0)) {
  875. // For unclear reasons the first GetWindowProperty always returns a length and format of 0.
  876. // Otherwise, last chunk, process finished.
  877. done = true;
  878. success = true;
  879. }
  880. } else {
  881. print_verbose("Failed to get selection data chunk.");
  882. done = true;
  883. }
  884. if (data) {
  885. XFree(data);
  886. data = nullptr;
  887. }
  888. if (done) {
  889. break;
  890. }
  891. }
  892. }
  893. if (success && (data_size > 0)) {
  894. ret.instantiate();
  895. PNGDriverCommon::png_to_image(incr_data.ptr(), incr_data.size(), false, ret);
  896. }
  897. } else if (bytes_left > 0) {
  898. if (data) {
  899. XFree(data);
  900. data = nullptr;
  901. }
  902. // Data is ready and can be processed all at once.
  903. result = XGetWindowProperty(x11_display, x11_window,
  904. transfer_prop, 0, bytes_left + 4, 0,
  905. AnyPropertyType, &type, &format,
  906. &len, &dummy, &data);
  907. if (result == Success) {
  908. ret.instantiate();
  909. PNGDriverCommon::png_to_image((uint8_t *)data, bytes_left, false, ret);
  910. } else {
  911. print_verbose("Failed to get selection data.");
  912. }
  913. if (data) {
  914. XFree(data);
  915. }
  916. }
  917. }
  918. return ret;
  919. }
  920. bool DisplayServerX11::clipboard_has_image() const {
  921. Atom target = _clipboard_get_image_target(
  922. XInternAtom(x11_display, "CLIPBOARD", 0),
  923. windows[MAIN_WINDOW_ID].x11_window);
  924. return target != None;
  925. }
  926. Bool DisplayServerX11::_predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg) {
  927. if (event->xany.window == *(Window *)arg) {
  928. return (event->type == SelectionRequest) ||
  929. (event->type == SelectionNotify);
  930. } else {
  931. return False;
  932. }
  933. }
  934. void DisplayServerX11::_clipboard_transfer_ownership(Atom p_source, Window x11_window) const {
  935. _THREAD_SAFE_METHOD_
  936. Window selection_owner = XGetSelectionOwner(x11_display, p_source);
  937. if (selection_owner != x11_window) {
  938. return;
  939. }
  940. // Block events polling while processing selection events.
  941. MutexLock mutex_lock(events_mutex);
  942. Atom clipboard_manager = XInternAtom(x11_display, "CLIPBOARD_MANAGER", False);
  943. Atom save_targets = XInternAtom(x11_display, "SAVE_TARGETS", False);
  944. XConvertSelection(x11_display, clipboard_manager, save_targets, None,
  945. x11_window, CurrentTime);
  946. // Process events from the queue.
  947. while (true) {
  948. if (!_wait_for_events()) {
  949. // Error or timeout, abort.
  950. break;
  951. }
  952. // Non-blocking wait for next event and remove it from the queue.
  953. XEvent ev;
  954. while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_save_targets, (XPointer)&x11_window)) {
  955. switch (ev.type) {
  956. case SelectionRequest:
  957. _handle_selection_request_event(&(ev.xselectionrequest));
  958. break;
  959. case SelectionNotify: {
  960. if (ev.xselection.target == save_targets) {
  961. // Once SelectionNotify is received, we're done whether it succeeded or not.
  962. return;
  963. }
  964. break;
  965. }
  966. }
  967. }
  968. }
  969. }
  970. int DisplayServerX11::get_screen_count() const {
  971. _THREAD_SAFE_METHOD_
  972. int count = 0;
  973. // Using Xinerama Extension
  974. int event_base, error_base;
  975. if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) {
  976. XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
  977. XFree(xsi);
  978. }
  979. if (count == 0) {
  980. count = XScreenCount(x11_display);
  981. }
  982. return count;
  983. }
  984. int DisplayServerX11::get_primary_screen() const {
  985. int event_base, error_base;
  986. if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) {
  987. return 0;
  988. } else {
  989. return XDefaultScreen(x11_display);
  990. }
  991. }
  992. int DisplayServerX11::get_keyboard_focus_screen() const {
  993. int count = get_screen_count();
  994. if (count < 2) {
  995. // Early exit with single monitor.
  996. return 0;
  997. }
  998. Window focus = 0;
  999. int revert_to = 0;
  1000. XGetInputFocus(x11_display, &focus, &revert_to);
  1001. if (focus) {
  1002. Window focus_child = 0;
  1003. int x = 0, y = 0;
  1004. XTranslateCoordinates(x11_display, focus, DefaultRootWindow(x11_display), 0, 0, &x, &y, &focus_child);
  1005. XWindowAttributes xwa;
  1006. XGetWindowAttributes(x11_display, focus, &xwa);
  1007. Rect2i window_rect = Rect2i(x, y, xwa.width, xwa.height);
  1008. // Find which monitor has the largest overlap with the given window.
  1009. int screen_index = 0;
  1010. int max_area = 0;
  1011. for (int i = 0; i < count; i++) {
  1012. Rect2i screen_rect = _screen_get_rect(i);
  1013. Rect2i intersection = screen_rect.intersection(window_rect);
  1014. int area = intersection.get_area();
  1015. if (area > max_area) {
  1016. max_area = area;
  1017. screen_index = i;
  1018. }
  1019. }
  1020. return screen_index;
  1021. }
  1022. return get_primary_screen();
  1023. }
  1024. Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const {
  1025. Rect2i rect(0, 0, 0, 0);
  1026. p_screen = _get_screen_index(p_screen);
  1027. int screen_count = get_screen_count();
  1028. ERR_FAIL_INDEX_V(p_screen, screen_count, Rect2i());
  1029. // Using Xinerama Extension.
  1030. bool found = false;
  1031. int event_base, error_base;
  1032. if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) {
  1033. int count;
  1034. XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
  1035. if (xsi) {
  1036. if (count > 0) {
  1037. // Check if screen is valid.
  1038. if (p_screen < count) {
  1039. rect.position.x = xsi[p_screen].x_org;
  1040. rect.position.y = xsi[p_screen].y_org;
  1041. rect.size.width = xsi[p_screen].width;
  1042. rect.size.height = xsi[p_screen].height;
  1043. found = true;
  1044. } else {
  1045. ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, count));
  1046. }
  1047. }
  1048. XFree(xsi);
  1049. }
  1050. }
  1051. if (!found) {
  1052. int count = XScreenCount(x11_display);
  1053. if (p_screen < count) {
  1054. Window root = XRootWindow(x11_display, p_screen);
  1055. XWindowAttributes xwa;
  1056. XGetWindowAttributes(x11_display, root, &xwa);
  1057. rect.position.x = xwa.x;
  1058. rect.position.y = xwa.y;
  1059. rect.size.width = xwa.width;
  1060. rect.size.height = xwa.height;
  1061. } else {
  1062. ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, count));
  1063. }
  1064. }
  1065. return rect;
  1066. }
  1067. Point2i DisplayServerX11::screen_get_position(int p_screen) const {
  1068. _THREAD_SAFE_METHOD_
  1069. return _screen_get_rect(p_screen).position;
  1070. }
  1071. Size2i DisplayServerX11::screen_get_size(int p_screen) const {
  1072. _THREAD_SAFE_METHOD_
  1073. return _screen_get_rect(p_screen).size;
  1074. }
  1075. // A Handler to avoid crashing on non-fatal X errors by default.
  1076. //
  1077. // The original X11 error formatter `_XPrintDefaultError` is defined here:
  1078. // https://gitlab.freedesktop.org/xorg/lib/libx11/-/blob/e45ca7b41dcd3ace7681d6897505f85d374640f2/src/XlibInt.c#L1322
  1079. // It is not exposed through the API, accesses X11 internals,
  1080. // and is much more complex, so this is a less complete simplified error X11 printer.
  1081. int default_window_error_handler(Display *display, XErrorEvent *error) {
  1082. static char message[1024];
  1083. XGetErrorText(display, error->error_code, message, sizeof(message));
  1084. ERR_PRINT(vformat("Unhandled XServer error: %s"
  1085. "\n Major opcode of failed request: %d"
  1086. "\n Serial number of failed request: %d"
  1087. "\n Current serial number in output stream: %d",
  1088. String::utf8(message), (uint64_t)error->request_code, (uint64_t)error->minor_code, (uint64_t)error->serial));
  1089. return 0;
  1090. }
  1091. bool g_bad_window = false;
  1092. int bad_window_error_handler(Display *display, XErrorEvent *error) {
  1093. if (error->error_code == BadWindow) {
  1094. g_bad_window = true;
  1095. } else {
  1096. return default_window_error_handler(display, error);
  1097. }
  1098. return 0;
  1099. }
  1100. Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
  1101. _THREAD_SAFE_METHOD_
  1102. p_screen = _get_screen_index(p_screen);
  1103. int screen_count = get_screen_count();
  1104. ERR_FAIL_INDEX_V(p_screen, screen_count, Rect2i());
  1105. bool is_multiscreen = screen_count > 1;
  1106. // Use full monitor size as fallback.
  1107. Rect2i rect = _screen_get_rect(p_screen);
  1108. // There's generally only one screen reported by xlib even in multi-screen setup,
  1109. // in this case it's just one virtual screen composed of all physical monitors.
  1110. int x11_screen_count = ScreenCount(x11_display);
  1111. Window x11_window = RootWindow(x11_display, p_screen < x11_screen_count ? p_screen : 0);
  1112. Atom type;
  1113. int format = 0;
  1114. unsigned long remaining = 0;
  1115. // Find active desktop for the root window.
  1116. unsigned int desktop_index = 0;
  1117. Atom desktop_prop = XInternAtom(x11_display, "_NET_CURRENT_DESKTOP", True);
  1118. if (desktop_prop != None) {
  1119. unsigned long desktop_len = 0;
  1120. unsigned char *desktop_data = nullptr;
  1121. if (XGetWindowProperty(x11_display, x11_window, desktop_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &desktop_len, &remaining, &desktop_data) == Success) {
  1122. if ((format == 32) && (desktop_len > 0) && desktop_data) {
  1123. desktop_index = (unsigned int)desktop_data[0];
  1124. }
  1125. if (desktop_data) {
  1126. XFree(desktop_data);
  1127. }
  1128. }
  1129. }
  1130. bool use_simple_method = true;
  1131. // First check for GTK work area, which is more accurate for multi-screen setup.
  1132. if (is_multiscreen) {
  1133. // Use already calculated work area when available.
  1134. Atom gtk_workareas_prop = XInternAtom(x11_display, "_GTK_WORKAREAS", False);
  1135. if (gtk_workareas_prop != None) {
  1136. char gtk_workarea_prop_name[32];
  1137. snprintf(gtk_workarea_prop_name, 32, "_GTK_WORKAREAS_D%d", desktop_index);
  1138. Atom gtk_workarea_prop = XInternAtom(x11_display, gtk_workarea_prop_name, True);
  1139. if (gtk_workarea_prop != None) {
  1140. unsigned long workarea_len = 0;
  1141. unsigned char *workarea_data = nullptr;
  1142. if (XGetWindowProperty(x11_display, x11_window, gtk_workarea_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &workarea_len, &remaining, &workarea_data) == Success) {
  1143. if ((format == 32) && (workarea_len % 4 == 0) && workarea_data) {
  1144. long *rect_data = (long *)workarea_data;
  1145. for (uint32_t data_offset = 0; data_offset < workarea_len; data_offset += 4) {
  1146. Rect2i workarea_rect;
  1147. workarea_rect.position.x = rect_data[data_offset];
  1148. workarea_rect.position.y = rect_data[data_offset + 1];
  1149. workarea_rect.size.x = rect_data[data_offset + 2];
  1150. workarea_rect.size.y = rect_data[data_offset + 3];
  1151. // Intersect with actual monitor size to find the correct area,
  1152. // because areas are not in the same order as screens from Xinerama.
  1153. if (rect.grow(-1).intersects(workarea_rect)) {
  1154. rect = rect.intersection(workarea_rect);
  1155. XFree(workarea_data);
  1156. return rect;
  1157. }
  1158. }
  1159. }
  1160. }
  1161. if (workarea_data) {
  1162. XFree(workarea_data);
  1163. }
  1164. }
  1165. }
  1166. // Fallback to calculating work area by hand from struts.
  1167. Atom client_list_prop = XInternAtom(x11_display, "_NET_CLIENT_LIST", True);
  1168. if (client_list_prop != None) {
  1169. unsigned long clients_len = 0;
  1170. unsigned char *clients_data = nullptr;
  1171. if (XGetWindowProperty(x11_display, x11_window, client_list_prop, 0, LONG_MAX, False, XA_WINDOW, &type, &format, &clients_len, &remaining, &clients_data) == Success) {
  1172. if ((format == 32) && (clients_len > 0) && clients_data) {
  1173. Window *windows_data = (Window *)clients_data;
  1174. Rect2i desktop_rect;
  1175. bool desktop_valid = false;
  1176. // Get full desktop size.
  1177. {
  1178. Atom desktop_geometry_prop = XInternAtom(x11_display, "_NET_DESKTOP_GEOMETRY", True);
  1179. if (desktop_geometry_prop != None) {
  1180. unsigned long geom_len = 0;
  1181. unsigned char *geom_data = nullptr;
  1182. if (XGetWindowProperty(x11_display, x11_window, desktop_geometry_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &geom_len, &remaining, &geom_data) == Success) {
  1183. if ((format == 32) && (geom_len >= 2) && geom_data) {
  1184. desktop_valid = true;
  1185. long *size_data = (long *)geom_data;
  1186. desktop_rect.size.x = size_data[0];
  1187. desktop_rect.size.y = size_data[1];
  1188. }
  1189. }
  1190. if (geom_data) {
  1191. XFree(geom_data);
  1192. }
  1193. }
  1194. }
  1195. // Get full desktop position.
  1196. if (desktop_valid) {
  1197. Atom desktop_viewport_prop = XInternAtom(x11_display, "_NET_DESKTOP_VIEWPORT", True);
  1198. if (desktop_viewport_prop != None) {
  1199. unsigned long viewport_len = 0;
  1200. unsigned char *viewport_data = nullptr;
  1201. if (XGetWindowProperty(x11_display, x11_window, desktop_viewport_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &viewport_len, &remaining, &viewport_data) == Success) {
  1202. if ((format == 32) && (viewport_len >= 2) && viewport_data) {
  1203. desktop_valid = true;
  1204. long *pos_data = (long *)viewport_data;
  1205. desktop_rect.position.x = pos_data[0];
  1206. desktop_rect.position.y = pos_data[1];
  1207. }
  1208. }
  1209. if (viewport_data) {
  1210. XFree(viewport_data);
  1211. }
  1212. }
  1213. }
  1214. if (desktop_valid) {
  1215. // Handle bad window errors silently because there's no other way to check
  1216. // that one of the windows has been destroyed in the meantime.
  1217. int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&bad_window_error_handler);
  1218. for (unsigned long win_index = 0; win_index < clients_len; ++win_index) {
  1219. g_bad_window = false;
  1220. // Remove strut size from desktop size to get a more accurate result.
  1221. bool strut_found = false;
  1222. unsigned long strut_len = 0;
  1223. unsigned char *strut_data = nullptr;
  1224. Atom strut_partial_prop = XInternAtom(x11_display, "_NET_WM_STRUT_PARTIAL", True);
  1225. if (strut_partial_prop != None) {
  1226. if (XGetWindowProperty(x11_display, windows_data[win_index], strut_partial_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &strut_len, &remaining, &strut_data) == Success) {
  1227. strut_found = true;
  1228. }
  1229. }
  1230. // Fallback to older strut property.
  1231. if (!g_bad_window && !strut_found) {
  1232. Atom strut_prop = XInternAtom(x11_display, "_NET_WM_STRUT", True);
  1233. if (strut_prop != None) {
  1234. if (XGetWindowProperty(x11_display, windows_data[win_index], strut_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &strut_len, &remaining, &strut_data) == Success) {
  1235. strut_found = true;
  1236. }
  1237. }
  1238. }
  1239. if (!g_bad_window && strut_found && (format == 32) && (strut_len >= 4) && strut_data) {
  1240. use_simple_method = false;
  1241. long *struts = (long *)strut_data;
  1242. long left = struts[0];
  1243. long right = struts[1];
  1244. long top = struts[2];
  1245. long bottom = struts[3];
  1246. long left_start_y, left_end_y, right_start_y, right_end_y;
  1247. long top_start_x, top_end_x, bottom_start_x, bottom_end_x;
  1248. if (strut_len >= 12) {
  1249. left_start_y = struts[4];
  1250. left_end_y = struts[5];
  1251. right_start_y = struts[6];
  1252. right_end_y = struts[7];
  1253. top_start_x = struts[8];
  1254. top_end_x = struts[9];
  1255. bottom_start_x = struts[10];
  1256. bottom_end_x = struts[11];
  1257. } else {
  1258. left_start_y = 0;
  1259. left_end_y = desktop_rect.size.y;
  1260. right_start_y = 0;
  1261. right_end_y = desktop_rect.size.y;
  1262. top_start_x = 0;
  1263. top_end_x = desktop_rect.size.x;
  1264. bottom_start_x = 0;
  1265. bottom_end_x = desktop_rect.size.x;
  1266. }
  1267. const Point2i &pos = desktop_rect.position;
  1268. const Size2i &size = desktop_rect.size;
  1269. Rect2i left_rect(pos.x, pos.y + left_start_y, left, left_end_y - left_start_y);
  1270. if (left_rect.size.x > 0) {
  1271. Rect2i intersection = rect.intersection(left_rect);
  1272. if (intersection.has_area() && intersection.size.x < rect.size.x) {
  1273. rect.position.x = left_rect.size.x;
  1274. rect.size.x = rect.size.x - intersection.size.x;
  1275. }
  1276. }
  1277. Rect2i right_rect(pos.x + size.x - right, pos.y + right_start_y, right, right_end_y - right_start_y);
  1278. if (right_rect.size.x > 0) {
  1279. Rect2i intersection = rect.intersection(right_rect);
  1280. if (intersection.has_area() && right_rect.size.x < rect.size.x) {
  1281. rect.size.x = intersection.position.x - rect.position.x;
  1282. }
  1283. }
  1284. Rect2i top_rect(pos.x + top_start_x, pos.y, top_end_x - top_start_x, top);
  1285. if (top_rect.size.y > 0) {
  1286. Rect2i intersection = rect.intersection(top_rect);
  1287. if (intersection.has_area() && intersection.size.y < rect.size.y) {
  1288. rect.position.y = top_rect.size.y;
  1289. rect.size.y = rect.size.y - intersection.size.y;
  1290. }
  1291. }
  1292. Rect2i bottom_rect(pos.x + bottom_start_x, pos.y + size.y - bottom, bottom_end_x - bottom_start_x, bottom);
  1293. if (bottom_rect.size.y > 0) {
  1294. Rect2i intersection = rect.intersection(bottom_rect);
  1295. if (intersection.has_area() && right_rect.size.y < rect.size.y) {
  1296. rect.size.y = intersection.position.y - rect.position.y;
  1297. }
  1298. }
  1299. }
  1300. if (strut_data) {
  1301. XFree(strut_data);
  1302. }
  1303. }
  1304. // Restore default error handler.
  1305. XSetErrorHandler(oldHandler);
  1306. }
  1307. }
  1308. }
  1309. if (clients_data) {
  1310. XFree(clients_data);
  1311. }
  1312. }
  1313. }
  1314. // Single screen or fallback for multi screen.
  1315. if (use_simple_method) {
  1316. // Get desktop available size from the global work area.
  1317. Atom workarea_prop = XInternAtom(x11_display, "_NET_WORKAREA", True);
  1318. if (workarea_prop != None) {
  1319. unsigned long workarea_len = 0;
  1320. unsigned char *workarea_data = nullptr;
  1321. if (XGetWindowProperty(x11_display, x11_window, workarea_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &workarea_len, &remaining, &workarea_data) == Success) {
  1322. if ((format == 32) && (workarea_len >= ((desktop_index + 1) * 4)) && workarea_data) {
  1323. long *rect_data = (long *)workarea_data;
  1324. int data_offset = desktop_index * 4;
  1325. Rect2i workarea_rect;
  1326. workarea_rect.position.x = rect_data[data_offset];
  1327. workarea_rect.position.y = rect_data[data_offset + 1];
  1328. workarea_rect.size.x = rect_data[data_offset + 2];
  1329. workarea_rect.size.y = rect_data[data_offset + 3];
  1330. // Intersect with actual monitor size to get a proper approximation in multi-screen setup.
  1331. if (!is_multiscreen) {
  1332. rect = workarea_rect;
  1333. } else if (rect.intersects(workarea_rect)) {
  1334. rect = rect.intersection(workarea_rect);
  1335. }
  1336. }
  1337. }
  1338. if (workarea_data) {
  1339. XFree(workarea_data);
  1340. }
  1341. }
  1342. }
  1343. return rect;
  1344. }
  1345. Rect2i DisplayServerX11::_screens_get_full_rect() const {
  1346. Rect2i full_rect;
  1347. int count = get_screen_count();
  1348. for (int i = 0; i < count; i++) {
  1349. if (i == 0) {
  1350. full_rect = _screen_get_rect(i);
  1351. continue;
  1352. }
  1353. Rect2i screen_rect = _screen_get_rect(i);
  1354. if (full_rect.position.x > screen_rect.position.x) {
  1355. full_rect.size.x += full_rect.position.x - screen_rect.position.x;
  1356. full_rect.position.x = screen_rect.position.x;
  1357. }
  1358. if (full_rect.position.y > screen_rect.position.y) {
  1359. full_rect.size.y += full_rect.position.y - screen_rect.position.y;
  1360. full_rect.position.y = screen_rect.position.y;
  1361. }
  1362. if (full_rect.position.x + full_rect.size.x < screen_rect.position.x + screen_rect.size.x) {
  1363. full_rect.size.x = screen_rect.position.x + screen_rect.size.x - full_rect.position.x;
  1364. }
  1365. if (full_rect.position.y + full_rect.size.y < screen_rect.position.y + screen_rect.size.y) {
  1366. full_rect.size.y = screen_rect.position.y + screen_rect.size.y - full_rect.position.y;
  1367. }
  1368. }
  1369. return full_rect;
  1370. }
  1371. int DisplayServerX11::screen_get_dpi(int p_screen) const {
  1372. _THREAD_SAFE_METHOD_
  1373. p_screen = _get_screen_index(p_screen);
  1374. int screen_count = get_screen_count();
  1375. ERR_FAIL_INDEX_V(p_screen, screen_count, 96);
  1376. //Get physical monitor Dimensions through XRandR and calculate dpi
  1377. Size2i sc = screen_get_size(p_screen);
  1378. if (xrandr_ext_ok) {
  1379. int count = 0;
  1380. if (xrr_get_monitors) {
  1381. xrr_monitor_info *monitors = xrr_get_monitors(x11_display, windows[MAIN_WINDOW_ID].x11_window, true, &count);
  1382. if (p_screen < count) {
  1383. double xdpi = sc.width / (double)monitors[p_screen].mwidth * 25.4;
  1384. double ydpi = sc.height / (double)monitors[p_screen].mheight * 25.4;
  1385. xrr_free_monitors(monitors);
  1386. return (xdpi + ydpi) / 2;
  1387. }
  1388. xrr_free_monitors(monitors);
  1389. } else if (p_screen == 0) {
  1390. XRRScreenSize *sizes = XRRSizes(x11_display, 0, &count);
  1391. if (sizes) {
  1392. double xdpi = sc.width / (double)sizes[0].mwidth * 25.4;
  1393. double ydpi = sc.height / (double)sizes[0].mheight * 25.4;
  1394. return (xdpi + ydpi) / 2;
  1395. }
  1396. }
  1397. }
  1398. int width_mm = DisplayWidthMM(x11_display, p_screen);
  1399. int height_mm = DisplayHeightMM(x11_display, p_screen);
  1400. double xdpi = (width_mm ? sc.width / (double)width_mm * 25.4 : 0);
  1401. double ydpi = (height_mm ? sc.height / (double)height_mm * 25.4 : 0);
  1402. if (xdpi || ydpi) {
  1403. return (xdpi + ydpi) / (xdpi && ydpi ? 2 : 1);
  1404. }
  1405. //could not get dpi
  1406. return 96;
  1407. }
  1408. int get_image_errorhandler(Display *dpy, XErrorEvent *ev) {
  1409. return 0;
  1410. }
  1411. Color DisplayServerX11::screen_get_pixel(const Point2i &p_position) const {
  1412. Point2i pos = p_position;
  1413. if (xwayland) {
  1414. return Color();
  1415. }
  1416. int (*old_handler)(Display *, XErrorEvent *) = XSetErrorHandler(&get_image_errorhandler);
  1417. Color color;
  1418. int number_of_screens = XScreenCount(x11_display);
  1419. for (int i = 0; i < number_of_screens; i++) {
  1420. Window root = XRootWindow(x11_display, i);
  1421. XWindowAttributes root_attrs;
  1422. XGetWindowAttributes(x11_display, root, &root_attrs);
  1423. if ((pos.x >= root_attrs.x) && (pos.x <= root_attrs.x + root_attrs.width) && (pos.y >= root_attrs.y) && (pos.y <= root_attrs.y + root_attrs.height)) {
  1424. XImage *image = XGetImage(x11_display, root, pos.x, pos.y, 1, 1, AllPlanes, XYPixmap);
  1425. if (image) {
  1426. XColor c;
  1427. c.pixel = XGetPixel(image, 0, 0);
  1428. XDestroyImage(image);
  1429. XQueryColor(x11_display, XDefaultColormap(x11_display, i), &c);
  1430. color = Color(float(c.red) / 65535.0, float(c.green) / 65535.0, float(c.blue) / 65535.0, 1.0);
  1431. break;
  1432. }
  1433. }
  1434. }
  1435. XSetErrorHandler(old_handler);
  1436. return color;
  1437. }
  1438. Ref<Image> DisplayServerX11::screen_get_image(int p_screen) const {
  1439. ERR_FAIL_INDEX_V(p_screen, get_screen_count(), Ref<Image>());
  1440. p_screen = _get_screen_index(p_screen);
  1441. int screen_count = get_screen_count();
  1442. ERR_FAIL_INDEX_V(p_screen, screen_count, Ref<Image>());
  1443. if (xwayland) {
  1444. return Ref<Image>();
  1445. }
  1446. int (*old_handler)(Display *, XErrorEvent *) = XSetErrorHandler(&get_image_errorhandler);
  1447. XImage *image = nullptr;
  1448. bool found = false;
  1449. int event_base, error_base;
  1450. if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) {
  1451. int xin_count;
  1452. XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &xin_count);
  1453. if (xsi) {
  1454. if (xin_count > 0) {
  1455. if (p_screen < xin_count) {
  1456. int x_count = XScreenCount(x11_display);
  1457. for (int i = 0; i < x_count; i++) {
  1458. Window root = XRootWindow(x11_display, i);
  1459. XWindowAttributes root_attrs;
  1460. XGetWindowAttributes(x11_display, root, &root_attrs);
  1461. if ((xsi[p_screen].x_org >= root_attrs.x) && (xsi[p_screen].x_org <= root_attrs.x + root_attrs.width) && (xsi[p_screen].y_org >= root_attrs.y) && (xsi[p_screen].y_org <= root_attrs.y + root_attrs.height)) {
  1462. found = true;
  1463. image = XGetImage(x11_display, root, xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height, AllPlanes, ZPixmap);
  1464. break;
  1465. }
  1466. }
  1467. } else {
  1468. ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, xin_count));
  1469. }
  1470. }
  1471. XFree(xsi);
  1472. }
  1473. }
  1474. if (!found) {
  1475. int x_count = XScreenCount(x11_display);
  1476. if (p_screen < x_count) {
  1477. Window root = XRootWindow(x11_display, p_screen);
  1478. XWindowAttributes root_attrs;
  1479. XGetWindowAttributes(x11_display, root, &root_attrs);
  1480. image = XGetImage(x11_display, root, root_attrs.x, root_attrs.y, root_attrs.width, root_attrs.height, AllPlanes, ZPixmap);
  1481. } else {
  1482. ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, x_count));
  1483. }
  1484. }
  1485. XSetErrorHandler(old_handler);
  1486. Ref<Image> img;
  1487. if (image) {
  1488. int width = image->width;
  1489. int height = image->height;
  1490. Vector<uint8_t> img_data;
  1491. img_data.resize(height * width * 4);
  1492. uint8_t *sr = (uint8_t *)image->data;
  1493. uint8_t *wr = (uint8_t *)img_data.ptrw();
  1494. if (image->bits_per_pixel == 24 && image->red_mask == 0xff0000 && image->green_mask == 0x00ff00 && image->blue_mask == 0x0000ff) {
  1495. for (int y = 0; y < height; y++) {
  1496. for (int x = 0; x < width; x++) {
  1497. wr[(y * width + x) * 4 + 0] = sr[(y * width + x) * 3 + 2];
  1498. wr[(y * width + x) * 4 + 1] = sr[(y * width + x) * 3 + 1];
  1499. wr[(y * width + x) * 4 + 2] = sr[(y * width + x) * 3 + 0];
  1500. wr[(y * width + x) * 4 + 3] = 255;
  1501. }
  1502. }
  1503. } else if (image->bits_per_pixel == 24 && image->red_mask == 0x0000ff && image->green_mask == 0x00ff00 && image->blue_mask == 0xff0000) {
  1504. for (int y = 0; y < height; y++) {
  1505. for (int x = 0; x < width; x++) {
  1506. wr[(y * width + x) * 4 + 0] = sr[(y * width + x) * 3 + 2];
  1507. wr[(y * width + x) * 4 + 1] = sr[(y * width + x) * 3 + 1];
  1508. wr[(y * width + x) * 4 + 2] = sr[(y * width + x) * 3 + 0];
  1509. wr[(y * width + x) * 4 + 3] = 255;
  1510. }
  1511. }
  1512. } else if (image->bits_per_pixel == 32 && image->red_mask == 0xff0000 && image->green_mask == 0x00ff00 && image->blue_mask == 0x0000ff) {
  1513. for (int y = 0; y < height; y++) {
  1514. for (int x = 0; x < width; x++) {
  1515. wr[(y * width + x) * 4 + 0] = sr[(y * width + x) * 4 + 2];
  1516. wr[(y * width + x) * 4 + 1] = sr[(y * width + x) * 4 + 1];
  1517. wr[(y * width + x) * 4 + 2] = sr[(y * width + x) * 4 + 0];
  1518. wr[(y * width + x) * 4 + 3] = 255;
  1519. }
  1520. }
  1521. } else {
  1522. String msg = vformat("XImage with RGB mask %x %x %x and depth %d is not supported.", (uint64_t)image->red_mask, (uint64_t)image->green_mask, (uint64_t)image->blue_mask, (int64_t)image->bits_per_pixel);
  1523. XDestroyImage(image);
  1524. ERR_FAIL_V_MSG(Ref<Image>(), msg);
  1525. }
  1526. img = Image::create_from_data(width, height, false, Image::FORMAT_RGBA8, img_data);
  1527. XDestroyImage(image);
  1528. }
  1529. return img;
  1530. }
  1531. float DisplayServerX11::screen_get_refresh_rate(int p_screen) const {
  1532. _THREAD_SAFE_METHOD_
  1533. p_screen = _get_screen_index(p_screen);
  1534. int screen_count = get_screen_count();
  1535. ERR_FAIL_INDEX_V(p_screen, screen_count, SCREEN_REFRESH_RATE_FALLBACK);
  1536. //Use xrandr to get screen refresh rate.
  1537. if (xrandr_ext_ok) {
  1538. XRRScreenResources *screen_info = XRRGetScreenResourcesCurrent(x11_display, windows[MAIN_WINDOW_ID].x11_window);
  1539. if (screen_info) {
  1540. RRMode current_mode = 0;
  1541. xrr_monitor_info *monitors = nullptr;
  1542. if (xrr_get_monitors) {
  1543. int count = 0;
  1544. monitors = xrr_get_monitors(x11_display, windows[MAIN_WINDOW_ID].x11_window, true, &count);
  1545. ERR_FAIL_INDEX_V(p_screen, count, SCREEN_REFRESH_RATE_FALLBACK);
  1546. } else {
  1547. ERR_PRINT("An error occurred while trying to get the screen refresh rate.");
  1548. return SCREEN_REFRESH_RATE_FALLBACK;
  1549. }
  1550. bool found_active_mode = false;
  1551. for (int crtc = 0; crtc < screen_info->ncrtc; crtc++) { // Loop through outputs to find which one is currently outputting.
  1552. XRRCrtcInfo *monitor_info = XRRGetCrtcInfo(x11_display, screen_info, screen_info->crtcs[crtc]);
  1553. if (monitor_info->x != monitors[p_screen].x || monitor_info->y != monitors[p_screen].y) { // If X and Y aren't the same as the monitor we're looking for, this isn't the right monitor. Continue.
  1554. continue;
  1555. }
  1556. if (monitor_info->mode != None) {
  1557. current_mode = monitor_info->mode;
  1558. found_active_mode = true;
  1559. break;
  1560. }
  1561. }
  1562. if (found_active_mode) {
  1563. for (int mode = 0; mode < screen_info->nmode; mode++) {
  1564. XRRModeInfo m_info = screen_info->modes[mode];
  1565. if (m_info.id == current_mode) {
  1566. // Snap to nearest 0.01 to stay consistent with other platforms.
  1567. return Math::snapped((float)m_info.dotClock / ((float)m_info.hTotal * (float)m_info.vTotal), 0.01);
  1568. }
  1569. }
  1570. }
  1571. ERR_PRINT("An error occurred while trying to get the screen refresh rate."); // We should have returned the refresh rate by now. An error must have occurred.
  1572. return SCREEN_REFRESH_RATE_FALLBACK;
  1573. } else {
  1574. ERR_PRINT("An error occurred while trying to get the screen refresh rate.");
  1575. return SCREEN_REFRESH_RATE_FALLBACK;
  1576. }
  1577. }
  1578. ERR_PRINT("An error occurred while trying to get the screen refresh rate.");
  1579. return SCREEN_REFRESH_RATE_FALLBACK;
  1580. }
  1581. #ifdef DBUS_ENABLED
  1582. void DisplayServerX11::screen_set_keep_on(bool p_enable) {
  1583. if (screen_is_kept_on() == p_enable) {
  1584. return;
  1585. }
  1586. if (p_enable) {
  1587. screensaver->inhibit();
  1588. } else {
  1589. screensaver->uninhibit();
  1590. }
  1591. keep_screen_on = p_enable;
  1592. }
  1593. bool DisplayServerX11::screen_is_kept_on() const {
  1594. return keep_screen_on;
  1595. }
  1596. #endif
  1597. Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const {
  1598. _THREAD_SAFE_METHOD_
  1599. Vector<int> ret;
  1600. for (const KeyValue<WindowID, WindowData> &E : windows) {
  1601. ret.push_back(E.key);
  1602. }
  1603. return ret;
  1604. }
  1605. DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, bool p_exclusive, WindowID p_transient_parent) {
  1606. _THREAD_SAFE_METHOD_
  1607. WindowID id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect, 0);
  1608. for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
  1609. if (p_flags & (1 << i)) {
  1610. window_set_flag(WindowFlags(i), true, id);
  1611. }
  1612. }
  1613. #ifdef RD_ENABLED
  1614. if (rendering_device) {
  1615. rendering_device->screen_create(id);
  1616. }
  1617. #endif
  1618. if (p_transient_parent != INVALID_WINDOW_ID) {
  1619. window_set_transient(id, p_transient_parent);
  1620. }
  1621. return id;
  1622. }
  1623. void DisplayServerX11::show_window(WindowID p_id) {
  1624. _THREAD_SAFE_METHOD_
  1625. WindowData &wd = windows[p_id];
  1626. popup_open(p_id);
  1627. DEBUG_LOG_X11("show_window: %lu (%u) \n", wd.x11_window, p_id);
  1628. XMapWindow(x11_display, wd.x11_window);
  1629. XSync(x11_display, False);
  1630. _validate_mode_on_map(p_id);
  1631. if (p_id == MAIN_WINDOW_ID) {
  1632. // Get main window size for boot splash drawing.
  1633. bool get_config_event = false;
  1634. // Search the X11 event queue for ConfigureNotify events and process all that are currently queued early.
  1635. {
  1636. MutexLock mutex_lock(events_mutex);
  1637. for (uint32_t event_index = 0; event_index < polled_events.size(); ++event_index) {
  1638. XEvent &config_event = polled_events[event_index];
  1639. if (config_event.type == ConfigureNotify) {
  1640. _window_changed(&config_event);
  1641. get_config_event = true;
  1642. }
  1643. }
  1644. XEvent config_event;
  1645. while (XCheckTypedEvent(x11_display, ConfigureNotify, &config_event)) {
  1646. _window_changed(&config_event);
  1647. get_config_event = true;
  1648. }
  1649. }
  1650. // Estimate maximize/full screen window size, ConfigureNotify may arrive only after maximize animation is finished.
  1651. if (!get_config_event && (wd.maximized || wd.fullscreen)) {
  1652. int screen = window_get_current_screen(p_id);
  1653. Size2i sz;
  1654. if (wd.maximized) {
  1655. sz = screen_get_usable_rect(screen).size;
  1656. if (!wd.borderless) {
  1657. Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
  1658. if (prop != None) {
  1659. Atom type;
  1660. int format;
  1661. unsigned long len;
  1662. unsigned long remaining;
  1663. unsigned char *data = nullptr;
  1664. if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
  1665. if (format == 32 && len == 4 && data) {
  1666. long *extents = (long *)data;
  1667. sz.width -= extents[0] + extents[1]; // left, right
  1668. sz.height -= extents[2] + extents[3]; // top, bottom
  1669. }
  1670. XFree(data);
  1671. }
  1672. }
  1673. }
  1674. } else {
  1675. sz = screen_get_size(screen);
  1676. }
  1677. if (sz == Size2i()) {
  1678. return;
  1679. }
  1680. wd.size = sz;
  1681. #if defined(RD_ENABLED)
  1682. if (rendering_context) {
  1683. rendering_context->window_set_size(p_id, sz.width, sz.height);
  1684. }
  1685. #endif
  1686. #if defined(GLES3_ENABLED)
  1687. if (gl_manager) {
  1688. gl_manager->window_resize(p_id, sz.width, sz.height);
  1689. }
  1690. if (gl_manager_egl) {
  1691. gl_manager_egl->window_resize(p_id, sz.width, sz.height);
  1692. }
  1693. #endif
  1694. }
  1695. }
  1696. }
  1697. void DisplayServerX11::delete_sub_window(WindowID p_id) {
  1698. _THREAD_SAFE_METHOD_
  1699. ERR_FAIL_COND(!windows.has(p_id));
  1700. ERR_FAIL_COND_MSG(p_id == MAIN_WINDOW_ID, "Main window can't be deleted");
  1701. popup_close(p_id);
  1702. WindowData &wd = windows[p_id];
  1703. DEBUG_LOG_X11("delete_sub_window: %lu (%u) \n", wd.x11_window, p_id);
  1704. if (window_mouseover_id == p_id) {
  1705. window_mouseover_id = INVALID_WINDOW_ID;
  1706. _send_window_event(windows[p_id], WINDOW_EVENT_MOUSE_EXIT);
  1707. }
  1708. while (wd.transient_children.size()) {
  1709. window_set_transient(*wd.transient_children.begin(), INVALID_WINDOW_ID);
  1710. }
  1711. if (wd.transient_parent != INVALID_WINDOW_ID) {
  1712. window_set_transient(p_id, INVALID_WINDOW_ID);
  1713. }
  1714. #if defined(RD_ENABLED)
  1715. if (rendering_device) {
  1716. rendering_device->screen_free(p_id);
  1717. }
  1718. if (rendering_context) {
  1719. rendering_context->window_destroy(p_id);
  1720. }
  1721. #endif
  1722. #ifdef GLES3_ENABLED
  1723. if (gl_manager) {
  1724. gl_manager->window_destroy(p_id);
  1725. }
  1726. if (gl_manager_egl) {
  1727. gl_manager_egl->window_destroy(p_id);
  1728. }
  1729. #endif
  1730. #ifdef ACCESSKIT_ENABLED
  1731. if (accessibility_driver) {
  1732. accessibility_driver->window_destroy(p_id);
  1733. }
  1734. #endif
  1735. if (wd.xic) {
  1736. XDestroyIC(wd.xic);
  1737. wd.xic = nullptr;
  1738. }
  1739. XDestroyWindow(x11_display, wd.x11_xim_window);
  1740. #ifdef XKB_ENABLED
  1741. if (xkb_loaded_v05p) {
  1742. if (wd.xkb_state) {
  1743. xkb_compose_state_unref(wd.xkb_state);
  1744. wd.xkb_state = nullptr;
  1745. }
  1746. }
  1747. #endif
  1748. XUnmapWindow(x11_display, wd.x11_window);
  1749. XDestroyWindow(x11_display, wd.x11_window);
  1750. window_set_rect_changed_callback(Callable(), p_id);
  1751. window_set_window_event_callback(Callable(), p_id);
  1752. window_set_input_event_callback(Callable(), p_id);
  1753. window_set_input_text_callback(Callable(), p_id);
  1754. window_set_drop_files_callback(Callable(), p_id);
  1755. windows.erase(p_id);
  1756. if (last_focused_window == p_id) {
  1757. last_focused_window = INVALID_WINDOW_ID;
  1758. }
  1759. }
  1760. int64_t DisplayServerX11::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const {
  1761. ERR_FAIL_COND_V(!windows.has(p_window), 0);
  1762. switch (p_handle_type) {
  1763. case DISPLAY_HANDLE: {
  1764. return (int64_t)x11_display;
  1765. }
  1766. case WINDOW_HANDLE: {
  1767. return (int64_t)windows[p_window].x11_window;
  1768. }
  1769. case WINDOW_VIEW: {
  1770. return 0; // Not supported.
  1771. }
  1772. #ifdef GLES3_ENABLED
  1773. case OPENGL_CONTEXT: {
  1774. if (gl_manager) {
  1775. return (int64_t)gl_manager->get_glx_context(p_window);
  1776. }
  1777. if (gl_manager_egl) {
  1778. return (int64_t)gl_manager_egl->get_context(p_window);
  1779. }
  1780. return 0;
  1781. }
  1782. case EGL_DISPLAY: {
  1783. if (gl_manager_egl) {
  1784. return (int64_t)gl_manager_egl->get_display(p_window);
  1785. }
  1786. return 0;
  1787. }
  1788. case EGL_CONFIG: {
  1789. if (gl_manager_egl) {
  1790. return (int64_t)gl_manager_egl->get_config(p_window);
  1791. }
  1792. return 0;
  1793. }
  1794. #endif
  1795. default: {
  1796. return 0;
  1797. }
  1798. }
  1799. }
  1800. void DisplayServerX11::window_attach_instance_id(ObjectID p_instance, WindowID p_window) {
  1801. ERR_FAIL_COND(!windows.has(p_window));
  1802. WindowData &wd = windows[p_window];
  1803. wd.instance_id = p_instance;
  1804. }
  1805. ObjectID DisplayServerX11::window_get_attached_instance_id(WindowID p_window) const {
  1806. ERR_FAIL_COND_V(!windows.has(p_window), ObjectID());
  1807. const WindowData &wd = windows[p_window];
  1808. return wd.instance_id;
  1809. }
  1810. DisplayServerX11::WindowID DisplayServerX11::get_window_at_screen_position(const Point2i &p_position) const {
  1811. WindowID found_window = INVALID_WINDOW_ID;
  1812. WindowID parent_window = INVALID_WINDOW_ID;
  1813. unsigned int focus_order = 0;
  1814. for (const KeyValue<WindowID, WindowData> &E : windows) {
  1815. const WindowData &wd = E.value;
  1816. // Discard windows with no focus.
  1817. if (wd.focus_order == 0) {
  1818. continue;
  1819. }
  1820. // Find topmost window which contains the given position.
  1821. WindowID window_id = E.key;
  1822. Rect2i win_rect = Rect2i(window_get_position(window_id), window_get_size(window_id));
  1823. if (win_rect.has_point(p_position)) {
  1824. // For siblings, pick the window which was focused last.
  1825. if ((parent_window != wd.transient_parent) || (wd.focus_order > focus_order)) {
  1826. found_window = window_id;
  1827. parent_window = wd.transient_parent;
  1828. focus_order = wd.focus_order;
  1829. }
  1830. }
  1831. }
  1832. return found_window;
  1833. }
  1834. void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window) {
  1835. _THREAD_SAFE_METHOD_
  1836. ERR_FAIL_COND(!windows.has(p_window));
  1837. WindowData &wd = windows[p_window];
  1838. XStoreName(x11_display, wd.x11_window, p_title.utf8().get_data());
  1839. Atom _net_wm_name = XInternAtom(x11_display, "_NET_WM_NAME", false);
  1840. Atom utf8_string = XInternAtom(x11_display, "UTF8_STRING", false);
  1841. if (_net_wm_name != None && utf8_string != None) {
  1842. CharString utf8_title = p_title.utf8();
  1843. XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)utf8_title.get_data(), utf8_title.length());
  1844. }
  1845. }
  1846. void DisplayServerX11::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
  1847. _THREAD_SAFE_METHOD_
  1848. ERR_FAIL_COND(!windows.has(p_window));
  1849. windows[p_window].mpath = p_region;
  1850. _update_window_mouse_passthrough(p_window);
  1851. }
  1852. void DisplayServerX11::_update_window_mouse_passthrough(WindowID p_window) {
  1853. ERR_FAIL_COND(!windows.has(p_window));
  1854. ERR_FAIL_COND(!xshaped_ext_ok);
  1855. const Vector<Vector2> region_path = windows[p_window].mpath;
  1856. int event_base, error_base;
  1857. const Bool ext_okay = XShapeQueryExtension(x11_display, &event_base, &error_base);
  1858. if (ext_okay) {
  1859. if (windows[p_window].mpass) {
  1860. Region region = XCreateRegion();
  1861. XShapeCombineRegion(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, region, ShapeSet);
  1862. XDestroyRegion(region);
  1863. } else if (region_path.is_empty()) {
  1864. XShapeCombineMask(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, None, ShapeSet);
  1865. } else {
  1866. XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * region_path.size());
  1867. for (int i = 0; i < region_path.size(); i++) {
  1868. points[i].x = region_path[i].x;
  1869. points[i].y = region_path[i].y;
  1870. }
  1871. Region region = XPolygonRegion(points, region_path.size(), EvenOddRule);
  1872. memfree(points);
  1873. XShapeCombineRegion(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, region, ShapeSet);
  1874. XDestroyRegion(region);
  1875. }
  1876. }
  1877. }
  1878. void DisplayServerX11::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
  1879. _THREAD_SAFE_METHOD_
  1880. ERR_FAIL_COND(!windows.has(p_window));
  1881. WindowData &wd = windows[p_window];
  1882. wd.rect_changed_callback = p_callable;
  1883. }
  1884. void DisplayServerX11::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
  1885. _THREAD_SAFE_METHOD_
  1886. ERR_FAIL_COND(!windows.has(p_window));
  1887. WindowData &wd = windows[p_window];
  1888. wd.event_callback = p_callable;
  1889. }
  1890. void DisplayServerX11::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) {
  1891. _THREAD_SAFE_METHOD_
  1892. ERR_FAIL_COND(!windows.has(p_window));
  1893. WindowData &wd = windows[p_window];
  1894. wd.input_event_callback = p_callable;
  1895. }
  1896. void DisplayServerX11::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) {
  1897. _THREAD_SAFE_METHOD_
  1898. ERR_FAIL_COND(!windows.has(p_window));
  1899. WindowData &wd = windows[p_window];
  1900. wd.input_text_callback = p_callable;
  1901. }
  1902. void DisplayServerX11::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) {
  1903. _THREAD_SAFE_METHOD_
  1904. ERR_FAIL_COND(!windows.has(p_window));
  1905. WindowData &wd = windows[p_window];
  1906. wd.drop_files_callback = p_callable;
  1907. }
  1908. int DisplayServerX11::window_get_current_screen(WindowID p_window) const {
  1909. _THREAD_SAFE_METHOD_
  1910. int count = get_screen_count();
  1911. if (count < 2) {
  1912. // Early exit with single monitor.
  1913. return 0;
  1914. }
  1915. ERR_FAIL_COND_V(!windows.has(p_window), INVALID_SCREEN);
  1916. const WindowData &wd = windows[p_window];
  1917. const Rect2i window_rect(wd.position, wd.size);
  1918. // Find which monitor has the largest overlap with the given window.
  1919. int screen_index = 0;
  1920. int max_area = 0;
  1921. for (int i = 0; i < count; i++) {
  1922. Rect2i screen_rect = _screen_get_rect(i);
  1923. Rect2i intersection = screen_rect.intersection(window_rect);
  1924. int area = intersection.get_area();
  1925. if (area > max_area) {
  1926. max_area = area;
  1927. screen_index = i;
  1928. }
  1929. }
  1930. return screen_index;
  1931. }
  1932. void DisplayServerX11::gl_window_make_current(DisplayServer::WindowID p_window_id) {
  1933. #if defined(GLES3_ENABLED)
  1934. if (gl_manager) {
  1935. gl_manager->window_make_current(p_window_id);
  1936. }
  1937. if (gl_manager_egl) {
  1938. gl_manager_egl->window_make_current(p_window_id);
  1939. }
  1940. #endif
  1941. }
  1942. void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window) {
  1943. _THREAD_SAFE_METHOD_
  1944. ERR_FAIL_COND(!windows.has(p_window));
  1945. p_screen = _get_screen_index(p_screen);
  1946. int screen_count = get_screen_count();
  1947. ERR_FAIL_INDEX(p_screen, screen_count);
  1948. if (window_get_current_screen(p_window) == p_screen) {
  1949. return;
  1950. }
  1951. WindowData &wd = windows[p_window];
  1952. if (wd.embed_parent) {
  1953. print_line("Embedded window can't be moved to another screen.");
  1954. return;
  1955. }
  1956. if (window_get_mode(p_window) == WINDOW_MODE_FULLSCREEN || window_get_mode(p_window) == WINDOW_MODE_MAXIMIZED) {
  1957. Point2i position = screen_get_position(p_screen);
  1958. Size2i size = screen_get_size(p_screen);
  1959. XMoveResizeWindow(x11_display, wd.x11_window, position.x, position.y, size.x, size.y);
  1960. } else {
  1961. Rect2i srect = screen_get_usable_rect(p_screen);
  1962. Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
  1963. Size2i wsize = window_get_size(p_window);
  1964. wpos += srect.position;
  1965. if (srect != Rect2i()) {
  1966. wpos = wpos.clamp(srect.position, srect.position + srect.size - wsize / 3);
  1967. }
  1968. window_set_position(wpos, p_window);
  1969. }
  1970. }
  1971. void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent) {
  1972. _THREAD_SAFE_METHOD_
  1973. ERR_FAIL_COND(p_window == p_parent);
  1974. ERR_FAIL_COND(!windows.has(p_window));
  1975. WindowData &wd_window = windows[p_window];
  1976. WindowID prev_parent = wd_window.transient_parent;
  1977. ERR_FAIL_COND(prev_parent == p_parent);
  1978. DEBUG_LOG_X11("window_set_transient: %lu (%u), prev_parent=%u, parent=%u\n", wd_window.x11_window, p_window, prev_parent, p_parent);
  1979. ERR_FAIL_COND_MSG(wd_window.on_top, "Windows with the 'on top' can't become transient.");
  1980. if (p_parent == INVALID_WINDOW_ID) {
  1981. //remove transient
  1982. ERR_FAIL_COND(prev_parent == INVALID_WINDOW_ID);
  1983. ERR_FAIL_COND(!windows.has(prev_parent));
  1984. WindowData &wd_parent = windows[prev_parent];
  1985. wd_window.transient_parent = INVALID_WINDOW_ID;
  1986. wd_parent.transient_children.erase(p_window);
  1987. XSetTransientForHint(x11_display, wd_window.x11_window, None);
  1988. XWindowAttributes xwa;
  1989. XSync(x11_display, False);
  1990. XGetWindowAttributes(x11_display, wd_parent.x11_window, &xwa);
  1991. // Set focus to parent sub window to avoid losing all focus when closing a nested sub-menu.
  1992. // RevertToPointerRoot is used to make sure we don't lose all focus in case
  1993. // a subwindow and its parent are both destroyed.
  1994. if (!wd_window.no_focus && !wd_window.is_popup && wd_window.focused) {
  1995. if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup && _window_focus_check()) {
  1996. _set_input_focus(wd_parent.x11_window, RevertToPointerRoot);
  1997. }
  1998. }
  1999. } else {
  2000. ERR_FAIL_COND(!windows.has(p_parent));
  2001. ERR_FAIL_COND_MSG(prev_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
  2002. WindowData &wd_parent = windows[p_parent];
  2003. wd_window.transient_parent = p_parent;
  2004. wd_parent.transient_children.insert(p_window);
  2005. XSetTransientForHint(x11_display, wd_window.x11_window, wd_parent.x11_window);
  2006. }
  2007. }
  2008. // Helper method. Assumes that the window id has already been checked and exists.
  2009. void DisplayServerX11::_update_size_hints(WindowID p_window) {
  2010. WindowData &wd = windows[p_window];
  2011. WindowMode window_mode = window_get_mode(p_window);
  2012. XSizeHints *xsh = XAllocSizeHints();
  2013. // Always set the position and size hints - they should be synchronized with the actual values after the window is mapped anyway
  2014. xsh->flags |= PPosition | PSize;
  2015. xsh->x = wd.position.x;
  2016. xsh->y = wd.position.y;
  2017. xsh->width = wd.size.width;
  2018. xsh->height = wd.size.height;
  2019. if (window_mode == WINDOW_MODE_FULLSCREEN || window_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
  2020. // Do not set any other hints to prevent the window manager from ignoring the fullscreen flags
  2021. } else if (window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
  2022. // If resizing is disabled, use the forced size
  2023. xsh->flags |= PMinSize | PMaxSize;
  2024. xsh->min_width = wd.size.x;
  2025. xsh->max_width = wd.size.x;
  2026. xsh->min_height = wd.size.y;
  2027. xsh->max_height = wd.size.y;
  2028. } else {
  2029. // Otherwise, just respect min_size and max_size
  2030. if (wd.min_size != Size2i()) {
  2031. xsh->flags |= PMinSize;
  2032. xsh->min_width = wd.min_size.x;
  2033. xsh->min_height = wd.min_size.y;
  2034. }
  2035. if (wd.max_size != Size2i()) {
  2036. xsh->flags |= PMaxSize;
  2037. xsh->max_width = wd.max_size.x;
  2038. xsh->max_height = wd.max_size.y;
  2039. }
  2040. }
  2041. XSetWMNormalHints(x11_display, wd.x11_window, xsh);
  2042. XFree(xsh);
  2043. }
  2044. void DisplayServerX11::_update_actions_hints(WindowID p_window) {
  2045. WindowData &wd = windows[p_window];
  2046. Atom prop = XInternAtom(x11_display, "_NET_WM_ALLOWED_ACTIONS", False);
  2047. if (prop != None) {
  2048. Atom wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False);
  2049. Atom wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False);
  2050. Atom wm_act_min = XInternAtom(x11_display, "_NET_WM_ACTION_MINIMIZE", False);
  2051. Atom type;
  2052. int format;
  2053. unsigned long len;
  2054. unsigned long remaining;
  2055. unsigned char *data = nullptr;
  2056. if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, 1024, False, XA_ATOM, &type, &format, &len, &remaining, &data) == Success) {
  2057. Atom *atoms = (Atom *)data;
  2058. Vector<Atom> new_atoms;
  2059. for (uint64_t i = 0; i < len; i++) {
  2060. if (atoms[i] != wm_act_max_horz && atoms[i] != wm_act_max_vert && atoms[i] != wm_act_min) {
  2061. new_atoms.push_back(atoms[i]);
  2062. }
  2063. }
  2064. if (!wd.no_max_btn) {
  2065. new_atoms.push_back(wm_act_max_horz);
  2066. new_atoms.push_back(wm_act_max_vert);
  2067. }
  2068. if (!wd.no_min_btn) {
  2069. new_atoms.push_back(wm_act_min);
  2070. }
  2071. XChangeProperty(x11_display, wd.x11_window, prop, XA_ATOM, 32, PropModeReplace, (unsigned char *)new_atoms.ptrw(), new_atoms.size());
  2072. XFree(data);
  2073. }
  2074. }
  2075. }
  2076. Point2i DisplayServerX11::window_get_position(WindowID p_window) const {
  2077. _THREAD_SAFE_METHOD_
  2078. ERR_FAIL_COND_V(!windows.has(p_window), Point2i());
  2079. const WindowData &wd = windows[p_window];
  2080. return wd.position;
  2081. }
  2082. Point2i DisplayServerX11::window_get_position_with_decorations(WindowID p_window) const {
  2083. _THREAD_SAFE_METHOD_
  2084. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  2085. const WindowData &wd = windows[p_window];
  2086. if (wd.fullscreen) {
  2087. return wd.position;
  2088. }
  2089. XWindowAttributes xwa;
  2090. XSync(x11_display, False);
  2091. XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
  2092. int x = wd.position.x;
  2093. int y = wd.position.y;
  2094. Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
  2095. if (prop != None) {
  2096. Atom type;
  2097. int format;
  2098. unsigned long len;
  2099. unsigned long remaining;
  2100. unsigned char *data = nullptr;
  2101. if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
  2102. if (format == 32 && len == 4 && data) {
  2103. long *extents = (long *)data;
  2104. x -= extents[0]; // left
  2105. y -= extents[2]; // top
  2106. }
  2107. XFree(data);
  2108. }
  2109. }
  2110. return Size2i(x, y);
  2111. }
  2112. void DisplayServerX11::window_set_position(const Point2i &p_position, WindowID p_window) {
  2113. _THREAD_SAFE_METHOD_
  2114. ERR_FAIL_COND(!windows.has(p_window));
  2115. WindowData &wd = windows[p_window];
  2116. if (wd.embed_parent) {
  2117. print_line("Embedded window can't be moved.");
  2118. return;
  2119. }
  2120. wd.position = p_position;
  2121. int x = 0;
  2122. int y = 0;
  2123. if (!window_get_flag(WINDOW_FLAG_BORDERLESS, p_window)) {
  2124. //exclude window decorations
  2125. XSync(x11_display, False);
  2126. Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
  2127. if (prop != None) {
  2128. Atom type;
  2129. int format;
  2130. unsigned long len;
  2131. unsigned long remaining;
  2132. unsigned char *data = nullptr;
  2133. if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
  2134. if (format == 32 && len == 4 && data) {
  2135. long *extents = (long *)data;
  2136. x = extents[0];
  2137. y = extents[2];
  2138. }
  2139. XFree(data);
  2140. }
  2141. }
  2142. }
  2143. XMoveWindow(x11_display, wd.x11_window, p_position.x - x, p_position.y - y);
  2144. _update_real_mouse_position(wd);
  2145. }
  2146. void DisplayServerX11::window_set_max_size(const Size2i p_size, WindowID p_window) {
  2147. _THREAD_SAFE_METHOD_
  2148. ERR_FAIL_COND(!windows.has(p_window));
  2149. WindowData &wd = windows[p_window];
  2150. if (wd.embed_parent) {
  2151. print_line("Embedded windows can't have a maximum size.");
  2152. return;
  2153. }
  2154. if ((p_size != Size2i()) && ((p_size.x < wd.min_size.x) || (p_size.y < wd.min_size.y))) {
  2155. ERR_PRINT("Maximum window size can't be smaller than minimum window size!");
  2156. return;
  2157. }
  2158. wd.max_size = p_size;
  2159. _update_size_hints(p_window);
  2160. XFlush(x11_display);
  2161. }
  2162. Size2i DisplayServerX11::window_get_max_size(WindowID p_window) const {
  2163. _THREAD_SAFE_METHOD_
  2164. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  2165. const WindowData &wd = windows[p_window];
  2166. return wd.max_size;
  2167. }
  2168. void DisplayServerX11::window_set_min_size(const Size2i p_size, WindowID p_window) {
  2169. _THREAD_SAFE_METHOD_
  2170. ERR_FAIL_COND(!windows.has(p_window));
  2171. WindowData &wd = windows[p_window];
  2172. if (wd.embed_parent) {
  2173. print_line("Embedded windows can't have a minimum size.");
  2174. return;
  2175. }
  2176. if ((p_size != Size2i()) && (wd.max_size != Size2i()) && ((p_size.x > wd.max_size.x) || (p_size.y > wd.max_size.y))) {
  2177. ERR_PRINT("Minimum window size can't be larger than maximum window size!");
  2178. return;
  2179. }
  2180. wd.min_size = p_size;
  2181. _update_size_hints(p_window);
  2182. XFlush(x11_display);
  2183. }
  2184. Size2i DisplayServerX11::window_get_min_size(WindowID p_window) const {
  2185. _THREAD_SAFE_METHOD_
  2186. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  2187. const WindowData &wd = windows[p_window];
  2188. return wd.min_size;
  2189. }
  2190. void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
  2191. _THREAD_SAFE_METHOD_
  2192. ERR_FAIL_COND(!windows.has(p_window));
  2193. Size2i size = p_size;
  2194. size = size.maxi(1);
  2195. WindowData &wd = windows[p_window];
  2196. if (wd.embed_parent) {
  2197. print_line("Embedded window can't be resized.");
  2198. return;
  2199. }
  2200. if (wd.size.width == size.width && wd.size.height == size.height) {
  2201. return;
  2202. }
  2203. XWindowAttributes xwa;
  2204. XSync(x11_display, False);
  2205. XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
  2206. int old_w = xwa.width;
  2207. int old_h = xwa.height;
  2208. // Update our videomode width and height
  2209. wd.size = size;
  2210. // Update the size hints first to make sure the window size can be set
  2211. _update_size_hints(p_window);
  2212. // Resize the window
  2213. XResizeWindow(x11_display, wd.x11_window, size.x, size.y);
  2214. for (int timeout = 0; timeout < 50; ++timeout) {
  2215. XSync(x11_display, False);
  2216. XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
  2217. if (old_w != xwa.width || old_h != xwa.height) {
  2218. break;
  2219. }
  2220. OS::get_singleton()->delay_usec(10'000);
  2221. }
  2222. // Keep rendering context window size in sync
  2223. #if defined(RD_ENABLED)
  2224. if (rendering_context) {
  2225. rendering_context->window_set_size(p_window, xwa.width, xwa.height);
  2226. }
  2227. #endif
  2228. #if defined(GLES3_ENABLED)
  2229. if (gl_manager) {
  2230. gl_manager->window_resize(p_window, xwa.width, xwa.height);
  2231. }
  2232. if (gl_manager_egl) {
  2233. gl_manager_egl->window_resize(p_window, xwa.width, xwa.height);
  2234. }
  2235. #endif
  2236. }
  2237. Size2i DisplayServerX11::window_get_size(WindowID p_window) const {
  2238. _THREAD_SAFE_METHOD_
  2239. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  2240. const WindowData &wd = windows[p_window];
  2241. return wd.size;
  2242. }
  2243. Size2i DisplayServerX11::window_get_size_with_decorations(WindowID p_window) const {
  2244. _THREAD_SAFE_METHOD_
  2245. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  2246. const WindowData &wd = windows[p_window];
  2247. if (wd.fullscreen) {
  2248. return wd.size;
  2249. }
  2250. XWindowAttributes xwa;
  2251. XSync(x11_display, False);
  2252. XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
  2253. int w = xwa.width;
  2254. int h = xwa.height;
  2255. Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
  2256. if (prop != None) {
  2257. Atom type;
  2258. int format;
  2259. unsigned long len;
  2260. unsigned long remaining;
  2261. unsigned char *data = nullptr;
  2262. if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
  2263. if (format == 32 && len == 4 && data) {
  2264. long *extents = (long *)data;
  2265. w += extents[0] + extents[1]; // left, right
  2266. h += extents[2] + extents[3]; // top, bottom
  2267. }
  2268. XFree(data);
  2269. }
  2270. }
  2271. return Size2i(w, h);
  2272. }
  2273. // Just a helper to reduce code duplication in `window_is_maximize_allowed`
  2274. // and `_set_wm_maximized`.
  2275. bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_atom_name) const {
  2276. ERR_FAIL_COND_V(!windows.has(p_window), false);
  2277. const WindowData &wd = windows[p_window];
  2278. Atom property = XInternAtom(x11_display, p_atom_name, False);
  2279. Atom type;
  2280. int format;
  2281. unsigned long len;
  2282. unsigned long remaining;
  2283. unsigned char *data = nullptr;
  2284. bool retval = false;
  2285. if (property == None) {
  2286. return false;
  2287. }
  2288. int result = XGetWindowProperty(
  2289. x11_display,
  2290. wd.x11_window,
  2291. property,
  2292. 0,
  2293. 1024,
  2294. False,
  2295. XA_ATOM,
  2296. &type,
  2297. &format,
  2298. &len,
  2299. &remaining,
  2300. &data);
  2301. if (result == Success && data) {
  2302. Atom *atoms = (Atom *)data;
  2303. Atom wm_act_max_horz;
  2304. Atom wm_act_max_vert;
  2305. bool checking_state = strcmp(p_atom_name, "_NET_WM_STATE") == 0;
  2306. if (checking_state) {
  2307. wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
  2308. wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
  2309. } else {
  2310. wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False);
  2311. wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False);
  2312. }
  2313. bool found_wm_act_max_horz = false;
  2314. bool found_wm_act_max_vert = false;
  2315. for (uint64_t i = 0; i < len; i++) {
  2316. if (atoms[i] == wm_act_max_horz) {
  2317. found_wm_act_max_horz = true;
  2318. }
  2319. if (atoms[i] == wm_act_max_vert) {
  2320. found_wm_act_max_vert = true;
  2321. }
  2322. if (checking_state) {
  2323. if (found_wm_act_max_horz && found_wm_act_max_vert) {
  2324. retval = true;
  2325. break;
  2326. }
  2327. } else {
  2328. if (found_wm_act_max_horz || found_wm_act_max_vert) {
  2329. retval = true;
  2330. break;
  2331. }
  2332. }
  2333. }
  2334. XFree(data);
  2335. }
  2336. return retval;
  2337. }
  2338. bool DisplayServerX11::_window_minimize_check(WindowID p_window) const {
  2339. const WindowData &wd = windows[p_window];
  2340. // Using EWMH instead of ICCCM, might work better for Wayland users.
  2341. Atom property = XInternAtom(x11_display, "_NET_WM_STATE", True);
  2342. Atom hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", True);
  2343. if (property == None || hidden == None) {
  2344. return false;
  2345. }
  2346. Atom type;
  2347. int format;
  2348. unsigned long len;
  2349. unsigned long remaining;
  2350. Atom *atoms = nullptr;
  2351. int result = XGetWindowProperty(
  2352. x11_display,
  2353. wd.x11_window,
  2354. property,
  2355. 0,
  2356. 32,
  2357. False,
  2358. XA_ATOM,
  2359. &type,
  2360. &format,
  2361. &len,
  2362. &remaining,
  2363. (unsigned char **)&atoms);
  2364. if (result == Success && atoms) {
  2365. for (unsigned int i = 0; i < len; i++) {
  2366. if (atoms[i] == hidden) {
  2367. XFree(atoms);
  2368. return true;
  2369. }
  2370. }
  2371. XFree(atoms);
  2372. }
  2373. return false;
  2374. }
  2375. bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
  2376. ERR_FAIL_COND_V(!windows.has(p_window), false);
  2377. const WindowData &wd = windows[p_window];
  2378. // Using EWMH -- Extended Window Manager Hints
  2379. Atom property = XInternAtom(x11_display, "_NET_WM_STATE", False);
  2380. Atom type;
  2381. int format;
  2382. unsigned long len;
  2383. unsigned long remaining;
  2384. unsigned char *data = nullptr;
  2385. bool retval = false;
  2386. if (property == None) {
  2387. return retval;
  2388. }
  2389. int result = XGetWindowProperty(
  2390. x11_display,
  2391. wd.x11_window,
  2392. property,
  2393. 0,
  2394. 1024,
  2395. False,
  2396. XA_ATOM,
  2397. &type,
  2398. &format,
  2399. &len,
  2400. &remaining,
  2401. &data);
  2402. if (result == Success) {
  2403. Atom *atoms = (Atom *)data;
  2404. Atom wm_fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
  2405. for (uint64_t i = 0; i < len; i++) {
  2406. if (atoms[i] == wm_fullscreen) {
  2407. retval = true;
  2408. break;
  2409. }
  2410. }
  2411. XFree(data);
  2412. }
  2413. return retval;
  2414. }
  2415. void DisplayServerX11::_validate_mode_on_map(WindowID p_window) {
  2416. // Check if we applied any window modes that didn't take effect while unmapped
  2417. const WindowData &wd = windows[p_window];
  2418. if (wd.fullscreen && !_window_fullscreen_check(p_window)) {
  2419. _set_wm_fullscreen(p_window, true, wd.exclusive_fullscreen);
  2420. } else if (wd.maximized && !_window_maximize_check(p_window, "_NET_WM_STATE")) {
  2421. _set_wm_maximized(p_window, true);
  2422. } else if (wd.minimized && !_window_minimize_check(p_window)) {
  2423. _set_wm_minimized(p_window, true);
  2424. }
  2425. if (wd.on_top) {
  2426. Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
  2427. Atom wm_above = XInternAtom(x11_display, "_NET_WM_STATE_ABOVE", False);
  2428. XClientMessageEvent xev;
  2429. memset(&xev, 0, sizeof(xev));
  2430. xev.type = ClientMessage;
  2431. xev.window = wd.x11_window;
  2432. xev.message_type = wm_state;
  2433. xev.format = 32;
  2434. xev.data.l[0] = _NET_WM_STATE_ADD;
  2435. xev.data.l[1] = wm_above;
  2436. xev.data.l[3] = 1;
  2437. XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xev);
  2438. }
  2439. }
  2440. bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const {
  2441. _THREAD_SAFE_METHOD_
  2442. return _window_maximize_check(p_window, "_NET_WM_ALLOWED_ACTIONS");
  2443. }
  2444. void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) {
  2445. ERR_FAIL_COND(!windows.has(p_window));
  2446. WindowData &wd = windows[p_window];
  2447. // Using EWMH -- Extended Window Manager Hints
  2448. XEvent xev;
  2449. Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
  2450. Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
  2451. Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
  2452. memset(&xev, 0, sizeof(xev));
  2453. xev.type = ClientMessage;
  2454. xev.xclient.window = wd.x11_window;
  2455. xev.xclient.message_type = wm_state;
  2456. xev.xclient.format = 32;
  2457. xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  2458. xev.xclient.data.l[1] = wm_max_horz;
  2459. xev.xclient.data.l[2] = wm_max_vert;
  2460. XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  2461. if (p_enabled && window_is_maximize_allowed(p_window)) {
  2462. // Wait for effective resizing (so the GLX context is too).
  2463. // Give up after 0.5s, it's not going to happen on this WM.
  2464. // https://github.com/godotengine/godot/issues/19978
  2465. for (int attempt = 0; window_get_mode(p_window) != WINDOW_MODE_MAXIMIZED && attempt < 50; attempt++) {
  2466. OS::get_singleton()->delay_usec(10'000);
  2467. }
  2468. }
  2469. wd.maximized = p_enabled;
  2470. }
  2471. void DisplayServerX11::_set_wm_minimized(WindowID p_window, bool p_enabled) {
  2472. WindowData &wd = windows[p_window];
  2473. // Using ICCCM -- Inter-Client Communication Conventions Manual
  2474. XEvent xev;
  2475. Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
  2476. memset(&xev, 0, sizeof(xev));
  2477. xev.type = ClientMessage;
  2478. xev.xclient.window = wd.x11_window;
  2479. xev.xclient.message_type = wm_change;
  2480. xev.xclient.format = 32;
  2481. xev.xclient.data.l[0] = p_enabled ? WM_IconicState : WM_NormalState;
  2482. XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  2483. Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
  2484. Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
  2485. memset(&xev, 0, sizeof(xev));
  2486. xev.type = ClientMessage;
  2487. xev.xclient.window = wd.x11_window;
  2488. xev.xclient.message_type = wm_state;
  2489. xev.xclient.format = 32;
  2490. xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  2491. xev.xclient.data.l[1] = wm_hidden;
  2492. XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  2493. wd.minimized = p_enabled;
  2494. }
  2495. void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled, bool p_exclusive) {
  2496. ERR_FAIL_COND(!windows.has(p_window));
  2497. WindowData &wd = windows[p_window];
  2498. if (p_enabled && !window_get_flag(WINDOW_FLAG_BORDERLESS, p_window)) {
  2499. // remove decorations if the window is not already borderless
  2500. Hints hints;
  2501. Atom property;
  2502. hints.flags = 2;
  2503. hints.decorations = 0;
  2504. property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
  2505. if (property != None) {
  2506. XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
  2507. }
  2508. }
  2509. if (p_enabled) {
  2510. // Set the window as resizable to prevent window managers to ignore the fullscreen state flag.
  2511. _update_size_hints(p_window);
  2512. }
  2513. // Using EWMH -- Extended Window Manager Hints
  2514. XEvent xev;
  2515. Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
  2516. Atom wm_fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
  2517. memset(&xev, 0, sizeof(xev));
  2518. xev.type = ClientMessage;
  2519. xev.xclient.window = wd.x11_window;
  2520. xev.xclient.message_type = wm_state;
  2521. xev.xclient.format = 32;
  2522. xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  2523. xev.xclient.data.l[1] = wm_fullscreen;
  2524. xev.xclient.data.l[2] = 0;
  2525. XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  2526. // set bypass compositor hint
  2527. Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False);
  2528. unsigned long compositing_disable_on = 0; // Use default.
  2529. if (p_enabled) {
  2530. if (p_exclusive) {
  2531. compositing_disable_on = 1; // Force composition OFF to reduce overhead.
  2532. } else {
  2533. compositing_disable_on = 2; // Force composition ON to allow popup windows.
  2534. }
  2535. }
  2536. if (bypass_compositor != None) {
  2537. XChangeProperty(x11_display, wd.x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1);
  2538. }
  2539. XFlush(x11_display);
  2540. if (!p_enabled) {
  2541. // Reset the non-resizable flags if we un-set these before.
  2542. _update_size_hints(p_window);
  2543. // put back or remove decorations according to the last set borderless state
  2544. Hints hints;
  2545. Atom property;
  2546. hints.flags = 2;
  2547. hints.decorations = wd.borderless ? 0 : 1;
  2548. property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
  2549. if (property != None) {
  2550. XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
  2551. }
  2552. }
  2553. }
  2554. void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
  2555. _THREAD_SAFE_METHOD_
  2556. ERR_FAIL_COND(!windows.has(p_window));
  2557. WindowData &wd = windows[p_window];
  2558. WindowMode old_mode = window_get_mode(p_window);
  2559. if (old_mode == p_mode) {
  2560. return; // do nothing
  2561. }
  2562. if (p_mode != WINDOW_MODE_WINDOWED && wd.embed_parent) {
  2563. print_line("Embedded window only supports Windowed mode.");
  2564. return;
  2565. }
  2566. // Remove all "extra" modes.
  2567. switch (old_mode) {
  2568. case WINDOW_MODE_WINDOWED: {
  2569. //do nothing
  2570. } break;
  2571. case WINDOW_MODE_MINIMIZED: {
  2572. _set_wm_minimized(p_window, false);
  2573. } break;
  2574. case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
  2575. case WINDOW_MODE_FULLSCREEN: {
  2576. //Remove full-screen
  2577. wd.fullscreen = false;
  2578. wd.exclusive_fullscreen = false;
  2579. _set_wm_fullscreen(p_window, false, false);
  2580. //un-maximize required for always on top
  2581. bool on_top = window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window);
  2582. window_set_position(wd.last_position_before_fs, p_window);
  2583. if (on_top) {
  2584. _set_wm_maximized(p_window, false);
  2585. }
  2586. } break;
  2587. case WINDOW_MODE_MAXIMIZED: {
  2588. _set_wm_maximized(p_window, false);
  2589. } break;
  2590. }
  2591. switch (p_mode) {
  2592. case WINDOW_MODE_WINDOWED: {
  2593. //do nothing
  2594. } break;
  2595. case WINDOW_MODE_MINIMIZED: {
  2596. _set_wm_minimized(p_window, true);
  2597. } break;
  2598. case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
  2599. case WINDOW_MODE_FULLSCREEN: {
  2600. wd.last_position_before_fs = wd.position;
  2601. if (window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window)) {
  2602. _set_wm_maximized(p_window, true);
  2603. }
  2604. wd.fullscreen = true;
  2605. if (p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
  2606. wd.exclusive_fullscreen = true;
  2607. _set_wm_fullscreen(p_window, true, true);
  2608. } else {
  2609. wd.exclusive_fullscreen = false;
  2610. _set_wm_fullscreen(p_window, true, false);
  2611. }
  2612. } break;
  2613. case WINDOW_MODE_MAXIMIZED: {
  2614. _set_wm_maximized(p_window, true);
  2615. } break;
  2616. }
  2617. }
  2618. DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) const {
  2619. _THREAD_SAFE_METHOD_
  2620. ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED);
  2621. const WindowData &wd = windows[p_window];
  2622. if (wd.fullscreen) { //if fullscreen, it's not in another mode
  2623. if (wd.exclusive_fullscreen) {
  2624. return WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
  2625. } else {
  2626. return WINDOW_MODE_FULLSCREEN;
  2627. }
  2628. }
  2629. // Test maximized.
  2630. // Using EWMH -- Extended Window Manager Hints
  2631. if (_window_maximize_check(p_window, "_NET_WM_STATE")) {
  2632. return WINDOW_MODE_MAXIMIZED;
  2633. }
  2634. {
  2635. if (_window_minimize_check(p_window)) {
  2636. return WINDOW_MODE_MINIMIZED;
  2637. }
  2638. }
  2639. // All other discarded, return windowed.
  2640. return WINDOW_MODE_WINDOWED;
  2641. }
  2642. void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
  2643. _THREAD_SAFE_METHOD_
  2644. ERR_FAIL_COND(!windows.has(p_window));
  2645. WindowData &wd = windows[p_window];
  2646. switch (p_flag) {
  2647. case WINDOW_FLAG_MAXIMIZE_DISABLED: {
  2648. wd.no_max_btn = p_enabled;
  2649. _update_actions_hints(p_window);
  2650. XFlush(x11_display);
  2651. } break;
  2652. case WINDOW_FLAG_MINIMIZE_DISABLED: {
  2653. wd.no_min_btn = p_enabled;
  2654. _update_actions_hints(p_window);
  2655. XFlush(x11_display);
  2656. } break;
  2657. case WINDOW_FLAG_RESIZE_DISABLED: {
  2658. if (p_enabled && wd.embed_parent) {
  2659. print_line("Embedded window resize can't be disabled.");
  2660. return;
  2661. }
  2662. wd.resize_disabled = p_enabled;
  2663. _update_size_hints(p_window);
  2664. _update_actions_hints(p_window);
  2665. XFlush(x11_display);
  2666. } break;
  2667. case WINDOW_FLAG_BORDERLESS: {
  2668. Hints hints;
  2669. Atom property;
  2670. hints.flags = 2;
  2671. hints.decorations = p_enabled ? 0 : 1;
  2672. property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
  2673. if (property != None) {
  2674. XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
  2675. }
  2676. // Preserve window size
  2677. if (!wd.embed_parent) {
  2678. window_set_size(window_get_size(p_window), p_window);
  2679. }
  2680. wd.borderless = p_enabled;
  2681. _update_window_mouse_passthrough(p_window);
  2682. } break;
  2683. case WINDOW_FLAG_ALWAYS_ON_TOP: {
  2684. ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID, "Can't make a window transient if the 'on top' flag is active.");
  2685. if (p_enabled && wd.embed_parent) {
  2686. print_line("Embedded window can't become on top.");
  2687. return;
  2688. }
  2689. if (p_enabled && wd.fullscreen) {
  2690. _set_wm_maximized(p_window, true);
  2691. }
  2692. Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
  2693. Atom wm_above = XInternAtom(x11_display, "_NET_WM_STATE_ABOVE", False);
  2694. XClientMessageEvent xev;
  2695. memset(&xev, 0, sizeof(xev));
  2696. xev.type = ClientMessage;
  2697. xev.window = wd.x11_window;
  2698. xev.message_type = wm_state;
  2699. xev.format = 32;
  2700. xev.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
  2701. xev.data.l[1] = wm_above;
  2702. xev.data.l[3] = 1;
  2703. XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xev);
  2704. if (!p_enabled && !wd.fullscreen) {
  2705. _set_wm_maximized(p_window, false);
  2706. }
  2707. wd.on_top = p_enabled;
  2708. } break;
  2709. case WINDOW_FLAG_TRANSPARENT: {
  2710. wd.layered_window = p_enabled;
  2711. } break;
  2712. case WINDOW_FLAG_NO_FOCUS: {
  2713. wd.no_focus = p_enabled;
  2714. } break;
  2715. case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
  2716. wd.mpass = p_enabled;
  2717. _update_window_mouse_passthrough(p_window);
  2718. } break;
  2719. case WINDOW_FLAG_POPUP: {
  2720. XWindowAttributes xwa;
  2721. XSync(x11_display, False);
  2722. XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
  2723. ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup.");
  2724. ERR_FAIL_COND_MSG((xwa.map_state == IsViewable) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened.");
  2725. if (p_enabled && wd.embed_parent) {
  2726. print_line("Embedded window can't be popup.");
  2727. return;
  2728. }
  2729. wd.is_popup = p_enabled;
  2730. } break;
  2731. default: {
  2732. }
  2733. }
  2734. }
  2735. bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) const {
  2736. _THREAD_SAFE_METHOD_
  2737. ERR_FAIL_COND_V(!windows.has(p_window), false);
  2738. const WindowData &wd = windows[p_window];
  2739. switch (p_flag) {
  2740. case WINDOW_FLAG_MAXIMIZE_DISABLED: {
  2741. return wd.no_max_btn;
  2742. } break;
  2743. case WINDOW_FLAG_MINIMIZE_DISABLED: {
  2744. return wd.no_min_btn;
  2745. } break;
  2746. case WINDOW_FLAG_RESIZE_DISABLED: {
  2747. return wd.resize_disabled;
  2748. } break;
  2749. case WINDOW_FLAG_BORDERLESS: {
  2750. bool borderless = wd.borderless;
  2751. Atom prop = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
  2752. if (prop != None) {
  2753. Atom type;
  2754. int format;
  2755. unsigned long len;
  2756. unsigned long remaining;
  2757. unsigned char *data = nullptr;
  2758. if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, sizeof(Hints), False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
  2759. if (data && (format == 32) && (len >= 5)) {
  2760. borderless = !(reinterpret_cast<Hints *>(data)->decorations);
  2761. }
  2762. if (data) {
  2763. XFree(data);
  2764. }
  2765. }
  2766. }
  2767. return borderless;
  2768. } break;
  2769. case WINDOW_FLAG_ALWAYS_ON_TOP: {
  2770. return wd.on_top;
  2771. } break;
  2772. case WINDOW_FLAG_TRANSPARENT: {
  2773. return wd.layered_window;
  2774. } break;
  2775. case WINDOW_FLAG_NO_FOCUS: {
  2776. return wd.no_focus;
  2777. } break;
  2778. case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
  2779. return wd.mpass;
  2780. } break;
  2781. case WINDOW_FLAG_POPUP: {
  2782. return wd.is_popup;
  2783. } break;
  2784. default: {
  2785. }
  2786. }
  2787. return false;
  2788. }
  2789. void DisplayServerX11::window_request_attention(WindowID p_window) {
  2790. _THREAD_SAFE_METHOD_
  2791. ERR_FAIL_COND(!windows.has(p_window));
  2792. const WindowData &wd = windows[p_window];
  2793. // Using EWMH -- Extended Window Manager Hints
  2794. //
  2795. // Sets the _NET_WM_STATE_DEMANDS_ATTENTION atom for WM_STATE
  2796. // Will be unset by the window manager after user react on the request for attention
  2797. XEvent xev;
  2798. Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
  2799. Atom wm_attention = XInternAtom(x11_display, "_NET_WM_STATE_DEMANDS_ATTENTION", False);
  2800. memset(&xev, 0, sizeof(xev));
  2801. xev.type = ClientMessage;
  2802. xev.xclient.window = wd.x11_window;
  2803. xev.xclient.message_type = wm_state;
  2804. xev.xclient.format = 32;
  2805. xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
  2806. xev.xclient.data.l[1] = wm_attention;
  2807. XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  2808. XFlush(x11_display);
  2809. }
  2810. void DisplayServerX11::window_move_to_foreground(WindowID p_window) {
  2811. _THREAD_SAFE_METHOD_
  2812. ERR_FAIL_COND(!windows.has(p_window));
  2813. const WindowData &wd = windows[p_window];
  2814. XEvent xev;
  2815. Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
  2816. memset(&xev, 0, sizeof(xev));
  2817. xev.type = ClientMessage;
  2818. xev.xclient.window = wd.x11_window;
  2819. xev.xclient.message_type = net_active_window;
  2820. xev.xclient.format = 32;
  2821. xev.xclient.data.l[0] = 1;
  2822. xev.xclient.data.l[1] = CurrentTime;
  2823. XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  2824. XFlush(x11_display);
  2825. }
  2826. DisplayServerX11::WindowID DisplayServerX11::get_focused_window() const {
  2827. return last_focused_window;
  2828. }
  2829. bool DisplayServerX11::window_is_focused(WindowID p_window) const {
  2830. _THREAD_SAFE_METHOD_
  2831. ERR_FAIL_COND_V(!windows.has(p_window), false);
  2832. const WindowData &wd = windows[p_window];
  2833. return wd.focused;
  2834. }
  2835. bool DisplayServerX11::window_can_draw(WindowID p_window) const {
  2836. //this seems to be all that is provided by X11
  2837. return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED;
  2838. }
  2839. bool DisplayServerX11::can_any_window_draw() const {
  2840. _THREAD_SAFE_METHOD_
  2841. for (const KeyValue<WindowID, WindowData> &E : windows) {
  2842. if (window_get_mode(E.key) != WINDOW_MODE_MINIMIZED) {
  2843. return true;
  2844. }
  2845. }
  2846. return false;
  2847. }
  2848. void DisplayServerX11::window_set_ime_active(const bool p_active, WindowID p_window) {
  2849. _THREAD_SAFE_METHOD_
  2850. ERR_FAIL_COND(!windows.has(p_window));
  2851. WindowData &wd = windows[p_window];
  2852. if (!wd.xic) {
  2853. return;
  2854. }
  2855. if (!wd.focused) {
  2856. wd.ime_active = false;
  2857. im_text = String();
  2858. im_selection = Vector2i();
  2859. return;
  2860. }
  2861. // Block events polling while changing input focus
  2862. // because it triggers some event polling internally.
  2863. if (p_active) {
  2864. MutexLock mutex_lock(events_mutex);
  2865. wd.ime_active = true;
  2866. XMapWindow(x11_display, wd.x11_xim_window);
  2867. XWindowAttributes xwa;
  2868. XSync(x11_display, False);
  2869. XGetWindowAttributes(x11_display, wd.x11_xim_window, &xwa);
  2870. if (xwa.map_state == IsViewable && _window_focus_check()) {
  2871. _set_input_focus(wd.x11_xim_window, RevertToParent);
  2872. }
  2873. XSetICFocus(wd.xic);
  2874. } else {
  2875. MutexLock mutex_lock(events_mutex);
  2876. XUnsetICFocus(wd.xic);
  2877. XUnmapWindow(x11_display, wd.x11_xim_window);
  2878. wd.ime_active = false;
  2879. im_text = String();
  2880. im_selection = Vector2i();
  2881. }
  2882. }
  2883. void DisplayServerX11::window_set_ime_position(const Point2i &p_pos, WindowID p_window) {
  2884. _THREAD_SAFE_METHOD_
  2885. ERR_FAIL_COND(!windows.has(p_window));
  2886. WindowData &wd = windows[p_window];
  2887. if (!wd.xic) {
  2888. return;
  2889. }
  2890. if (!wd.focused) {
  2891. return;
  2892. }
  2893. if (wd.ime_active) {
  2894. XWindowAttributes xwa;
  2895. XSync(x11_display, False);
  2896. XGetWindowAttributes(x11_display, wd.x11_xim_window, &xwa);
  2897. if (xwa.map_state == IsViewable) {
  2898. XMoveWindow(x11_display, wd.x11_xim_window, p_pos.x, p_pos.y);
  2899. }
  2900. }
  2901. }
  2902. int DisplayServerX11::accessibility_should_increase_contrast() const {
  2903. #ifdef DBUS_ENABLED
  2904. return portal_desktop->get_high_contrast();
  2905. #endif
  2906. return -1;
  2907. }
  2908. int DisplayServerX11::accessibility_screen_reader_active() const {
  2909. #ifdef DBUS_ENABLED
  2910. if (atspi_monitor->is_supported()) {
  2911. return atspi_monitor->is_active();
  2912. }
  2913. #endif
  2914. return -1;
  2915. }
  2916. Point2i DisplayServerX11::ime_get_selection() const {
  2917. return im_selection;
  2918. }
  2919. String DisplayServerX11::ime_get_text() const {
  2920. return im_text;
  2921. }
  2922. void DisplayServerX11::cursor_set_shape(CursorShape p_shape) {
  2923. _THREAD_SAFE_METHOD_
  2924. ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
  2925. if (p_shape == current_cursor) {
  2926. return;
  2927. }
  2928. if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
  2929. if (cursors[p_shape] != None) {
  2930. for (const KeyValue<WindowID, WindowData> &E : windows) {
  2931. XDefineCursor(x11_display, E.value.x11_window, cursors[p_shape]);
  2932. }
  2933. } else if (cursors[CURSOR_ARROW] != None) {
  2934. for (const KeyValue<WindowID, WindowData> &E : windows) {
  2935. XDefineCursor(x11_display, E.value.x11_window, cursors[CURSOR_ARROW]);
  2936. }
  2937. }
  2938. }
  2939. current_cursor = p_shape;
  2940. }
  2941. DisplayServerX11::CursorShape DisplayServerX11::cursor_get_shape() const {
  2942. return current_cursor;
  2943. }
  2944. void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
  2945. _THREAD_SAFE_METHOD_
  2946. ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
  2947. if (p_cursor.is_valid()) {
  2948. HashMap<CursorShape, Vector<Variant>>::Iterator cursor_c = cursors_cache.find(p_shape);
  2949. if (cursor_c) {
  2950. if (cursor_c->value[0] == p_cursor && cursor_c->value[1] == p_hotspot) {
  2951. cursor_set_shape(p_shape);
  2952. return;
  2953. }
  2954. cursors_cache.erase(p_shape);
  2955. }
  2956. Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
  2957. ERR_FAIL_COND(image.is_null());
  2958. Vector2i texture_size = image->get_size();
  2959. // Create the cursor structure
  2960. XcursorImage *cursor_image = XcursorImageCreate(texture_size.width, texture_size.height);
  2961. XcursorUInt image_size = texture_size.width * texture_size.height;
  2962. XcursorDim size = sizeof(XcursorPixel) * image_size;
  2963. cursor_image->version = 1;
  2964. cursor_image->size = size;
  2965. cursor_image->xhot = p_hotspot.x;
  2966. cursor_image->yhot = p_hotspot.y;
  2967. // allocate memory to contain the whole file
  2968. cursor_image->pixels = (XcursorPixel *)memalloc(size);
  2969. for (XcursorPixel index = 0; index < image_size; index++) {
  2970. int row_index = std::floor(index / texture_size.width);
  2971. int column_index = index % int(texture_size.width);
  2972. *(cursor_image->pixels + index) = image->get_pixel(column_index, row_index).to_argb32();
  2973. }
  2974. ERR_FAIL_NULL(cursor_image->pixels);
  2975. // Save it for a further usage
  2976. cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_image);
  2977. Vector<Variant> params;
  2978. params.push_back(p_cursor);
  2979. params.push_back(p_hotspot);
  2980. cursors_cache.insert(p_shape, params);
  2981. if (p_shape == current_cursor) {
  2982. if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
  2983. for (const KeyValue<WindowID, WindowData> &E : windows) {
  2984. XDefineCursor(x11_display, E.value.x11_window, cursors[p_shape]);
  2985. }
  2986. }
  2987. }
  2988. memfree(cursor_image->pixels);
  2989. XcursorImageDestroy(cursor_image);
  2990. } else {
  2991. // Reset to default system cursor
  2992. if (cursor_img[p_shape]) {
  2993. cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_img[p_shape]);
  2994. }
  2995. cursors_cache.erase(p_shape);
  2996. CursorShape c = current_cursor;
  2997. current_cursor = CURSOR_MAX;
  2998. cursor_set_shape(c);
  2999. }
  3000. }
  3001. bool DisplayServerX11::get_swap_cancel_ok() {
  3002. return swap_cancel_ok;
  3003. }
  3004. int DisplayServerX11::keyboard_get_layout_count() const {
  3005. int _group_count = 0;
  3006. XkbDescRec *kbd = XkbAllocKeyboard();
  3007. if (kbd) {
  3008. kbd->dpy = x11_display;
  3009. XkbGetControls(x11_display, XkbAllControlsMask, kbd);
  3010. XkbGetNames(x11_display, XkbSymbolsNameMask, kbd);
  3011. const Atom *groups = kbd->names->groups;
  3012. if (kbd->ctrls != nullptr) {
  3013. _group_count = kbd->ctrls->num_groups;
  3014. } else {
  3015. while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
  3016. _group_count++;
  3017. }
  3018. }
  3019. XkbFreeKeyboard(kbd, 0, true);
  3020. }
  3021. return _group_count;
  3022. }
  3023. int DisplayServerX11::keyboard_get_current_layout() const {
  3024. XkbStateRec state;
  3025. XkbGetState(x11_display, XkbUseCoreKbd, &state);
  3026. return state.group;
  3027. }
  3028. void DisplayServerX11::keyboard_set_current_layout(int p_index) {
  3029. ERR_FAIL_INDEX(p_index, keyboard_get_layout_count());
  3030. XkbLockGroup(x11_display, XkbUseCoreKbd, p_index);
  3031. }
  3032. String DisplayServerX11::keyboard_get_layout_language(int p_index) const {
  3033. String ret;
  3034. XkbDescRec *kbd = XkbAllocKeyboard();
  3035. if (kbd) {
  3036. kbd->dpy = x11_display;
  3037. XkbGetControls(x11_display, XkbAllControlsMask, kbd);
  3038. XkbGetNames(x11_display, XkbSymbolsNameMask, kbd);
  3039. XkbGetNames(x11_display, XkbGroupNamesMask, kbd);
  3040. int _group_count = 0;
  3041. const Atom *groups = kbd->names->groups;
  3042. if (kbd->ctrls != nullptr) {
  3043. _group_count = kbd->ctrls->num_groups;
  3044. } else {
  3045. while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
  3046. _group_count++;
  3047. }
  3048. }
  3049. Atom names = kbd->names->symbols;
  3050. if (names != None) {
  3051. Vector<String> info = get_atom_name(x11_display, names).split("+");
  3052. if (p_index >= 0 && p_index < _group_count) {
  3053. if (p_index + 1 < info.size()) {
  3054. ret = info[p_index + 1]; // Skip "pc" at the start and "inet"/"group" at the end of symbols.
  3055. } else {
  3056. ret = "en"; // No symbol for layout fallback to "en".
  3057. }
  3058. } else {
  3059. ERR_PRINT("Index " + itos(p_index) + "is out of bounds (" + itos(_group_count) + ").");
  3060. }
  3061. }
  3062. XkbFreeKeyboard(kbd, 0, true);
  3063. }
  3064. return ret.substr(0, 2);
  3065. }
  3066. String DisplayServerX11::keyboard_get_layout_name(int p_index) const {
  3067. String ret;
  3068. XkbDescRec *kbd = XkbAllocKeyboard();
  3069. if (kbd) {
  3070. kbd->dpy = x11_display;
  3071. XkbGetControls(x11_display, XkbAllControlsMask, kbd);
  3072. XkbGetNames(x11_display, XkbSymbolsNameMask, kbd);
  3073. XkbGetNames(x11_display, XkbGroupNamesMask, kbd);
  3074. int _group_count = 0;
  3075. const Atom *groups = kbd->names->groups;
  3076. if (kbd->ctrls != nullptr) {
  3077. _group_count = kbd->ctrls->num_groups;
  3078. } else {
  3079. while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
  3080. _group_count++;
  3081. }
  3082. }
  3083. if (p_index >= 0 && p_index < _group_count) {
  3084. ret = get_atom_name(x11_display, groups[p_index]);
  3085. } else {
  3086. ERR_PRINT("Index " + itos(p_index) + "is out of bounds (" + itos(_group_count) + ").");
  3087. }
  3088. XkbFreeKeyboard(kbd, 0, true);
  3089. }
  3090. return ret;
  3091. }
  3092. Key DisplayServerX11::keyboard_get_keycode_from_physical(Key p_keycode) const {
  3093. Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK;
  3094. Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK;
  3095. unsigned int xkeycode = KeyMappingX11::get_xlibcode(keycode_no_mod);
  3096. KeySym xkeysym = XkbKeycodeToKeysym(x11_display, xkeycode, keyboard_get_current_layout(), 0);
  3097. if (is_ascii_lower_case(xkeysym)) {
  3098. xkeysym -= ('a' - 'A');
  3099. }
  3100. Key key = KeyMappingX11::get_keycode(xkeysym);
  3101. // If not found, fallback to QWERTY.
  3102. // This should match the behavior of the event pump
  3103. if (key == Key::NONE) {
  3104. return p_keycode;
  3105. }
  3106. return (Key)(key | modifiers);
  3107. }
  3108. Key DisplayServerX11::keyboard_get_label_from_physical(Key p_keycode) const {
  3109. Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK;
  3110. Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK;
  3111. unsigned int xkeycode = KeyMappingX11::get_xlibcode(keycode_no_mod);
  3112. KeySym xkeysym = XkbKeycodeToKeysym(x11_display, xkeycode, keyboard_get_current_layout(), 0);
  3113. if (is_ascii_lower_case(xkeysym)) {
  3114. xkeysym -= ('a' - 'A');
  3115. }
  3116. Key key = KeyMappingX11::get_keycode(xkeysym);
  3117. #ifdef XKB_ENABLED
  3118. if (xkb_loaded_v08p) {
  3119. String keysym = String::chr(xkb_keysym_to_utf32(xkb_keysym_to_upper(xkeysym)));
  3120. key = fix_key_label(keysym[0], KeyMappingX11::get_keycode(xkeysym));
  3121. }
  3122. #endif
  3123. // If not found, fallback to QWERTY.
  3124. // This should match the behavior of the event pump
  3125. if (key == Key::NONE) {
  3126. return p_keycode;
  3127. }
  3128. return (Key)(key | modifiers);
  3129. }
  3130. bool DisplayServerX11::color_picker(const Callable &p_callback) {
  3131. WindowID window_id = last_focused_window;
  3132. if (!windows.has(window_id)) {
  3133. window_id = MAIN_WINDOW_ID;
  3134. }
  3135. String xid = vformat("x11:%x", (uint64_t)windows[window_id].x11_window);
  3136. return portal_desktop->color_picker(xid, p_callback);
  3137. }
  3138. DisplayServerX11::Property DisplayServerX11::_read_property(Display *p_display, Window p_window, Atom p_property) {
  3139. Atom actual_type = None;
  3140. int actual_format = 0;
  3141. unsigned long nitems = 0;
  3142. unsigned long bytes_after = 0;
  3143. unsigned char *ret = nullptr;
  3144. // Keep trying to read the property until there are no bytes unread.
  3145. if (p_property != None) {
  3146. int read_bytes = 1024;
  3147. do {
  3148. if (ret != nullptr) {
  3149. XFree(ret);
  3150. }
  3151. XGetWindowProperty(p_display, p_window, p_property, 0, read_bytes, False, AnyPropertyType,
  3152. &actual_type, &actual_format, &nitems, &bytes_after,
  3153. &ret);
  3154. read_bytes *= 2;
  3155. } while (bytes_after != 0);
  3156. }
  3157. Property p = { ret, actual_format, (int)nitems, actual_type };
  3158. return p;
  3159. }
  3160. static Atom pick_target_from_list(Display *p_display, const Atom *p_list, int p_count) {
  3161. static const char *target_type = "text/uri-list";
  3162. for (int i = 0; i < p_count; i++) {
  3163. Atom atom = p_list[i];
  3164. if (atom != None && get_atom_name(p_display, atom) == target_type) {
  3165. return atom;
  3166. }
  3167. }
  3168. return None;
  3169. }
  3170. static Atom pick_target_from_atoms(Display *p_disp, Atom p_t1, Atom p_t2, Atom p_t3) {
  3171. static const char *target_type = "text/uri-list";
  3172. if (p_t1 != None && get_atom_name(p_disp, p_t1) == target_type) {
  3173. return p_t1;
  3174. }
  3175. if (p_t2 != None && get_atom_name(p_disp, p_t2) == target_type) {
  3176. return p_t2;
  3177. }
  3178. if (p_t3 != None && get_atom_name(p_disp, p_t3) == target_type) {
  3179. return p_t3;
  3180. }
  3181. return None;
  3182. }
  3183. void DisplayServerX11::_get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state) {
  3184. state->set_shift_pressed((p_x11_state & ShiftMask));
  3185. state->set_ctrl_pressed((p_x11_state & ControlMask));
  3186. state->set_alt_pressed((p_x11_state & Mod1Mask /*|| p_x11_state&Mod5Mask*/)); //altgr should not count as alt
  3187. state->set_meta_pressed((p_x11_state & Mod4Mask));
  3188. }
  3189. void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, LocalVector<XEvent> &p_events, uint32_t &p_event_index, bool p_echo) {
  3190. WindowData &wd = windows[p_window];
  3191. // X11 functions don't know what const is
  3192. XKeyEvent *xkeyevent = p_event;
  3193. if (wd.ime_in_progress) {
  3194. return;
  3195. }
  3196. if (wd.ime_suppress_next_keyup) {
  3197. wd.ime_suppress_next_keyup = false;
  3198. if (xkeyevent->type != KeyPress) {
  3199. return;
  3200. }
  3201. }
  3202. // This code was pretty difficult to write.
  3203. // The docs stink and every toolkit seems to
  3204. // do it in a different way.
  3205. /* Phase 1, obtain a proper keysym */
  3206. // This was also very difficult to figure out.
  3207. // You'd expect you could just use Keysym provided by
  3208. // XKeycodeToKeysym to obtain internationalized
  3209. // input.. WRONG!!
  3210. // you must use XLookupString (???) which not only wastes
  3211. // cycles generating an unnecessary string, but also
  3212. // still works in half the cases. (won't handle deadkeys)
  3213. // For more complex input methods (deadkeys and more advanced)
  3214. // you have to use XmbLookupString (??).
  3215. // So then you have to choose which of both results
  3216. // you want to keep.
  3217. // This is a real bizarreness and cpu waster.
  3218. KeySym keysym_keycode = 0; // keysym used to find a keycode
  3219. KeySym keysym_unicode = 0; // keysym used to find unicode
  3220. // XLookupString returns keysyms usable as nice keycodes.
  3221. char str[256] = {};
  3222. XKeyEvent xkeyevent_no_mod = *xkeyevent;
  3223. xkeyevent_no_mod.state &= 0xFF00;
  3224. XLookupString(xkeyevent, str, 255, &keysym_unicode, nullptr);
  3225. XLookupString(&xkeyevent_no_mod, nullptr, 0, &keysym_keycode, nullptr);
  3226. String keysym;
  3227. #ifdef XKB_ENABLED
  3228. if (xkb_loaded_v08p) {
  3229. KeySym keysym_unicode_nm = 0; // keysym used to find unicode
  3230. XLookupString(&xkeyevent_no_mod, nullptr, 0, &keysym_unicode_nm, nullptr);
  3231. keysym = String::chr(xkb_keysym_to_utf32(xkb_keysym_to_upper(keysym_unicode_nm)));
  3232. }
  3233. #endif
  3234. // Meanwhile, XLookupString returns keysyms useful for unicode.
  3235. if (!xmbstring) {
  3236. // keep a temporary buffer for the string
  3237. xmbstring = (char *)memalloc(sizeof(char) * 8);
  3238. xmblen = 8;
  3239. }
  3240. if (xkeyevent->type == KeyPress && wd.xic) {
  3241. Status status;
  3242. #ifdef X_HAVE_UTF8_STRING
  3243. int utf8len = 8;
  3244. char *utf8string = (char *)memalloc(sizeof(char) * utf8len);
  3245. int utf8bytes = Xutf8LookupString(wd.xic, xkeyevent, utf8string,
  3246. utf8len - 1, &keysym_unicode, &status);
  3247. if (status == XBufferOverflow) {
  3248. utf8len = utf8bytes + 1;
  3249. utf8string = (char *)memrealloc(utf8string, utf8len);
  3250. utf8bytes = Xutf8LookupString(wd.xic, xkeyevent, utf8string,
  3251. utf8len - 1, &keysym_unicode, &status);
  3252. }
  3253. utf8string[utf8bytes] = '\0';
  3254. if (status == XLookupChars) {
  3255. bool keypress = xkeyevent->type == KeyPress;
  3256. Key keycode = Key::NONE;
  3257. if (KeyMappingX11::is_sym_numpad(keysym_unicode)) {
  3258. // Special case for numpad keys.
  3259. keycode = KeyMappingX11::get_keycode(keysym_unicode);
  3260. }
  3261. if (keycode == Key::NONE) {
  3262. keycode = KeyMappingX11::get_keycode(keysym_keycode);
  3263. }
  3264. Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
  3265. if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) {
  3266. keycode -= 'a' - 'A';
  3267. }
  3268. String tmp = String::utf8(utf8string, utf8bytes);
  3269. for (int i = 0; i < tmp.length(); i++) {
  3270. Ref<InputEventKey> k;
  3271. k.instantiate();
  3272. if (physical_keycode == Key::NONE && keycode == Key::NONE && tmp[i] == 0) {
  3273. continue;
  3274. }
  3275. if (keycode == Key::NONE) {
  3276. keycode = (Key)physical_keycode;
  3277. }
  3278. _get_key_modifier_state(xkeyevent->state, k);
  3279. k->set_window_id(p_window);
  3280. k->set_pressed(keypress);
  3281. k->set_keycode(keycode);
  3282. k->set_physical_keycode(physical_keycode);
  3283. if (!keysym.is_empty()) {
  3284. k->set_key_label(fix_key_label(keysym[0], keycode));
  3285. } else {
  3286. k->set_key_label(keycode);
  3287. }
  3288. if (keypress) {
  3289. k->set_unicode(fix_unicode(tmp[i]));
  3290. }
  3291. k->set_echo(false);
  3292. if (k->get_keycode() == Key::BACKTAB) {
  3293. //make it consistent across platforms.
  3294. k->set_keycode(Key::TAB);
  3295. k->set_physical_keycode(Key::TAB);
  3296. k->set_shift_pressed(true);
  3297. }
  3298. Input::get_singleton()->parse_input_event(k);
  3299. }
  3300. memfree(utf8string);
  3301. return;
  3302. }
  3303. memfree(utf8string);
  3304. #else
  3305. do {
  3306. int mnbytes = XmbLookupString(xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status);
  3307. xmbstring[mnbytes] = '\0';
  3308. if (status == XBufferOverflow) {
  3309. xmblen = mnbytes + 1;
  3310. xmbstring = (char *)memrealloc(xmbstring, xmblen);
  3311. }
  3312. } while (status == XBufferOverflow);
  3313. #endif
  3314. #ifdef XKB_ENABLED
  3315. } else if (xkeyevent->type == KeyPress && wd.xkb_state && xkb_loaded_v05p) {
  3316. xkb_compose_feed_result res = xkb_compose_state_feed(wd.xkb_state, keysym_unicode);
  3317. if (res == XKB_COMPOSE_FEED_ACCEPTED) {
  3318. if (xkb_compose_state_get_status(wd.xkb_state) == XKB_COMPOSE_COMPOSED) {
  3319. bool keypress = xkeyevent->type == KeyPress;
  3320. Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
  3321. KeyLocation key_location = KeyMappingX11::get_location(xkeyevent->keycode);
  3322. Key keycode = Key::NONE;
  3323. if (KeyMappingX11::is_sym_numpad(keysym_unicode)) {
  3324. // Special case for numpad keys.
  3325. keycode = KeyMappingX11::get_keycode(keysym_unicode);
  3326. }
  3327. if (keycode == Key::NONE) {
  3328. keycode = KeyMappingX11::get_keycode(keysym_keycode);
  3329. }
  3330. if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) {
  3331. keycode -= 'a' - 'A';
  3332. }
  3333. char str_xkb[256] = {};
  3334. int str_xkb_size = xkb_compose_state_get_utf8(wd.xkb_state, str_xkb, 255);
  3335. String tmp = String::utf8(str_xkb, str_xkb_size);
  3336. for (int i = 0; i < tmp.length(); i++) {
  3337. Ref<InputEventKey> k;
  3338. k.instantiate();
  3339. if (physical_keycode == Key::NONE && keycode == Key::NONE && tmp[i] == 0) {
  3340. continue;
  3341. }
  3342. if (keycode == Key::NONE) {
  3343. keycode = (Key)physical_keycode;
  3344. }
  3345. _get_key_modifier_state(xkeyevent->state, k);
  3346. k->set_window_id(p_window);
  3347. k->set_pressed(keypress);
  3348. k->set_keycode(keycode);
  3349. k->set_physical_keycode(physical_keycode);
  3350. if (!keysym.is_empty()) {
  3351. k->set_key_label(fix_key_label(keysym[0], keycode));
  3352. } else {
  3353. k->set_key_label(keycode);
  3354. }
  3355. if (keypress) {
  3356. k->set_unicode(fix_unicode(tmp[i]));
  3357. }
  3358. k->set_location(key_location);
  3359. k->set_echo(false);
  3360. if (k->get_keycode() == Key::BACKTAB) {
  3361. //make it consistent across platforms.
  3362. k->set_keycode(Key::TAB);
  3363. k->set_physical_keycode(Key::TAB);
  3364. k->set_shift_pressed(true);
  3365. }
  3366. Input::get_singleton()->parse_input_event(k);
  3367. }
  3368. return;
  3369. }
  3370. }
  3371. #endif
  3372. }
  3373. /* Phase 2, obtain a Godot keycode from the keysym */
  3374. // KeyMappingX11 just translated the X11 keysym to a PIGUI
  3375. // keysym, so it works in all platforms the same.
  3376. Key keycode = Key::NONE;
  3377. if (KeyMappingX11::is_sym_numpad(keysym_unicode) || KeyMappingX11::is_sym_numpad(keysym_keycode)) {
  3378. // Special case for numpad keys.
  3379. keycode = KeyMappingX11::get_keycode(keysym_unicode);
  3380. }
  3381. if (keycode == Key::NONE) {
  3382. keycode = KeyMappingX11::get_keycode(keysym_keycode);
  3383. }
  3384. Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
  3385. KeyLocation key_location = KeyMappingX11::get_location(xkeyevent->keycode);
  3386. /* Phase 3, obtain a unicode character from the keysym */
  3387. // KeyMappingX11 also translates keysym to unicode.
  3388. // It does a binary search on a table to translate
  3389. // most properly.
  3390. char32_t unicode = keysym_unicode > 0 ? KeyMappingX11::get_unicode_from_keysym(keysym_unicode) : 0;
  3391. /* Phase 4, determine if event must be filtered */
  3392. // This seems to be a side-effect of using XIM.
  3393. // XFilterEvent looks like a core X11 function,
  3394. // but it's actually just used to see if we must
  3395. // ignore a deadkey, or events XIM determines
  3396. // must not reach the actual gui.
  3397. // Guess it was a design problem of the extension
  3398. bool keypress = xkeyevent->type == KeyPress;
  3399. if (physical_keycode == Key::NONE && keycode == Key::NONE && unicode == 0) {
  3400. return;
  3401. }
  3402. if (keycode == Key::NONE) {
  3403. keycode = (Key)physical_keycode;
  3404. }
  3405. /* Phase 5, determine modifier mask */
  3406. // No problems here, except I had no way to
  3407. // know Mod1 was ALT and Mod4 was META (applekey/winkey)
  3408. // just tried Mods until i found them.
  3409. //print_verbose("mod1: "+itos(xkeyevent->state&Mod1Mask)+" mod 5: "+itos(xkeyevent->state&Mod5Mask));
  3410. Ref<InputEventKey> k;
  3411. k.instantiate();
  3412. k->set_window_id(p_window);
  3413. _get_key_modifier_state(xkeyevent->state, k);
  3414. /* Phase 6, determine echo character */
  3415. // Echo characters in X11 are a keyrelease and a keypress
  3416. // one after the other with the (almot) same timestamp.
  3417. // To detect them, i compare to the next event in list and
  3418. // check that their difference in time is below a threshold.
  3419. if (xkeyevent->type != KeyPress) {
  3420. p_echo = false;
  3421. // make sure there are events pending,
  3422. // so this call won't block.
  3423. if (p_event_index + 1 < p_events.size()) {
  3424. XEvent &peek_event = p_events[p_event_index + 1];
  3425. // I'm using a threshold of 5 msecs,
  3426. // since sometimes there seems to be a little
  3427. // jitter. I'm still not convinced that all this approach
  3428. // is correct, but the xorg developers are
  3429. // not very helpful today.
  3430. #define ABSDIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
  3431. ::Time threshold = ABSDIFF(peek_event.xkey.time, xkeyevent->time);
  3432. #undef ABSDIFF
  3433. if (peek_event.type == KeyPress && threshold < 5) {
  3434. KeySym rk;
  3435. XLookupString((XKeyEvent *)&peek_event, str, 256, &rk, nullptr);
  3436. if (rk == keysym_keycode) {
  3437. // Consume to next event.
  3438. ++p_event_index;
  3439. _handle_key_event(p_window, (XKeyEvent *)&peek_event, p_events, p_event_index, true);
  3440. return; //ignore current, echo next
  3441. }
  3442. }
  3443. // use the time from peek_event so it always works
  3444. }
  3445. // save the time to check for echo when keypress happens
  3446. }
  3447. /* Phase 7, send event to Window */
  3448. k->set_pressed(keypress);
  3449. if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) {
  3450. keycode -= int('a' - 'A');
  3451. }
  3452. k->set_keycode(keycode);
  3453. k->set_physical_keycode((Key)physical_keycode);
  3454. if (!keysym.is_empty()) {
  3455. k->set_key_label(fix_key_label(keysym[0], keycode));
  3456. } else {
  3457. k->set_key_label(keycode);
  3458. }
  3459. if (keypress) {
  3460. k->set_unicode(fix_unicode(unicode));
  3461. }
  3462. k->set_location(key_location);
  3463. k->set_echo(p_echo);
  3464. if (k->get_keycode() == Key::BACKTAB) {
  3465. //make it consistent across platforms.
  3466. k->set_keycode(Key::TAB);
  3467. k->set_physical_keycode(Key::TAB);
  3468. k->set_shift_pressed(true);
  3469. }
  3470. //don't set mod state if modifier keys are released by themselves
  3471. //else event.is_action() will not work correctly here
  3472. if (!k->is_pressed()) {
  3473. if (k->get_keycode() == Key::SHIFT) {
  3474. k->set_shift_pressed(false);
  3475. } else if (k->get_keycode() == Key::CTRL) {
  3476. k->set_ctrl_pressed(false);
  3477. } else if (k->get_keycode() == Key::ALT) {
  3478. k->set_alt_pressed(false);
  3479. } else if (k->get_keycode() == Key::META) {
  3480. k->set_meta_pressed(false);
  3481. }
  3482. }
  3483. bool last_is_pressed = Input::get_singleton()->is_key_pressed(k->get_keycode());
  3484. if (k->is_pressed()) {
  3485. if (last_is_pressed) {
  3486. k->set_echo(true);
  3487. }
  3488. }
  3489. Input::get_singleton()->parse_input_event(k);
  3490. }
  3491. Atom DisplayServerX11::_process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property, Atom p_selection) const {
  3492. if (p_target == XInternAtom(x11_display, "TARGETS", 0)) {
  3493. // Request to list all supported targets.
  3494. Atom data[9];
  3495. data[0] = XInternAtom(x11_display, "TARGETS", 0);
  3496. data[1] = XInternAtom(x11_display, "SAVE_TARGETS", 0);
  3497. data[2] = XInternAtom(x11_display, "MULTIPLE", 0);
  3498. data[3] = XInternAtom(x11_display, "UTF8_STRING", 0);
  3499. data[4] = XInternAtom(x11_display, "COMPOUND_TEXT", 0);
  3500. data[5] = XInternAtom(x11_display, "TEXT", 0);
  3501. data[6] = XA_STRING;
  3502. data[7] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0);
  3503. data[8] = XInternAtom(x11_display, "text/plain", 0);
  3504. XChangeProperty(x11_display,
  3505. p_requestor,
  3506. p_property,
  3507. XA_ATOM,
  3508. 32,
  3509. PropModeReplace,
  3510. (unsigned char *)&data,
  3511. std::size(data));
  3512. return p_property;
  3513. } else if (p_target == XInternAtom(x11_display, "SAVE_TARGETS", 0)) {
  3514. // Request to check if SAVE_TARGETS is supported, nothing special to do.
  3515. XChangeProperty(x11_display,
  3516. p_requestor,
  3517. p_property,
  3518. XInternAtom(x11_display, "NULL", False),
  3519. 32,
  3520. PropModeReplace,
  3521. nullptr,
  3522. 0);
  3523. return p_property;
  3524. } else if (p_target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
  3525. p_target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
  3526. p_target == XInternAtom(x11_display, "TEXT", 0) ||
  3527. p_target == XA_STRING ||
  3528. p_target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
  3529. p_target == XInternAtom(x11_display, "text/plain", 0)) {
  3530. // Directly using internal clipboard because we know our window
  3531. // is the owner during a selection request.
  3532. CharString clip;
  3533. static const char *target_type = "PRIMARY";
  3534. if (p_selection != None && get_atom_name(x11_display, p_selection) == target_type) {
  3535. clip = internal_clipboard_primary.utf8();
  3536. } else {
  3537. clip = internal_clipboard.utf8();
  3538. }
  3539. XChangeProperty(x11_display,
  3540. p_requestor,
  3541. p_property,
  3542. p_target,
  3543. 8,
  3544. PropModeReplace,
  3545. (unsigned char *)clip.get_data(),
  3546. clip.length());
  3547. return p_property;
  3548. } else {
  3549. char *target_name = XGetAtomName(x11_display, p_target);
  3550. print_verbose(vformat("Target '%s' not supported.", target_name));
  3551. if (target_name) {
  3552. XFree(target_name);
  3553. }
  3554. return None;
  3555. }
  3556. }
  3557. void DisplayServerX11::_handle_selection_request_event(XSelectionRequestEvent *p_event) const {
  3558. XEvent respond;
  3559. if (p_event->target == XInternAtom(x11_display, "MULTIPLE", 0)) {
  3560. // Request for multiple target conversions at once.
  3561. Atom atom_pair = XInternAtom(x11_display, "ATOM_PAIR", False);
  3562. respond.xselection.property = None;
  3563. Atom type;
  3564. int format;
  3565. unsigned long len;
  3566. unsigned long remaining;
  3567. unsigned char *data = nullptr;
  3568. if (XGetWindowProperty(x11_display, p_event->requestor, p_event->property, 0, LONG_MAX, False, atom_pair, &type, &format, &len, &remaining, &data) == Success) {
  3569. if ((len >= 2) && data) {
  3570. Atom *targets = (Atom *)data;
  3571. for (uint64_t i = 0; i < len; i += 2) {
  3572. Atom target = targets[i];
  3573. Atom &property = targets[i + 1];
  3574. property = _process_selection_request_target(target, p_event->requestor, property, p_event->selection);
  3575. }
  3576. XChangeProperty(x11_display,
  3577. p_event->requestor,
  3578. p_event->property,
  3579. atom_pair,
  3580. 32,
  3581. PropModeReplace,
  3582. (unsigned char *)targets,
  3583. len);
  3584. respond.xselection.property = p_event->property;
  3585. }
  3586. XFree(data);
  3587. }
  3588. } else {
  3589. // Request for target conversion.
  3590. respond.xselection.property = _process_selection_request_target(p_event->target, p_event->requestor, p_event->property, p_event->selection);
  3591. }
  3592. respond.xselection.type = SelectionNotify;
  3593. respond.xselection.display = p_event->display;
  3594. respond.xselection.requestor = p_event->requestor;
  3595. respond.xselection.selection = p_event->selection;
  3596. respond.xselection.target = p_event->target;
  3597. respond.xselection.time = p_event->time;
  3598. XSendEvent(x11_display, p_event->requestor, True, NoEventMask, &respond);
  3599. XFlush(x11_display);
  3600. }
  3601. int DisplayServerX11::_xim_preedit_start_callback(::XIM xim, ::XPointer client_data,
  3602. ::XPointer call_data) {
  3603. DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
  3604. WindowID window_id = ds->_get_focused_window_or_popup();
  3605. WindowData &wd = ds->windows[window_id];
  3606. if (wd.ime_active) {
  3607. wd.ime_in_progress = true;
  3608. }
  3609. return -1; // Allow preedit strings of any length (no limit).
  3610. }
  3611. void DisplayServerX11::_xim_preedit_done_callback(::XIM xim, ::XPointer client_data,
  3612. ::XPointer call_data) {
  3613. DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
  3614. WindowID window_id = ds->_get_focused_window_or_popup();
  3615. WindowData &wd = ds->windows[window_id];
  3616. if (wd.ime_active) {
  3617. wd.ime_in_progress = false;
  3618. wd.ime_suppress_next_keyup = true;
  3619. }
  3620. }
  3621. void DisplayServerX11::_xim_preedit_draw_callback(::XIM xim, ::XPointer client_data,
  3622. ::XIMPreeditDrawCallbackStruct *call_data) {
  3623. DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
  3624. WindowID window_id = ds->_get_focused_window_or_popup();
  3625. WindowData &wd = ds->windows[window_id];
  3626. XIMText *xim_text = call_data->text;
  3627. if (wd.ime_active) {
  3628. if (xim_text != nullptr) {
  3629. String changed_text;
  3630. if (xim_text->encoding_is_wchar) {
  3631. changed_text = String(xim_text->string.wide_char);
  3632. } else {
  3633. changed_text.append_utf8(xim_text->string.multi_byte);
  3634. }
  3635. if (call_data->chg_length < 0) {
  3636. ds->im_text = ds->im_text.substr(0, call_data->chg_first) + changed_text;
  3637. } else {
  3638. ds->im_text = ds->im_text.substr(0, call_data->chg_first) + changed_text + ds->im_text.substr(call_data->chg_length);
  3639. }
  3640. // Find the start and end of the selection.
  3641. int start = 0, count = 0;
  3642. for (int i = 0; i < xim_text->length; i++) {
  3643. if (xim_text->feedback[i] & XIMReverse) {
  3644. if (count == 0) {
  3645. start = i;
  3646. count = 1;
  3647. } else {
  3648. count++;
  3649. }
  3650. }
  3651. }
  3652. if (count > 0) {
  3653. ds->im_selection = Point2i(start + call_data->chg_first, count);
  3654. } else {
  3655. ds->im_selection = Point2i(call_data->caret, 0);
  3656. }
  3657. } else {
  3658. ds->im_text = String();
  3659. ds->im_selection = Point2i();
  3660. }
  3661. callable_mp((Object *)OS_Unix::get_singleton()->get_main_loop(), &Object::notification).call_deferred(MainLoop::NOTIFICATION_OS_IME_UPDATE, false);
  3662. }
  3663. }
  3664. void DisplayServerX11::_xim_preedit_caret_callback(::XIM xim, ::XPointer client_data,
  3665. ::XIMPreeditCaretCallbackStruct *call_data) {
  3666. }
  3667. void DisplayServerX11::_xim_destroy_callback(::XIM im, ::XPointer client_data,
  3668. ::XPointer call_data) {
  3669. WARN_PRINT("Input method stopped");
  3670. DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
  3671. ds->xim = nullptr;
  3672. for (KeyValue<WindowID, WindowData> &E : ds->windows) {
  3673. E.value.xic = nullptr;
  3674. }
  3675. }
  3676. void DisplayServerX11::_window_changed(XEvent *event) {
  3677. WindowID window_id = MAIN_WINDOW_ID;
  3678. // Assign the event to the relevant window
  3679. for (const KeyValue<WindowID, WindowData> &E : windows) {
  3680. if (event->xany.window == E.value.x11_window) {
  3681. window_id = E.key;
  3682. break;
  3683. }
  3684. }
  3685. Rect2i new_rect;
  3686. WindowData &wd = windows[window_id];
  3687. if (wd.x11_window != event->xany.window) { // Check if the correct window, in case it was not main window or anything else
  3688. return;
  3689. }
  3690. // Query display server about a possible new window state.
  3691. wd.fullscreen = _window_fullscreen_check(window_id);
  3692. wd.maximized = _window_maximize_check(window_id, "_NET_WM_STATE") && !wd.fullscreen;
  3693. wd.minimized = _window_minimize_check(window_id) && !wd.fullscreen && !wd.maximized;
  3694. // Readjusting the window position if the window is being reparented by the window manager for decoration
  3695. Window root, parent, *children;
  3696. unsigned int nchildren;
  3697. if (XQueryTree(x11_display, wd.x11_window, &root, &parent, &children, &nchildren) && wd.parent != parent) {
  3698. wd.parent = parent;
  3699. if (!wd.embed_parent) {
  3700. window_set_position(wd.position, window_id);
  3701. }
  3702. }
  3703. XFree(children);
  3704. {
  3705. //the position in xconfigure is not useful here, obtain it manually
  3706. int x = 0, y = 0;
  3707. Window child;
  3708. XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
  3709. new_rect.position.x = x;
  3710. new_rect.position.y = y;
  3711. new_rect.size.width = event->xconfigure.width;
  3712. new_rect.size.height = event->xconfigure.height;
  3713. }
  3714. if (new_rect == Rect2i(wd.position, wd.size)) {
  3715. return;
  3716. }
  3717. wd.position = new_rect.position;
  3718. wd.size = new_rect.size;
  3719. #if defined(RD_ENABLED)
  3720. if (rendering_context) {
  3721. rendering_context->window_set_size(window_id, wd.size.width, wd.size.height);
  3722. }
  3723. #endif
  3724. #if defined(GLES3_ENABLED)
  3725. if (gl_manager) {
  3726. gl_manager->window_resize(window_id, wd.size.width, wd.size.height);
  3727. }
  3728. if (gl_manager_egl) {
  3729. gl_manager_egl->window_resize(window_id, wd.size.width, wd.size.height);
  3730. }
  3731. #endif
  3732. if (wd.rect_changed_callback.is_valid()) {
  3733. wd.rect_changed_callback.call(new_rect);
  3734. }
  3735. }
  3736. DisplayServer::WindowID DisplayServerX11::_get_focused_window_or_popup() const {
  3737. const List<WindowID>::Element *E = popup_list.back();
  3738. if (E) {
  3739. return E->get();
  3740. }
  3741. return last_focused_window;
  3742. }
  3743. void DisplayServerX11::_dispatch_input_events(const Ref<InputEvent> &p_event) {
  3744. static_cast<DisplayServerX11 *>(get_singleton())->_dispatch_input_event(p_event);
  3745. }
  3746. void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) {
  3747. {
  3748. List<WindowID>::Element *E = popup_list.back();
  3749. if (E && Object::cast_to<InputEventKey>(*p_event)) {
  3750. // Redirect keyboard input to active popup.
  3751. if (windows.has(E->get())) {
  3752. Callable callable = windows[E->get()].input_event_callback;
  3753. if (callable.is_valid()) {
  3754. callable.call(p_event);
  3755. }
  3756. }
  3757. return;
  3758. }
  3759. }
  3760. Ref<InputEventFromWindow> event_from_window = p_event;
  3761. if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
  3762. // Send to a single window.
  3763. if (windows.has(event_from_window->get_window_id())) {
  3764. Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
  3765. if (callable.is_valid()) {
  3766. callable.call(p_event);
  3767. }
  3768. }
  3769. } else {
  3770. // Send to all windows. Copy all pending callbacks, since callback can erase window.
  3771. Vector<Callable> cbs;
  3772. for (KeyValue<WindowID, WindowData> &E : windows) {
  3773. Callable callable = E.value.input_event_callback;
  3774. if (callable.is_valid()) {
  3775. cbs.push_back(callable);
  3776. }
  3777. }
  3778. for (const Callable &cb : cbs) {
  3779. cb.call(p_event);
  3780. }
  3781. }
  3782. }
  3783. void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_event) {
  3784. if (wd.event_callback.is_valid()) {
  3785. Variant event = int(p_event);
  3786. wd.event_callback.call(event);
  3787. }
  3788. }
  3789. void DisplayServerX11::_set_input_focus(Window p_window, int p_revert_to) {
  3790. Window focused_window;
  3791. int focus_ret_state;
  3792. XGetInputFocus(x11_display, &focused_window, &focus_ret_state);
  3793. // Only attempt to change focus if the window isn't already focused, in order to
  3794. // prevent issues with Godot stealing input focus with alternative window managers.
  3795. if (p_window != focused_window) {
  3796. XSetInputFocus(x11_display, p_window, p_revert_to, CurrentTime);
  3797. }
  3798. }
  3799. void DisplayServerX11::_poll_events_thread(void *ud) {
  3800. DisplayServerX11 *display_server = static_cast<DisplayServerX11 *>(ud);
  3801. display_server->_poll_events();
  3802. }
  3803. Bool DisplayServerX11::_predicate_all_events(Display *display, XEvent *event, XPointer arg) {
  3804. // Just accept all events.
  3805. return True;
  3806. }
  3807. bool DisplayServerX11::_wait_for_events() const {
  3808. int x11_fd = ConnectionNumber(x11_display);
  3809. fd_set in_fds;
  3810. XFlush(x11_display);
  3811. FD_ZERO(&in_fds);
  3812. FD_SET(x11_fd, &in_fds);
  3813. struct timeval tv;
  3814. tv.tv_usec = 0;
  3815. tv.tv_sec = 1;
  3816. // Wait for next event or timeout.
  3817. int num_ready_fds = select(x11_fd + 1, &in_fds, nullptr, nullptr, &tv);
  3818. if (num_ready_fds > 0) {
  3819. // Event received.
  3820. return true;
  3821. } else {
  3822. // Error or timeout.
  3823. if (num_ready_fds < 0) {
  3824. ERR_PRINT("_wait_for_events: select error: " + itos(errno));
  3825. }
  3826. return false;
  3827. }
  3828. }
  3829. void DisplayServerX11::_poll_events() {
  3830. while (!events_thread_done.is_set()) {
  3831. _wait_for_events();
  3832. // Process events from the queue.
  3833. {
  3834. MutexLock mutex_lock(events_mutex);
  3835. _check_pending_events(polled_events);
  3836. }
  3837. }
  3838. }
  3839. void DisplayServerX11::_check_pending_events(LocalVector<XEvent> &r_events) {
  3840. // Flush to make sure to gather all pending events.
  3841. XFlush(x11_display);
  3842. // Non-blocking wait for next event and remove it from the queue.
  3843. XEvent ev = {};
  3844. while (XCheckIfEvent(x11_display, &ev, _predicate_all_events, nullptr)) {
  3845. // Check if the input manager wants to process the event.
  3846. if (XFilterEvent(&ev, None)) {
  3847. // Event has been filtered by the Input Manager,
  3848. // it has to be ignored and a new one will be received.
  3849. continue;
  3850. }
  3851. // Handle selection request events directly in the event thread, because
  3852. // communication through the x server takes several events sent back and forth
  3853. // and we don't want to block other programs while processing only one each frame.
  3854. if (ev.type == SelectionRequest) {
  3855. _handle_selection_request_event(&(ev.xselectionrequest));
  3856. continue;
  3857. }
  3858. r_events.push_back(ev);
  3859. }
  3860. }
  3861. DisplayServer::WindowID DisplayServerX11::window_get_active_popup() const {
  3862. const List<WindowID>::Element *E = popup_list.back();
  3863. if (E) {
  3864. return E->get();
  3865. } else {
  3866. return INVALID_WINDOW_ID;
  3867. }
  3868. }
  3869. void DisplayServerX11::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) {
  3870. _THREAD_SAFE_METHOD_
  3871. ERR_FAIL_COND(!windows.has(p_window));
  3872. WindowData &wd = windows[p_window];
  3873. wd.parent_safe_rect = p_rect;
  3874. }
  3875. Rect2i DisplayServerX11::window_get_popup_safe_rect(WindowID p_window) const {
  3876. _THREAD_SAFE_METHOD_
  3877. ERR_FAIL_COND_V(!windows.has(p_window), Rect2i());
  3878. const WindowData &wd = windows[p_window];
  3879. return wd.parent_safe_rect;
  3880. }
  3881. void DisplayServerX11::popup_open(WindowID p_window) {
  3882. _THREAD_SAFE_METHOD_
  3883. bool has_popup_ancestor = false;
  3884. WindowID transient_root = p_window;
  3885. while (true) {
  3886. WindowID parent = windows[transient_root].transient_parent;
  3887. if (parent == INVALID_WINDOW_ID) {
  3888. break;
  3889. } else {
  3890. transient_root = parent;
  3891. if (windows[parent].is_popup) {
  3892. has_popup_ancestor = true;
  3893. break;
  3894. }
  3895. }
  3896. }
  3897. // Detect tooltips and other similar popups that shouldn't block input to their parent.
  3898. bool ignores_input = window_get_flag(WINDOW_FLAG_NO_FOCUS, p_window) && window_get_flag(WINDOW_FLAG_MOUSE_PASSTHROUGH, p_window);
  3899. WindowData &wd = windows[p_window];
  3900. if (wd.is_popup || (has_popup_ancestor && !ignores_input)) {
  3901. // Find current popup parent, or root popup if new window is not transient.
  3902. List<WindowID>::Element *C = nullptr;
  3903. List<WindowID>::Element *E = popup_list.back();
  3904. while (E) {
  3905. if (wd.transient_parent != E->get() || wd.transient_parent == INVALID_WINDOW_ID) {
  3906. C = E;
  3907. E = E->prev();
  3908. } else {
  3909. break;
  3910. }
  3911. }
  3912. if (C) {
  3913. _send_window_event(windows[C->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
  3914. }
  3915. time_since_popup = OS::get_singleton()->get_ticks_msec();
  3916. popup_list.push_back(p_window);
  3917. }
  3918. }
  3919. void DisplayServerX11::popup_close(WindowID p_window) {
  3920. _THREAD_SAFE_METHOD_
  3921. List<WindowID>::Element *E = popup_list.find(p_window);
  3922. while (E) {
  3923. List<WindowID>::Element *F = E->next();
  3924. WindowID win_id = E->get();
  3925. popup_list.erase(E);
  3926. if (win_id != p_window) {
  3927. // Only request close on related windows, not this window. We are already processing it.
  3928. _send_window_event(windows[win_id], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
  3929. }
  3930. E = F;
  3931. }
  3932. }
  3933. bool DisplayServerX11::mouse_process_popups() {
  3934. _THREAD_SAFE_METHOD_
  3935. if (popup_list.is_empty()) {
  3936. return false;
  3937. }
  3938. uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup;
  3939. if (delta < 250) {
  3940. return false;
  3941. }
  3942. int number_of_screens = XScreenCount(x11_display);
  3943. bool closed = false;
  3944. for (int i = 0; i < number_of_screens; i++) {
  3945. Window root, child;
  3946. int root_x, root_y, win_x, win_y;
  3947. unsigned int mask;
  3948. if (XQueryPointer(x11_display, XRootWindow(x11_display, i), &root, &child, &root_x, &root_y, &win_x, &win_y, &mask)) {
  3949. XWindowAttributes root_attrs;
  3950. XGetWindowAttributes(x11_display, root, &root_attrs);
  3951. Vector2i pos = Vector2i(root_attrs.x + root_x, root_attrs.y + root_y);
  3952. if (mask != last_mouse_monitor_mask) {
  3953. if (((mask & Button1Mask) || (mask & Button2Mask) || (mask & Button3Mask) || (mask & Button4Mask) || (mask & Button5Mask))) {
  3954. List<WindowID>::Element *C = nullptr;
  3955. List<WindowID>::Element *E = popup_list.back();
  3956. // Find top popup to close.
  3957. while (E) {
  3958. // Popup window area.
  3959. Rect2i win_rect = Rect2i(window_get_position_with_decorations(E->get()), window_get_size_with_decorations(E->get()));
  3960. // Area of the parent window, which responsible for opening sub-menu.
  3961. Rect2i safe_rect = window_get_popup_safe_rect(E->get());
  3962. if (win_rect.has_point(pos)) {
  3963. break;
  3964. } else if (safe_rect != Rect2i() && safe_rect.has_point(pos)) {
  3965. break;
  3966. } else {
  3967. C = E;
  3968. E = E->prev();
  3969. }
  3970. }
  3971. if (C) {
  3972. _send_window_event(windows[C->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
  3973. closed = true;
  3974. }
  3975. }
  3976. }
  3977. last_mouse_monitor_mask = mask;
  3978. }
  3979. }
  3980. return closed;
  3981. }
  3982. bool DisplayServerX11::_window_focus_check() {
  3983. Window focused_window;
  3984. int focus_ret_state;
  3985. XGetInputFocus(x11_display, &focused_window, &focus_ret_state);
  3986. bool has_focus = false;
  3987. for (const KeyValue<int, DisplayServerX11::WindowData> &wid : windows) {
  3988. if (wid.value.x11_window == focused_window || (wid.value.xic && wid.value.ime_active && wid.value.x11_xim_window == focused_window)) {
  3989. has_focus = true;
  3990. break;
  3991. }
  3992. }
  3993. return has_focus;
  3994. }
  3995. void DisplayServerX11::process_events() {
  3996. ERR_FAIL_COND(!Thread::is_main_thread());
  3997. _THREAD_SAFE_LOCK_
  3998. #ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
  3999. static int frame = 0;
  4000. ++frame;
  4001. #endif
  4002. bool ignore_events = mouse_process_popups();
  4003. if (app_focused) {
  4004. //verify that one of the windows has focus, else send focus out notification
  4005. bool focus_found = false;
  4006. for (const KeyValue<WindowID, WindowData> &E : windows) {
  4007. if (E.value.focused) {
  4008. focus_found = true;
  4009. break;
  4010. }
  4011. }
  4012. if (!focus_found) {
  4013. uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_no_focus;
  4014. if (delta > 250) {
  4015. //X11 can go between windows and have no focus for a while, when creating them or something else. Use this as safety to avoid unnecessary focus in/outs.
  4016. if (OS::get_singleton()->get_main_loop()) {
  4017. DEBUG_LOG_X11("All focus lost, triggering NOTIFICATION_APPLICATION_FOCUS_OUT\n");
  4018. OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
  4019. }
  4020. app_focused = false;
  4021. }
  4022. } else {
  4023. time_since_no_focus = OS::get_singleton()->get_ticks_msec();
  4024. }
  4025. }
  4026. do_mouse_warp = false;
  4027. // Is the current mouse mode one where it needs to be grabbed.
  4028. bool mouse_mode_grab = mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN;
  4029. xi.pressure = 0;
  4030. xi.tilt = Vector2();
  4031. xi.pressure_supported = false;
  4032. LocalVector<XEvent> events;
  4033. {
  4034. // Block events polling while flushing events.
  4035. MutexLock mutex_lock(events_mutex);
  4036. events = polled_events;
  4037. polled_events.clear();
  4038. // Check for more pending events to avoid an extra frame delay.
  4039. _check_pending_events(events);
  4040. }
  4041. for (uint32_t event_index = 0; event_index < events.size(); ++event_index) {
  4042. XEvent &event = events[event_index];
  4043. bool ime_window_event = false;
  4044. WindowID window_id = MAIN_WINDOW_ID;
  4045. // Assign the event to the relevant window
  4046. for (const KeyValue<WindowID, WindowData> &E : windows) {
  4047. if (event.xany.window == E.value.x11_window) {
  4048. window_id = E.key;
  4049. break;
  4050. }
  4051. if (event.xany.window == E.value.x11_xim_window) {
  4052. window_id = E.key;
  4053. ime_window_event = true;
  4054. break;
  4055. }
  4056. }
  4057. if (XGetEventData(x11_display, &event.xcookie)) {
  4058. if (event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
  4059. XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
  4060. switch (event_data->evtype) {
  4061. case XI_HierarchyChanged:
  4062. case XI_DeviceChanged: {
  4063. _refresh_device_info();
  4064. } break;
  4065. case XI_RawMotion: {
  4066. if (ime_window_event || ignore_events) {
  4067. break;
  4068. }
  4069. XIRawEvent *raw_event = (XIRawEvent *)event_data;
  4070. int device_id = raw_event->sourceid;
  4071. // Determine the axis used (called valuators in XInput for some forsaken reason)
  4072. // Mask is a bitmask indicating which axes are involved.
  4073. // We are interested in the values of axes 0 and 1.
  4074. if (raw_event->valuators.mask_len <= 0) {
  4075. break;
  4076. }
  4077. const double *values = raw_event->raw_values;
  4078. double rel_x = 0.0;
  4079. double rel_y = 0.0;
  4080. if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_ABSX)) {
  4081. rel_x = *values;
  4082. values++;
  4083. }
  4084. if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_ABSY)) {
  4085. rel_y = *values;
  4086. values++;
  4087. }
  4088. if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_PRESSURE)) {
  4089. HashMap<int, Vector2>::Iterator pen_pressure = xi.pen_pressure_range.find(device_id);
  4090. if (pen_pressure) {
  4091. Vector2 pen_pressure_range = pen_pressure->value;
  4092. if (pen_pressure_range != Vector2()) {
  4093. xi.pressure_supported = true;
  4094. xi.pressure = (*values - pen_pressure_range[0]) /
  4095. (pen_pressure_range[1] - pen_pressure_range[0]);
  4096. }
  4097. }
  4098. values++;
  4099. }
  4100. if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_TILTX)) {
  4101. HashMap<int, Vector2>::Iterator pen_tilt_x = xi.pen_tilt_x_range.find(device_id);
  4102. if (pen_tilt_x) {
  4103. Vector2 pen_tilt_x_range = pen_tilt_x->value;
  4104. if (pen_tilt_x_range[0] != 0 && *values < 0) {
  4105. xi.tilt.x = *values / -pen_tilt_x_range[0];
  4106. } else if (pen_tilt_x_range[1] != 0) {
  4107. xi.tilt.x = *values / pen_tilt_x_range[1];
  4108. }
  4109. }
  4110. values++;
  4111. }
  4112. if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_TILTY)) {
  4113. HashMap<int, Vector2>::Iterator pen_tilt_y = xi.pen_tilt_y_range.find(device_id);
  4114. if (pen_tilt_y) {
  4115. Vector2 pen_tilt_y_range = pen_tilt_y->value;
  4116. if (pen_tilt_y_range[0] != 0 && *values < 0) {
  4117. xi.tilt.y = *values / -pen_tilt_y_range[0];
  4118. } else if (pen_tilt_y_range[1] != 0) {
  4119. xi.tilt.y = *values / pen_tilt_y_range[1];
  4120. }
  4121. }
  4122. values++;
  4123. }
  4124. HashMap<int, bool>::Iterator pen_inverted = xi.pen_inverted_devices.find(device_id);
  4125. if (pen_inverted) {
  4126. xi.pen_inverted = pen_inverted->value;
  4127. }
  4128. // https://bugs.freedesktop.org/show_bug.cgi?id=71609
  4129. // http://lists.libsdl.org/pipermail/commits-libsdl.org/2015-June/000282.html
  4130. if (raw_event->time == xi.last_relative_time && rel_x == xi.relative_motion.x && rel_y == xi.relative_motion.y) {
  4131. break; // Flush duplicate to avoid overly fast motion
  4132. }
  4133. xi.old_raw_pos.x = xi.raw_pos.x;
  4134. xi.old_raw_pos.y = xi.raw_pos.y;
  4135. xi.raw_pos.x = rel_x;
  4136. xi.raw_pos.y = rel_y;
  4137. HashMap<int, Vector2>::Iterator abs_info = xi.absolute_devices.find(device_id);
  4138. if (abs_info) {
  4139. // Absolute mode device
  4140. Vector2 mult = abs_info->value;
  4141. xi.relative_motion.x += (xi.raw_pos.x - xi.old_raw_pos.x) * mult.x;
  4142. xi.relative_motion.y += (xi.raw_pos.y - xi.old_raw_pos.y) * mult.y;
  4143. } else {
  4144. // Relative mode device
  4145. xi.relative_motion.x = xi.raw_pos.x;
  4146. xi.relative_motion.y = xi.raw_pos.y;
  4147. }
  4148. xi.last_relative_time = raw_event->time;
  4149. } break;
  4150. #ifdef TOUCH_ENABLED
  4151. case XI_TouchBegin:
  4152. case XI_TouchEnd: {
  4153. if (ime_window_event || ignore_events) {
  4154. break;
  4155. }
  4156. bool is_begin = event_data->evtype == XI_TouchBegin;
  4157. int index = event_data->detail;
  4158. Vector2 pos = Vector2(event_data->event_x, event_data->event_y);
  4159. Ref<InputEventScreenTouch> st;
  4160. st.instantiate();
  4161. st->set_window_id(window_id);
  4162. st->set_index(index);
  4163. st->set_position(pos);
  4164. st->set_pressed(is_begin);
  4165. if (is_begin) {
  4166. if (xi.state.has(index)) { // Defensive
  4167. break;
  4168. }
  4169. xi.state[index] = pos;
  4170. if (xi.state.size() == 1) {
  4171. // X11 may send a motion event when a touch gesture begins, that would result
  4172. // in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out
  4173. xi.mouse_pos_to_filter = pos;
  4174. }
  4175. Input::get_singleton()->parse_input_event(st);
  4176. } else {
  4177. if (!xi.state.has(index)) { // Defensive
  4178. break;
  4179. }
  4180. xi.state.erase(index);
  4181. Input::get_singleton()->parse_input_event(st);
  4182. }
  4183. } break;
  4184. case XI_TouchUpdate: {
  4185. if (ime_window_event || ignore_events) {
  4186. break;
  4187. }
  4188. int index = event_data->detail;
  4189. Vector2 pos = Vector2(event_data->event_x, event_data->event_y);
  4190. HashMap<int, Vector2>::Iterator curr_pos_elem = xi.state.find(index);
  4191. if (!curr_pos_elem) { // Defensive
  4192. break;
  4193. }
  4194. if (curr_pos_elem->value != pos) {
  4195. Ref<InputEventScreenDrag> sd;
  4196. sd.instantiate();
  4197. sd->set_window_id(window_id);
  4198. sd->set_index(index);
  4199. sd->set_position(pos);
  4200. sd->set_relative(pos - curr_pos_elem->value);
  4201. sd->set_relative_screen_position(sd->get_relative());
  4202. Input::get_singleton()->parse_input_event(sd);
  4203. curr_pos_elem->value = pos;
  4204. }
  4205. } break;
  4206. #endif
  4207. }
  4208. }
  4209. }
  4210. XFreeEventData(x11_display, &event.xcookie);
  4211. switch (event.type) {
  4212. case MapNotify: {
  4213. DEBUG_LOG_X11("[%u] MapNotify window=%lu (%u) \n", frame, event.xmap.window, window_id);
  4214. if (ime_window_event) {
  4215. break;
  4216. }
  4217. const WindowData &wd = windows[window_id];
  4218. XWindowAttributes xwa;
  4219. XSync(x11_display, False);
  4220. XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
  4221. _update_actions_hints(window_id);
  4222. XFlush(x11_display);
  4223. // Set focus when menu window is started.
  4224. // RevertToPointerRoot is used to make sure we don't lose all focus in case
  4225. // a subwindow and its parent are both destroyed.
  4226. if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup && _window_focus_check()) {
  4227. _set_input_focus(wd.x11_window, RevertToPointerRoot);
  4228. }
  4229. // Have we failed to set fullscreen while the window was unmapped?
  4230. _validate_mode_on_map(window_id);
  4231. // On KDE Plasma, when the parent window of an embedded process is restored after being minimized,
  4232. // only the embedded window receives the Map notification, causing it to
  4233. // appear without its parent.
  4234. if (wd.embed_parent) {
  4235. XMapWindow(x11_display, wd.embed_parent);
  4236. }
  4237. } break;
  4238. case Expose: {
  4239. DEBUG_LOG_X11("[%u] Expose window=%lu (%u), count='%u' \n", frame, event.xexpose.window, window_id, event.xexpose.count);
  4240. if (ime_window_event) {
  4241. break;
  4242. }
  4243. windows[window_id].fullscreen = _window_fullscreen_check(window_id);
  4244. Main::force_redraw();
  4245. } break;
  4246. case NoExpose: {
  4247. DEBUG_LOG_X11("[%u] NoExpose drawable=%lu (%u) \n", frame, event.xnoexpose.drawable, window_id);
  4248. if (ime_window_event) {
  4249. break;
  4250. }
  4251. windows[window_id].minimized = true;
  4252. } break;
  4253. case VisibilityNotify: {
  4254. DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state);
  4255. if (ime_window_event) {
  4256. break;
  4257. }
  4258. windows[window_id].minimized = _window_minimize_check(window_id);
  4259. } break;
  4260. case LeaveNotify: {
  4261. DEBUG_LOG_X11("[%u] LeaveNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
  4262. if (ime_window_event) {
  4263. break;
  4264. }
  4265. if (!mouse_mode_grab && window_mouseover_id == window_id) {
  4266. window_mouseover_id = INVALID_WINDOW_ID;
  4267. _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
  4268. }
  4269. } break;
  4270. case EnterNotify: {
  4271. DEBUG_LOG_X11("[%u] EnterNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
  4272. if (ime_window_event) {
  4273. break;
  4274. }
  4275. if (!mouse_mode_grab && window_mouseover_id != window_id) {
  4276. if (window_mouseover_id != INVALID_WINDOW_ID) {
  4277. _send_window_event(windows[window_mouseover_id], WINDOW_EVENT_MOUSE_EXIT);
  4278. }
  4279. window_mouseover_id = window_id;
  4280. _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
  4281. }
  4282. } break;
  4283. case FocusIn: {
  4284. DEBUG_LOG_X11("[%u] FocusIn window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode);
  4285. if (ime_window_event || (event.xfocus.detail == NotifyInferior)) {
  4286. break;
  4287. }
  4288. WindowData &wd = windows[window_id];
  4289. last_focused_window = window_id;
  4290. wd.focused = true;
  4291. // Keep track of focus order for overlapping windows.
  4292. static unsigned int focus_order = 0;
  4293. wd.focus_order = ++focus_order;
  4294. #ifdef ACCESSKIT_ENABLED
  4295. if (accessibility_driver) {
  4296. accessibility_driver->accessibility_set_window_focused(window_id, true);
  4297. }
  4298. #endif
  4299. _send_window_event(wd, WINDOW_EVENT_FOCUS_IN);
  4300. if (mouse_mode_grab) {
  4301. // Show and update the cursor if confined and the window regained focus.
  4302. for (const KeyValue<WindowID, WindowData> &E : windows) {
  4303. if (mouse_mode == MOUSE_MODE_CONFINED) {
  4304. XUndefineCursor(x11_display, E.value.x11_window);
  4305. } else if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) { // Or re-hide it.
  4306. XDefineCursor(x11_display, E.value.x11_window, null_cursor);
  4307. }
  4308. XGrabPointer(
  4309. x11_display, E.value.x11_window, True,
  4310. ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
  4311. GrabModeAsync, GrabModeAsync, E.value.x11_window, None, CurrentTime);
  4312. }
  4313. }
  4314. #ifdef TOUCH_ENABLED
  4315. // Grab touch devices to avoid OS gesture interference
  4316. /*for (int i = 0; i < xi.touch_devices.size(); ++i) {
  4317. XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
  4318. }*/
  4319. #endif
  4320. if (!app_focused) {
  4321. if (OS::get_singleton()->get_main_loop()) {
  4322. OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
  4323. }
  4324. app_focused = true;
  4325. }
  4326. } break;
  4327. case FocusOut: {
  4328. DEBUG_LOG_X11("[%u] FocusOut window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode);
  4329. WindowData &wd = windows[window_id];
  4330. if (ime_window_event || (event.xfocus.detail == NotifyInferior)) {
  4331. break;
  4332. }
  4333. if (wd.ime_active) {
  4334. MutexLock mutex_lock(events_mutex);
  4335. XUnsetICFocus(wd.xic);
  4336. XUnmapWindow(x11_display, wd.x11_xim_window);
  4337. wd.ime_active = false;
  4338. im_text = String();
  4339. im_selection = Vector2i();
  4340. OS_Unix::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
  4341. }
  4342. wd.focused = false;
  4343. Input::get_singleton()->release_pressed_events();
  4344. #ifdef ACCESSKIT_ENABLED
  4345. if (accessibility_driver) {
  4346. accessibility_driver->accessibility_set_window_focused(window_id, false);
  4347. }
  4348. #endif
  4349. _send_window_event(wd, WINDOW_EVENT_FOCUS_OUT);
  4350. if (mouse_mode_grab) {
  4351. for (const KeyValue<WindowID, WindowData> &E : windows) {
  4352. //dear X11, I try, I really try, but you never work, you do whatever you want.
  4353. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  4354. // Show the cursor if we're in captured mode so it doesn't look weird.
  4355. XUndefineCursor(x11_display, E.value.x11_window);
  4356. }
  4357. }
  4358. XUngrabPointer(x11_display, CurrentTime);
  4359. }
  4360. #ifdef TOUCH_ENABLED
  4361. // Ungrab touch devices so input works as usual while we are unfocused
  4362. /*for (int i = 0; i < xi.touch_devices.size(); ++i) {
  4363. XIUngrabDevice(x11_display, xi.touch_devices[i], CurrentTime);
  4364. }*/
  4365. // Release every pointer to avoid sticky points
  4366. for (const KeyValue<int, Vector2> &E : xi.state) {
  4367. Ref<InputEventScreenTouch> st;
  4368. st.instantiate();
  4369. st->set_index(E.key);
  4370. st->set_window_id(window_id);
  4371. st->set_position(E.value);
  4372. Input::get_singleton()->parse_input_event(st);
  4373. }
  4374. xi.state.clear();
  4375. #endif
  4376. } break;
  4377. case ConfigureNotify: {
  4378. DEBUG_LOG_X11("[%u] ConfigureNotify window=%lu (%u), event=%lu, above=%lu, override_redirect=%u \n", frame, event.xconfigure.window, window_id, event.xconfigure.event, event.xconfigure.above, event.xconfigure.override_redirect);
  4379. if (event.xconfigure.window == windows[window_id].x11_xim_window) {
  4380. break;
  4381. }
  4382. _window_changed(&event);
  4383. } break;
  4384. case ButtonPress:
  4385. case ButtonRelease: {
  4386. if (ime_window_event || ignore_events) {
  4387. break;
  4388. }
  4389. /* exit in case of a mouse button press */
  4390. last_timestamp = event.xbutton.time;
  4391. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  4392. event.xbutton.x = last_mouse_pos.x;
  4393. event.xbutton.y = last_mouse_pos.y;
  4394. }
  4395. Ref<InputEventMouseButton> mb;
  4396. mb.instantiate();
  4397. mb->set_window_id(window_id);
  4398. _get_key_modifier_state(event.xbutton.state, mb);
  4399. mb->set_button_index((MouseButton)event.xbutton.button);
  4400. if (mb->get_button_index() == MouseButton::RIGHT) {
  4401. mb->set_button_index(MouseButton::MIDDLE);
  4402. } else if (mb->get_button_index() == MouseButton::MIDDLE) {
  4403. mb->set_button_index(MouseButton::RIGHT);
  4404. }
  4405. mb->set_position(Vector2(event.xbutton.x, event.xbutton.y));
  4406. mb->set_global_position(mb->get_position());
  4407. mb->set_pressed((event.type == ButtonPress));
  4408. if (mb->is_pressed() && mb->get_button_index() >= MouseButton::WHEEL_UP && mb->get_button_index() <= MouseButton::WHEEL_RIGHT) {
  4409. MouseButtonMask mask = mouse_button_to_mask(mb->get_button_index());
  4410. BitField<MouseButtonMask> scroll_mask = mouse_get_button_state();
  4411. scroll_mask.set_flag(mask);
  4412. mb->set_button_mask(scroll_mask);
  4413. } else {
  4414. mb->set_button_mask(mouse_get_button_state());
  4415. }
  4416. const WindowData &wd = windows[window_id];
  4417. if (event.type == ButtonPress) {
  4418. DEBUG_LOG_X11("[%u] ButtonPress window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index());
  4419. // Ensure window focus on click.
  4420. // RevertToPointerRoot is used to make sure we don't lose all focus in case
  4421. // a subwindow and its parent are both destroyed.
  4422. if (!wd.no_focus && !wd.is_popup) {
  4423. _set_input_focus(wd.x11_window, RevertToPointerRoot);
  4424. }
  4425. uint64_t diff = OS::get_singleton()->get_ticks_usec() / 1000 - last_click_ms;
  4426. if (mb->get_button_index() == last_click_button_index) {
  4427. if (diff < 400 && Vector2(last_click_pos).distance_to(Vector2(event.xbutton.x, event.xbutton.y)) < 5) {
  4428. last_click_ms = 0;
  4429. last_click_pos = Point2i(-100, -100);
  4430. last_click_button_index = MouseButton::NONE;
  4431. mb->set_double_click(true);
  4432. }
  4433. } else if (mb->get_button_index() < MouseButton::WHEEL_UP || mb->get_button_index() > MouseButton::WHEEL_RIGHT) {
  4434. last_click_button_index = mb->get_button_index();
  4435. }
  4436. if (!mb->is_double_click()) {
  4437. last_click_ms += diff;
  4438. last_click_pos = Point2i(event.xbutton.x, event.xbutton.y);
  4439. }
  4440. } else {
  4441. DEBUG_LOG_X11("[%u] ButtonRelease window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index());
  4442. WindowID window_id_other = INVALID_WINDOW_ID;
  4443. Window wd_other_x11_window;
  4444. if (!wd.focused) {
  4445. // Propagate the event to the focused window,
  4446. // because it's received only on the topmost window.
  4447. // Note: This is needed for drag & drop to work between windows,
  4448. // because the engine expects events to keep being processed
  4449. // on the same window dragging started.
  4450. for (const KeyValue<WindowID, WindowData> &E : windows) {
  4451. if (E.value.focused) {
  4452. if (E.key != window_id) {
  4453. window_id_other = E.key;
  4454. wd_other_x11_window = E.value.x11_window;
  4455. }
  4456. break;
  4457. }
  4458. }
  4459. }
  4460. if (window_id_other != INVALID_WINDOW_ID) {
  4461. int x, y;
  4462. Window child;
  4463. XTranslateCoordinates(x11_display, wd.x11_window, wd_other_x11_window, event.xbutton.x, event.xbutton.y, &x, &y, &child);
  4464. mb->set_window_id(window_id_other);
  4465. mb->set_position(Vector2(x, y));
  4466. mb->set_global_position(mb->get_position());
  4467. }
  4468. }
  4469. Input::get_singleton()->parse_input_event(mb);
  4470. } break;
  4471. case MotionNotify: {
  4472. if (ime_window_event || ignore_events) {
  4473. break;
  4474. }
  4475. // The X11 API requires filtering one-by-one through the motion
  4476. // notify events, in order to figure out which event is the one
  4477. // generated by warping the mouse pointer.
  4478. WindowID focused_window_id = _get_focused_window_or_popup();
  4479. if (!windows.has(focused_window_id)) {
  4480. focused_window_id = MAIN_WINDOW_ID;
  4481. }
  4482. while (true) {
  4483. if (mouse_mode == MOUSE_MODE_CAPTURED && event.xmotion.x == windows[focused_window_id].size.width / 2 && event.xmotion.y == windows[focused_window_id].size.height / 2) {
  4484. //this is likely the warp event since it was warped here
  4485. center = Vector2(event.xmotion.x, event.xmotion.y);
  4486. break;
  4487. }
  4488. if (event_index + 1 < events.size()) {
  4489. const XEvent &next_event = events[event_index + 1];
  4490. if (next_event.type == MotionNotify) {
  4491. ++event_index;
  4492. event = next_event;
  4493. } else {
  4494. break;
  4495. }
  4496. } else {
  4497. break;
  4498. }
  4499. }
  4500. last_timestamp = event.xmotion.time;
  4501. // Motion is also simple.
  4502. // A little hack is in order
  4503. // to be able to send relative motion events.
  4504. Point2i pos(event.xmotion.x, event.xmotion.y);
  4505. // Avoidance of spurious mouse motion (see handling of touch)
  4506. bool filter = false;
  4507. // Adding some tolerance to match better Point2i to Vector2
  4508. if (xi.state.size() && Vector2(pos).distance_squared_to(xi.mouse_pos_to_filter) < 2) {
  4509. filter = true;
  4510. }
  4511. // Invalidate to avoid filtering a possible legitimate similar event coming later
  4512. xi.mouse_pos_to_filter = Vector2(1e10, 1e10);
  4513. if (filter) {
  4514. break;
  4515. }
  4516. const WindowData &wd = windows[window_id];
  4517. bool focused = wd.focused;
  4518. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  4519. if (xi.relative_motion.x == 0 && xi.relative_motion.y == 0) {
  4520. break;
  4521. }
  4522. Point2i new_center = pos;
  4523. pos = last_mouse_pos + xi.relative_motion;
  4524. center = new_center;
  4525. do_mouse_warp = focused; // warp the cursor if we're focused in
  4526. }
  4527. if (!last_mouse_pos_valid) {
  4528. last_mouse_pos = pos;
  4529. last_mouse_pos_valid = true;
  4530. }
  4531. // Hackish but relative mouse motion is already handled in the RawMotion event.
  4532. // RawMotion does not provide the absolute mouse position (whereas MotionNotify does).
  4533. // Therefore, RawMotion cannot be the authority on absolute mouse position.
  4534. // RawMotion provides more precision than MotionNotify, which doesn't sense subpixel motion.
  4535. // Therefore, MotionNotify cannot be the authority on relative mouse motion.
  4536. // This means we need to take a combined approach...
  4537. Point2i rel;
  4538. // Only use raw input if in capture mode. Otherwise use the classic behavior.
  4539. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  4540. rel = xi.relative_motion;
  4541. } else {
  4542. rel = pos - last_mouse_pos;
  4543. }
  4544. // Reset to prevent lingering motion
  4545. xi.relative_motion.x = 0;
  4546. xi.relative_motion.y = 0;
  4547. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  4548. pos = Point2i(windows[focused_window_id].size.width / 2, windows[focused_window_id].size.height / 2);
  4549. }
  4550. BitField<MouseButtonMask> last_button_state = MouseButtonMask::NONE;
  4551. if (event.xmotion.state & Button1Mask) {
  4552. last_button_state.set_flag(MouseButtonMask::LEFT);
  4553. }
  4554. if (event.xmotion.state & Button2Mask) {
  4555. last_button_state.set_flag(MouseButtonMask::MIDDLE);
  4556. }
  4557. if (event.xmotion.state & Button3Mask) {
  4558. last_button_state.set_flag(MouseButtonMask::RIGHT);
  4559. }
  4560. if (event.xmotion.state & Button4Mask) {
  4561. last_button_state.set_flag(MouseButtonMask::MB_XBUTTON1);
  4562. }
  4563. if (event.xmotion.state & Button5Mask) {
  4564. last_button_state.set_flag(MouseButtonMask::MB_XBUTTON2);
  4565. }
  4566. Ref<InputEventMouseMotion> mm;
  4567. mm.instantiate();
  4568. mm->set_window_id(window_id);
  4569. if (xi.pressure_supported) {
  4570. mm->set_pressure(xi.pressure);
  4571. } else {
  4572. mm->set_pressure(bool(last_button_state.has_flag(MouseButtonMask::LEFT)) ? 1.0f : 0.0f);
  4573. }
  4574. mm->set_tilt(xi.tilt);
  4575. mm->set_pen_inverted(xi.pen_inverted);
  4576. _get_key_modifier_state(event.xmotion.state, mm);
  4577. mm->set_button_mask(last_button_state);
  4578. mm->set_position(pos);
  4579. mm->set_global_position(pos);
  4580. mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
  4581. mm->set_screen_velocity(mm->get_velocity());
  4582. mm->set_relative(rel);
  4583. mm->set_relative_screen_position(rel);
  4584. last_mouse_pos = pos;
  4585. // printf("rel: %d,%d\n", rel.x, rel.y );
  4586. // Don't propagate the motion event unless we have focus
  4587. // this is so that the relative motion doesn't get messed up
  4588. // after we regain focus.
  4589. // Adjusted to parse the input event if the window is not focused allowing mouse hovering on the editor
  4590. // the embedding process has focus.
  4591. if (!focused) {
  4592. // Propagate the event to the focused window,
  4593. // because it's received only on the topmost window.
  4594. // Note: This is needed for drag & drop to work between windows,
  4595. // because the engine expects events to keep being processed
  4596. // on the same window dragging started.
  4597. for (const KeyValue<WindowID, WindowData> &E : windows) {
  4598. const WindowData &wd_other = E.value;
  4599. if (wd_other.focused) {
  4600. int x, y;
  4601. Window child;
  4602. XTranslateCoordinates(x11_display, wd.x11_window, wd_other.x11_window, event.xmotion.x, event.xmotion.y, &x, &y, &child);
  4603. Point2i pos_focused(x, y);
  4604. mm->set_window_id(E.key);
  4605. mm->set_position(pos_focused);
  4606. mm->set_global_position(pos_focused);
  4607. mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
  4608. break;
  4609. }
  4610. }
  4611. }
  4612. Input::get_singleton()->parse_input_event(mm);
  4613. } break;
  4614. case KeyPress:
  4615. case KeyRelease: {
  4616. if (ignore_events) {
  4617. break;
  4618. }
  4619. #ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
  4620. if (event.type == KeyPress) {
  4621. DEBUG_LOG_X11("[%u] KeyPress window=%lu (%u), keycode=%u, time=%lu \n", frame, event.xkey.window, window_id, event.xkey.keycode, event.xkey.time);
  4622. } else {
  4623. DEBUG_LOG_X11("[%u] KeyRelease window=%lu (%u), keycode=%u, time=%lu \n", frame, event.xkey.window, window_id, event.xkey.keycode, event.xkey.time);
  4624. }
  4625. #endif
  4626. last_timestamp = event.xkey.time;
  4627. // key event is a little complex, so
  4628. // it will be handled in its own function.
  4629. _handle_key_event(window_id, &event.xkey, events, event_index);
  4630. } break;
  4631. case SelectionNotify:
  4632. if (ime_window_event) {
  4633. break;
  4634. }
  4635. if (event.xselection.target == requested) {
  4636. Property p = _read_property(x11_display, windows[window_id].x11_window, XInternAtom(x11_display, "PRIMARY", 0));
  4637. Vector<String> files = String((char *)p.data).split("\r\n", false);
  4638. XFree(p.data);
  4639. for (int i = 0; i < files.size(); i++) {
  4640. files.write[i] = files[i].replace("file://", "").uri_file_decode();
  4641. }
  4642. if (windows[window_id].drop_files_callback.is_valid()) {
  4643. Variant v_files = files;
  4644. const Variant *v_args[1] = { &v_files };
  4645. Variant ret;
  4646. Callable::CallError ce;
  4647. windows[window_id].drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce);
  4648. if (ce.error != Callable::CallError::CALL_OK) {
  4649. ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(windows[window_id].drop_files_callback, v_args, 1, ce)));
  4650. }
  4651. }
  4652. //Reply that all is well.
  4653. XClientMessageEvent m;
  4654. memset(&m, 0, sizeof(m));
  4655. m.type = ClientMessage;
  4656. m.display = x11_display;
  4657. m.window = xdnd_source_window;
  4658. m.message_type = xdnd_finished;
  4659. m.format = 32;
  4660. m.data.l[0] = windows[window_id].x11_window;
  4661. m.data.l[1] = 1;
  4662. m.data.l[2] = xdnd_action_copy; //We only ever copy.
  4663. XSendEvent(x11_display, xdnd_source_window, False, NoEventMask, (XEvent *)&m);
  4664. }
  4665. break;
  4666. case ClientMessage:
  4667. if (ime_window_event) {
  4668. break;
  4669. }
  4670. if ((unsigned int)event.xclient.data.l[0] == (unsigned int)wm_delete) {
  4671. _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST);
  4672. }
  4673. else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_enter) {
  4674. //File(s) have been dragged over the window, check for supported target (text/uri-list)
  4675. xdnd_version = (event.xclient.data.l[1] >> 24);
  4676. Window source = event.xclient.data.l[0];
  4677. bool more_than_3 = event.xclient.data.l[1] & 1;
  4678. if (more_than_3) {
  4679. Property p = _read_property(x11_display, source, XInternAtom(x11_display, "XdndTypeList", False));
  4680. requested = pick_target_from_list(x11_display, (Atom *)p.data, p.nitems);
  4681. XFree(p.data);
  4682. } else {
  4683. requested = pick_target_from_atoms(x11_display, event.xclient.data.l[2], event.xclient.data.l[3], event.xclient.data.l[4]);
  4684. }
  4685. } else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_position) {
  4686. //xdnd position event, reply with an XDND status message
  4687. //just depending on type of data for now
  4688. XClientMessageEvent m;
  4689. memset(&m, 0, sizeof(m));
  4690. m.type = ClientMessage;
  4691. m.display = event.xclient.display;
  4692. m.window = event.xclient.data.l[0];
  4693. m.message_type = xdnd_status;
  4694. m.format = 32;
  4695. m.data.l[0] = windows[window_id].x11_window;
  4696. m.data.l[1] = (requested != None);
  4697. m.data.l[2] = 0; //empty rectangle
  4698. m.data.l[3] = 0;
  4699. m.data.l[4] = xdnd_action_copy;
  4700. XSendEvent(x11_display, event.xclient.data.l[0], False, NoEventMask, (XEvent *)&m);
  4701. XFlush(x11_display);
  4702. } else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_drop) {
  4703. if (requested != None) {
  4704. xdnd_source_window = event.xclient.data.l[0];
  4705. if (xdnd_version >= 1) {
  4706. XConvertSelection(x11_display, xdnd_selection, requested, XInternAtom(x11_display, "PRIMARY", 0), windows[window_id].x11_window, event.xclient.data.l[2]);
  4707. } else {
  4708. XConvertSelection(x11_display, xdnd_selection, requested, XInternAtom(x11_display, "PRIMARY", 0), windows[window_id].x11_window, CurrentTime);
  4709. }
  4710. } else {
  4711. //Reply that we're not interested.
  4712. XClientMessageEvent m;
  4713. memset(&m, 0, sizeof(m));
  4714. m.type = ClientMessage;
  4715. m.display = event.xclient.display;
  4716. m.window = event.xclient.data.l[0];
  4717. m.message_type = xdnd_finished;
  4718. m.format = 32;
  4719. m.data.l[0] = windows[window_id].x11_window;
  4720. m.data.l[1] = 0;
  4721. m.data.l[2] = None; //Failed.
  4722. XSendEvent(x11_display, event.xclient.data.l[0], False, NoEventMask, (XEvent *)&m);
  4723. }
  4724. }
  4725. break;
  4726. default:
  4727. break;
  4728. }
  4729. }
  4730. XFlush(x11_display);
  4731. if (do_mouse_warp) {
  4732. XWarpPointer(x11_display, None, windows[MAIN_WINDOW_ID].x11_window,
  4733. 0, 0, 0, 0, (int)windows[MAIN_WINDOW_ID].size.width / 2, (int)windows[MAIN_WINDOW_ID].size.height / 2);
  4734. /*
  4735. Window root, child;
  4736. int root_x, root_y;
  4737. int win_x, win_y;
  4738. unsigned int mask;
  4739. XQueryPointer( x11_display, x11_window, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask );
  4740. printf("Root: %d,%d\n", root_x, root_y);
  4741. printf("Win: %d,%d\n", win_x, win_y);
  4742. */
  4743. }
  4744. #ifdef DBUS_ENABLED
  4745. if (portal_desktop) {
  4746. portal_desktop->process_callbacks();
  4747. }
  4748. #endif
  4749. _THREAD_SAFE_UNLOCK_
  4750. Input::get_singleton()->flush_buffered_events();
  4751. }
  4752. void DisplayServerX11::release_rendering_thread() {
  4753. #if defined(GLES3_ENABLED)
  4754. if (gl_manager) {
  4755. gl_manager->release_current();
  4756. }
  4757. if (gl_manager_egl) {
  4758. gl_manager_egl->release_current();
  4759. }
  4760. #endif
  4761. }
  4762. void DisplayServerX11::swap_buffers() {
  4763. #if defined(GLES3_ENABLED)
  4764. if (gl_manager) {
  4765. gl_manager->swap_buffers();
  4766. }
  4767. if (gl_manager_egl) {
  4768. gl_manager_egl->swap_buffers();
  4769. }
  4770. #endif
  4771. }
  4772. void DisplayServerX11::_update_context(WindowData &wd) {
  4773. XClassHint *classHint = XAllocClassHint();
  4774. if (classHint) {
  4775. CharString name_str;
  4776. switch (context) {
  4777. case CONTEXT_EDITOR:
  4778. name_str = "Godot_Editor";
  4779. break;
  4780. case CONTEXT_PROJECTMAN:
  4781. name_str = "Godot_ProjectList";
  4782. break;
  4783. case CONTEXT_ENGINE:
  4784. name_str = "Godot_Engine";
  4785. break;
  4786. }
  4787. CharString class_str;
  4788. if (context == CONTEXT_ENGINE) {
  4789. String config_name = GLOBAL_GET("application/config/name");
  4790. if (config_name.length() == 0) {
  4791. class_str = "Godot_Engine";
  4792. } else {
  4793. class_str = config_name.utf8();
  4794. }
  4795. } else {
  4796. class_str = "Godot";
  4797. }
  4798. classHint->res_class = class_str.ptrw();
  4799. classHint->res_name = name_str.ptrw();
  4800. XSetClassHint(x11_display, wd.x11_window, classHint);
  4801. XFree(classHint);
  4802. }
  4803. }
  4804. void DisplayServerX11::set_context(Context p_context) {
  4805. _THREAD_SAFE_METHOD_
  4806. context = p_context;
  4807. for (KeyValue<WindowID, WindowData> &E : windows) {
  4808. _update_context(E.value);
  4809. }
  4810. }
  4811. bool DisplayServerX11::is_window_transparency_available() const {
  4812. CharString net_wm_cm_name = vformat("_NET_WM_CM_S%d", XDefaultScreen(x11_display)).ascii();
  4813. Atom net_wm_cm = XInternAtom(x11_display, net_wm_cm_name.get_data(), False);
  4814. if (net_wm_cm == None) {
  4815. return false;
  4816. }
  4817. if (XGetSelectionOwner(x11_display, net_wm_cm) == None) {
  4818. return false;
  4819. }
  4820. #if defined(RD_ENABLED)
  4821. if (rendering_device && !rendering_device->is_composite_alpha_supported()) {
  4822. return false;
  4823. }
  4824. #endif
  4825. return OS::get_singleton()->is_layered_allowed();
  4826. }
  4827. void DisplayServerX11::set_native_icon(const String &p_filename) {
  4828. WARN_PRINT("Native icon not supported by this display server.");
  4829. }
  4830. bool g_set_icon_error = false;
  4831. int set_icon_errorhandler(Display *dpy, XErrorEvent *ev) {
  4832. g_set_icon_error = true;
  4833. return 0;
  4834. }
  4835. void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
  4836. _THREAD_SAFE_METHOD_
  4837. WindowData &wd = windows[MAIN_WINDOW_ID];
  4838. int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&set_icon_errorhandler);
  4839. Atom net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
  4840. if (p_icon.is_valid()) {
  4841. ERR_FAIL_COND(p_icon->get_width() <= 0 || p_icon->get_height() <= 0);
  4842. Ref<Image> img = p_icon->duplicate();
  4843. img->convert(Image::FORMAT_RGBA8);
  4844. while (true) {
  4845. int w = img->get_width();
  4846. int h = img->get_height();
  4847. if (g_set_icon_error) {
  4848. g_set_icon_error = false;
  4849. WARN_PRINT(vformat("Icon too large (%dx%d), attempting to downscale icon.", w, h));
  4850. int new_width, new_height;
  4851. if (w > h) {
  4852. new_width = w / 2;
  4853. new_height = h * new_width / w;
  4854. } else {
  4855. new_height = h / 2;
  4856. new_width = w * new_height / h;
  4857. }
  4858. w = new_width;
  4859. h = new_height;
  4860. if (!w || !h) {
  4861. WARN_PRINT("Unable to set icon.");
  4862. break;
  4863. }
  4864. img->resize(w, h, Image::INTERPOLATE_CUBIC);
  4865. }
  4866. // We're using long to have wordsize (32Bit build -> 32 Bits, 64 Bit build -> 64 Bits
  4867. Vector<long> pd;
  4868. pd.resize(2 + w * h);
  4869. pd.write[0] = w;
  4870. pd.write[1] = h;
  4871. const uint8_t *r = img->get_data().ptr();
  4872. long *wr = &pd.write[2];
  4873. uint8_t const *pr = r;
  4874. for (int i = 0; i < w * h; i++) {
  4875. long v = 0;
  4876. // A R G B
  4877. v |= pr[3] << 24 | pr[0] << 16 | pr[1] << 8 | pr[2];
  4878. *wr++ = v;
  4879. pr += 4;
  4880. }
  4881. if (net_wm_icon != None) {
  4882. XChangeProperty(x11_display, wd.x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pd.ptr(), pd.size());
  4883. }
  4884. if (!g_set_icon_error) {
  4885. break;
  4886. }
  4887. }
  4888. } else {
  4889. XDeleteProperty(x11_display, wd.x11_window, net_wm_icon);
  4890. }
  4891. XFlush(x11_display);
  4892. XSetErrorHandler(oldHandler);
  4893. }
  4894. void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
  4895. _THREAD_SAFE_METHOD_
  4896. #if defined(RD_ENABLED)
  4897. if (rendering_context) {
  4898. rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
  4899. }
  4900. #endif
  4901. #if defined(GLES3_ENABLED)
  4902. if (gl_manager) {
  4903. gl_manager->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
  4904. }
  4905. if (gl_manager_egl) {
  4906. gl_manager_egl->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
  4907. }
  4908. #endif
  4909. }
  4910. DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_window) const {
  4911. _THREAD_SAFE_METHOD_
  4912. #if defined(RD_ENABLED)
  4913. if (rendering_context) {
  4914. return rendering_context->window_get_vsync_mode(p_window);
  4915. }
  4916. #endif
  4917. #if defined(GLES3_ENABLED)
  4918. if (gl_manager) {
  4919. return gl_manager->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
  4920. }
  4921. if (gl_manager_egl) {
  4922. return gl_manager_egl->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
  4923. }
  4924. #endif
  4925. return DisplayServer::VSYNC_ENABLED;
  4926. }
  4927. void DisplayServerX11::window_start_drag(WindowID p_window) {
  4928. _THREAD_SAFE_METHOD_
  4929. ERR_FAIL_COND(!windows.has(p_window));
  4930. WindowData &wd = windows[p_window];
  4931. if (wd.embed_parent) {
  4932. return; // Embedded window.
  4933. }
  4934. XClientMessageEvent m;
  4935. memset(&m, 0, sizeof(m));
  4936. XUngrabPointer(x11_display, CurrentTime);
  4937. Window root_return, child_return;
  4938. int root_x, root_y, win_x, win_y;
  4939. unsigned int mask_return;
  4940. Bool xquerypointer_result = XQueryPointer(x11_display, wd.x11_window, &root_return, &child_return, &root_x, &root_y, &win_x, &win_y, &mask_return);
  4941. m.type = ClientMessage;
  4942. m.window = wd.x11_window;
  4943. m.message_type = XInternAtom(x11_display, "_NET_WM_MOVERESIZE", True);
  4944. m.format = 32;
  4945. if (xquerypointer_result) {
  4946. m.data.l[0] = root_x;
  4947. m.data.l[1] = root_y;
  4948. m.data.l[3] = Button1;
  4949. }
  4950. m.data.l[2] = _NET_WM_MOVERESIZE_MOVE;
  4951. m.data.l[4] = 1; // Source - normal application.
  4952. XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&m);
  4953. XSync(x11_display, 0);
  4954. }
  4955. void DisplayServerX11::window_start_resize(WindowResizeEdge p_edge, WindowID p_window) {
  4956. _THREAD_SAFE_METHOD_
  4957. ERR_FAIL_INDEX(int(p_edge), WINDOW_EDGE_MAX);
  4958. ERR_FAIL_COND(!windows.has(p_window));
  4959. WindowData &wd = windows[p_window];
  4960. if (wd.embed_parent) {
  4961. return; // Embedded window.
  4962. }
  4963. XClientMessageEvent m;
  4964. memset(&m, 0, sizeof(m));
  4965. XUngrabPointer(x11_display, CurrentTime);
  4966. Window root_return, child_return;
  4967. int root_x, root_y, win_x, win_y;
  4968. unsigned int mask_return;
  4969. Bool xquerypointer_result = XQueryPointer(x11_display, wd.x11_window, &root_return, &child_return, &root_x, &root_y, &win_x, &win_y, &mask_return);
  4970. m.type = ClientMessage;
  4971. m.window = wd.x11_window;
  4972. m.message_type = XInternAtom(x11_display, "_NET_WM_MOVERESIZE", True);
  4973. m.format = 32;
  4974. if (xquerypointer_result) {
  4975. m.data.l[0] = root_x;
  4976. m.data.l[1] = root_y;
  4977. m.data.l[3] = Button1;
  4978. }
  4979. switch (p_edge) {
  4980. case DisplayServer::WINDOW_EDGE_TOP_LEFT: {
  4981. m.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
  4982. } break;
  4983. case DisplayServer::WINDOW_EDGE_TOP: {
  4984. m.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOP;
  4985. } break;
  4986. case DisplayServer::WINDOW_EDGE_TOP_RIGHT: {
  4987. m.data.l[2] = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
  4988. } break;
  4989. case DisplayServer::WINDOW_EDGE_LEFT: {
  4990. m.data.l[2] = _NET_WM_MOVERESIZE_SIZE_LEFT;
  4991. } break;
  4992. case DisplayServer::WINDOW_EDGE_RIGHT: {
  4993. m.data.l[2] = _NET_WM_MOVERESIZE_SIZE_RIGHT;
  4994. } break;
  4995. case DisplayServer::WINDOW_EDGE_BOTTOM_LEFT: {
  4996. m.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
  4997. } break;
  4998. case DisplayServer::WINDOW_EDGE_BOTTOM: {
  4999. m.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
  5000. } break;
  5001. case DisplayServer::WINDOW_EDGE_BOTTOM_RIGHT: {
  5002. m.data.l[2] = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
  5003. } break;
  5004. default:
  5005. break;
  5006. }
  5007. m.data.l[4] = 1; // Source - normal application.
  5008. XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&m);
  5009. XSync(x11_display, 0);
  5010. }
  5011. pid_t get_window_pid(Display *p_display, Window p_window) {
  5012. Atom atom = XInternAtom(p_display, "_NET_WM_PID", False);
  5013. Atom actualType;
  5014. int actualFormat;
  5015. unsigned long nItems, bytesAfter;
  5016. unsigned char *prop = nullptr;
  5017. if (XGetWindowProperty(p_display, p_window, atom, 0, sizeof(pid_t), False, AnyPropertyType,
  5018. &actualType, &actualFormat, &nItems, &bytesAfter, &prop) == Success) {
  5019. if (nItems > 0) {
  5020. pid_t pid = *(pid_t *)prop;
  5021. XFree(prop);
  5022. return pid;
  5023. }
  5024. }
  5025. return 0; // PID not found.
  5026. }
  5027. Window find_window_from_process_id_internal(Display *p_display, pid_t p_process_id, Window p_window) {
  5028. Window dummy;
  5029. Window *children;
  5030. unsigned int num_children;
  5031. if (!XQueryTree(p_display, p_window, &dummy, &dummy, &children, &num_children)) {
  5032. return 0;
  5033. }
  5034. for (unsigned int i = 0; i < num_children; i++) {
  5035. pid_t pid = get_window_pid(p_display, children[i]);
  5036. if (pid == p_process_id) {
  5037. return children[i];
  5038. }
  5039. }
  5040. // Then check children of children.
  5041. for (unsigned int i = 0; i < num_children; i++) {
  5042. Window wnd = find_window_from_process_id_internal(p_display, p_process_id, children[i]);
  5043. if (wnd != 0) {
  5044. return wnd;
  5045. }
  5046. }
  5047. if (children) {
  5048. XFree(children);
  5049. }
  5050. return 0;
  5051. }
  5052. Window find_window_from_process_id(Display *p_display, pid_t p_process_id) {
  5053. // Handle bad window errors silently because while looping
  5054. // windows can be destroyed, resulting in BadWindow errors.
  5055. int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&bad_window_error_handler);
  5056. const int screencount = XScreenCount(p_display);
  5057. Window process_window = 0;
  5058. for (int screen_index = 0; screen_index < screencount; screen_index++) {
  5059. Window root = RootWindow(p_display, screen_index);
  5060. Window wnd = find_window_from_process_id_internal(p_display, p_process_id, root);
  5061. if (wnd != 0) {
  5062. process_window = wnd;
  5063. break;
  5064. }
  5065. }
  5066. // Restore default error handler.
  5067. XSetErrorHandler(oldHandler);
  5068. return process_window;
  5069. }
  5070. Point2i DisplayServerX11::_get_window_position(Window p_window) const {
  5071. int x = 0, y = 0;
  5072. Window child;
  5073. XTranslateCoordinates(x11_display, p_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
  5074. return Point2i(x, y);
  5075. }
  5076. Rect2i DisplayServerX11::_get_window_rect(Window p_window) const {
  5077. XWindowAttributes xwa;
  5078. XGetWindowAttributes(x11_display, p_window, &xwa);
  5079. return Rect2i(xwa.x, xwa.y, xwa.width, xwa.height);
  5080. }
  5081. void DisplayServerX11::_set_window_taskbar_pager_enabled(Window p_window, bool p_enabled) {
  5082. Atom wmState = XInternAtom(x11_display, "_NET_WM_STATE", False);
  5083. Atom skipTaskbar = XInternAtom(x11_display, "_NET_WM_STATE_SKIP_TASKBAR", False);
  5084. Atom skipPager = XInternAtom(x11_display, "_NET_WM_STATE_SKIP_PAGER", False);
  5085. XClientMessageEvent xev;
  5086. memset(&xev, 0, sizeof(xev));
  5087. xev.type = ClientMessage;
  5088. xev.window = p_window;
  5089. xev.message_type = wmState;
  5090. xev.format = 32;
  5091. xev.data.l[0] = p_enabled ? _NET_WM_STATE_REMOVE : _NET_WM_STATE_ADD; // When enabled, we must remove the skip.
  5092. xev.data.l[1] = skipTaskbar;
  5093. xev.data.l[2] = skipPager;
  5094. xev.data.l[3] = 0;
  5095. xev.data.l[4] = 0;
  5096. // Send the client message to the root window.
  5097. XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xev);
  5098. }
  5099. Error DisplayServerX11::embed_process(WindowID p_window, OS::ProcessID p_pid, const Rect2i &p_rect, bool p_visible, bool p_grab_focus) {
  5100. _THREAD_SAFE_METHOD_
  5101. ERR_FAIL_COND_V(!windows.has(p_window), FAILED);
  5102. const WindowData &wd = windows[p_window];
  5103. DEBUG_LOG_X11("Starting embedding %ld to window %lu \n", p_pid, wd.x11_window);
  5104. EmbeddedProcessData *ep = nullptr;
  5105. if (embedded_processes.has(p_pid)) {
  5106. ep = embedded_processes.get(p_pid);
  5107. } else {
  5108. // New process, trying to find the window.
  5109. Window process_window = find_window_from_process_id(x11_display, p_pid);
  5110. if (!process_window) {
  5111. return ERR_DOES_NOT_EXIST;
  5112. }
  5113. DEBUG_LOG_X11("Process %ld window found: %lu \n", p_pid, process_window);
  5114. ep = memnew(EmbeddedProcessData);
  5115. ep->process_window = process_window;
  5116. ep->visible = true;
  5117. XSetTransientForHint(x11_display, process_window, wd.x11_window);
  5118. _set_window_taskbar_pager_enabled(process_window, false);
  5119. embedded_processes.insert(p_pid, ep);
  5120. }
  5121. // Handle bad window errors silently because just in case the embedded window was closed.
  5122. int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&bad_window_error_handler);
  5123. if (p_visible) {
  5124. // Resize and move the window to match the desired rectangle.
  5125. // X11 does not allow moving the window entirely outside the screen boundaries.
  5126. // To ensure the window remains visible, we will resize it to fit within both the screen and the specified rectangle.
  5127. Rect2i desired_rect = p_rect;
  5128. // First resize the desired rect to fit inside all the screens without considering the
  5129. // working area.
  5130. Rect2i screens_full_rect = _screens_get_full_rect();
  5131. Vector2i screens_full_end = screens_full_rect.get_end();
  5132. if (desired_rect.position.x < screens_full_rect.position.x) {
  5133. desired_rect.size.x = MAX(desired_rect.size.x - (screens_full_rect.position.x - desired_rect.position.x), 0);
  5134. desired_rect.position.x = screens_full_rect.position.x;
  5135. }
  5136. if (desired_rect.position.x + desired_rect.size.x > screens_full_end.x) {
  5137. desired_rect.size.x = MAX(screens_full_end.x - desired_rect.position.x, 0);
  5138. }
  5139. if (desired_rect.position.y < screens_full_rect.position.y) {
  5140. desired_rect.size.y = MAX(desired_rect.size.y - (screens_full_rect.position.y - desired_rect.position.y), 0);
  5141. desired_rect.position.y = screens_full_rect.position.y;
  5142. }
  5143. if (desired_rect.position.y + desired_rect.size.y > screens_full_end.y) {
  5144. desired_rect.size.y = MAX(screens_full_end.y - desired_rect.position.y, 0);
  5145. }
  5146. // Second, for each screen, check if the desired rectangle is within a portion of the screen
  5147. // that is outside the working area. Each screen can have a different working area
  5148. // depending on top, bottom, or side panels.
  5149. int desired_area = desired_rect.get_area();
  5150. int count = get_screen_count();
  5151. for (int i = 0; i < count; i++) {
  5152. Rect2i screen_rect = _screen_get_rect(i);
  5153. if (screen_rect.intersection(desired_rect).get_area() == 0) {
  5154. continue;
  5155. }
  5156. // The desired rect is inside this screen.
  5157. Rect2i screen_usable_rect = screen_get_usable_rect(i);
  5158. int screen_usable_area = screen_usable_rect.intersection(desired_rect).get_area();
  5159. if (screen_usable_area == desired_area) {
  5160. // The desired rect is fulling inside the usable rect of the screen. No need to resize.
  5161. continue;
  5162. }
  5163. if (desired_rect.position.x >= screen_rect.position.x && desired_rect.position.x < screen_usable_rect.position.x) {
  5164. int offset = screen_usable_rect.position.x - desired_rect.position.x;
  5165. desired_rect.size.x = MAX(desired_rect.size.x - offset, 0);
  5166. desired_rect.position.x += offset;
  5167. }
  5168. if (desired_rect.position.y >= screen_rect.position.y && desired_rect.position.y < screen_usable_rect.position.y) {
  5169. int offset = screen_usable_rect.position.y - desired_rect.position.y;
  5170. desired_rect.size.y = MAX(desired_rect.size.y - offset, 0);
  5171. desired_rect.position.y += offset;
  5172. }
  5173. Vector2i desired_end = desired_rect.get_end();
  5174. Vector2i screen_end = screen_rect.get_end();
  5175. Vector2i screen_usable_end = screen_usable_rect.get_end();
  5176. if (desired_end.x > screen_usable_end.x && desired_end.x <= screen_end.x) {
  5177. desired_rect.size.x = MAX(desired_rect.size.x - (desired_end.x - screen_usable_end.x), 0);
  5178. }
  5179. if (desired_end.y > screen_usable_end.y && desired_end.y <= screen_end.y) {
  5180. desired_rect.size.y = MAX(desired_rect.size.y - (desired_end.y - screen_usable_end.y), 0);
  5181. }
  5182. }
  5183. if (desired_rect.size.x <= 100 || desired_rect.size.y <= 100) {
  5184. p_visible = false;
  5185. }
  5186. if (p_visible) {
  5187. Rect2i current_process_window_rect = _get_window_rect(ep->process_window);
  5188. if (current_process_window_rect != desired_rect) {
  5189. DEBUG_LOG_X11("Embedding XMoveResizeWindow process %ld, window %lu to %d, %d, %d, %d \n", p_pid, wd.x11_window, desired_rect.position.x, desired_rect.position.y, desired_rect.size.x, desired_rect.size.y);
  5190. XMoveResizeWindow(x11_display, ep->process_window, desired_rect.position.x, desired_rect.position.y, desired_rect.size.x, desired_rect.size.y);
  5191. }
  5192. }
  5193. }
  5194. if (ep->visible != p_visible) {
  5195. if (p_visible) {
  5196. XMapWindow(x11_display, ep->process_window);
  5197. } else {
  5198. XUnmapWindow(x11_display, ep->process_window);
  5199. }
  5200. ep->visible = p_visible;
  5201. }
  5202. if (p_grab_focus && p_visible) {
  5203. Window focused_window = 0;
  5204. int revert_to = 0;
  5205. XGetInputFocus(x11_display, &focused_window, &revert_to);
  5206. if (focused_window != ep->process_window) {
  5207. // Be sure that the window is visible to prevent BadMatch error when calling XSetInputFocus on a not viewable window.
  5208. XWindowAttributes attr;
  5209. if (XGetWindowAttributes(x11_display, ep->process_window, &attr) && attr.map_state == IsViewable) {
  5210. XSetInputFocus(x11_display, ep->process_window, RevertToParent, CurrentTime);
  5211. }
  5212. }
  5213. }
  5214. // Restore default error handler.
  5215. XSetErrorHandler(oldHandler);
  5216. return OK;
  5217. }
  5218. Error DisplayServerX11::request_close_embedded_process(OS::ProcessID p_pid) {
  5219. _THREAD_SAFE_METHOD_
  5220. if (!embedded_processes.has(p_pid)) {
  5221. return ERR_DOES_NOT_EXIST;
  5222. }
  5223. EmbeddedProcessData *ep = embedded_processes.get(p_pid);
  5224. // Handle bad window errors silently because just in case the embedded window was closed.
  5225. int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&bad_window_error_handler);
  5226. // Check if the window is still valid.
  5227. XWindowAttributes attr;
  5228. if (XGetWindowAttributes(x11_display, ep->process_window, &attr)) {
  5229. // Send the message to gracefully close the window.
  5230. XEvent ev;
  5231. memset(&ev, 0, sizeof(ev));
  5232. ev.xclient.type = ClientMessage;
  5233. ev.xclient.window = ep->process_window;
  5234. ev.xclient.message_type = XInternAtom(x11_display, "WM_PROTOCOLS", True);
  5235. ev.xclient.format = 32;
  5236. ev.xclient.data.l[0] = XInternAtom(x11_display, "WM_DELETE_WINDOW", False);
  5237. ev.xclient.data.l[1] = CurrentTime;
  5238. XSendEvent(x11_display, ep->process_window, False, NoEventMask, &ev);
  5239. }
  5240. // Restore default error handler.
  5241. XSetErrorHandler(oldHandler);
  5242. return OK;
  5243. }
  5244. Error DisplayServerX11::remove_embedded_process(OS::ProcessID p_pid) {
  5245. _THREAD_SAFE_METHOD_
  5246. if (!embedded_processes.has(p_pid)) {
  5247. return ERR_DOES_NOT_EXIST;
  5248. }
  5249. EmbeddedProcessData *ep = embedded_processes.get(p_pid);
  5250. request_close_embedded_process(p_pid);
  5251. embedded_processes.erase(p_pid);
  5252. memdelete(ep);
  5253. return OK;
  5254. }
  5255. OS::ProcessID DisplayServerX11::get_focused_process_id() {
  5256. Window focused_window = 0;
  5257. int revert_to = 0;
  5258. XGetInputFocus(x11_display, &focused_window, &revert_to);
  5259. if (focused_window == None) {
  5260. return 0;
  5261. }
  5262. return get_window_pid(x11_display, focused_window);
  5263. }
  5264. Vector<String> DisplayServerX11::get_rendering_drivers_func() {
  5265. Vector<String> drivers;
  5266. #ifdef VULKAN_ENABLED
  5267. drivers.push_back("vulkan");
  5268. #endif
  5269. #ifdef GLES3_ENABLED
  5270. drivers.push_back("opengl3");
  5271. drivers.push_back("opengl3_es");
  5272. #endif
  5273. drivers.push_back("dummy");
  5274. return drivers;
  5275. }
  5276. DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) {
  5277. DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error));
  5278. return ds;
  5279. }
  5280. DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, Window p_parent_window) {
  5281. //Create window
  5282. XVisualInfo visualInfo;
  5283. bool vi_selected = false;
  5284. #ifdef GLES3_ENABLED
  5285. if (gl_manager) {
  5286. Error err;
  5287. visualInfo = gl_manager->get_vi(x11_display, err);
  5288. ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't acquire visual info from display.");
  5289. vi_selected = true;
  5290. }
  5291. if (gl_manager_egl) {
  5292. XVisualInfo visual_info_template;
  5293. int visual_id = gl_manager_egl->display_get_native_visual_id(x11_display);
  5294. ERR_FAIL_COND_V_MSG(visual_id < 0, INVALID_WINDOW_ID, "Unable to get a visual id.");
  5295. visual_info_template.visualid = (VisualID)visual_id;
  5296. int number_of_visuals = 0;
  5297. XVisualInfo *vi_list = XGetVisualInfo(x11_display, VisualIDMask, &visual_info_template, &number_of_visuals);
  5298. ERR_FAIL_COND_V(number_of_visuals <= 0, INVALID_WINDOW_ID);
  5299. visualInfo = vi_list[0];
  5300. XFree(vi_list);
  5301. }
  5302. #endif
  5303. if (!vi_selected) {
  5304. long visualMask = VisualScreenMask;
  5305. int numberOfVisuals;
  5306. XVisualInfo vInfoTemplate = {};
  5307. vInfoTemplate.screen = DefaultScreen(x11_display);
  5308. XVisualInfo *vi_list = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals);
  5309. ERR_FAIL_NULL_V(vi_list, INVALID_WINDOW_ID);
  5310. visualInfo = vi_list[0];
  5311. if (OS::get_singleton()->is_layered_allowed()) {
  5312. for (int i = 0; i < numberOfVisuals; i++) {
  5313. XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi_list[i].visual);
  5314. if (!pict_format) {
  5315. continue;
  5316. }
  5317. visualInfo = vi_list[i];
  5318. if (pict_format->direct.alphaMask > 0) {
  5319. break;
  5320. }
  5321. }
  5322. }
  5323. XFree(vi_list);
  5324. }
  5325. Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, visualInfo.screen), visualInfo.visual, AllocNone);
  5326. XSetWindowAttributes windowAttributes = {};
  5327. windowAttributes.colormap = colormap;
  5328. windowAttributes.background_pixel = 0xFFFFFFFF;
  5329. windowAttributes.border_pixel = 0;
  5330. windowAttributes.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask;
  5331. unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
  5332. if (OS::get_singleton()->is_layered_allowed()) {
  5333. windowAttributes.background_pixmap = None;
  5334. windowAttributes.background_pixel = 0;
  5335. windowAttributes.border_pixmap = None;
  5336. valuemask |= CWBackPixel;
  5337. }
  5338. WindowID id = window_id_counter++;
  5339. WindowData &wd = windows[id];
  5340. if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
  5341. wd.no_focus = true;
  5342. }
  5343. if (p_flags & WINDOW_FLAG_POPUP_BIT) {
  5344. wd.is_popup = true;
  5345. }
  5346. // Setup for menu subwindows:
  5347. // - override_redirect forces the WM not to interfere with the window, to avoid delays due to
  5348. // handling decorations and placement.
  5349. // On the other hand, focus changes need to be handled manually when this is set.
  5350. // - save_under is a hint for the WM to keep the content of windows behind to avoid repaint.
  5351. if (wd.no_focus) {
  5352. windowAttributes.override_redirect = True;
  5353. windowAttributes.save_under = True;
  5354. valuemask |= CWOverrideRedirect | CWSaveUnder;
  5355. }
  5356. int rq_screen = get_screen_from_rect(p_rect);
  5357. if (rq_screen < 0) {
  5358. rq_screen = get_primary_screen(); // Requested window rect is outside any screen bounds.
  5359. }
  5360. Rect2i win_rect = p_rect;
  5361. if (!p_parent_window) {
  5362. // No parent.
  5363. if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
  5364. Rect2i screen_rect = Rect2i(screen_get_position(rq_screen), screen_get_size(rq_screen));
  5365. win_rect = screen_rect;
  5366. } else {
  5367. Rect2i srect = screen_get_usable_rect(rq_screen);
  5368. Point2i wpos = p_rect.position;
  5369. wpos = wpos.clamp(srect.position, srect.position + srect.size - p_rect.size / 3);
  5370. win_rect.position = wpos;
  5371. }
  5372. }
  5373. // Position and size hints are set from these values before they are updated to the actual
  5374. // window size, so we need to initialize them here.
  5375. wd.position = win_rect.position;
  5376. wd.size = win_rect.size;
  5377. {
  5378. wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), win_rect.position.x, win_rect.position.y, win_rect.size.width > 0 ? win_rect.size.width : 1, win_rect.size.height > 0 ? win_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes);
  5379. wd.parent = RootWindow(x11_display, visualInfo.screen);
  5380. DEBUG_LOG_X11("CreateWindow window=%lu, parent: %lu \n", wd.x11_window, wd.parent);
  5381. if (p_parent_window) {
  5382. wd.embed_parent = p_parent_window;
  5383. XSetTransientForHint(x11_display, wd.x11_window, p_parent_window);
  5384. }
  5385. XSetWindowAttributes window_attributes_ime = {};
  5386. window_attributes_ime.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask;
  5387. wd.x11_xim_window = XCreateWindow(x11_display, wd.x11_window, 0, 0, 1, 1, 0, CopyFromParent, InputOnly, CopyFromParent, CWEventMask, &window_attributes_ime);
  5388. #ifdef XKB_ENABLED
  5389. if (dead_tbl && xkb_loaded_v05p) {
  5390. wd.xkb_state = xkb_compose_state_new(dead_tbl, XKB_COMPOSE_STATE_NO_FLAGS);
  5391. }
  5392. #endif
  5393. #ifdef ACCESSKIT_ENABLED
  5394. if (accessibility_driver && !accessibility_driver->window_create(id, nullptr)) {
  5395. if (OS::get_singleton()->is_stdout_verbose()) {
  5396. ERR_PRINT("Can't create an accessibility adapter for window, accessibility support disabled!");
  5397. }
  5398. memdelete(accessibility_driver);
  5399. accessibility_driver = nullptr;
  5400. }
  5401. #endif
  5402. // Enable receiving notification when the window is initialized (MapNotify)
  5403. // so the focus can be set at the right time.
  5404. if (!wd.no_focus && !wd.is_popup) {
  5405. XSelectInput(x11_display, wd.x11_window, StructureNotifyMask);
  5406. }
  5407. //associate PID
  5408. // make PID known to X11
  5409. {
  5410. const long pid = OS::get_singleton()->get_process_id();
  5411. Atom net_wm_pid = XInternAtom(x11_display, "_NET_WM_PID", False);
  5412. if (net_wm_pid != None) {
  5413. XChangeProperty(x11_display, wd.x11_window, net_wm_pid, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1);
  5414. }
  5415. }
  5416. long im_event_mask = 0;
  5417. {
  5418. XIEventMask all_event_mask;
  5419. XSetWindowAttributes new_attr;
  5420. new_attr.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
  5421. ButtonReleaseMask | EnterWindowMask |
  5422. LeaveWindowMask | PointerMotionMask |
  5423. Button1MotionMask |
  5424. Button2MotionMask | Button3MotionMask |
  5425. Button4MotionMask | Button5MotionMask |
  5426. ButtonMotionMask | KeymapStateMask |
  5427. ExposureMask | VisibilityChangeMask |
  5428. StructureNotifyMask |
  5429. SubstructureNotifyMask | SubstructureRedirectMask |
  5430. FocusChangeMask | PropertyChangeMask |
  5431. ColormapChangeMask | OwnerGrabButtonMask |
  5432. im_event_mask;
  5433. XChangeWindowAttributes(x11_display, wd.x11_window, CWEventMask, &new_attr);
  5434. static unsigned char all_mask_data[XIMaskLen(XI_LASTEVENT)] = {};
  5435. all_event_mask.deviceid = XIAllDevices;
  5436. all_event_mask.mask_len = sizeof(all_mask_data);
  5437. all_event_mask.mask = all_mask_data;
  5438. XISetMask(all_event_mask.mask, XI_HierarchyChanged);
  5439. #ifdef TOUCH_ENABLED
  5440. if (xi.touch_devices.size()) {
  5441. XISetMask(all_event_mask.mask, XI_TouchBegin);
  5442. XISetMask(all_event_mask.mask, XI_TouchUpdate);
  5443. XISetMask(all_event_mask.mask, XI_TouchEnd);
  5444. XISetMask(all_event_mask.mask, XI_TouchOwnership);
  5445. }
  5446. #endif
  5447. XISelectEvents(x11_display, wd.x11_window, &all_event_mask, 1);
  5448. }
  5449. /* set the titlebar name */
  5450. XStoreName(x11_display, wd.x11_window, "Godot");
  5451. XSetWMProtocols(x11_display, wd.x11_window, &wm_delete, 1);
  5452. if (xdnd_aware != None) {
  5453. XChangeProperty(x11_display, wd.x11_window, xdnd_aware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&xdnd_version, 1);
  5454. }
  5455. if (xim && xim_style) {
  5456. // Block events polling while changing input focus
  5457. // because it triggers some event polling internally.
  5458. MutexLock mutex_lock(events_mutex);
  5459. // Force on-the-spot for the over-the-spot style.
  5460. if ((xim_style & XIMPreeditPosition) != 0) {
  5461. xim_style &= ~XIMPreeditPosition;
  5462. xim_style |= XIMPreeditCallbacks;
  5463. }
  5464. if ((xim_style & XIMPreeditCallbacks) != 0) {
  5465. ::XIMCallback preedit_start_callback;
  5466. preedit_start_callback.client_data = (::XPointer)(this);
  5467. preedit_start_callback.callback = (::XIMProc)(void *)(_xim_preedit_start_callback);
  5468. ::XIMCallback preedit_done_callback;
  5469. preedit_done_callback.client_data = (::XPointer)(this);
  5470. preedit_done_callback.callback = (::XIMProc)(_xim_preedit_done_callback);
  5471. ::XIMCallback preedit_draw_callback;
  5472. preedit_draw_callback.client_data = (::XPointer)(this);
  5473. preedit_draw_callback.callback = (::XIMProc)(_xim_preedit_draw_callback);
  5474. ::XIMCallback preedit_caret_callback;
  5475. preedit_caret_callback.client_data = (::XPointer)(this);
  5476. preedit_caret_callback.callback = (::XIMProc)(_xim_preedit_caret_callback);
  5477. ::XVaNestedList preedit_attributes = XVaCreateNestedList(0,
  5478. XNPreeditStartCallback, &preedit_start_callback,
  5479. XNPreeditDoneCallback, &preedit_done_callback,
  5480. XNPreeditDrawCallback, &preedit_draw_callback,
  5481. XNPreeditCaretCallback, &preedit_caret_callback,
  5482. (char *)nullptr);
  5483. wd.xic = XCreateIC(xim,
  5484. XNInputStyle, xim_style,
  5485. XNClientWindow, wd.x11_xim_window,
  5486. XNFocusWindow, wd.x11_xim_window,
  5487. XNPreeditAttributes, preedit_attributes,
  5488. (char *)nullptr);
  5489. XFree(preedit_attributes);
  5490. } else {
  5491. wd.xic = XCreateIC(xim,
  5492. XNInputStyle, xim_style,
  5493. XNClientWindow, wd.x11_xim_window,
  5494. XNFocusWindow, wd.x11_xim_window,
  5495. (char *)nullptr);
  5496. }
  5497. if (XGetICValues(wd.xic, XNFilterEvents, &im_event_mask, nullptr) != nullptr) {
  5498. WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value");
  5499. XDestroyIC(wd.xic);
  5500. wd.xic = nullptr;
  5501. }
  5502. if (wd.xic) {
  5503. XUnsetICFocus(wd.xic);
  5504. } else {
  5505. WARN_PRINT("XCreateIC couldn't create wd.xic");
  5506. }
  5507. } else {
  5508. wd.xic = nullptr;
  5509. WARN_PRINT("XCreateIC couldn't create wd.xic");
  5510. }
  5511. _update_context(wd);
  5512. if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
  5513. Hints hints;
  5514. Atom property;
  5515. hints.flags = 2;
  5516. hints.decorations = 0;
  5517. property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
  5518. if (property != None) {
  5519. XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
  5520. }
  5521. }
  5522. if (wd.is_popup || wd.no_focus || (wd.embed_parent && !kde5_embed_workaround)) {
  5523. // Set Utility type to disable fade animations.
  5524. Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
  5525. Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
  5526. if (wt_atom != None && type_atom != None) {
  5527. XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
  5528. }
  5529. } else {
  5530. Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
  5531. Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
  5532. if (wt_atom != None && type_atom != None) {
  5533. XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
  5534. }
  5535. }
  5536. if (p_parent_window) {
  5537. // Disable the window in the taskbar and alt-tab.
  5538. _set_window_taskbar_pager_enabled(wd.x11_window, false);
  5539. }
  5540. _update_size_hints(id);
  5541. #if defined(RD_ENABLED)
  5542. if (rendering_context) {
  5543. union {
  5544. #ifdef VULKAN_ENABLED
  5545. RenderingContextDriverVulkanX11::WindowPlatformData vulkan;
  5546. #endif
  5547. } wpd;
  5548. #ifdef VULKAN_ENABLED
  5549. if (rendering_driver == "vulkan") {
  5550. wpd.vulkan.window = wd.x11_window;
  5551. wpd.vulkan.display = x11_display;
  5552. }
  5553. #endif
  5554. Error err = rendering_context->window_create(id, &wpd);
  5555. ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, vformat("Can't create a %s window", rendering_driver));
  5556. rendering_context->window_set_size(id, win_rect.size.width, win_rect.size.height);
  5557. rendering_context->window_set_vsync_mode(id, p_vsync_mode);
  5558. }
  5559. #endif
  5560. #ifdef GLES3_ENABLED
  5561. if (gl_manager) {
  5562. Error err = gl_manager->window_create(id, wd.x11_window, x11_display, win_rect.size.width, win_rect.size.height);
  5563. ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL window");
  5564. }
  5565. if (gl_manager_egl) {
  5566. Error err = gl_manager_egl->window_create(id, x11_display, &wd.x11_window, win_rect.size.width, win_rect.size.height);
  5567. ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Failed to create an OpenGLES window.");
  5568. }
  5569. window_set_vsync_mode(p_vsync_mode, id);
  5570. #endif
  5571. //set_class_hint(x11_display, wd.x11_window);
  5572. XFlush(x11_display);
  5573. XSync(x11_display, False);
  5574. //XSetErrorHandler(oldHandler);
  5575. }
  5576. window_set_mode(p_mode, id);
  5577. //sync size
  5578. {
  5579. XWindowAttributes xwa;
  5580. XSync(x11_display, False);
  5581. XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
  5582. wd.position.x = xwa.x;
  5583. wd.position.y = xwa.y;
  5584. wd.size.width = xwa.width;
  5585. wd.size.height = xwa.height;
  5586. }
  5587. //set cursor
  5588. if (cursors[current_cursor] != None) {
  5589. XDefineCursor(x11_display, wd.x11_window, cursors[current_cursor]);
  5590. }
  5591. return id;
  5592. }
  5593. static bool _is_xim_style_supported(const ::XIMStyle &p_style) {
  5594. const ::XIMStyle supported_preedit = XIMPreeditCallbacks | XIMPreeditPosition | XIMPreeditNothing | XIMPreeditNone;
  5595. const ::XIMStyle supported_status = XIMStatusNothing | XIMStatusNone;
  5596. // Check preedit style is supported
  5597. if ((p_style & supported_preedit) == 0) {
  5598. return false;
  5599. }
  5600. // Check status style is supported
  5601. if ((p_style & supported_status) == 0) {
  5602. return false;
  5603. }
  5604. return true;
  5605. }
  5606. static ::XIMStyle _get_best_xim_style(const ::XIMStyle &p_style_a, const ::XIMStyle &p_style_b) {
  5607. if (p_style_a == 0) {
  5608. return p_style_b;
  5609. }
  5610. if (p_style_b == 0) {
  5611. return p_style_a;
  5612. }
  5613. const ::XIMStyle preedit = XIMPreeditArea | XIMPreeditCallbacks | XIMPreeditPosition | XIMPreeditNothing | XIMPreeditNone;
  5614. const ::XIMStyle status = XIMStatusArea | XIMStatusCallbacks | XIMStatusNothing | XIMStatusNone;
  5615. ::XIMStyle a = p_style_a & preedit;
  5616. ::XIMStyle b = p_style_b & preedit;
  5617. if (a != b) {
  5618. // Compare preedit styles.
  5619. if ((a | b) & XIMPreeditCallbacks) {
  5620. return a == XIMPreeditCallbacks ? p_style_a : p_style_b;
  5621. } else if ((a | b) & XIMPreeditPosition) {
  5622. return a == XIMPreeditPosition ? p_style_a : p_style_b;
  5623. } else if ((a | b) & XIMPreeditArea) {
  5624. return a == XIMPreeditArea ? p_style_a : p_style_b;
  5625. } else if ((a | b) & XIMPreeditNothing) {
  5626. return a == XIMPreeditNothing ? p_style_a : p_style_b;
  5627. }
  5628. } else {
  5629. // Preedit styles are the same, compare status styles.
  5630. a = p_style_a & status;
  5631. b = p_style_b & status;
  5632. if ((a | b) & XIMStatusCallbacks) {
  5633. return a == XIMStatusCallbacks ? p_style_a : p_style_b;
  5634. } else if ((a | b) & XIMStatusArea) {
  5635. return a == XIMStatusArea ? p_style_a : p_style_b;
  5636. } else if ((a | b) & XIMStatusNothing) {
  5637. return a == XIMStatusNothing ? p_style_a : p_style_b;
  5638. }
  5639. }
  5640. return p_style_a;
  5641. }
  5642. DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) {
  5643. KeyMappingX11::initialize();
  5644. String current_desk = OS::get_singleton()->get_environment("XDG_CURRENT_DESKTOP").to_lower();
  5645. String session_desk = OS::get_singleton()->get_environment("XDG_SESSION_DESKTOP").to_lower();
  5646. swap_cancel_ok = (current_desk.contains("kde") || session_desk.contains("kde") || current_desk.contains("lxqt") || session_desk.contains("lxqt"));
  5647. xwayland = OS::get_singleton()->get_environment("XDG_SESSION_TYPE").to_lower() == "wayland";
  5648. kde5_embed_workaround = current_desk == "kde" && OS::get_singleton()->get_environment("KDE_SESSION_VERSION") == "5";
  5649. native_menu = memnew(NativeMenu);
  5650. context = p_context;
  5651. #ifdef SOWRAP_ENABLED
  5652. #ifdef DEBUG_ENABLED
  5653. int dylibloader_verbose = 1;
  5654. #else
  5655. int dylibloader_verbose = 0;
  5656. #endif
  5657. if (initialize_xlib(dylibloader_verbose) != 0) {
  5658. r_error = ERR_UNAVAILABLE;
  5659. ERR_FAIL_MSG("Can't load Xlib dynamically.");
  5660. }
  5661. if (initialize_xcursor(dylibloader_verbose) != 0) {
  5662. r_error = ERR_UNAVAILABLE;
  5663. ERR_FAIL_MSG("Can't load XCursor dynamically.");
  5664. }
  5665. #ifdef XKB_ENABLED
  5666. bool xkb_loaded = (initialize_xkbcommon(dylibloader_verbose) == 0);
  5667. xkb_loaded_v05p = xkb_loaded;
  5668. if (!xkb_context_new || !xkb_compose_table_new_from_locale || !xkb_compose_table_unref || !xkb_context_unref || !xkb_compose_state_feed || !xkb_compose_state_unref || !xkb_compose_state_new || !xkb_compose_state_get_status || !xkb_compose_state_get_utf8) {
  5669. xkb_loaded_v05p = false;
  5670. print_verbose("Detected XKBcommon library version older than 0.5, dead key composition and Unicode key labels disabled.");
  5671. }
  5672. xkb_loaded_v08p = xkb_loaded;
  5673. if (!xkb_keysym_to_utf32 || !xkb_keysym_to_upper) {
  5674. xkb_loaded_v08p = false;
  5675. print_verbose("Detected XKBcommon library version older than 0.8, Unicode key labels disabled.");
  5676. }
  5677. #endif
  5678. if (initialize_xext(dylibloader_verbose) != 0) {
  5679. r_error = ERR_UNAVAILABLE;
  5680. ERR_FAIL_MSG("Can't load Xext dynamically.");
  5681. }
  5682. if (initialize_xinerama(dylibloader_verbose) != 0) {
  5683. xinerama_ext_ok = false;
  5684. }
  5685. if (initialize_xrandr(dylibloader_verbose) != 0) {
  5686. xrandr_ext_ok = false;
  5687. }
  5688. if (initialize_xrender(dylibloader_verbose) != 0) {
  5689. r_error = ERR_UNAVAILABLE;
  5690. ERR_FAIL_MSG("Can't load Xrender dynamically.");
  5691. }
  5692. if (initialize_xinput2(dylibloader_verbose) != 0) {
  5693. r_error = ERR_UNAVAILABLE;
  5694. ERR_FAIL_MSG("Can't load Xinput2 dynamically.");
  5695. }
  5696. #else
  5697. #ifdef XKB_ENABLED
  5698. bool xkb_loaded = true;
  5699. xkb_loaded_v05p = true;
  5700. xkb_loaded_v08p = true;
  5701. #endif
  5702. #endif
  5703. #ifdef XKB_ENABLED
  5704. if (xkb_loaded) {
  5705. xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  5706. if (xkb_ctx) {
  5707. const char *locale = getenv("LC_ALL");
  5708. if (!locale || !*locale) {
  5709. locale = getenv("LC_CTYPE");
  5710. }
  5711. if (!locale || !*locale) {
  5712. locale = getenv("LANG");
  5713. }
  5714. if (!locale || !*locale) {
  5715. locale = "C";
  5716. }
  5717. dead_tbl = xkb_compose_table_new_from_locale(xkb_ctx, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
  5718. }
  5719. }
  5720. #endif
  5721. Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
  5722. r_error = OK;
  5723. #ifdef SOWRAP_ENABLED
  5724. {
  5725. if (!XcursorImageCreate || !XcursorImageLoadCursor || !XcursorImageDestroy || !XcursorGetDefaultSize || !XcursorGetTheme || !XcursorLibraryLoadImage) {
  5726. // There's no API to check version, check if functions are available instead.
  5727. ERR_PRINT("Unsupported Xcursor library version.");
  5728. r_error = ERR_UNAVAILABLE;
  5729. return;
  5730. }
  5731. }
  5732. #endif
  5733. for (int i = 0; i < CURSOR_MAX; i++) {
  5734. cursors[i] = None;
  5735. cursor_img[i] = nullptr;
  5736. }
  5737. XInitThreads(); //always use threads
  5738. /** XLIB INITIALIZATION **/
  5739. x11_display = XOpenDisplay(nullptr);
  5740. if (!x11_display) {
  5741. ERR_PRINT("X11 Display is not available");
  5742. r_error = ERR_UNAVAILABLE;
  5743. return;
  5744. }
  5745. if (xshaped_ext_ok) {
  5746. int version_major = 0;
  5747. int version_minor = 0;
  5748. int rc = XShapeQueryVersion(x11_display, &version_major, &version_minor);
  5749. print_verbose(vformat("Xshape %d.%d detected.", version_major, version_minor));
  5750. if (rc != 1 || version_major < 1) {
  5751. xshaped_ext_ok = false;
  5752. print_verbose("Unsupported Xshape library version.");
  5753. }
  5754. }
  5755. if (xinerama_ext_ok) {
  5756. int version_major = 0;
  5757. int version_minor = 0;
  5758. int rc = XineramaQueryVersion(x11_display, &version_major, &version_minor);
  5759. print_verbose(vformat("Xinerama %d.%d detected.", version_major, version_minor));
  5760. if (rc != 1 || version_major < 1) {
  5761. xinerama_ext_ok = false;
  5762. print_verbose("Unsupported Xinerama library version.");
  5763. }
  5764. }
  5765. if (xrandr_ext_ok) {
  5766. int version_major = 0;
  5767. int version_minor = 0;
  5768. int rc = XRRQueryVersion(x11_display, &version_major, &version_minor);
  5769. print_verbose(vformat("Xrandr %d.%d detected.", version_major, version_minor));
  5770. if (rc != 1 || (version_major == 1 && version_minor < 3) || (version_major < 1)) {
  5771. xrandr_ext_ok = false;
  5772. print_verbose("Unsupported Xrandr library version.");
  5773. }
  5774. }
  5775. {
  5776. int version_major = 0;
  5777. int version_minor = 0;
  5778. int rc = XRenderQueryVersion(x11_display, &version_major, &version_minor);
  5779. print_verbose(vformat("Xrender %d.%d detected.", version_major, version_minor));
  5780. if (rc != 1 || (version_major == 0 && version_minor < 11)) {
  5781. ERR_PRINT("Unsupported Xrender library version.");
  5782. r_error = ERR_UNAVAILABLE;
  5783. XCloseDisplay(x11_display);
  5784. return;
  5785. }
  5786. }
  5787. {
  5788. int version_major = 2; // Report 2.2 as supported by engine, but should work with 2.1 or 2.0 library as well.
  5789. int version_minor = 2;
  5790. int rc = XIQueryVersion(x11_display, &version_major, &version_minor);
  5791. print_verbose(vformat("Xinput %d.%d detected.", version_major, version_minor));
  5792. if (rc != Success || (version_major < 2)) {
  5793. ERR_PRINT("Unsupported Xinput2 library version.");
  5794. r_error = ERR_UNAVAILABLE;
  5795. XCloseDisplay(x11_display);
  5796. return;
  5797. }
  5798. }
  5799. char *modifiers = nullptr;
  5800. Bool xkb_dar = False;
  5801. XAutoRepeatOn(x11_display);
  5802. xkb_dar = XkbSetDetectableAutoRepeat(x11_display, True, nullptr);
  5803. // Try to support IME if detectable auto-repeat is supported
  5804. if (xkb_dar == True) {
  5805. #ifdef X_HAVE_UTF8_STRING
  5806. // Xutf8LookupString will be used later instead of XmbLookupString before
  5807. // the multibyte sequences can be converted to unicode string.
  5808. modifiers = XSetLocaleModifiers("");
  5809. #endif
  5810. }
  5811. if (modifiers == nullptr) {
  5812. if (OS::get_singleton()->is_stdout_verbose()) {
  5813. WARN_PRINT("IME is disabled");
  5814. }
  5815. XSetLocaleModifiers("@im=none");
  5816. WARN_PRINT("Error setting locale modifiers");
  5817. }
  5818. const char *err;
  5819. int xrandr_major = 0;
  5820. int xrandr_minor = 0;
  5821. int event_base, error_base;
  5822. xrandr_ext_ok = XRRQueryExtension(x11_display, &event_base, &error_base);
  5823. xrandr_handle = dlopen("libXrandr.so.2", RTLD_LAZY);
  5824. if (!xrandr_handle) {
  5825. err = dlerror();
  5826. // For some arcane reason, NetBSD now ships libXrandr.so.3 while the rest of the world has libXrandr.so.2...
  5827. // In case this happens for other X11 platforms in the future, let's give it a try too before failing.
  5828. xrandr_handle = dlopen("libXrandr.so.3", RTLD_LAZY);
  5829. if (!xrandr_handle) {
  5830. fprintf(stderr, "could not load libXrandr.so.2, Error: %s\n", err);
  5831. }
  5832. }
  5833. if (xrandr_handle) {
  5834. XRRQueryVersion(x11_display, &xrandr_major, &xrandr_minor);
  5835. if (((xrandr_major << 8) | xrandr_minor) >= 0x0105) {
  5836. xrr_get_monitors = (xrr_get_monitors_t)dlsym(xrandr_handle, "XRRGetMonitors");
  5837. if (!xrr_get_monitors) {
  5838. err = dlerror();
  5839. fprintf(stderr, "could not find symbol XRRGetMonitors\nError: %s\n", err);
  5840. } else {
  5841. xrr_free_monitors = (xrr_free_monitors_t)dlsym(xrandr_handle, "XRRFreeMonitors");
  5842. if (!xrr_free_monitors) {
  5843. err = dlerror();
  5844. fprintf(stderr, "could not find XRRFreeMonitors\nError: %s\n", err);
  5845. xrr_get_monitors = nullptr;
  5846. }
  5847. }
  5848. }
  5849. }
  5850. if (!_refresh_device_info()) {
  5851. OS::get_singleton()->alert("Your system does not support XInput 2.\n"
  5852. "Please upgrade your distribution.",
  5853. "Unable to initialize XInput");
  5854. r_error = ERR_UNAVAILABLE;
  5855. return;
  5856. }
  5857. xim = XOpenIM(x11_display, nullptr, nullptr, nullptr);
  5858. if (xim == nullptr) {
  5859. WARN_PRINT("XOpenIM failed");
  5860. xim_style = 0L;
  5861. } else {
  5862. ::XIMCallback im_destroy_callback;
  5863. im_destroy_callback.client_data = (::XPointer)(this);
  5864. im_destroy_callback.callback = (::XIMProc)(_xim_destroy_callback);
  5865. if (XSetIMValues(xim, XNDestroyCallback, &im_destroy_callback,
  5866. nullptr) != nullptr) {
  5867. WARN_PRINT("Error setting XIM destroy callback");
  5868. }
  5869. ::XIMStyles *xim_styles = nullptr;
  5870. xim_style = 0L;
  5871. char *imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, nullptr);
  5872. if (imvalret != nullptr || xim_styles == nullptr) {
  5873. fprintf(stderr, "Input method doesn't support any styles\n");
  5874. }
  5875. if (xim_styles) {
  5876. xim_style = 0L;
  5877. for (int i = 0; i < xim_styles->count_styles; i++) {
  5878. const ::XIMStyle &style = xim_styles->supported_styles[i];
  5879. if (!_is_xim_style_supported(style)) {
  5880. continue;
  5881. }
  5882. xim_style = _get_best_xim_style(xim_style, style);
  5883. }
  5884. XFree(xim_styles);
  5885. }
  5886. XFree(imvalret);
  5887. }
  5888. /* Atom internment */
  5889. wm_delete = XInternAtom(x11_display, "WM_DELETE_WINDOW", true);
  5890. // Set Xdnd (drag & drop) support.
  5891. xdnd_aware = XInternAtom(x11_display, "XdndAware", False);
  5892. xdnd_enter = XInternAtom(x11_display, "XdndEnter", False);
  5893. xdnd_position = XInternAtom(x11_display, "XdndPosition", False);
  5894. xdnd_status = XInternAtom(x11_display, "XdndStatus", False);
  5895. xdnd_action_copy = XInternAtom(x11_display, "XdndActionCopy", False);
  5896. xdnd_drop = XInternAtom(x11_display, "XdndDrop", False);
  5897. xdnd_finished = XInternAtom(x11_display, "XdndFinished", False);
  5898. xdnd_selection = XInternAtom(x11_display, "XdndSelection", False);
  5899. #ifdef SPEECHD_ENABLED
  5900. // Init TTS
  5901. bool tts_enabled = GLOBAL_GET("audio/general/text_to_speech");
  5902. if (tts_enabled) {
  5903. initialize_tts();
  5904. }
  5905. #endif
  5906. #ifdef ACCESSKIT_ENABLED
  5907. if (accessibility_get_mode() != DisplayServer::AccessibilityMode::ACCESSIBILITY_DISABLED) {
  5908. accessibility_driver = memnew(AccessibilityDriverAccessKit);
  5909. if (accessibility_driver->init() != OK) {
  5910. memdelete(accessibility_driver);
  5911. accessibility_driver = nullptr;
  5912. }
  5913. }
  5914. #endif
  5915. //!!!!!!!!!!!!!!!!!!!!!!!!!!
  5916. //TODO - do Vulkan and OpenGL support checks, driver selection and fallback
  5917. rendering_driver = p_rendering_driver;
  5918. bool driver_found = false;
  5919. String executable_name = OS::get_singleton()->get_executable_path().get_file();
  5920. // Initialize context and rendering device.
  5921. if (rendering_driver == "dummy") {
  5922. RasterizerDummy::make_current();
  5923. driver_found = true;
  5924. }
  5925. #if defined(RD_ENABLED)
  5926. #if defined(VULKAN_ENABLED)
  5927. if (rendering_driver == "vulkan") {
  5928. rendering_context = memnew(RenderingContextDriverVulkanX11);
  5929. }
  5930. #endif // VULKAN_ENABLED
  5931. if (rendering_context) {
  5932. if (rendering_context->initialize() != OK) {
  5933. memdelete(rendering_context);
  5934. rendering_context = nullptr;
  5935. #if defined(GLES3_ENABLED)
  5936. bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3");
  5937. if (fallback_to_opengl3 && rendering_driver != "opengl3") {
  5938. WARN_PRINT("Your video card drivers seem not to support the required Vulkan version, switching to OpenGL 3.");
  5939. rendering_driver = "opengl3";
  5940. OS::get_singleton()->set_current_rendering_method("gl_compatibility");
  5941. OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
  5942. } else
  5943. #endif // GLES3_ENABLED
  5944. {
  5945. r_error = ERR_CANT_CREATE;
  5946. if (p_rendering_driver == "vulkan") {
  5947. OS::get_singleton()->alert(
  5948. vformat("Your video card drivers seem not to support the required Vulkan version.\n\n"
  5949. "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n"
  5950. "You can enable the OpenGL 3 driver by starting the engine from the\n"
  5951. "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n"
  5952. "If you recently updated your video card drivers, try rebooting.",
  5953. executable_name),
  5954. "Unable to initialize Vulkan video driver");
  5955. }
  5956. ERR_FAIL_MSG(vformat("Could not initialize %s", rendering_driver));
  5957. }
  5958. }
  5959. driver_found = true;
  5960. }
  5961. #endif // RD_ENABLED
  5962. #if defined(GLES3_ENABLED)
  5963. if (rendering_driver == "opengl3" || rendering_driver == "opengl3_es") {
  5964. if (getenv("DRI_PRIME") == nullptr) {
  5965. int use_prime = -1;
  5966. if (getenv("PRIMUS_DISPLAY") ||
  5967. getenv("PRIMUS_libGLd") ||
  5968. getenv("PRIMUS_libGLa") ||
  5969. getenv("PRIMUS_libGL") ||
  5970. getenv("PRIMUS_LOAD_GLOBAL") ||
  5971. getenv("BUMBLEBEE_SOCKET")) {
  5972. print_verbose("Optirun/primusrun detected. Skipping GPU detection");
  5973. use_prime = 0;
  5974. }
  5975. // Some tools use fake libGL libraries and have them override the real one using
  5976. // LD_LIBRARY_PATH, so we skip them. *But* Steam also sets LD_LIBRARY_PATH for its
  5977. // runtime and includes system `/lib` and `/lib64`... so ignore Steam.
  5978. if (use_prime == -1 && getenv("LD_LIBRARY_PATH") && !getenv("STEAM_RUNTIME_LIBRARY_PATH")) {
  5979. String ld_library_path(getenv("LD_LIBRARY_PATH"));
  5980. Vector<String> libraries = ld_library_path.split(":");
  5981. for (int i = 0; i < libraries.size(); ++i) {
  5982. if (FileAccess::exists(libraries[i] + "/libGL.so.1") ||
  5983. FileAccess::exists(libraries[i] + "/libGL.so")) {
  5984. print_verbose("Custom libGL override detected. Skipping GPU detection");
  5985. use_prime = 0;
  5986. }
  5987. }
  5988. }
  5989. if (use_prime == -1) {
  5990. print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic.");
  5991. use_prime = DetectPrimeX11::detect_prime();
  5992. }
  5993. if (use_prime) {
  5994. print_line("Found discrete GPU, setting DRI_PRIME=1 to use it.");
  5995. print_line("Note: Set DRI_PRIME=0 in the environment to disable Godot from using the discrete GPU.");
  5996. setenv("DRI_PRIME", "1", 1);
  5997. }
  5998. }
  5999. }
  6000. if (rendering_driver == "opengl3") {
  6001. gl_manager = memnew(GLManager_X11(p_resolution, GLManager_X11::GLES_3_0_COMPATIBLE));
  6002. if (gl_manager->initialize(x11_display) != OK || gl_manager->open_display(x11_display) != OK) {
  6003. memdelete(gl_manager);
  6004. gl_manager = nullptr;
  6005. bool fallback = GLOBAL_GET("rendering/gl_compatibility/fallback_to_gles");
  6006. if (fallback) {
  6007. WARN_PRINT("Your video card drivers seem not to support the required OpenGL version, switching to OpenGLES.");
  6008. rendering_driver = "opengl3_es";
  6009. OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
  6010. } else {
  6011. r_error = ERR_UNAVAILABLE;
  6012. OS::get_singleton()->alert(
  6013. vformat("Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n"
  6014. "If possible, consider updating your video card drivers or using the Vulkan driver.\n\n"
  6015. "You can enable the Vulkan driver by starting the engine from the\n"
  6016. "command line with the command:\n\n \"%s\" --rendering-driver vulkan\n\n"
  6017. "If you recently updated your video card drivers, try rebooting.",
  6018. executable_name),
  6019. "Unable to initialize OpenGL video driver");
  6020. ERR_FAIL_MSG("Could not initialize OpenGL.");
  6021. }
  6022. } else {
  6023. driver_found = true;
  6024. RasterizerGLES3::make_current(true);
  6025. }
  6026. }
  6027. if (rendering_driver == "opengl3_es") {
  6028. gl_manager_egl = memnew(GLManagerEGL_X11);
  6029. if (gl_manager_egl->initialize() != OK || gl_manager_egl->open_display(x11_display) != OK) {
  6030. memdelete(gl_manager_egl);
  6031. gl_manager_egl = nullptr;
  6032. r_error = ERR_UNAVAILABLE;
  6033. OS::get_singleton()->alert(
  6034. "Your video card drivers seem not to support the required OpenGL ES 3.0 version.\n\n"
  6035. "If possible, consider updating your video card drivers.\n\n"
  6036. "If you recently updated your video card drivers, try rebooting.",
  6037. "Unable to initialize OpenGL ES video driver");
  6038. ERR_FAIL_MSG("Could not initialize OpenGL ES.");
  6039. }
  6040. driver_found = true;
  6041. RasterizerGLES3::make_current(false);
  6042. }
  6043. #endif // GLES3_ENABLED
  6044. if (!driver_found) {
  6045. r_error = ERR_UNAVAILABLE;
  6046. ERR_FAIL_MSG("Video driver not found.");
  6047. }
  6048. Point2i window_position;
  6049. if (p_position != nullptr) {
  6050. window_position = *p_position;
  6051. } else {
  6052. if (p_screen == SCREEN_OF_MAIN_WINDOW) {
  6053. p_screen = SCREEN_PRIMARY;
  6054. }
  6055. Rect2i scr_rect = screen_get_usable_rect(p_screen);
  6056. window_position = scr_rect.position + (scr_rect.size - p_resolution) / 2;
  6057. }
  6058. WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution), p_parent_window);
  6059. if (main_window == INVALID_WINDOW_ID) {
  6060. r_error = ERR_CANT_CREATE;
  6061. return;
  6062. }
  6063. for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
  6064. if (p_flags & (1 << i)) {
  6065. window_set_flag(WindowFlags(i), true, main_window);
  6066. }
  6067. }
  6068. #if defined(RD_ENABLED)
  6069. if (rendering_context) {
  6070. rendering_device = memnew(RenderingDevice);
  6071. if (rendering_device->initialize(rendering_context, MAIN_WINDOW_ID) != OK) {
  6072. memdelete(rendering_device);
  6073. rendering_device = nullptr;
  6074. memdelete(rendering_context);
  6075. rendering_context = nullptr;
  6076. r_error = ERR_UNAVAILABLE;
  6077. return;
  6078. }
  6079. rendering_device->screen_create(MAIN_WINDOW_ID);
  6080. RendererCompositorRD::make_current();
  6081. }
  6082. #endif // RD_ENABLED
  6083. {
  6084. //set all event master mask
  6085. XIEventMask all_master_event_mask;
  6086. static unsigned char all_master_mask_data[XIMaskLen(XI_LASTEVENT)] = {};
  6087. all_master_event_mask.deviceid = XIAllMasterDevices;
  6088. all_master_event_mask.mask_len = sizeof(all_master_mask_data);
  6089. all_master_event_mask.mask = all_master_mask_data;
  6090. XISetMask(all_master_event_mask.mask, XI_DeviceChanged);
  6091. XISetMask(all_master_event_mask.mask, XI_RawMotion);
  6092. XISelectEvents(x11_display, DefaultRootWindow(x11_display), &all_master_event_mask, 1);
  6093. }
  6094. cursor_size = XcursorGetDefaultSize(x11_display);
  6095. cursor_theme = XcursorGetTheme(x11_display);
  6096. if (!cursor_theme) {
  6097. print_verbose("XcursorGetTheme could not get cursor theme");
  6098. cursor_theme = "default";
  6099. }
  6100. for (int i = 0; i < CURSOR_MAX; i++) {
  6101. static const char *cursor_file[] = {
  6102. "left_ptr",
  6103. "xterm",
  6104. "hand2",
  6105. "cross",
  6106. "watch",
  6107. "left_ptr_watch",
  6108. "fleur",
  6109. "dnd-move",
  6110. "crossed_circle",
  6111. "v_double_arrow",
  6112. "h_double_arrow",
  6113. "size_bdiag",
  6114. "size_fdiag",
  6115. "move",
  6116. "row_resize",
  6117. "col_resize",
  6118. "question_arrow"
  6119. };
  6120. cursor_img[i] = XcursorLibraryLoadImage(cursor_file[i], cursor_theme, cursor_size);
  6121. if (!cursor_img[i]) {
  6122. const char *fallback = nullptr;
  6123. switch (i) {
  6124. case CURSOR_POINTING_HAND:
  6125. fallback = "pointer";
  6126. break;
  6127. case CURSOR_CROSS:
  6128. fallback = "crosshair";
  6129. break;
  6130. case CURSOR_WAIT:
  6131. fallback = "wait";
  6132. break;
  6133. case CURSOR_BUSY:
  6134. fallback = "progress";
  6135. break;
  6136. case CURSOR_DRAG:
  6137. fallback = "grabbing";
  6138. break;
  6139. case CURSOR_CAN_DROP:
  6140. fallback = "hand1";
  6141. break;
  6142. case CURSOR_FORBIDDEN:
  6143. fallback = "forbidden";
  6144. break;
  6145. case CURSOR_VSIZE:
  6146. fallback = "ns-resize";
  6147. break;
  6148. case CURSOR_HSIZE:
  6149. fallback = "ew-resize";
  6150. break;
  6151. case CURSOR_BDIAGSIZE:
  6152. fallback = "fd_double_arrow";
  6153. break;
  6154. case CURSOR_FDIAGSIZE:
  6155. fallback = "bd_double_arrow";
  6156. break;
  6157. case CURSOR_MOVE:
  6158. cursor_img[i] = cursor_img[CURSOR_DRAG];
  6159. break;
  6160. case CURSOR_VSPLIT:
  6161. fallback = "sb_v_double_arrow";
  6162. break;
  6163. case CURSOR_HSPLIT:
  6164. fallback = "sb_h_double_arrow";
  6165. break;
  6166. case CURSOR_HELP:
  6167. fallback = "help";
  6168. break;
  6169. }
  6170. if (fallback != nullptr) {
  6171. cursor_img[i] = XcursorLibraryLoadImage(fallback, cursor_theme, cursor_size);
  6172. }
  6173. }
  6174. if (cursor_img[i]) {
  6175. cursors[i] = XcursorImageLoadCursor(x11_display, cursor_img[i]);
  6176. } else {
  6177. print_verbose("Failed loading custom cursor: " + String(cursor_file[i]));
  6178. }
  6179. }
  6180. {
  6181. // Creating an empty/transparent cursor
  6182. // Create 1x1 bitmap
  6183. Pixmap cursormask = XCreatePixmap(x11_display,
  6184. RootWindow(x11_display, DefaultScreen(x11_display)), 1, 1, 1);
  6185. // Fill with zero
  6186. XGCValues xgc;
  6187. xgc.function = GXclear;
  6188. GC gc = XCreateGC(x11_display, cursormask, GCFunction, &xgc);
  6189. XFillRectangle(x11_display, cursormask, gc, 0, 0, 1, 1);
  6190. // Color value doesn't matter. Mask zero means no foreground or background will be drawn
  6191. XColor col = {};
  6192. Cursor cursor = XCreatePixmapCursor(x11_display,
  6193. cursormask, // source (using cursor mask as placeholder, since it'll all be ignored)
  6194. cursormask, // mask
  6195. &col, &col, 0, 0);
  6196. XFreePixmap(x11_display, cursormask);
  6197. XFreeGC(x11_display, gc);
  6198. if (cursor == None) {
  6199. ERR_PRINT("FAILED CREATING CURSOR");
  6200. }
  6201. null_cursor = cursor;
  6202. }
  6203. cursor_set_shape(CURSOR_BUSY);
  6204. // Search the X11 event queue for ConfigureNotify events and process all
  6205. // that are currently queued early, so we can get the final window size
  6206. // for correctly drawing of the bootsplash.
  6207. XEvent config_event;
  6208. while (XCheckTypedEvent(x11_display, ConfigureNotify, &config_event)) {
  6209. _window_changed(&config_event);
  6210. }
  6211. events_thread.start(_poll_events_thread, this);
  6212. _update_real_mouse_position(windows[MAIN_WINDOW_ID]);
  6213. #ifdef DBUS_ENABLED
  6214. screensaver = memnew(FreeDesktopScreenSaver);
  6215. screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
  6216. portal_desktop = memnew(FreeDesktopPortalDesktop);
  6217. atspi_monitor = memnew(FreeDesktopAtSPIMonitor);
  6218. #endif // DBUS_ENABLED
  6219. XSetErrorHandler(&default_window_error_handler);
  6220. r_error = OK;
  6221. }
  6222. DisplayServerX11::~DisplayServerX11() {
  6223. // Send owned clipboard data to clipboard manager before exit.
  6224. Window x11_main_window = windows[MAIN_WINDOW_ID].x11_window;
  6225. _clipboard_transfer_ownership(XA_PRIMARY, x11_main_window);
  6226. _clipboard_transfer_ownership(XInternAtom(x11_display, "CLIPBOARD", 0), x11_main_window);
  6227. events_thread_done.set();
  6228. events_thread.wait_to_finish();
  6229. if (native_menu) {
  6230. memdelete(native_menu);
  6231. native_menu = nullptr;
  6232. }
  6233. //destroy all windows
  6234. for (KeyValue<WindowID, WindowData> &E : windows) {
  6235. #if defined(RD_ENABLED)
  6236. if (rendering_device) {
  6237. rendering_device->screen_free(E.key);
  6238. }
  6239. if (rendering_context) {
  6240. rendering_context->window_destroy(E.key);
  6241. }
  6242. #endif
  6243. #ifdef GLES3_ENABLED
  6244. if (gl_manager) {
  6245. gl_manager->window_destroy(E.key);
  6246. }
  6247. if (gl_manager_egl) {
  6248. gl_manager_egl->window_destroy(E.key);
  6249. }
  6250. #endif
  6251. #ifdef ACCESSKIT_ENABLED
  6252. if (accessibility_driver) {
  6253. accessibility_driver->window_destroy(E.key);
  6254. }
  6255. #endif
  6256. WindowData &wd = E.value;
  6257. if (wd.xic) {
  6258. XDestroyIC(wd.xic);
  6259. wd.xic = nullptr;
  6260. }
  6261. XDestroyWindow(x11_display, wd.x11_xim_window);
  6262. #ifdef XKB_ENABLED
  6263. if (xkb_loaded_v05p) {
  6264. if (wd.xkb_state) {
  6265. xkb_compose_state_unref(wd.xkb_state);
  6266. wd.xkb_state = nullptr;
  6267. }
  6268. }
  6269. #endif
  6270. XUnmapWindow(x11_display, wd.x11_window);
  6271. XDestroyWindow(x11_display, wd.x11_window);
  6272. }
  6273. #ifdef XKB_ENABLED
  6274. if (xkb_loaded_v05p) {
  6275. if (dead_tbl) {
  6276. xkb_compose_table_unref(dead_tbl);
  6277. }
  6278. if (xkb_ctx) {
  6279. xkb_context_unref(xkb_ctx);
  6280. }
  6281. }
  6282. #endif
  6283. //destroy drivers
  6284. #if defined(RD_ENABLED)
  6285. if (rendering_device) {
  6286. memdelete(rendering_device);
  6287. rendering_device = nullptr;
  6288. }
  6289. if (rendering_context) {
  6290. memdelete(rendering_context);
  6291. rendering_context = nullptr;
  6292. }
  6293. #endif
  6294. #ifdef GLES3_ENABLED
  6295. if (gl_manager) {
  6296. memdelete(gl_manager);
  6297. gl_manager = nullptr;
  6298. }
  6299. if (gl_manager_egl) {
  6300. memdelete(gl_manager_egl);
  6301. gl_manager_egl = nullptr;
  6302. }
  6303. #endif
  6304. if (xrandr_handle) {
  6305. dlclose(xrandr_handle);
  6306. }
  6307. for (int i = 0; i < CURSOR_MAX; i++) {
  6308. if (cursors[i] != None) {
  6309. XFreeCursor(x11_display, cursors[i]);
  6310. }
  6311. if (cursor_img[i] != nullptr) {
  6312. XcursorImageDestroy(cursor_img[i]);
  6313. }
  6314. }
  6315. if (xim) {
  6316. XCloseIM(xim);
  6317. }
  6318. XCloseDisplay(x11_display);
  6319. if (xmbstring) {
  6320. memfree(xmbstring);
  6321. }
  6322. #ifdef ACCESSKIT_ENABLED
  6323. if (accessibility_driver) {
  6324. memdelete(accessibility_driver);
  6325. }
  6326. #endif
  6327. #ifdef SPEECHD_ENABLED
  6328. if (tts) {
  6329. memdelete(tts);
  6330. }
  6331. #endif
  6332. #ifdef DBUS_ENABLED
  6333. memdelete(screensaver);
  6334. memdelete(portal_desktop);
  6335. memdelete(atspi_monitor);
  6336. #endif
  6337. }
  6338. void DisplayServerX11::register_x11_driver() {
  6339. register_create_function("x11", create_func, get_rendering_drivers_func);
  6340. }
  6341. #endif // X11 enabled