display_server_windows.cpp 235 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452
  1. /**************************************************************************/
  2. /* display_server_windows.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_windows.h"
  31. #include "drop_target_windows.h"
  32. #include "os_windows.h"
  33. #include "scene/main/window.h"
  34. #include "wgl_detect_version.h"
  35. #include "core/config/project_settings.h"
  36. #include "core/io/marshalls.h"
  37. #include "core/io/xml_parser.h"
  38. #include "core/version.h"
  39. #include "drivers/png/png_driver_common.h"
  40. #include "main/main.h"
  41. #include "scene/resources/texture.h"
  42. #include "servers/rendering/dummy/rasterizer_dummy.h"
  43. #if defined(VULKAN_ENABLED)
  44. #include "rendering_context_driver_vulkan_windows.h"
  45. #endif
  46. #if defined(D3D12_ENABLED)
  47. #include "drivers/d3d12/rendering_context_driver_d3d12.h"
  48. #endif
  49. #if defined(GLES3_ENABLED)
  50. #include "drivers/gles3/rasterizer_gles3.h"
  51. #endif
  52. #if defined(ACCESSKIT_ENABLED)
  53. #include "drivers/accesskit/accessibility_driver_accesskit.h"
  54. #endif
  55. #include <avrt.h>
  56. #include <dwmapi.h>
  57. #include <propkey.h>
  58. #include <propvarutil.h>
  59. #include <shellapi.h>
  60. #include <shlwapi.h>
  61. #include <shobjidl.h>
  62. #include <wbemcli.h>
  63. #ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
  64. #define DWMWA_USE_IMMERSIVE_DARK_MODE 20
  65. #endif
  66. #ifndef DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1
  67. #define DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 19
  68. #endif
  69. #ifndef DWMWA_WINDOW_CORNER_PREFERENCE
  70. #define DWMWA_WINDOW_CORNER_PREFERENCE 33
  71. #endif
  72. #ifndef DWMWCP_DEFAULT
  73. #define DWMWCP_DEFAULT 0
  74. #endif
  75. #ifndef DWMWCP_DONOTROUND
  76. #define DWMWCP_DONOTROUND 1
  77. #endif
  78. #define WM_INDICATOR_CALLBACK_MESSAGE (WM_USER + 1)
  79. int constexpr FS_TRANSP_BORDER = 2;
  80. static String format_error_message(DWORD id) {
  81. LPWSTR messageBuffer = nullptr;
  82. size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  83. nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
  84. String msg = "Error " + itos(id) + ": " + String::utf16((const char16_t *)messageBuffer, size);
  85. LocalFree(messageBuffer);
  86. return msg;
  87. }
  88. static void track_mouse_leave_event(HWND hWnd) {
  89. TRACKMOUSEEVENT tme;
  90. tme.cbSize = sizeof(TRACKMOUSEEVENT);
  91. tme.dwFlags = TME_LEAVE;
  92. tme.hwndTrack = hWnd;
  93. tme.dwHoverTime = HOVER_DEFAULT;
  94. TrackMouseEvent(&tme);
  95. }
  96. bool DisplayServerWindows::has_feature(Feature p_feature) const {
  97. switch (p_feature) {
  98. #ifndef DISABLE_DEPRECATED
  99. case FEATURE_GLOBAL_MENU: {
  100. return (native_menu && native_menu->has_feature(NativeMenu::FEATURE_GLOBAL_MENU));
  101. } break;
  102. #endif
  103. case FEATURE_SUBWINDOWS:
  104. case FEATURE_TOUCHSCREEN:
  105. case FEATURE_MOUSE:
  106. case FEATURE_MOUSE_WARP:
  107. case FEATURE_CLIPBOARD:
  108. case FEATURE_CURSOR_SHAPE:
  109. case FEATURE_CUSTOM_CURSOR_SHAPE:
  110. case FEATURE_IME:
  111. case FEATURE_WINDOW_TRANSPARENCY:
  112. case FEATURE_HIDPI:
  113. case FEATURE_ICON:
  114. case FEATURE_NATIVE_ICON:
  115. case FEATURE_NATIVE_DIALOG:
  116. case FEATURE_NATIVE_DIALOG_INPUT:
  117. case FEATURE_NATIVE_DIALOG_FILE:
  118. case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
  119. //case FEATURE_NATIVE_DIALOG_FILE_MIME:
  120. case FEATURE_SWAP_BUFFERS:
  121. case FEATURE_KEEP_SCREEN_ON:
  122. case FEATURE_TEXT_TO_SPEECH:
  123. case FEATURE_SCREEN_CAPTURE:
  124. case FEATURE_STATUS_INDICATOR:
  125. case FEATURE_WINDOW_EMBEDDING:
  126. case FEATURE_WINDOW_DRAG:
  127. case FEATURE_SCREEN_EXCLUDE_FROM_CAPTURE:
  128. return true;
  129. case FEATURE_EMOJI_AND_SYMBOL_PICKER:
  130. return (os_ver.dwBuildNumber >= 17134); // Windows 10 Redstone 4 (1803)+ only.
  131. #ifdef ACCESSKIT_ENABLED
  132. case FEATURE_ACCESSIBILITY_SCREEN_READER: {
  133. return (accessibility_driver != nullptr);
  134. } break;
  135. #endif
  136. default:
  137. return false;
  138. }
  139. }
  140. String DisplayServerWindows::get_name() const {
  141. return "Windows";
  142. }
  143. void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
  144. if (p_mode == MOUSE_MODE_HIDDEN || p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
  145. // Hide cursor before moving.
  146. if (hCursor == nullptr) {
  147. hCursor = SetCursor(nullptr);
  148. } else {
  149. SetCursor(nullptr);
  150. }
  151. }
  152. if (windows.has(MAIN_WINDOW_ID) && (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN)) {
  153. // Mouse is grabbed (captured or confined).
  154. WindowID window_id = _get_focused_window_or_popup();
  155. if (!windows.has(window_id)) {
  156. window_id = MAIN_WINDOW_ID;
  157. }
  158. WindowData &wd = windows[window_id];
  159. int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0;
  160. RECT clipRect;
  161. GetClientRect(wd.hWnd, &clipRect);
  162. clipRect.right -= off_x;
  163. ClientToScreen(wd.hWnd, (POINT *)&clipRect.left);
  164. ClientToScreen(wd.hWnd, (POINT *)&clipRect.right);
  165. ClipCursor(&clipRect);
  166. if (p_mode == MOUSE_MODE_CAPTURED) {
  167. center = window_get_size() / 2;
  168. POINT pos = { (int)center.x, (int)center.y };
  169. ClientToScreen(wd.hWnd, &pos);
  170. SetCursorPos(pos.x, pos.y);
  171. SetCapture(wd.hWnd);
  172. _register_raw_input_devices(window_id);
  173. }
  174. } else {
  175. // Mouse is free to move around (not captured or confined).
  176. // When the user is moving a window, it's important to not ReleaseCapture because it will cause
  177. // the window movement to stop and if the user tries to move the Windows when it's not activated,
  178. // it will prevent the window movement. It's probably impossible to move the Window while it's captured anyway.
  179. if (!_has_moving_window()) {
  180. ReleaseCapture();
  181. }
  182. ClipCursor(nullptr);
  183. _register_raw_input_devices(INVALID_WINDOW_ID);
  184. }
  185. if (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED) {
  186. // Show cursor.
  187. CursorShape c = cursor_shape;
  188. cursor_shape = CURSOR_MAX;
  189. cursor_set_shape(c);
  190. }
  191. }
  192. DisplayServer::WindowID DisplayServerWindows::_get_focused_window_or_popup() const {
  193. const List<WindowID>::Element *E = popup_list.back();
  194. if (E) {
  195. return E->get();
  196. }
  197. return last_focused_window;
  198. }
  199. bool DisplayServerWindows::_has_moving_window() const {
  200. for (const KeyValue<WindowID, WindowData> &E : windows) {
  201. if (E.value.move_timer_id) {
  202. return true;
  203. }
  204. }
  205. return false;
  206. }
  207. void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window) {
  208. use_raw_input = true;
  209. RAWINPUTDEVICE rid[2] = {};
  210. rid[0].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
  211. rid[0].usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE
  212. rid[0].dwFlags = 0;
  213. rid[1].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
  214. rid[1].usUsage = 0x06; // HID_USAGE_GENERIC_KEYBOARD
  215. rid[1].dwFlags = 0;
  216. if (p_target_window != INVALID_WINDOW_ID && windows.has(p_target_window)) {
  217. // Follow the defined window
  218. rid[0].hwndTarget = windows[p_target_window].hWnd;
  219. rid[1].hwndTarget = windows[p_target_window].hWnd;
  220. } else {
  221. // Follow the keyboard focus
  222. rid[0].hwndTarget = nullptr;
  223. rid[1].hwndTarget = nullptr;
  224. }
  225. if (RegisterRawInputDevices(rid, 2, sizeof(rid[0])) == FALSE) {
  226. // Registration failed.
  227. use_raw_input = false;
  228. }
  229. }
  230. void DisplayServerWindows::initialize_tts() const {
  231. const_cast<DisplayServerWindows *>(this)->tts = memnew(TTS_Windows);
  232. }
  233. bool DisplayServerWindows::tts_is_speaking() const {
  234. if (unlikely(!tts)) {
  235. initialize_tts();
  236. }
  237. ERR_FAIL_NULL_V(tts, false);
  238. return tts->is_speaking();
  239. }
  240. bool DisplayServerWindows::tts_is_paused() const {
  241. if (unlikely(!tts)) {
  242. initialize_tts();
  243. }
  244. ERR_FAIL_NULL_V(tts, false);
  245. return tts->is_paused();
  246. }
  247. TypedArray<Dictionary> DisplayServerWindows::tts_get_voices() const {
  248. if (unlikely(!tts)) {
  249. initialize_tts();
  250. }
  251. ERR_FAIL_NULL_V(tts, TypedArray<Dictionary>());
  252. return tts->get_voices();
  253. }
  254. void DisplayServerWindows::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) {
  255. if (unlikely(!tts)) {
  256. initialize_tts();
  257. }
  258. ERR_FAIL_NULL(tts);
  259. tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt);
  260. }
  261. void DisplayServerWindows::tts_pause() {
  262. if (unlikely(!tts)) {
  263. initialize_tts();
  264. }
  265. ERR_FAIL_NULL(tts);
  266. tts->pause();
  267. }
  268. void DisplayServerWindows::tts_resume() {
  269. if (unlikely(!tts)) {
  270. initialize_tts();
  271. }
  272. ERR_FAIL_NULL(tts);
  273. tts->resume();
  274. }
  275. void DisplayServerWindows::tts_stop() {
  276. if (unlikely(!tts)) {
  277. initialize_tts();
  278. }
  279. ERR_FAIL_NULL(tts);
  280. tts->stop();
  281. }
  282. Error DisplayServerWindows::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) {
  283. return _file_dialog_with_options_show(p_title, p_current_directory, String(), p_filename, p_show_hidden, p_mode, p_filters, TypedArray<Dictionary>(), p_callback, false, p_window_id);
  284. }
  285. Error DisplayServerWindows::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) {
  286. return _file_dialog_with_options_show(p_title, p_current_directory, p_root, p_filename, p_show_hidden, p_mode, p_filters, p_options, p_callback, true, p_window_id);
  287. }
  288. GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wnon-virtual-dtor") // Silence warning due to a COM API weirdness.
  289. class FileDialogEventHandler : public IFileDialogEvents, public IFileDialogControlEvents {
  290. LONG ref_count = 1;
  291. int ctl_id = 1;
  292. HashMap<int, String> ctls;
  293. Dictionary selected;
  294. String root;
  295. public:
  296. // IUnknown methods
  297. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv) {
  298. static const QITAB qit[] = {
  299. #ifdef __MINGW32__
  300. { &__uuidof(IFileDialogEvents), static_cast<decltype(qit[0].dwOffset)>(OFFSETOFCLASS(IFileDialogEvents, FileDialogEventHandler)) },
  301. { &__uuidof(IFileDialogControlEvents), static_cast<decltype(qit[0].dwOffset)>(OFFSETOFCLASS(IFileDialogControlEvents, FileDialogEventHandler)) },
  302. #else
  303. QITABENT(FileDialogEventHandler, IFileDialogEvents),
  304. QITABENT(FileDialogEventHandler, IFileDialogControlEvents),
  305. #endif
  306. { nullptr, 0 },
  307. };
  308. return QISearch(this, qit, riid, ppv);
  309. }
  310. ULONG STDMETHODCALLTYPE AddRef() {
  311. return InterlockedIncrement(&ref_count);
  312. }
  313. ULONG STDMETHODCALLTYPE Release() {
  314. long ref = InterlockedDecrement(&ref_count);
  315. if (!ref) {
  316. delete this;
  317. }
  318. return ref;
  319. }
  320. // IFileDialogEvents methods
  321. HRESULT STDMETHODCALLTYPE OnFileOk(IFileDialog *) { return S_OK; }
  322. HRESULT STDMETHODCALLTYPE OnFolderChange(IFileDialog *) { return S_OK; }
  323. HRESULT STDMETHODCALLTYPE OnFolderChanging(IFileDialog *p_pfd, IShellItem *p_item) {
  324. if (root.is_empty()) {
  325. return S_OK;
  326. }
  327. LPWSTR lpw_path = nullptr;
  328. p_item->GetDisplayName(SIGDN_FILESYSPATH, &lpw_path);
  329. if (!lpw_path) {
  330. return S_FALSE;
  331. }
  332. String path = String::utf16((const char16_t *)lpw_path).replace_char('\\', '/').trim_prefix(R"(\\?\)").simplify_path();
  333. if (!path.begins_with(root.simplify_path())) {
  334. return S_FALSE;
  335. }
  336. return S_OK;
  337. }
  338. HRESULT STDMETHODCALLTYPE OnHelp(IFileDialog *) { return S_OK; }
  339. HRESULT STDMETHODCALLTYPE OnSelectionChange(IFileDialog *) { return S_OK; }
  340. HRESULT STDMETHODCALLTYPE OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; }
  341. HRESULT STDMETHODCALLTYPE OnTypeChange(IFileDialog *pfd) { return S_OK; }
  342. HRESULT STDMETHODCALLTYPE OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; }
  343. // IFileDialogControlEvents methods
  344. HRESULT STDMETHODCALLTYPE OnItemSelected(IFileDialogCustomize *p_pfdc, DWORD p_ctl_id, DWORD p_item_idx) {
  345. if (ctls.has(p_ctl_id)) {
  346. selected[ctls[p_ctl_id]] = (int)p_item_idx;
  347. }
  348. return S_OK;
  349. }
  350. HRESULT STDMETHODCALLTYPE OnButtonClicked(IFileDialogCustomize *, DWORD) { return S_OK; }
  351. HRESULT STDMETHODCALLTYPE OnCheckButtonToggled(IFileDialogCustomize *p_pfdc, DWORD p_ctl_id, BOOL p_checked) {
  352. if (ctls.has(p_ctl_id)) {
  353. selected[ctls[p_ctl_id]] = (bool)p_checked;
  354. }
  355. return S_OK;
  356. }
  357. HRESULT STDMETHODCALLTYPE OnControlActivating(IFileDialogCustomize *, DWORD) { return S_OK; }
  358. Dictionary get_selected() {
  359. return selected;
  360. }
  361. void set_root(const String &p_root) {
  362. root = p_root;
  363. }
  364. void add_option(IFileDialogCustomize *p_pfdc, const String &p_name, const Vector<String> &p_options, int p_default) {
  365. int gid = ctl_id++;
  366. int cid = ctl_id++;
  367. if (p_options.is_empty()) {
  368. // Add check box.
  369. p_pfdc->StartVisualGroup(gid, L"");
  370. p_pfdc->AddCheckButton(cid, (LPCWSTR)p_name.utf16().get_data(), p_default);
  371. p_pfdc->SetControlState(cid, CDCS_VISIBLE | CDCS_ENABLED);
  372. p_pfdc->EndVisualGroup();
  373. selected[p_name] = (bool)p_default;
  374. } else {
  375. // Add combo box.
  376. p_pfdc->StartVisualGroup(gid, (LPCWSTR)p_name.utf16().get_data());
  377. p_pfdc->AddComboBox(cid);
  378. p_pfdc->SetControlState(cid, CDCS_VISIBLE | CDCS_ENABLED);
  379. for (int i = 0; i < p_options.size(); i++) {
  380. p_pfdc->AddControlItem(cid, i, (LPCWSTR)p_options[i].utf16().get_data());
  381. }
  382. p_pfdc->SetSelectedControlItem(cid, p_default);
  383. p_pfdc->EndVisualGroup();
  384. selected[p_name] = p_default;
  385. }
  386. ctls[cid] = p_name;
  387. }
  388. virtual ~FileDialogEventHandler() {}
  389. };
  390. GODOT_GCC_WARNING_POP
  391. LRESULT CALLBACK WndProcFileDialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  392. DisplayServerWindows *ds_win = static_cast<DisplayServerWindows *>(DisplayServer::get_singleton());
  393. if (ds_win) {
  394. return ds_win->WndProcFileDialog(hWnd, uMsg, wParam, lParam);
  395. } else {
  396. return DefWindowProcW(hWnd, uMsg, wParam, lParam);
  397. }
  398. }
  399. LRESULT DisplayServerWindows::WndProcFileDialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  400. MutexLock lock(file_dialog_mutex);
  401. if (file_dialog_wnd.has(hWnd)) {
  402. if (file_dialog_wnd[hWnd]->close_requested.is_set()) {
  403. IPropertyStore *prop_store;
  404. HRESULT hr = SHGetPropertyStoreForWindow(hWnd, IID_IPropertyStore, (void **)&prop_store);
  405. if (hr == S_OK) {
  406. PROPVARIANT val;
  407. PropVariantInit(&val);
  408. prop_store->SetValue(PKEY_AppUserModel_ID, val);
  409. prop_store->Release();
  410. }
  411. DestroyWindow(hWnd);
  412. file_dialog_wnd.erase(hWnd);
  413. }
  414. }
  415. return DefWindowProcW(hWnd, uMsg, wParam, lParam);
  416. }
  417. void DisplayServerWindows::_thread_fd_monitor(void *p_ud) {
  418. DisplayServerWindows *ds = static_cast<DisplayServerWindows *>(get_singleton());
  419. FileDialogData *fd = (FileDialogData *)p_ud;
  420. if (fd->mode < 0 && fd->mode >= DisplayServer::FILE_DIALOG_MODE_SAVE_MAX) {
  421. fd->finished.set();
  422. return;
  423. }
  424. CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
  425. int64_t x = fd->wrect.position.x;
  426. int64_t y = fd->wrect.position.y;
  427. int64_t w = fd->wrect.size.x;
  428. int64_t h = fd->wrect.size.y;
  429. WNDCLASSW wc = {};
  430. wc.lpfnWndProc = (WNDPROC)::WndProcFileDialog;
  431. wc.hInstance = GetModuleHandle(nullptr);
  432. wc.lpszClassName = L"Engine File Dialog";
  433. RegisterClassW(&wc);
  434. HWND hwnd_dialog = CreateWindowExW(WS_EX_APPWINDOW, L"Engine File Dialog", L"", WS_OVERLAPPEDWINDOW, x, y, w, h, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
  435. if (hwnd_dialog) {
  436. {
  437. MutexLock lock(ds->file_dialog_mutex);
  438. ds->file_dialog_wnd[hwnd_dialog] = fd;
  439. }
  440. HICON mainwindow_icon = (HICON)SendMessage(fd->hwnd_owner, WM_GETICON, ICON_SMALL, 0);
  441. if (mainwindow_icon) {
  442. SendMessage(hwnd_dialog, WM_SETICON, ICON_SMALL, (LPARAM)mainwindow_icon);
  443. }
  444. mainwindow_icon = (HICON)SendMessage(fd->hwnd_owner, WM_GETICON, ICON_BIG, 0);
  445. if (mainwindow_icon) {
  446. SendMessage(hwnd_dialog, WM_SETICON, ICON_BIG, (LPARAM)mainwindow_icon);
  447. }
  448. IPropertyStore *prop_store;
  449. HRESULT hr = SHGetPropertyStoreForWindow(hwnd_dialog, IID_IPropertyStore, (void **)&prop_store);
  450. if (hr == S_OK) {
  451. PROPVARIANT val;
  452. InitPropVariantFromString((PCWSTR)fd->appid.utf16().get_data(), &val);
  453. prop_store->SetValue(PKEY_AppUserModel_ID, val);
  454. prop_store->Release();
  455. }
  456. }
  457. SetCurrentProcessExplicitAppUserModelID((PCWSTR)fd->appid.utf16().get_data());
  458. Vector<Char16String> filter_names;
  459. Vector<Char16String> filter_exts;
  460. for (const String &E : fd->filters) {
  461. Vector<String> tokens = E.split(";");
  462. if (tokens.size() >= 1) {
  463. String flt = tokens[0].strip_edges();
  464. int filter_slice_count = flt.get_slice_count(",");
  465. Vector<String> exts;
  466. for (int j = 0; j < filter_slice_count; j++) {
  467. String str = (flt.get_slicec(',', j).strip_edges());
  468. if (!str.is_empty()) {
  469. exts.push_back(str);
  470. }
  471. }
  472. if (!exts.is_empty()) {
  473. String str = String(";").join(exts);
  474. filter_exts.push_back(str.utf16());
  475. if (tokens.size() == 2) {
  476. filter_names.push_back(tokens[1].strip_edges().utf16());
  477. } else {
  478. filter_names.push_back(str.utf16());
  479. }
  480. }
  481. }
  482. }
  483. if (filter_names.is_empty()) {
  484. filter_exts.push_back(String("*.*").utf16());
  485. filter_names.push_back((RTR("All Files") + " (*.*)").utf16());
  486. }
  487. Vector<COMDLG_FILTERSPEC> filters;
  488. for (int i = 0; i < filter_names.size(); i++) {
  489. filters.push_back({ (LPCWSTR)filter_names[i].ptr(), (LPCWSTR)filter_exts[i].ptr() });
  490. }
  491. HRESULT hr = S_OK;
  492. IFileDialog *pfd = nullptr;
  493. if (fd->mode == DisplayServer::FILE_DIALOG_MODE_SAVE_FILE) {
  494. hr = CoCreateInstance(CLSID_FileSaveDialog, nullptr, CLSCTX_INPROC_SERVER, IID_IFileSaveDialog, (void **)&pfd);
  495. } else {
  496. hr = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, IID_IFileOpenDialog, (void **)&pfd);
  497. }
  498. if (SUCCEEDED(hr)) {
  499. IFileDialogEvents *pfde = nullptr;
  500. FileDialogEventHandler *event_handler = new FileDialogEventHandler();
  501. hr = event_handler->QueryInterface(IID_PPV_ARGS(&pfde));
  502. DWORD cookie = 0;
  503. hr = pfd->Advise(pfde, &cookie);
  504. IFileDialogCustomize *pfdc = nullptr;
  505. hr = pfd->QueryInterface(IID_PPV_ARGS(&pfdc));
  506. for (int i = 0; i < fd->options.size(); i++) {
  507. const Dictionary &item = fd->options[i];
  508. if (!item.has("name") || !item.has("values") || !item.has("default")) {
  509. continue;
  510. }
  511. event_handler->add_option(pfdc, item["name"], item["values"], item["default"]);
  512. }
  513. event_handler->set_root(fd->root);
  514. pfdc->Release();
  515. DWORD flags;
  516. pfd->GetOptions(&flags);
  517. if (fd->mode == DisplayServer::FILE_DIALOG_MODE_OPEN_FILES) {
  518. flags |= FOS_ALLOWMULTISELECT;
  519. }
  520. if (fd->mode == DisplayServer::FILE_DIALOG_MODE_OPEN_DIR) {
  521. flags |= FOS_PICKFOLDERS;
  522. }
  523. if (fd->show_hidden) {
  524. flags |= FOS_FORCESHOWHIDDEN;
  525. }
  526. pfd->SetOptions(flags | FOS_FORCEFILESYSTEM);
  527. pfd->SetTitle((LPCWSTR)fd->title.utf16().get_data());
  528. String dir = ProjectSettings::get_singleton()->globalize_path(fd->current_directory);
  529. if (dir == ".") {
  530. dir = OS::get_singleton()->get_executable_path().get_base_dir();
  531. }
  532. if (dir.is_relative_path() || dir == ".") {
  533. Char16String current_dir_name;
  534. size_t str_len = GetCurrentDirectoryW(0, nullptr);
  535. current_dir_name.resize(str_len + 1);
  536. GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
  537. if (dir == ".") {
  538. dir = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace_char('\\', '/');
  539. } else {
  540. dir = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace_char('\\', '/').path_join(dir);
  541. }
  542. }
  543. dir = dir.simplify_path();
  544. dir = dir.trim_prefix(R"(\\?\)").replace_char('/', '\\');
  545. IShellItem *shellitem = nullptr;
  546. hr = SHCreateItemFromParsingName((LPCWSTR)dir.utf16().ptr(), nullptr, IID_IShellItem, (void **)&shellitem);
  547. if (SUCCEEDED(hr)) {
  548. pfd->SetDefaultFolder(shellitem);
  549. pfd->SetFolder(shellitem);
  550. }
  551. pfd->SetFileName((LPCWSTR)fd->filename.utf16().get_data());
  552. pfd->SetFileTypes(filters.size(), filters.ptr());
  553. pfd->SetFileTypeIndex(0);
  554. hr = pfd->Show(hwnd_dialog);
  555. pfd->Unadvise(cookie);
  556. Dictionary options = event_handler->get_selected();
  557. pfde->Release();
  558. event_handler->Release();
  559. UINT index = 0;
  560. pfd->GetFileTypeIndex(&index);
  561. if (index > 0) {
  562. index = index - 1;
  563. }
  564. if (SUCCEEDED(hr)) {
  565. Vector<String> file_names;
  566. if (fd->mode == DisplayServer::FILE_DIALOG_MODE_OPEN_FILES) {
  567. IShellItemArray *results;
  568. hr = static_cast<IFileOpenDialog *>(pfd)->GetResults(&results);
  569. if (SUCCEEDED(hr)) {
  570. DWORD count = 0;
  571. results->GetCount(&count);
  572. for (DWORD i = 0; i < count; i++) {
  573. IShellItem *result;
  574. results->GetItemAt(i, &result);
  575. PWSTR file_path = nullptr;
  576. hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
  577. if (SUCCEEDED(hr)) {
  578. file_names.push_back(String::utf16((const char16_t *)file_path).replace_char('\\', '/').trim_prefix(R"(\\?\)"));
  579. CoTaskMemFree(file_path);
  580. }
  581. result->Release();
  582. }
  583. results->Release();
  584. }
  585. } else {
  586. IShellItem *result;
  587. hr = pfd->GetResult(&result);
  588. if (SUCCEEDED(hr)) {
  589. PWSTR file_path = nullptr;
  590. hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
  591. if (SUCCEEDED(hr)) {
  592. file_names.push_back(String::utf16((const char16_t *)file_path).replace_char('\\', '/').trim_prefix(R"(\\?\)"));
  593. CoTaskMemFree(file_path);
  594. }
  595. result->Release();
  596. }
  597. }
  598. if (fd->callback.is_valid()) {
  599. MutexLock lock(ds->file_dialog_mutex);
  600. FileDialogCallback cb;
  601. cb.callback = fd->callback;
  602. cb.status = true;
  603. cb.files = file_names;
  604. cb.index = index;
  605. cb.options = options;
  606. cb.opt_in_cb = fd->options_in_cb;
  607. ds->pending_cbs.push_back(cb);
  608. }
  609. } else {
  610. if (fd->callback.is_valid()) {
  611. MutexLock lock(ds->file_dialog_mutex);
  612. FileDialogCallback cb;
  613. cb.callback = fd->callback;
  614. cb.status = false;
  615. cb.files = Vector<String>();
  616. cb.index = index;
  617. cb.options = options;
  618. cb.opt_in_cb = fd->options_in_cb;
  619. ds->pending_cbs.push_back(cb);
  620. }
  621. }
  622. pfd->Release();
  623. } else {
  624. if (fd->callback.is_valid()) {
  625. MutexLock lock(ds->file_dialog_mutex);
  626. FileDialogCallback cb;
  627. cb.callback = fd->callback;
  628. cb.status = false;
  629. cb.files = Vector<String>();
  630. cb.index = 0;
  631. cb.options = Dictionary();
  632. cb.opt_in_cb = fd->options_in_cb;
  633. ds->pending_cbs.push_back(cb);
  634. }
  635. }
  636. {
  637. MutexLock lock(ds->file_dialog_mutex);
  638. if (hwnd_dialog && ds->file_dialog_wnd.has(hwnd_dialog)) {
  639. IPropertyStore *prop_store;
  640. hr = SHGetPropertyStoreForWindow(hwnd_dialog, IID_IPropertyStore, (void **)&prop_store);
  641. if (hr == S_OK) {
  642. PROPVARIANT val;
  643. PropVariantInit(&val);
  644. prop_store->SetValue(PKEY_AppUserModel_ID, val);
  645. prop_store->Release();
  646. }
  647. DestroyWindow(hwnd_dialog);
  648. ds->file_dialog_wnd.erase(hwnd_dialog);
  649. }
  650. }
  651. UnregisterClassW(L"Engine File Dialog", GetModuleHandle(nullptr));
  652. CoUninitialize();
  653. fd->finished.set();
  654. if (fd->window_id != INVALID_WINDOW_ID) {
  655. callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(fd->window_id);
  656. }
  657. }
  658. Error DisplayServerWindows::_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, bool p_options_in_cb, WindowID p_window_id) {
  659. _THREAD_SAFE_METHOD_
  660. ERR_FAIL_INDEX_V(int(p_mode), FILE_DIALOG_MODE_SAVE_MAX, FAILED);
  661. String appname;
  662. if (Engine::get_singleton()->is_editor_hint()) {
  663. appname = "Godot.GodotEditor." + String(GODOT_VERSION_BRANCH);
  664. } else {
  665. String name = GLOBAL_GET("application/config/name");
  666. String version = GLOBAL_GET("application/config/version");
  667. if (version.is_empty()) {
  668. version = "0";
  669. }
  670. String clean_app_name = name.to_pascal_case();
  671. for (int i = 0; i < clean_app_name.length(); i++) {
  672. if (!is_ascii_alphanumeric_char(clean_app_name[i]) && clean_app_name[i] != '_' && clean_app_name[i] != '.') {
  673. clean_app_name[i] = '_';
  674. }
  675. }
  676. clean_app_name = clean_app_name.substr(0, 120 - version.length()).trim_suffix(".");
  677. appname = "Godot." + clean_app_name + "." + version;
  678. }
  679. FileDialogData *fd = memnew(FileDialogData);
  680. if (windows.has(p_window_id) && !windows[p_window_id].is_popup) {
  681. fd->hwnd_owner = windows[p_window_id].hWnd;
  682. RECT crect;
  683. GetWindowRect(fd->hwnd_owner, &crect);
  684. fd->wrect = Rect2i(crect.left, crect.top, crect.right - crect.left, crect.bottom - crect.top);
  685. } else {
  686. fd->hwnd_owner = nullptr;
  687. fd->wrect = Rect2i(CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT);
  688. }
  689. fd->appid = appname;
  690. fd->title = p_title;
  691. fd->current_directory = p_current_directory;
  692. fd->root = p_root;
  693. fd->filename = p_filename;
  694. fd->show_hidden = p_show_hidden;
  695. fd->mode = p_mode;
  696. fd->window_id = p_window_id;
  697. fd->filters = p_filters;
  698. fd->options = p_options;
  699. fd->callback = p_callback;
  700. fd->options_in_cb = p_options_in_cb;
  701. fd->finished.clear();
  702. fd->close_requested.clear();
  703. fd->listener_thread.start(DisplayServerWindows::_thread_fd_monitor, fd);
  704. file_dialogs.push_back(fd);
  705. return OK;
  706. }
  707. void DisplayServerWindows::process_file_dialog_callbacks() {
  708. MutexLock lock(file_dialog_mutex);
  709. while (!pending_cbs.is_empty()) {
  710. FileDialogCallback cb = pending_cbs.front()->get();
  711. pending_cbs.pop_front();
  712. if (cb.opt_in_cb) {
  713. Variant ret;
  714. Callable::CallError ce;
  715. const Variant *args[4] = { &cb.status, &cb.files, &cb.index, &cb.options };
  716. cb.callback.callp(args, 4, ret, ce);
  717. if (ce.error != Callable::CallError::CALL_OK) {
  718. ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(cb.callback, args, 4, ce)));
  719. }
  720. } else {
  721. Variant ret;
  722. Callable::CallError ce;
  723. const Variant *args[3] = { &cb.status, &cb.files, &cb.index };
  724. cb.callback.callp(args, 3, ret, ce);
  725. if (ce.error != Callable::CallError::CALL_OK) {
  726. ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(cb.callback, args, 3, ce)));
  727. }
  728. }
  729. }
  730. }
  731. void DisplayServerWindows::beep() const {
  732. MessageBeep(MB_OK);
  733. }
  734. void DisplayServerWindows::_mouse_update_mode() {
  735. _THREAD_SAFE_METHOD_
  736. MouseMode wanted_mouse_mode = mouse_mode_override_enabled
  737. ? mouse_mode_override
  738. : mouse_mode_base;
  739. if (mouse_mode == wanted_mouse_mode) {
  740. // Already in the same mode; do nothing.
  741. return;
  742. }
  743. mouse_mode = wanted_mouse_mode;
  744. _set_mouse_mode_impl(wanted_mouse_mode);
  745. }
  746. void DisplayServerWindows::mouse_set_mode(MouseMode p_mode) {
  747. ERR_FAIL_INDEX(p_mode, MouseMode::MOUSE_MODE_MAX);
  748. if (p_mode == mouse_mode_base) {
  749. return;
  750. }
  751. mouse_mode_base = p_mode;
  752. _mouse_update_mode();
  753. }
  754. DisplayServer::MouseMode DisplayServerWindows::mouse_get_mode() const {
  755. return mouse_mode;
  756. }
  757. void DisplayServerWindows::mouse_set_mode_override(MouseMode p_mode) {
  758. ERR_FAIL_INDEX(p_mode, MouseMode::MOUSE_MODE_MAX);
  759. if (p_mode == mouse_mode_override) {
  760. return;
  761. }
  762. mouse_mode_override = p_mode;
  763. _mouse_update_mode();
  764. }
  765. DisplayServer::MouseMode DisplayServerWindows::mouse_get_mode_override() const {
  766. return mouse_mode_override;
  767. }
  768. void DisplayServerWindows::mouse_set_mode_override_enabled(bool p_override_enabled) {
  769. if (p_override_enabled == mouse_mode_override_enabled) {
  770. return;
  771. }
  772. mouse_mode_override_enabled = p_override_enabled;
  773. _mouse_update_mode();
  774. }
  775. bool DisplayServerWindows::mouse_is_mode_override_enabled() const {
  776. return mouse_mode_override_enabled;
  777. }
  778. void DisplayServerWindows::warp_mouse(const Point2i &p_position) {
  779. _THREAD_SAFE_METHOD_
  780. WindowID window_id = _get_focused_window_or_popup();
  781. if (!windows.has(window_id)) {
  782. return; // No focused window?
  783. }
  784. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  785. old_x = p_position.x;
  786. old_y = p_position.y;
  787. } else {
  788. POINT p;
  789. p.x = p_position.x;
  790. p.y = p_position.y;
  791. ClientToScreen(windows[window_id].hWnd, &p);
  792. SetCursorPos(p.x, p.y);
  793. }
  794. }
  795. Point2i DisplayServerWindows::mouse_get_position() const {
  796. POINT p;
  797. GetCursorPos(&p);
  798. return Point2i(p.x, p.y) - _get_screens_origin();
  799. }
  800. BitField<MouseButtonMask> DisplayServerWindows::mouse_get_button_state() const {
  801. BitField<MouseButtonMask> last_button_state = MouseButtonMask::NONE;
  802. if (GetKeyState(VK_LBUTTON) & (1 << 15)) {
  803. last_button_state.set_flag(MouseButtonMask::LEFT);
  804. }
  805. if (GetKeyState(VK_RBUTTON) & (1 << 15)) {
  806. last_button_state.set_flag(MouseButtonMask::RIGHT);
  807. }
  808. if (GetKeyState(VK_MBUTTON) & (1 << 15)) {
  809. last_button_state.set_flag(MouseButtonMask::MIDDLE);
  810. }
  811. if (GetKeyState(VK_XBUTTON1) & (1 << 15)) {
  812. last_button_state.set_flag(MouseButtonMask::MB_XBUTTON1);
  813. }
  814. if (GetKeyState(VK_XBUTTON2) & (1 << 15)) {
  815. last_button_state.set_flag(MouseButtonMask::MB_XBUTTON2);
  816. }
  817. return last_button_state;
  818. }
  819. void DisplayServerWindows::clipboard_set(const String &p_text) {
  820. _THREAD_SAFE_METHOD_
  821. if (!windows.has(MAIN_WINDOW_ID)) {
  822. return;
  823. }
  824. // Convert LF line endings to CRLF in clipboard content.
  825. // Otherwise, line endings won't be visible when pasted in other software.
  826. String text = p_text.replace("\r\n", "\n").replace("\n", "\r\n"); // Avoid \r\r\n.
  827. if (!OpenClipboard(windows[MAIN_WINDOW_ID].hWnd)) {
  828. ERR_FAIL_MSG("Unable to open clipboard.");
  829. }
  830. EmptyClipboard();
  831. Char16String utf16 = text.utf16();
  832. HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (utf16.length() + 1) * sizeof(WCHAR));
  833. ERR_FAIL_NULL_MSG(mem, "Unable to allocate memory for clipboard contents.");
  834. LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
  835. memcpy(lptstrCopy, utf16.get_data(), (utf16.length() + 1) * sizeof(WCHAR));
  836. GlobalUnlock(mem);
  837. SetClipboardData(CF_UNICODETEXT, mem);
  838. // Set the CF_TEXT version (not needed?).
  839. CharString utf8 = text.utf8();
  840. mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
  841. ERR_FAIL_NULL_MSG(mem, "Unable to allocate memory for clipboard contents.");
  842. LPTSTR ptr = (LPTSTR)GlobalLock(mem);
  843. memcpy(ptr, utf8.get_data(), utf8.length());
  844. ptr[utf8.length()] = 0;
  845. GlobalUnlock(mem);
  846. SetClipboardData(CF_TEXT, mem);
  847. CloseClipboard();
  848. }
  849. String DisplayServerWindows::clipboard_get() const {
  850. _THREAD_SAFE_METHOD_
  851. if (!windows.has(MAIN_WINDOW_ID)) {
  852. return String();
  853. }
  854. String ret;
  855. if (!OpenClipboard(windows[MAIN_WINDOW_ID].hWnd)) {
  856. ERR_FAIL_V_MSG("", "Unable to open clipboard.");
  857. }
  858. if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
  859. HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
  860. if (mem != nullptr) {
  861. LPWSTR ptr = (LPWSTR)GlobalLock(mem);
  862. if (ptr != nullptr) {
  863. ret = String::utf16((const char16_t *)ptr);
  864. GlobalUnlock(mem);
  865. }
  866. }
  867. } else if (IsClipboardFormatAvailable(CF_TEXT)) {
  868. HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
  869. if (mem != nullptr) {
  870. LPTSTR ptr = (LPTSTR)GlobalLock(mem);
  871. if (ptr != nullptr) {
  872. ret.append_utf8((const char *)ptr);
  873. GlobalUnlock(mem);
  874. }
  875. }
  876. }
  877. CloseClipboard();
  878. return ret;
  879. }
  880. Ref<Image> DisplayServerWindows::clipboard_get_image() const {
  881. Ref<Image> image;
  882. if (!windows.has(last_focused_window)) {
  883. return image; // No focused window?
  884. }
  885. if (!OpenClipboard(windows[last_focused_window].hWnd)) {
  886. ERR_FAIL_V_MSG(image, "Unable to open clipboard.");
  887. }
  888. UINT png_format = RegisterClipboardFormatA("PNG");
  889. if (png_format && IsClipboardFormatAvailable(png_format)) {
  890. HANDLE png_handle = GetClipboardData(png_format);
  891. if (png_handle) {
  892. size_t png_size = GlobalSize(png_handle);
  893. uint8_t *png_data = (uint8_t *)GlobalLock(png_handle);
  894. image.instantiate();
  895. PNGDriverCommon::png_to_image(png_data, png_size, false, image);
  896. GlobalUnlock(png_handle);
  897. }
  898. } else if (IsClipboardFormatAvailable(CF_DIB)) {
  899. HGLOBAL mem = GetClipboardData(CF_DIB);
  900. if (mem != nullptr) {
  901. BITMAPINFO *ptr = static_cast<BITMAPINFO *>(GlobalLock(mem));
  902. if (ptr != nullptr) {
  903. BITMAPINFOHEADER *info = &ptr->bmiHeader;
  904. void *dib_bits = (void *)(ptr->bmiColors);
  905. // Draw DIB image to temporary DC surface and read it back as BGRA8.
  906. HDC dc = GetDC(nullptr);
  907. if (dc) {
  908. HDC hdc = CreateCompatibleDC(dc);
  909. if (hdc) {
  910. HBITMAP hbm = CreateCompatibleBitmap(dc, info->biWidth, std::abs(info->biHeight));
  911. if (hbm) {
  912. SelectObject(hdc, hbm);
  913. SetDIBitsToDevice(hdc, 0, 0, info->biWidth, std::abs(info->biHeight), 0, 0, 0, std::abs(info->biHeight), dib_bits, ptr, DIB_RGB_COLORS);
  914. BITMAPINFO bmp_info = {};
  915. bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader);
  916. bmp_info.bmiHeader.biWidth = info->biWidth;
  917. bmp_info.bmiHeader.biHeight = -std::abs(info->biHeight);
  918. bmp_info.bmiHeader.biPlanes = 1;
  919. bmp_info.bmiHeader.biBitCount = 32;
  920. bmp_info.bmiHeader.biCompression = BI_RGB;
  921. Vector<uint8_t> img_data;
  922. img_data.resize(info->biWidth * std::abs(info->biHeight) * 4);
  923. GetDIBits(hdc, hbm, 0, std::abs(info->biHeight), img_data.ptrw(), &bmp_info, DIB_RGB_COLORS);
  924. uint8_t *wr = (uint8_t *)img_data.ptrw();
  925. for (int i = 0; i < info->biWidth * std::abs(info->biHeight); i++) {
  926. SWAP(wr[i * 4 + 0], wr[i * 4 + 2]); // Swap B and R.
  927. if (info->biBitCount != 32) {
  928. wr[i * 4 + 3] = 255; // Set A to solid if it's not in the source image.
  929. }
  930. }
  931. image = Image::create_from_data(info->biWidth, std::abs(info->biHeight), false, Image::Format::FORMAT_RGBA8, img_data);
  932. DeleteObject(hbm);
  933. }
  934. DeleteDC(hdc);
  935. }
  936. ReleaseDC(nullptr, dc);
  937. }
  938. GlobalUnlock(mem);
  939. }
  940. }
  941. }
  942. CloseClipboard();
  943. return image;
  944. }
  945. bool DisplayServerWindows::clipboard_has() const {
  946. return (IsClipboardFormatAvailable(CF_TEXT) ||
  947. IsClipboardFormatAvailable(CF_UNICODETEXT) ||
  948. IsClipboardFormatAvailable(CF_OEMTEXT));
  949. }
  950. bool DisplayServerWindows::clipboard_has_image() const {
  951. UINT png_format = RegisterClipboardFormatA("PNG");
  952. return ((png_format && IsClipboardFormatAvailable(png_format)) || IsClipboardFormatAvailable(CF_DIB));
  953. }
  954. typedef struct {
  955. int count;
  956. int screen;
  957. HMONITOR monitor;
  958. } EnumScreenData;
  959. static BOOL CALLBACK _MonitorEnumProcPrim(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
  960. EnumScreenData *data = (EnumScreenData *)dwData;
  961. if ((lprcMonitor->left == 0) && (lprcMonitor->top == 0)) {
  962. data->screen = data->count;
  963. return FALSE;
  964. }
  965. data->count++;
  966. return TRUE;
  967. }
  968. static BOOL CALLBACK _MonitorEnumProcScreen(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
  969. EnumScreenData *data = (EnumScreenData *)dwData;
  970. if (data->monitor == hMonitor) {
  971. data->screen = data->count;
  972. }
  973. data->count++;
  974. return TRUE;
  975. }
  976. static BOOL CALLBACK _MonitorEnumProcCount(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
  977. int *data = (int *)dwData;
  978. (*data)++;
  979. return TRUE;
  980. }
  981. int DisplayServerWindows::get_screen_count() const {
  982. _THREAD_SAFE_METHOD_
  983. int data = 0;
  984. EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcCount, (LPARAM)&data);
  985. return data;
  986. }
  987. int DisplayServerWindows::get_primary_screen() const {
  988. EnumScreenData data = { 0, 0, nullptr };
  989. EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcPrim, (LPARAM)&data);
  990. return data.screen;
  991. }
  992. int DisplayServerWindows::get_keyboard_focus_screen() const {
  993. HWND hwnd = GetForegroundWindow();
  994. if (hwnd) {
  995. EnumScreenData data = { 0, 0, MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) };
  996. EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcScreen, (LPARAM)&data);
  997. return data.screen;
  998. } else {
  999. return get_primary_screen();
  1000. }
  1001. }
  1002. typedef struct {
  1003. int count;
  1004. int screen;
  1005. Point2 pos;
  1006. } EnumPosData;
  1007. static BOOL CALLBACK _MonitorEnumProcPos(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
  1008. EnumPosData *data = (EnumPosData *)dwData;
  1009. if (data->count == data->screen) {
  1010. data->pos.x = lprcMonitor->left;
  1011. data->pos.y = lprcMonitor->top;
  1012. }
  1013. data->count++;
  1014. return TRUE;
  1015. }
  1016. static BOOL CALLBACK _MonitorEnumProcOrigin(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
  1017. EnumPosData *data = (EnumPosData *)dwData;
  1018. data->pos = data->pos.min(Point2(lprcMonitor->left, lprcMonitor->top));
  1019. return TRUE;
  1020. }
  1021. Point2i DisplayServerWindows::_get_screens_origin() const {
  1022. _THREAD_SAFE_METHOD_
  1023. EnumPosData data = { 0, 0, Point2() };
  1024. EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcOrigin, (LPARAM)&data);
  1025. return data.pos;
  1026. }
  1027. Point2i DisplayServerWindows::screen_get_position(int p_screen) const {
  1028. _THREAD_SAFE_METHOD_
  1029. p_screen = _get_screen_index(p_screen);
  1030. EnumPosData data = { 0, p_screen, Point2() };
  1031. EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcPos, (LPARAM)&data);
  1032. return data.pos - _get_screens_origin();
  1033. }
  1034. typedef struct {
  1035. int count;
  1036. int screen;
  1037. Size2 size;
  1038. } EnumSizeData;
  1039. typedef struct {
  1040. int count;
  1041. int screen;
  1042. Rect2i rect;
  1043. } EnumRectData;
  1044. typedef struct {
  1045. Vector<DISPLAYCONFIG_PATH_INFO> paths;
  1046. Vector<DISPLAYCONFIG_MODE_INFO> modes;
  1047. int count;
  1048. int screen;
  1049. float rate;
  1050. } EnumRefreshRateData;
  1051. static BOOL CALLBACK _MonitorEnumProcSize(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
  1052. EnumSizeData *data = (EnumSizeData *)dwData;
  1053. if (data->count == data->screen) {
  1054. data->size.x = lprcMonitor->right - lprcMonitor->left;
  1055. data->size.y = lprcMonitor->bottom - lprcMonitor->top;
  1056. }
  1057. data->count++;
  1058. return TRUE;
  1059. }
  1060. Size2i DisplayServerWindows::screen_get_size(int p_screen) const {
  1061. _THREAD_SAFE_METHOD_
  1062. p_screen = _get_screen_index(p_screen);
  1063. EnumSizeData data = { 0, p_screen, Size2() };
  1064. EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcSize, (LPARAM)&data);
  1065. return data.size;
  1066. }
  1067. static BOOL CALLBACK _MonitorEnumProcUsableSize(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
  1068. EnumRectData *data = (EnumRectData *)dwData;
  1069. if (data->count == data->screen) {
  1070. MONITORINFO minfo;
  1071. memset(&minfo, 0, sizeof(MONITORINFO));
  1072. minfo.cbSize = sizeof(MONITORINFO);
  1073. GetMonitorInfoA(hMonitor, &minfo);
  1074. data->rect.position.x = minfo.rcWork.left;
  1075. data->rect.position.y = minfo.rcWork.top;
  1076. data->rect.size.x = minfo.rcWork.right - minfo.rcWork.left;
  1077. data->rect.size.y = minfo.rcWork.bottom - minfo.rcWork.top;
  1078. }
  1079. data->count++;
  1080. return TRUE;
  1081. }
  1082. static BOOL CALLBACK _MonitorEnumProcRefreshRate(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
  1083. EnumRefreshRateData *data = (EnumRefreshRateData *)dwData;
  1084. if (data->count == data->screen) {
  1085. MONITORINFOEXW minfo;
  1086. memset(&minfo, 0, sizeof(minfo));
  1087. minfo.cbSize = sizeof(minfo);
  1088. GetMonitorInfoW(hMonitor, &minfo);
  1089. bool found = false;
  1090. for (const DISPLAYCONFIG_PATH_INFO &path : data->paths) {
  1091. DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name;
  1092. memset(&source_name, 0, sizeof(source_name));
  1093. source_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
  1094. source_name.header.size = sizeof(source_name);
  1095. source_name.header.adapterId = path.sourceInfo.adapterId;
  1096. source_name.header.id = path.sourceInfo.id;
  1097. if (DisplayConfigGetDeviceInfo(&source_name.header) == ERROR_SUCCESS) {
  1098. if (wcscmp(minfo.szDevice, source_name.viewGdiDeviceName) == 0 && path.targetInfo.refreshRate.Numerator != 0 && path.targetInfo.refreshRate.Denominator != 0) {
  1099. data->rate = (double)path.targetInfo.refreshRate.Numerator / (double)path.targetInfo.refreshRate.Denominator;
  1100. found = true;
  1101. break;
  1102. }
  1103. }
  1104. }
  1105. if (!found) {
  1106. DEVMODEW dm;
  1107. memset(&dm, 0, sizeof(dm));
  1108. dm.dmSize = sizeof(dm);
  1109. EnumDisplaySettingsW(minfo.szDevice, ENUM_CURRENT_SETTINGS, &dm);
  1110. data->rate = dm.dmDisplayFrequency;
  1111. }
  1112. }
  1113. data->count++;
  1114. return TRUE;
  1115. }
  1116. Rect2i DisplayServerWindows::screen_get_usable_rect(int p_screen) const {
  1117. _THREAD_SAFE_METHOD_
  1118. p_screen = _get_screen_index(p_screen);
  1119. EnumRectData data = { 0, p_screen, Rect2i() };
  1120. EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcUsableSize, (LPARAM)&data);
  1121. data.rect.position -= _get_screens_origin();
  1122. return data.rect;
  1123. }
  1124. typedef struct {
  1125. int count;
  1126. int screen;
  1127. int dpi;
  1128. } EnumDpiData;
  1129. enum _MonitorDpiType {
  1130. MDT_Effective_DPI = 0,
  1131. MDT_Angular_DPI = 1,
  1132. MDT_Raw_DPI = 2,
  1133. MDT_Default = MDT_Effective_DPI
  1134. };
  1135. static int QueryDpiForMonitor(HMONITOR hmon, _MonitorDpiType dpiType = MDT_Default) {
  1136. int dpiX = 96, dpiY = 96;
  1137. static HMODULE Shcore = nullptr;
  1138. typedef HRESULT(WINAPI * GetDPIForMonitor_t)(HMONITOR hmonitor, _MonitorDpiType dpiType, UINT * dpiX, UINT * dpiY);
  1139. static GetDPIForMonitor_t getDPIForMonitor = nullptr;
  1140. if (Shcore == nullptr) {
  1141. Shcore = LoadLibraryW(L"Shcore.dll");
  1142. getDPIForMonitor = Shcore ? (GetDPIForMonitor_t)(void *)GetProcAddress(Shcore, "GetDpiForMonitor") : nullptr;
  1143. if ((Shcore == nullptr) || (getDPIForMonitor == nullptr)) {
  1144. if (Shcore) {
  1145. FreeLibrary(Shcore);
  1146. }
  1147. Shcore = (HMODULE)INVALID_HANDLE_VALUE;
  1148. }
  1149. }
  1150. UINT x = 0, y = 0;
  1151. if (hmon && (Shcore != (HMODULE)INVALID_HANDLE_VALUE)) {
  1152. HRESULT hr = getDPIForMonitor(hmon, dpiType /*MDT_Effective_DPI*/, &x, &y);
  1153. if (SUCCEEDED(hr) && (x > 0) && (y > 0)) {
  1154. dpiX = (int)x;
  1155. dpiY = (int)y;
  1156. }
  1157. } else {
  1158. static int overallX = 0, overallY = 0;
  1159. if (overallX <= 0 || overallY <= 0) {
  1160. HDC hdc = GetDC(nullptr);
  1161. if (hdc) {
  1162. overallX = GetDeviceCaps(hdc, LOGPIXELSX);
  1163. overallY = GetDeviceCaps(hdc, LOGPIXELSY);
  1164. ReleaseDC(nullptr, hdc);
  1165. }
  1166. }
  1167. if (overallX > 0 && overallY > 0) {
  1168. dpiX = overallX;
  1169. dpiY = overallY;
  1170. }
  1171. }
  1172. return (dpiX + dpiY) / 2;
  1173. }
  1174. static BOOL CALLBACK _MonitorEnumProcDpi(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
  1175. EnumDpiData *data = (EnumDpiData *)dwData;
  1176. if (data->count == data->screen) {
  1177. data->dpi = QueryDpiForMonitor(hMonitor);
  1178. }
  1179. data->count++;
  1180. return TRUE;
  1181. }
  1182. int DisplayServerWindows::screen_get_dpi(int p_screen) const {
  1183. _THREAD_SAFE_METHOD_
  1184. p_screen = _get_screen_index(p_screen);
  1185. EnumDpiData data = { 0, p_screen, 72 };
  1186. EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcDpi, (LPARAM)&data);
  1187. return data.dpi;
  1188. }
  1189. Color DisplayServerWindows::screen_get_pixel(const Point2i &p_position) const {
  1190. Point2i pos = p_position + _get_screens_origin();
  1191. POINT p;
  1192. p.x = pos.x;
  1193. p.y = pos.y;
  1194. if (win81p_LogicalToPhysicalPointForPerMonitorDPI) {
  1195. win81p_LogicalToPhysicalPointForPerMonitorDPI(nullptr, &p);
  1196. }
  1197. HDC dc = GetDC(nullptr);
  1198. if (dc) {
  1199. COLORREF col = GetPixel(dc, p.x, p.y);
  1200. if (col != CLR_INVALID) {
  1201. ReleaseDC(nullptr, dc);
  1202. return Color(float(col & 0x000000FF) / 255.0f, float((col & 0x0000FF00) >> 8) / 255.0f, float((col & 0x00FF0000) >> 16) / 255.0f, 1.0f);
  1203. }
  1204. ReleaseDC(nullptr, dc);
  1205. }
  1206. return Color();
  1207. }
  1208. Ref<Image> DisplayServerWindows::screen_get_image(int p_screen) const {
  1209. ERR_FAIL_INDEX_V(p_screen, get_screen_count(), Ref<Image>());
  1210. switch (p_screen) {
  1211. case SCREEN_PRIMARY: {
  1212. p_screen = get_primary_screen();
  1213. } break;
  1214. case SCREEN_OF_MAIN_WINDOW: {
  1215. p_screen = window_get_current_screen(MAIN_WINDOW_ID);
  1216. } break;
  1217. default:
  1218. break;
  1219. }
  1220. Point2i pos = screen_get_position(p_screen) + _get_screens_origin();
  1221. Size2i size = screen_get_size(p_screen);
  1222. POINT p1;
  1223. p1.x = pos.x;
  1224. p1.y = pos.y;
  1225. POINT p2;
  1226. p2.x = pos.x + size.x;
  1227. p2.y = pos.y + size.y;
  1228. if (win81p_LogicalToPhysicalPointForPerMonitorDPI) {
  1229. win81p_LogicalToPhysicalPointForPerMonitorDPI(nullptr, &p1);
  1230. win81p_LogicalToPhysicalPointForPerMonitorDPI(nullptr, &p2);
  1231. }
  1232. Ref<Image> img;
  1233. HDC dc = GetDC(nullptr);
  1234. if (dc) {
  1235. HDC hdc = CreateCompatibleDC(dc);
  1236. int width = p2.x - p1.x;
  1237. int height = p2.y - p1.y;
  1238. if (hdc) {
  1239. HBITMAP hbm = CreateCompatibleBitmap(dc, width, height);
  1240. if (hbm) {
  1241. SelectObject(hdc, hbm);
  1242. BitBlt(hdc, 0, 0, width, height, dc, p1.x, p1.y, SRCCOPY);
  1243. BITMAPINFO bmp_info = {};
  1244. bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader);
  1245. bmp_info.bmiHeader.biWidth = width;
  1246. bmp_info.bmiHeader.biHeight = -height;
  1247. bmp_info.bmiHeader.biPlanes = 1;
  1248. bmp_info.bmiHeader.biBitCount = 32;
  1249. bmp_info.bmiHeader.biCompression = BI_RGB;
  1250. Vector<uint8_t> img_data;
  1251. img_data.resize(width * height * 4);
  1252. GetDIBits(hdc, hbm, 0, height, img_data.ptrw(), &bmp_info, DIB_RGB_COLORS);
  1253. uint8_t *wr = (uint8_t *)img_data.ptrw();
  1254. for (int i = 0; i < width * height; i++) {
  1255. SWAP(wr[i * 4 + 0], wr[i * 4 + 2]); // Swap B and R.
  1256. }
  1257. img = Image::create_from_data(width, height, false, Image::FORMAT_RGBA8, img_data);
  1258. DeleteObject(hbm);
  1259. }
  1260. DeleteDC(hdc);
  1261. }
  1262. ReleaseDC(nullptr, dc);
  1263. }
  1264. return img;
  1265. }
  1266. Ref<Image> DisplayServerWindows::screen_get_image_rect(const Rect2i &p_rect) const {
  1267. Point2i pos = p_rect.position + _get_screens_origin();
  1268. Size2i size = p_rect.size;
  1269. POINT p1;
  1270. p1.x = pos.x;
  1271. p1.y = pos.y;
  1272. POINT p2;
  1273. p2.x = pos.x + size.x;
  1274. p2.y = pos.y + size.y;
  1275. if (win81p_LogicalToPhysicalPointForPerMonitorDPI) {
  1276. win81p_LogicalToPhysicalPointForPerMonitorDPI(0, &p1);
  1277. win81p_LogicalToPhysicalPointForPerMonitorDPI(0, &p2);
  1278. }
  1279. Ref<Image> img;
  1280. HDC dc = GetDC(0);
  1281. if (dc) {
  1282. HDC hdc = CreateCompatibleDC(dc);
  1283. int width = p2.x - p1.x;
  1284. int height = p2.y - p1.y;
  1285. if (hdc) {
  1286. HBITMAP hbm = CreateCompatibleBitmap(dc, width, height);
  1287. if (hbm) {
  1288. SelectObject(hdc, hbm);
  1289. BitBlt(hdc, 0, 0, width, height, dc, p1.x, p1.y, SRCCOPY);
  1290. BITMAPINFO bmp_info = {};
  1291. bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader);
  1292. bmp_info.bmiHeader.biWidth = width;
  1293. bmp_info.bmiHeader.biHeight = -height;
  1294. bmp_info.bmiHeader.biPlanes = 1;
  1295. bmp_info.bmiHeader.biBitCount = 32;
  1296. bmp_info.bmiHeader.biCompression = BI_RGB;
  1297. Vector<uint8_t> img_data;
  1298. img_data.resize(width * height * 4);
  1299. GetDIBits(hdc, hbm, 0, height, img_data.ptrw(), &bmp_info, DIB_RGB_COLORS);
  1300. uint8_t *wr = (uint8_t *)img_data.ptrw();
  1301. for (int i = 0; i < width * height; i++) {
  1302. SWAP(wr[i * 4 + 0], wr[i * 4 + 2]); // Swap B and R.
  1303. }
  1304. img = Image::create_from_data(width, height, false, Image::FORMAT_RGBA8, img_data);
  1305. DeleteObject(hbm);
  1306. }
  1307. DeleteDC(hdc);
  1308. }
  1309. ReleaseDC(NULL, dc);
  1310. }
  1311. return img;
  1312. }
  1313. float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const {
  1314. _THREAD_SAFE_METHOD_
  1315. p_screen = _get_screen_index(p_screen);
  1316. EnumRefreshRateData data = { Vector<DISPLAYCONFIG_PATH_INFO>(), Vector<DISPLAYCONFIG_MODE_INFO>(), 0, p_screen, SCREEN_REFRESH_RATE_FALLBACK };
  1317. uint32_t path_count = 0;
  1318. uint32_t mode_count = 0;
  1319. if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &path_count, &mode_count) == ERROR_SUCCESS) {
  1320. data.paths.resize(path_count);
  1321. data.modes.resize(mode_count);
  1322. if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &path_count, data.paths.ptrw(), &mode_count, data.modes.ptrw(), nullptr) != ERROR_SUCCESS) {
  1323. data.paths.clear();
  1324. data.modes.clear();
  1325. }
  1326. }
  1327. EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcRefreshRate, (LPARAM)&data);
  1328. return data.rate;
  1329. }
  1330. void DisplayServerWindows::screen_set_keep_on(bool p_enable) {
  1331. if (keep_screen_on == p_enable) {
  1332. return;
  1333. }
  1334. if (p_enable) {
  1335. const String reason = "Godot Engine running with display/window/energy_saving/keep_screen_on = true";
  1336. Char16String reason_utf16 = reason.utf16();
  1337. REASON_CONTEXT context;
  1338. context.Version = POWER_REQUEST_CONTEXT_VERSION;
  1339. context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
  1340. context.Reason.SimpleReasonString = (LPWSTR)(reason_utf16.ptrw());
  1341. power_request = PowerCreateRequest(&context);
  1342. if (power_request == INVALID_HANDLE_VALUE) {
  1343. print_error("Failed to enable screen_keep_on.");
  1344. return;
  1345. }
  1346. if (PowerSetRequest(power_request, POWER_REQUEST_TYPE::PowerRequestSystemRequired) == 0) {
  1347. print_error("Failed to request system sleep override.");
  1348. return;
  1349. }
  1350. if (PowerSetRequest(power_request, POWER_REQUEST_TYPE::PowerRequestDisplayRequired) == 0) {
  1351. print_error("Failed to request display timeout override.");
  1352. return;
  1353. }
  1354. } else {
  1355. PowerClearRequest(power_request, POWER_REQUEST_TYPE::PowerRequestSystemRequired);
  1356. PowerClearRequest(power_request, POWER_REQUEST_TYPE::PowerRequestDisplayRequired);
  1357. CloseHandle(power_request);
  1358. power_request = nullptr;
  1359. }
  1360. keep_screen_on = p_enable;
  1361. }
  1362. bool DisplayServerWindows::screen_is_kept_on() const {
  1363. return keep_screen_on;
  1364. }
  1365. Vector<DisplayServer::WindowID> DisplayServerWindows::get_window_list() const {
  1366. _THREAD_SAFE_METHOD_
  1367. Vector<DisplayServer::WindowID> ret;
  1368. for (const KeyValue<WindowID, WindowData> &E : windows) {
  1369. ret.push_back(E.key);
  1370. }
  1371. return ret;
  1372. }
  1373. DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(const Point2i &p_position) const {
  1374. Point2i offset = _get_screens_origin();
  1375. POINT p;
  1376. p.x = p_position.x + offset.x;
  1377. p.y = p_position.y + offset.y;
  1378. HWND hwnd = WindowFromPoint(p);
  1379. for (const KeyValue<WindowID, WindowData> &E : windows) {
  1380. if (E.value.hWnd == hwnd) {
  1381. return E.key;
  1382. }
  1383. }
  1384. return INVALID_WINDOW_ID;
  1385. }
  1386. DisplayServer::WindowID DisplayServerWindows::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) {
  1387. _THREAD_SAFE_METHOD_
  1388. WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect, p_exclusive, p_transient_parent, NULL);
  1389. ERR_FAIL_COND_V_MSG(window_id == INVALID_WINDOW_ID, INVALID_WINDOW_ID, "Failed to create sub window.");
  1390. WindowData &wd = windows[window_id];
  1391. if (p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT) {
  1392. wd.resizable = false;
  1393. }
  1394. if (p_flags & WINDOW_FLAG_MINIMIZE_DISABLED_BIT) {
  1395. wd.no_min_btn = true;
  1396. }
  1397. if (p_flags & WINDOW_FLAG_MAXIMIZE_DISABLED_BIT) {
  1398. wd.no_max_btn = true;
  1399. }
  1400. if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
  1401. wd.borderless = true;
  1402. }
  1403. if (p_flags & WINDOW_FLAG_ALWAYS_ON_TOP_BIT && p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
  1404. wd.always_on_top = true;
  1405. }
  1406. if (p_flags & WINDOW_FLAG_SHARP_CORNERS_BIT) {
  1407. wd.sharp_corners = true;
  1408. }
  1409. if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
  1410. wd.no_focus = true;
  1411. }
  1412. if (p_flags & WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT) {
  1413. wd.mpass = true;
  1414. }
  1415. if (p_flags & WINDOW_FLAG_EXCLUDE_FROM_CAPTURE_BIT) {
  1416. wd.hide_from_capture = true;
  1417. if (os_ver.dwBuildNumber >= 19041) {
  1418. SetWindowDisplayAffinity(wd.hWnd, WDA_EXCLUDEFROMCAPTURE);
  1419. } else {
  1420. SetWindowDisplayAffinity(wd.hWnd, WDA_MONITOR);
  1421. }
  1422. }
  1423. if (p_flags & WINDOW_FLAG_POPUP_BIT) {
  1424. wd.is_popup = true;
  1425. }
  1426. if (p_flags & WINDOW_FLAG_TRANSPARENT_BIT) {
  1427. if (OS::get_singleton()->is_layered_allowed()) {
  1428. DWM_BLURBEHIND bb;
  1429. ZeroMemory(&bb, sizeof(bb));
  1430. HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
  1431. bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
  1432. bb.hRgnBlur = hRgn;
  1433. bb.fEnable = TRUE;
  1434. DwmEnableBlurBehindWindow(wd.hWnd, &bb);
  1435. }
  1436. wd.layered_window = true;
  1437. }
  1438. // Inherit icons from MAIN_WINDOW for all sub windows.
  1439. HICON mainwindow_icon = (HICON)SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_GETICON, ICON_SMALL, 0);
  1440. if (mainwindow_icon) {
  1441. SendMessage(windows[window_id].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)mainwindow_icon);
  1442. }
  1443. mainwindow_icon = (HICON)SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_GETICON, ICON_BIG, 0);
  1444. if (mainwindow_icon) {
  1445. SendMessage(windows[window_id].hWnd, WM_SETICON, ICON_BIG, (LPARAM)mainwindow_icon);
  1446. }
  1447. #ifdef RD_ENABLED
  1448. if (rendering_device) {
  1449. rendering_device->screen_create(window_id);
  1450. }
  1451. #endif
  1452. return window_id;
  1453. }
  1454. bool DisplayServerWindows::_is_always_on_top_recursive(WindowID p_window) const {
  1455. ERR_FAIL_COND_V(!windows.has(p_window), false);
  1456. const WindowData &wd = windows[p_window];
  1457. if (wd.always_on_top) {
  1458. return true;
  1459. }
  1460. if (wd.transient_parent != INVALID_WINDOW_ID) {
  1461. return _is_always_on_top_recursive(wd.transient_parent);
  1462. }
  1463. return false;
  1464. }
  1465. void DisplayServerWindows::show_window(WindowID p_id) {
  1466. ERR_FAIL_COND(!windows.has(p_id));
  1467. WindowData &wd = windows[p_id];
  1468. popup_open(p_id);
  1469. if (p_id != MAIN_WINDOW_ID) {
  1470. _update_window_style(p_id);
  1471. }
  1472. wd.initialized = true;
  1473. if (wd.maximized) {
  1474. ShowWindow(wd.hWnd, SW_SHOWMAXIMIZED);
  1475. SetForegroundWindow(wd.hWnd); // Slightly higher priority.
  1476. SetFocus(wd.hWnd); // Set keyboard focus.
  1477. } else if (wd.minimized) {
  1478. ShowWindow(wd.hWnd, SW_SHOWMINIMIZED);
  1479. } else if (wd.no_focus) {
  1480. // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
  1481. ShowWindow(wd.hWnd, SW_SHOWNA);
  1482. } else if (wd.is_popup) {
  1483. ShowWindow(wd.hWnd, SW_SHOWNA);
  1484. SetFocus(wd.hWnd); // Set keyboard focus.
  1485. } else {
  1486. ShowWindow(wd.hWnd, SW_SHOW);
  1487. SetForegroundWindow(wd.hWnd); // Slightly higher priority.
  1488. SetFocus(wd.hWnd); // Set keyboard focus.
  1489. }
  1490. if (_is_always_on_top_recursive(p_id)) {
  1491. SetWindowPos(wd.hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0));
  1492. }
  1493. }
  1494. void DisplayServerWindows::delete_sub_window(WindowID p_window) {
  1495. _THREAD_SAFE_METHOD_
  1496. ERR_FAIL_COND(!windows.has(p_window));
  1497. ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window cannot be deleted.");
  1498. popup_close(p_window);
  1499. WindowData &wd = windows[p_window];
  1500. IPropertyStore *prop_store;
  1501. HRESULT hr = SHGetPropertyStoreForWindow(wd.hWnd, IID_IPropertyStore, (void **)&prop_store);
  1502. if (hr == S_OK) {
  1503. PROPVARIANT val;
  1504. PropVariantInit(&val);
  1505. prop_store->SetValue(PKEY_AppUserModel_ID, val);
  1506. prop_store->Release();
  1507. }
  1508. while (wd.transient_children.size()) {
  1509. window_set_transient(*wd.transient_children.begin(), INVALID_WINDOW_ID);
  1510. }
  1511. if (wd.transient_parent != INVALID_WINDOW_ID) {
  1512. window_set_transient(p_window, INVALID_WINDOW_ID);
  1513. }
  1514. #ifdef RD_ENABLED
  1515. if (rendering_device) {
  1516. rendering_device->screen_free(p_window);
  1517. }
  1518. if (rendering_context) {
  1519. rendering_context->window_destroy(p_window);
  1520. }
  1521. #endif
  1522. #ifdef GLES3_ENABLED
  1523. if (gl_manager_angle) {
  1524. gl_manager_angle->window_destroy(p_window);
  1525. }
  1526. if (gl_manager_native) {
  1527. gl_manager_native->window_destroy(p_window);
  1528. }
  1529. #endif
  1530. if ((tablet_get_current_driver() == "wintab") && wintab_available && wd.wtctx) {
  1531. wintab_WTClose(wd.wtctx);
  1532. wd.wtctx = nullptr;
  1533. }
  1534. if (wd.drop_target != nullptr) {
  1535. RevokeDragDrop(wd.hWnd);
  1536. wd.drop_target->Release();
  1537. }
  1538. DestroyWindow(wd.hWnd);
  1539. windows.erase(p_window);
  1540. if (last_focused_window == p_window) {
  1541. last_focused_window = INVALID_WINDOW_ID;
  1542. }
  1543. }
  1544. void DisplayServerWindows::gl_window_make_current(DisplayServer::WindowID p_window_id) {
  1545. #if defined(GLES3_ENABLED)
  1546. if (gl_manager_angle) {
  1547. gl_manager_angle->window_make_current(p_window_id);
  1548. }
  1549. if (gl_manager_native) {
  1550. gl_manager_native->window_make_current(p_window_id);
  1551. }
  1552. #endif
  1553. }
  1554. int64_t DisplayServerWindows::window_get_native_handle(HandleType p_handle_type, WindowID p_window) const {
  1555. ERR_FAIL_COND_V(!windows.has(p_window), 0);
  1556. switch (p_handle_type) {
  1557. case DISPLAY_HANDLE: {
  1558. return 0; // Not supported.
  1559. }
  1560. case WINDOW_HANDLE: {
  1561. return (int64_t)windows[p_window].hWnd;
  1562. }
  1563. #if defined(GLES3_ENABLED)
  1564. case WINDOW_VIEW: {
  1565. if (gl_manager_native) {
  1566. return (int64_t)gl_manager_native->get_hdc(p_window);
  1567. } else {
  1568. return (int64_t)GetDC(windows[p_window].hWnd);
  1569. }
  1570. }
  1571. case OPENGL_CONTEXT: {
  1572. if (gl_manager_native) {
  1573. return (int64_t)gl_manager_native->get_hglrc(p_window);
  1574. }
  1575. if (gl_manager_angle) {
  1576. return (int64_t)gl_manager_angle->get_context(p_window);
  1577. }
  1578. return 0;
  1579. }
  1580. case EGL_DISPLAY: {
  1581. if (gl_manager_angle) {
  1582. return (int64_t)gl_manager_angle->get_display(p_window);
  1583. }
  1584. return 0;
  1585. }
  1586. case EGL_CONFIG: {
  1587. if (gl_manager_angle) {
  1588. return (int64_t)gl_manager_angle->get_config(p_window);
  1589. }
  1590. return 0;
  1591. }
  1592. #endif
  1593. default: {
  1594. return 0;
  1595. }
  1596. }
  1597. }
  1598. void DisplayServerWindows::window_attach_instance_id(ObjectID p_instance, WindowID p_window) {
  1599. _THREAD_SAFE_METHOD_
  1600. ERR_FAIL_COND(!windows.has(p_window));
  1601. windows[p_window].instance_id = p_instance;
  1602. }
  1603. ObjectID DisplayServerWindows::window_get_attached_instance_id(WindowID p_window) const {
  1604. _THREAD_SAFE_METHOD_
  1605. ERR_FAIL_COND_V(!windows.has(p_window), ObjectID());
  1606. return windows[p_window].instance_id;
  1607. }
  1608. void DisplayServerWindows::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
  1609. _THREAD_SAFE_METHOD_
  1610. ERR_FAIL_COND(!windows.has(p_window));
  1611. windows[p_window].rect_changed_callback = p_callable;
  1612. }
  1613. void DisplayServerWindows::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
  1614. _THREAD_SAFE_METHOD_
  1615. ERR_FAIL_COND(!windows.has(p_window));
  1616. windows[p_window].event_callback = p_callable;
  1617. }
  1618. void DisplayServerWindows::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) {
  1619. _THREAD_SAFE_METHOD_
  1620. ERR_FAIL_COND(!windows.has(p_window));
  1621. windows[p_window].input_event_callback = p_callable;
  1622. }
  1623. void DisplayServerWindows::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) {
  1624. _THREAD_SAFE_METHOD_
  1625. ERR_FAIL_COND(!windows.has(p_window));
  1626. windows[p_window].input_text_callback = p_callable;
  1627. }
  1628. void DisplayServerWindows::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) {
  1629. _THREAD_SAFE_METHOD_
  1630. ERR_FAIL_COND(!windows.has(p_window));
  1631. WindowData &window_data = windows[p_window];
  1632. window_data.drop_files_callback = p_callable;
  1633. if (window_data.drop_target == nullptr) {
  1634. window_data.drop_target = memnew(DropTargetWindows(&window_data));
  1635. ERR_FAIL_COND(RegisterDragDrop(window_data.hWnd, window_data.drop_target) != S_OK);
  1636. }
  1637. }
  1638. void DisplayServerWindows::window_set_title(const String &p_title, WindowID p_window) {
  1639. _THREAD_SAFE_METHOD_
  1640. ERR_FAIL_COND(!windows.has(p_window));
  1641. SetWindowTextW(windows[p_window].hWnd, (LPCWSTR)(p_title.utf16().get_data()));
  1642. }
  1643. Size2i DisplayServerWindows::window_get_title_size(const String &p_title, WindowID p_window) const {
  1644. _THREAD_SAFE_METHOD_
  1645. Size2i size;
  1646. ERR_FAIL_COND_V(!windows.has(p_window), size);
  1647. const WindowData &wd = windows[p_window];
  1648. if (wd.fullscreen || wd.minimized || wd.borderless) {
  1649. return size;
  1650. }
  1651. HDC hdc = GetDCEx(wd.hWnd, nullptr, DCX_WINDOW);
  1652. if (hdc) {
  1653. Char16String s = p_title.utf16();
  1654. SIZE text_size;
  1655. if (GetTextExtentPoint32W(hdc, (LPCWSTR)(s.get_data()), s.length(), &text_size)) {
  1656. size.x = text_size.cx;
  1657. size.y = text_size.cy;
  1658. }
  1659. ReleaseDC(wd.hWnd, hdc);
  1660. }
  1661. RECT rect;
  1662. if (DwmGetWindowAttribute(wd.hWnd, DWMWA_CAPTION_BUTTON_BOUNDS, &rect, sizeof(RECT)) == S_OK) {
  1663. if (rect.right - rect.left > 0) {
  1664. ClientToScreen(wd.hWnd, (POINT *)&rect.left);
  1665. ClientToScreen(wd.hWnd, (POINT *)&rect.right);
  1666. if (win81p_PhysicalToLogicalPointForPerMonitorDPI) {
  1667. win81p_PhysicalToLogicalPointForPerMonitorDPI(nullptr, (POINT *)&rect.left);
  1668. win81p_PhysicalToLogicalPointForPerMonitorDPI(nullptr, (POINT *)&rect.right);
  1669. }
  1670. size.x += (rect.right - rect.left);
  1671. size.y = MAX(size.y, rect.bottom - rect.top);
  1672. }
  1673. }
  1674. if (icon.is_valid()) {
  1675. size.x += 32;
  1676. } else {
  1677. size.x += 16;
  1678. }
  1679. return size;
  1680. }
  1681. void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
  1682. _THREAD_SAFE_METHOD_
  1683. ERR_FAIL_COND(!windows.has(p_window));
  1684. windows[p_window].mpath = p_region;
  1685. _update_window_mouse_passthrough(p_window);
  1686. }
  1687. void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) {
  1688. ERR_FAIL_COND(!windows.has(p_window));
  1689. const WindowData &wd = windows[p_window];
  1690. bool clip_pixel = (wd.multiwindow_fs || (wd.borderless && wd.maximized));
  1691. bool pass_set = (wd.mpath.size() > 0);
  1692. if (!clip_pixel && !pass_set) {
  1693. SetWindowRgn(wd.hWnd, nullptr, TRUE);
  1694. } else {
  1695. HRGN region = nullptr;
  1696. if (pass_set) {
  1697. Vector<POINT> points;
  1698. points.resize(wd.mpath.size());
  1699. POINT *points_ptr = points.ptrw();
  1700. for (int i = 0; i < wd.mpath.size(); i++) {
  1701. if (wd.borderless) {
  1702. points_ptr[i].x = wd.mpath[i].x;
  1703. points_ptr[i].y = wd.mpath[i].y;
  1704. } else {
  1705. points_ptr[i].x = wd.mpath[i].x + GetSystemMetrics(SM_CXSIZEFRAME);
  1706. points_ptr[i].y = wd.mpath[i].y + GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYCAPTION);
  1707. }
  1708. }
  1709. region = CreatePolygonRgn(points.ptr(), points.size(), ALTERNATE);
  1710. } else {
  1711. region = CreateRectRgn(0, 0, wd.width, wd.height);
  1712. }
  1713. if (clip_pixel) {
  1714. HRGN region_clip = CreateRectRgn(0, 0, wd.width, wd.height);
  1715. CombineRgn(region, region, region_clip, RGN_AND);
  1716. DeleteObject(region_clip);
  1717. }
  1718. SetWindowRgn(wd.hWnd, region, FALSE);
  1719. }
  1720. }
  1721. int DisplayServerWindows::window_get_current_screen(WindowID p_window) const {
  1722. _THREAD_SAFE_METHOD_
  1723. ERR_FAIL_COND_V(!windows.has(p_window), -1);
  1724. EnumScreenData data = { 0, 0, MonitorFromWindow(windows[p_window].hWnd, MONITOR_DEFAULTTONEAREST) };
  1725. EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcScreen, (LPARAM)&data);
  1726. return data.screen;
  1727. }
  1728. void DisplayServerWindows::window_set_current_screen(int p_screen, WindowID p_window) {
  1729. _THREAD_SAFE_METHOD_
  1730. ERR_FAIL_COND(!windows.has(p_window));
  1731. ERR_FAIL_INDEX(p_screen, get_screen_count());
  1732. if (window_get_current_screen(p_window) == p_screen) {
  1733. return;
  1734. }
  1735. const WindowData &wd = windows[p_window];
  1736. if (wd.parent_hwnd) {
  1737. print_line("Embedded window can't be moved to another screen.");
  1738. return;
  1739. }
  1740. if (wd.fullscreen) {
  1741. Point2 pos = screen_get_position(p_screen) + _get_screens_origin();
  1742. Size2 size = screen_get_size(p_screen);
  1743. int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0;
  1744. MoveWindow(wd.hWnd, pos.x, pos.y, size.width + off_x, size.height, TRUE);
  1745. } else if (wd.maximized) {
  1746. Point2 pos = screen_get_position(p_screen) + _get_screens_origin();
  1747. Size2 size = screen_get_size(p_screen);
  1748. int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0;
  1749. ShowWindow(wd.hWnd, SW_RESTORE);
  1750. MoveWindow(wd.hWnd, pos.x, pos.y, size.width + off_x, size.height, TRUE);
  1751. ShowWindow(wd.hWnd, SW_MAXIMIZE);
  1752. } else {
  1753. Rect2i srect = screen_get_usable_rect(p_screen);
  1754. Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
  1755. Size2i wsize = window_get_size(p_window);
  1756. wpos += srect.position;
  1757. wpos = wpos.clamp(srect.position, srect.position + srect.size - wsize / 3);
  1758. window_set_position(wpos, p_window);
  1759. }
  1760. }
  1761. Point2i DisplayServerWindows::window_get_position(WindowID p_window) const {
  1762. _THREAD_SAFE_METHOD_
  1763. ERR_FAIL_COND_V(!windows.has(p_window), Point2i());
  1764. const WindowData &wd = windows[p_window];
  1765. if (wd.minimized) {
  1766. return wd.last_pos;
  1767. }
  1768. POINT point;
  1769. point.x = 0;
  1770. point.y = 0;
  1771. ClientToScreen(wd.hWnd, &point);
  1772. return Point2i(point.x, point.y) - _get_screens_origin();
  1773. }
  1774. Point2i DisplayServerWindows::window_get_position_with_decorations(WindowID p_window) const {
  1775. _THREAD_SAFE_METHOD_
  1776. ERR_FAIL_COND_V(!windows.has(p_window), Point2i());
  1777. const WindowData &wd = windows[p_window];
  1778. if (wd.minimized) {
  1779. return wd.last_pos;
  1780. }
  1781. RECT r;
  1782. if (GetWindowRect(wd.hWnd, &r)) {
  1783. return Point2i(r.left, r.top) - _get_screens_origin();
  1784. }
  1785. return Point2i();
  1786. }
  1787. void DisplayServerWindows::_update_real_mouse_position(WindowID p_window) {
  1788. ERR_FAIL_COND(!windows.has(p_window));
  1789. POINT mouse_pos;
  1790. if (GetCursorPos(&mouse_pos) && ScreenToClient(windows[p_window].hWnd, &mouse_pos)) {
  1791. if (mouse_pos.x > 0 && mouse_pos.y > 0 && mouse_pos.x <= windows[p_window].width && mouse_pos.y <= windows[p_window].height) {
  1792. old_x = mouse_pos.x;
  1793. old_y = mouse_pos.y;
  1794. old_invalid = false;
  1795. Input::get_singleton()->set_mouse_position(Point2i(mouse_pos.x, mouse_pos.y));
  1796. }
  1797. }
  1798. }
  1799. void DisplayServerWindows::window_set_position(const Point2i &p_position, WindowID p_window) {
  1800. _THREAD_SAFE_METHOD_
  1801. ERR_FAIL_COND(!windows.has(p_window));
  1802. WindowData &wd = windows[p_window];
  1803. if (wd.parent_hwnd) {
  1804. print_line("Embedded window can't be moved.");
  1805. return;
  1806. }
  1807. if (wd.fullscreen || wd.maximized) {
  1808. return;
  1809. }
  1810. Point2i offset = _get_screens_origin();
  1811. RECT rc;
  1812. rc.left = p_position.x + offset.x;
  1813. rc.right = p_position.x + wd.width + offset.x;
  1814. rc.bottom = p_position.y + wd.height + offset.y;
  1815. rc.top = p_position.y + offset.y;
  1816. const DWORD style = GetWindowLongPtr(wd.hWnd, GWL_STYLE);
  1817. const DWORD exStyle = GetWindowLongPtr(wd.hWnd, GWL_EXSTYLE);
  1818. AdjustWindowRectEx(&rc, style, false, exStyle);
  1819. MoveWindow(wd.hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
  1820. wd.last_pos = p_position;
  1821. _update_real_mouse_position(p_window);
  1822. }
  1823. void DisplayServerWindows::window_set_exclusive(WindowID p_window, bool p_exclusive) {
  1824. _THREAD_SAFE_METHOD_
  1825. ERR_FAIL_COND(!windows.has(p_window));
  1826. WindowData &wd = windows[p_window];
  1827. if (wd.exclusive != p_exclusive) {
  1828. wd.exclusive = p_exclusive;
  1829. if (wd.transient_parent != INVALID_WINDOW_ID) {
  1830. if (wd.exclusive) {
  1831. WindowData &wd_parent = windows[wd.transient_parent];
  1832. SetWindowLongPtr(wd.hWnd, GWLP_HWNDPARENT, (LONG_PTR)wd_parent.hWnd);
  1833. } else {
  1834. SetWindowLongPtr(wd.hWnd, GWLP_HWNDPARENT, (LONG_PTR) nullptr);
  1835. }
  1836. }
  1837. }
  1838. }
  1839. void DisplayServerWindows::window_set_transient(WindowID p_window, WindowID p_parent) {
  1840. _THREAD_SAFE_METHOD_
  1841. ERR_FAIL_COND(p_window == p_parent);
  1842. ERR_FAIL_COND(!windows.has(p_window));
  1843. WindowData &wd_window = windows[p_window];
  1844. ERR_FAIL_COND(wd_window.transient_parent == p_parent);
  1845. ERR_FAIL_COND_MSG(wd_window.always_on_top, "Windows with the 'on top' can't become transient.");
  1846. if (p_parent == INVALID_WINDOW_ID) {
  1847. // Remove transient.
  1848. ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID);
  1849. ERR_FAIL_COND(!windows.has(wd_window.transient_parent));
  1850. WindowData &wd_parent = windows[wd_window.transient_parent];
  1851. wd_window.transient_parent = INVALID_WINDOW_ID;
  1852. wd_parent.transient_children.erase(p_window);
  1853. if (wd_window.exclusive) {
  1854. SetWindowLongPtr(wd_window.hWnd, GWLP_HWNDPARENT, (LONG_PTR) nullptr);
  1855. }
  1856. } else {
  1857. ERR_FAIL_COND(!windows.has(p_parent));
  1858. ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
  1859. WindowData &wd_parent = windows[p_parent];
  1860. wd_window.transient_parent = p_parent;
  1861. wd_parent.transient_children.insert(p_window);
  1862. if (wd_window.exclusive) {
  1863. SetWindowLongPtr(wd_window.hWnd, GWLP_HWNDPARENT, (LONG_PTR)wd_parent.hWnd);
  1864. }
  1865. }
  1866. }
  1867. void DisplayServerWindows::window_set_max_size(const Size2i p_size, WindowID p_window) {
  1868. _THREAD_SAFE_METHOD_
  1869. ERR_FAIL_COND(!windows.has(p_window));
  1870. WindowData &wd = windows[p_window];
  1871. if (wd.parent_hwnd) {
  1872. print_line("Embedded windows can't have a maximum size.");
  1873. return;
  1874. }
  1875. if ((p_size != Size2()) && ((p_size.x < wd.min_size.x) || (p_size.y < wd.min_size.y))) {
  1876. ERR_PRINT("Maximum window size can't be smaller than minimum window size!");
  1877. return;
  1878. }
  1879. wd.max_size = p_size;
  1880. }
  1881. Size2i DisplayServerWindows::window_get_max_size(WindowID p_window) const {
  1882. _THREAD_SAFE_METHOD_
  1883. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  1884. const WindowData &wd = windows[p_window];
  1885. return wd.max_size;
  1886. }
  1887. void DisplayServerWindows::window_set_min_size(const Size2i p_size, WindowID p_window) {
  1888. _THREAD_SAFE_METHOD_
  1889. ERR_FAIL_COND(!windows.has(p_window));
  1890. WindowData &wd = windows[p_window];
  1891. if (wd.parent_hwnd) {
  1892. print_line("Embedded windows can't have a minimum size.");
  1893. return;
  1894. }
  1895. if ((p_size != Size2()) && (wd.max_size != Size2()) && ((p_size.x > wd.max_size.x) || (p_size.y > wd.max_size.y))) {
  1896. ERR_PRINT("Minimum window size can't be larger than maximum window size!");
  1897. return;
  1898. }
  1899. wd.min_size = p_size;
  1900. }
  1901. Size2i DisplayServerWindows::window_get_min_size(WindowID p_window) const {
  1902. _THREAD_SAFE_METHOD_
  1903. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  1904. const WindowData &wd = windows[p_window];
  1905. return wd.min_size;
  1906. }
  1907. void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_window) {
  1908. _THREAD_SAFE_METHOD_
  1909. ERR_FAIL_COND(!windows.has(p_window));
  1910. WindowData &wd = windows[p_window];
  1911. if (wd.parent_hwnd) {
  1912. print_line("Embedded window can't be resized.");
  1913. return;
  1914. }
  1915. if (wd.fullscreen || wd.maximized) {
  1916. return;
  1917. }
  1918. int w = p_size.width;
  1919. int h = p_size.height;
  1920. RECT rect;
  1921. GetWindowRect(wd.hWnd, &rect);
  1922. if (!wd.borderless) {
  1923. RECT crect;
  1924. GetClientRect(wd.hWnd, &crect);
  1925. w += (rect.right - rect.left) - (crect.right - crect.left);
  1926. h += (rect.bottom - rect.top) - (crect.bottom - crect.top);
  1927. }
  1928. MoveWindow(wd.hWnd, rect.left, rect.top, w, h, TRUE);
  1929. }
  1930. Size2i DisplayServerWindows::window_get_size(WindowID p_window) const {
  1931. _THREAD_SAFE_METHOD_
  1932. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  1933. const WindowData &wd = windows[p_window];
  1934. // GetClientRect() returns a zero rect for a minimized window, so we need to get the size in another way.
  1935. if (wd.minimized) {
  1936. return Size2(wd.width, wd.height);
  1937. }
  1938. RECT r;
  1939. if (GetClientRect(wd.hWnd, &r)) { // Retrieves area inside of window border, including decoration.
  1940. int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0;
  1941. return Size2(r.right - r.left - off_x, r.bottom - r.top);
  1942. }
  1943. return Size2();
  1944. }
  1945. Size2i DisplayServerWindows::window_get_size_with_decorations(WindowID p_window) const {
  1946. _THREAD_SAFE_METHOD_
  1947. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  1948. const WindowData &wd = windows[p_window];
  1949. RECT r;
  1950. if (GetWindowRect(wd.hWnd, &r)) { // Retrieves area inside of window border, including decoration.
  1951. int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0;
  1952. return Size2(r.right - r.left - off_x, r.bottom - r.top);
  1953. }
  1954. return Size2();
  1955. }
  1956. void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_initialized, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_no_min_btn, bool p_no_max_btn, bool p_minimized, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, bool p_embed_child, DWORD &r_style, DWORD &r_style_ex) {
  1957. // Windows docs for window styles:
  1958. // https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles
  1959. // https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles
  1960. r_style = 0;
  1961. r_style_ex = WS_EX_WINDOWEDGE;
  1962. if (p_main_window) {
  1963. // When embedded, we don't want the window to have WS_EX_APPWINDOW because it will
  1964. // show the embedded process in the taskbar and Alt-Tab.
  1965. if (!p_embed_child) {
  1966. r_style_ex |= WS_EX_APPWINDOW;
  1967. }
  1968. if (p_initialized) {
  1969. r_style |= WS_VISIBLE;
  1970. }
  1971. }
  1972. if (p_embed_child) {
  1973. r_style |= WS_POPUP;
  1974. } else if (p_fullscreen || p_borderless) {
  1975. r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past.
  1976. if (p_minimized) {
  1977. r_style |= WS_MINIMIZE;
  1978. } else if (p_maximized) {
  1979. r_style |= WS_MAXIMIZE;
  1980. }
  1981. if (!p_fullscreen) {
  1982. r_style |= WS_SYSMENU;
  1983. if (!p_no_min_btn) {
  1984. r_style |= WS_MINIMIZEBOX;
  1985. }
  1986. if (!p_no_max_btn) {
  1987. r_style |= WS_MAXIMIZEBOX;
  1988. }
  1989. }
  1990. } else {
  1991. if (p_resizable) {
  1992. if (p_minimized) {
  1993. r_style = WS_OVERLAPPEDWINDOW | WS_MINIMIZE;
  1994. } else if (p_maximized) {
  1995. r_style = WS_OVERLAPPEDWINDOW | WS_MAXIMIZE;
  1996. } else {
  1997. r_style = WS_OVERLAPPEDWINDOW;
  1998. }
  1999. if (p_no_min_btn) {
  2000. r_style &= ~WS_MINIMIZEBOX;
  2001. }
  2002. if (p_no_max_btn) {
  2003. r_style &= ~WS_MAXIMIZEBOX;
  2004. }
  2005. } else {
  2006. if (p_minimized) {
  2007. r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZE;
  2008. } else {
  2009. r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;
  2010. }
  2011. if (!p_no_min_btn) {
  2012. r_style |= WS_MINIMIZEBOX;
  2013. }
  2014. if (!p_no_max_btn) {
  2015. r_style |= WS_MAXIMIZEBOX;
  2016. }
  2017. }
  2018. }
  2019. if (p_no_activate_focus && !p_embed_child) {
  2020. r_style_ex |= WS_EX_TOPMOST | WS_EX_NOACTIVATE;
  2021. }
  2022. if (!p_borderless && !p_no_activate_focus && p_initialized) {
  2023. r_style |= WS_VISIBLE;
  2024. }
  2025. r_style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  2026. r_style_ex |= WS_EX_ACCEPTFILES;
  2027. if (OS::get_singleton()->get_current_rendering_driver_name() == "d3d12") {
  2028. r_style_ex |= WS_EX_NOREDIRECTIONBITMAP;
  2029. }
  2030. }
  2031. void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repaint) {
  2032. _THREAD_SAFE_METHOD_
  2033. ERR_FAIL_COND(!windows.has(p_window));
  2034. WindowData &wd = windows[p_window];
  2035. DWORD style = 0;
  2036. DWORD style_ex = 0;
  2037. _get_window_style(p_window == MAIN_WINDOW_ID, wd.initialized, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.no_min_btn, wd.no_max_btn, wd.minimized, wd.maximized, wd.maximized_fs, wd.no_focus || wd.is_popup, wd.parent_hwnd, style, style_ex);
  2038. SetWindowLongPtr(wd.hWnd, GWL_STYLE, style);
  2039. SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex);
  2040. if (icon.is_valid()) {
  2041. set_icon(icon);
  2042. }
  2043. SetWindowPos(wd.hWnd, _is_always_on_top_recursive(p_window) ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0));
  2044. if (p_repaint) {
  2045. RECT rect;
  2046. GetWindowRect(wd.hWnd, &rect);
  2047. int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0;
  2048. MoveWindow(wd.hWnd, rect.left, rect.top, rect.right - rect.left + off_x, rect.bottom - rect.top, TRUE);
  2049. }
  2050. }
  2051. void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window) {
  2052. _THREAD_SAFE_METHOD_
  2053. ERR_FAIL_COND(!windows.has(p_window));
  2054. WindowData &wd = windows[p_window];
  2055. if (p_mode != WINDOW_MODE_WINDOWED && wd.parent_hwnd) {
  2056. print_line("Embedded window only supports Windowed mode.");
  2057. return;
  2058. }
  2059. bool was_fullscreen = wd.fullscreen;
  2060. wd.was_fullscreen_pre_min = false;
  2061. if (p_mode == WINDOW_MODE_MAXIMIZED && wd.borderless) {
  2062. p_mode = WINDOW_MODE_FULLSCREEN;
  2063. }
  2064. if (wd.fullscreen && p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
  2065. RECT rect;
  2066. wd.fullscreen = false;
  2067. wd.multiwindow_fs = false;
  2068. // Restore previous maximized state.
  2069. wd.maximized = wd.was_maximized_pre_fs;
  2070. _update_window_style(p_window, false);
  2071. // Restore window rect after exiting fullscreen.
  2072. if (wd.pre_fs_valid) {
  2073. rect = wd.pre_fs_rect;
  2074. } else {
  2075. rect.left = 0;
  2076. rect.right = wd.width;
  2077. rect.top = 0;
  2078. rect.bottom = wd.height;
  2079. }
  2080. ShowWindow(wd.hWnd, SW_RESTORE);
  2081. MoveWindow(wd.hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
  2082. if (restore_mouse_trails > 1) {
  2083. SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, nullptr, 0);
  2084. restore_mouse_trails = 0;
  2085. }
  2086. }
  2087. if (p_mode == WINDOW_MODE_WINDOWED) {
  2088. ShowWindow(wd.hWnd, SW_NORMAL);
  2089. wd.maximized = false;
  2090. wd.minimized = false;
  2091. }
  2092. if (p_mode == WINDOW_MODE_MAXIMIZED) {
  2093. ShowWindow(wd.hWnd, SW_MAXIMIZE);
  2094. wd.maximized = true;
  2095. wd.minimized = false;
  2096. }
  2097. if (p_mode == WINDOW_MODE_MINIMIZED) {
  2098. ShowWindow(wd.hWnd, SW_MINIMIZE);
  2099. wd.maximized = false;
  2100. wd.minimized = true;
  2101. wd.was_fullscreen_pre_min = was_fullscreen;
  2102. }
  2103. if (p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
  2104. wd.multiwindow_fs = false;
  2105. } else if (p_mode == WINDOW_MODE_FULLSCREEN) {
  2106. wd.multiwindow_fs = true;
  2107. }
  2108. _update_window_style(p_window, false);
  2109. if ((p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) && !wd.fullscreen) {
  2110. if (wd.minimized || wd.maximized) {
  2111. ShowWindow(wd.hWnd, SW_RESTORE);
  2112. }
  2113. // Save previous maximized stare.
  2114. wd.was_maximized_pre_fs = wd.maximized;
  2115. if (!was_fullscreen) {
  2116. // Save non-fullscreen rect before entering fullscreen.
  2117. GetWindowRect(wd.hWnd, &wd.pre_fs_rect);
  2118. wd.pre_fs_valid = true;
  2119. }
  2120. int cs = window_get_current_screen(p_window);
  2121. Point2 pos = screen_get_position(cs) + _get_screens_origin();
  2122. Size2 size = screen_get_size(cs);
  2123. wd.fullscreen = true;
  2124. wd.maximized = false;
  2125. wd.minimized = false;
  2126. _update_window_style(p_window, false);
  2127. int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0;
  2128. MoveWindow(wd.hWnd, pos.x, pos.y, size.width + off_x, size.height, TRUE);
  2129. // If the user has mouse trails enabled in windows, then sometimes the cursor disappears in fullscreen mode.
  2130. // Save number of trails so we can restore when exiting, then turn off mouse trails
  2131. SystemParametersInfoA(SPI_GETMOUSETRAILS, 0, &restore_mouse_trails, 0);
  2132. if (restore_mouse_trails > 1) {
  2133. SystemParametersInfoA(SPI_SETMOUSETRAILS, 0, nullptr, 0);
  2134. }
  2135. }
  2136. _update_window_mouse_passthrough(p_window);
  2137. }
  2138. DisplayServer::WindowMode DisplayServerWindows::window_get_mode(WindowID p_window) const {
  2139. _THREAD_SAFE_METHOD_
  2140. ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED);
  2141. const WindowData &wd = windows[p_window];
  2142. if (wd.fullscreen) {
  2143. if (wd.multiwindow_fs) {
  2144. return WINDOW_MODE_FULLSCREEN;
  2145. } else {
  2146. return WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
  2147. }
  2148. } else if (wd.minimized) {
  2149. return WINDOW_MODE_MINIMIZED;
  2150. } else if (wd.maximized) {
  2151. return WINDOW_MODE_MAXIMIZED;
  2152. } else {
  2153. return WINDOW_MODE_WINDOWED;
  2154. }
  2155. }
  2156. bool DisplayServerWindows::window_is_maximize_allowed(WindowID p_window) const {
  2157. _THREAD_SAFE_METHOD_
  2158. ERR_FAIL_COND_V(!windows.has(p_window), false);
  2159. const WindowData &wd = windows[p_window];
  2160. const DWORD style = GetWindowLongPtr(wd.hWnd, GWL_STYLE);
  2161. return (style & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX;
  2162. }
  2163. void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
  2164. _THREAD_SAFE_METHOD_
  2165. ERR_FAIL_COND(!windows.has(p_window));
  2166. WindowData &wd = windows[p_window];
  2167. switch (p_flag) {
  2168. case WINDOW_FLAG_MINIMIZE_DISABLED: {
  2169. wd.no_min_btn = p_enabled;
  2170. _update_window_style(p_window);
  2171. } break;
  2172. case WINDOW_FLAG_MAXIMIZE_DISABLED: {
  2173. wd.no_max_btn = p_enabled;
  2174. _update_window_style(p_window);
  2175. } break;
  2176. case WINDOW_FLAG_RESIZE_DISABLED: {
  2177. if (p_enabled && wd.parent_hwnd) {
  2178. print_line("Embedded window resize can't be disabled.");
  2179. return;
  2180. }
  2181. wd.resizable = !p_enabled;
  2182. _update_window_style(p_window);
  2183. } break;
  2184. case WINDOW_FLAG_BORDERLESS: {
  2185. wd.borderless = p_enabled;
  2186. _update_window_mouse_passthrough(p_window);
  2187. _update_window_style(p_window);
  2188. ShowWindow(wd.hWnd, (wd.no_focus || wd.is_popup) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window.
  2189. } break;
  2190. case WINDOW_FLAG_ALWAYS_ON_TOP: {
  2191. ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID && p_enabled, "Transient windows can't become on top.");
  2192. if (p_enabled && wd.parent_hwnd) {
  2193. print_line("Embedded window can't become on top.");
  2194. return;
  2195. }
  2196. wd.always_on_top = p_enabled;
  2197. _update_window_style(p_window);
  2198. } break;
  2199. case WINDOW_FLAG_SHARP_CORNERS: {
  2200. wd.sharp_corners = p_enabled;
  2201. DWORD value = wd.sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT;
  2202. ::DwmSetWindowAttribute(wd.hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value));
  2203. _update_window_style(p_window);
  2204. } break;
  2205. case WINDOW_FLAG_TRANSPARENT: {
  2206. if (p_enabled) {
  2207. // Enable per-pixel alpha.
  2208. if (OS::get_singleton()->is_layered_allowed()) {
  2209. DWM_BLURBEHIND bb;
  2210. ZeroMemory(&bb, sizeof(bb));
  2211. HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
  2212. bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
  2213. bb.hRgnBlur = hRgn;
  2214. bb.fEnable = TRUE;
  2215. DwmEnableBlurBehindWindow(wd.hWnd, &bb);
  2216. }
  2217. wd.layered_window = true;
  2218. } else {
  2219. // Disable per-pixel alpha.
  2220. wd.layered_window = false;
  2221. if (OS::get_singleton()->is_layered_allowed()) {
  2222. DWM_BLURBEHIND bb;
  2223. ZeroMemory(&bb, sizeof(bb));
  2224. HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
  2225. bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
  2226. bb.hRgnBlur = hRgn;
  2227. bb.fEnable = FALSE;
  2228. DwmEnableBlurBehindWindow(wd.hWnd, &bb);
  2229. }
  2230. }
  2231. } break;
  2232. case WINDOW_FLAG_NO_FOCUS: {
  2233. wd.no_focus = p_enabled;
  2234. _update_window_style(p_window);
  2235. } break;
  2236. case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
  2237. wd.mpass = p_enabled;
  2238. } break;
  2239. case WINDOW_FLAG_EXCLUDE_FROM_CAPTURE: {
  2240. wd.hide_from_capture = p_enabled;
  2241. if (p_enabled) {
  2242. if (os_ver.dwBuildNumber >= 19041) {
  2243. SetWindowDisplayAffinity(wd.hWnd, WDA_EXCLUDEFROMCAPTURE);
  2244. } else {
  2245. SetWindowDisplayAffinity(wd.hWnd, WDA_MONITOR);
  2246. }
  2247. } else {
  2248. SetWindowDisplayAffinity(wd.hWnd, WDA_NONE);
  2249. }
  2250. } break;
  2251. case WINDOW_FLAG_POPUP: {
  2252. ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup.");
  2253. ERR_FAIL_COND_MSG(IsWindowVisible(wd.hWnd) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened.");
  2254. if (p_enabled && wd.parent_hwnd) {
  2255. print_line("Embedded window can't be popup.");
  2256. return;
  2257. }
  2258. wd.is_popup = p_enabled;
  2259. } break;
  2260. default:
  2261. break;
  2262. }
  2263. }
  2264. bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window) const {
  2265. _THREAD_SAFE_METHOD_
  2266. ERR_FAIL_COND_V(!windows.has(p_window), false);
  2267. const WindowData &wd = windows[p_window];
  2268. switch (p_flag) {
  2269. case WINDOW_FLAG_MAXIMIZE_DISABLED: {
  2270. return wd.no_max_btn;
  2271. } break;
  2272. case WINDOW_FLAG_MINIMIZE_DISABLED: {
  2273. return wd.no_min_btn;
  2274. } break;
  2275. case WINDOW_FLAG_RESIZE_DISABLED: {
  2276. return !wd.resizable;
  2277. } break;
  2278. case WINDOW_FLAG_BORDERLESS: {
  2279. return wd.borderless;
  2280. } break;
  2281. case WINDOW_FLAG_ALWAYS_ON_TOP: {
  2282. return wd.always_on_top;
  2283. } break;
  2284. case WINDOW_FLAG_SHARP_CORNERS: {
  2285. return wd.sharp_corners;
  2286. } break;
  2287. case WINDOW_FLAG_TRANSPARENT: {
  2288. return wd.layered_window;
  2289. } break;
  2290. case WINDOW_FLAG_NO_FOCUS: {
  2291. return wd.no_focus;
  2292. } break;
  2293. case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
  2294. return wd.mpass;
  2295. } break;
  2296. case WINDOW_FLAG_EXCLUDE_FROM_CAPTURE: {
  2297. return wd.hide_from_capture;
  2298. } break;
  2299. case WINDOW_FLAG_POPUP: {
  2300. return wd.is_popup;
  2301. } break;
  2302. default:
  2303. break;
  2304. }
  2305. return false;
  2306. }
  2307. void DisplayServerWindows::window_request_attention(WindowID p_window) {
  2308. _THREAD_SAFE_METHOD_
  2309. ERR_FAIL_COND(!windows.has(p_window));
  2310. const WindowData &wd = windows[p_window];
  2311. FLASHWINFO info;
  2312. info.cbSize = sizeof(FLASHWINFO);
  2313. info.hwnd = wd.hWnd;
  2314. info.dwFlags = FLASHW_ALL;
  2315. info.dwTimeout = 0;
  2316. info.uCount = 2;
  2317. FlashWindowEx(&info);
  2318. }
  2319. void DisplayServerWindows::window_move_to_foreground(WindowID p_window) {
  2320. _THREAD_SAFE_METHOD_
  2321. ERR_FAIL_COND(!windows.has(p_window));
  2322. WindowData &wd = windows[p_window];
  2323. if (!wd.no_focus && !wd.is_popup) {
  2324. SetForegroundWindow(wd.hWnd);
  2325. }
  2326. }
  2327. bool DisplayServerWindows::window_is_focused(WindowID p_window) const {
  2328. _THREAD_SAFE_METHOD_
  2329. ERR_FAIL_COND_V(!windows.has(p_window), false);
  2330. const WindowData &wd = windows[p_window];
  2331. return wd.window_focused;
  2332. }
  2333. DisplayServerWindows::WindowID DisplayServerWindows::get_focused_window() const {
  2334. return last_focused_window;
  2335. }
  2336. bool DisplayServerWindows::window_can_draw(WindowID p_window) const {
  2337. _THREAD_SAFE_METHOD_
  2338. ERR_FAIL_COND_V(!windows.has(p_window), false);
  2339. const WindowData &wd = windows[p_window];
  2340. return !wd.minimized;
  2341. }
  2342. bool DisplayServerWindows::can_any_window_draw() const {
  2343. _THREAD_SAFE_METHOD_
  2344. for (const KeyValue<WindowID, WindowData> &E : windows) {
  2345. if (!E.value.minimized) {
  2346. return true;
  2347. }
  2348. }
  2349. return false;
  2350. }
  2351. int DisplayServerWindows::accessibility_should_increase_contrast() const {
  2352. HIGHCONTRASTA hc;
  2353. hc.cbSize = sizeof(HIGHCONTRAST);
  2354. if (!SystemParametersInfoA(SPI_GETHIGHCONTRAST, sizeof(HIGHCONTRAST), &hc, 0)) {
  2355. return -1;
  2356. }
  2357. return (hc.dwFlags & HCF_HIGHCONTRASTON);
  2358. }
  2359. int DisplayServerWindows::accessibility_should_reduce_animation() const {
  2360. BOOL anim_enabled = false; // Note: this should be BOOL (WinAPI), not bool (C++), since SystemParametersInfoA expect variable with specific size.
  2361. if (!SystemParametersInfoA(SPI_GETCLIENTAREAANIMATION, 0, &anim_enabled, 0)) {
  2362. return -1;
  2363. }
  2364. return (!anim_enabled);
  2365. }
  2366. int DisplayServerWindows::accessibility_should_reduce_transparency() const {
  2367. BOOL tr_enabled = false; // Note: this should be BOOL (WinAPI), not bool (C++), since SystemParametersInfoA expect variable with specific size.
  2368. if (!SystemParametersInfoA(SPI_GETDISABLEOVERLAPPEDCONTENT, 0, &tr_enabled, 0)) {
  2369. return -1;
  2370. }
  2371. return tr_enabled;
  2372. }
  2373. int DisplayServerWindows::accessibility_screen_reader_active() const {
  2374. BOOL sr_enabled = false; // Note: this should be BOOL (WinAPI), not bool (C++), since SystemParametersInfoA expect variable with specific size.
  2375. if (SystemParametersInfoA(SPI_GETSCREENREADER, 0, &sr_enabled, 0) && sr_enabled) {
  2376. return true;
  2377. }
  2378. static const WCHAR *narrator_mutex_name = L"NarratorRunning";
  2379. HANDLE narrator_mutex = OpenMutexW(MUTEX_ALL_ACCESS, false, narrator_mutex_name);
  2380. if (narrator_mutex) {
  2381. CloseHandle(narrator_mutex);
  2382. return true;
  2383. }
  2384. return false;
  2385. }
  2386. Vector2i DisplayServerWindows::ime_get_selection() const {
  2387. _THREAD_SAFE_METHOD_
  2388. DisplayServer::WindowID window_id = _get_focused_window_or_popup();
  2389. const WindowData &wd = windows[window_id];
  2390. if (!wd.ime_active) {
  2391. return Vector2i();
  2392. }
  2393. int cursor = ImmGetCompositionStringW(wd.im_himc, GCS_CURSORPOS, nullptr, 0);
  2394. int32_t length = ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, nullptr, 0);
  2395. wchar_t *string = reinterpret_cast<wchar_t *>(memalloc(length));
  2396. ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, string, length);
  2397. int32_t utf32_cursor = 0;
  2398. for (int32_t i = 0; i < length / int32_t(sizeof(wchar_t)); i++) {
  2399. if ((string[i] & 0xfffffc00) == 0xd800) {
  2400. i++;
  2401. }
  2402. if (i < cursor) {
  2403. utf32_cursor++;
  2404. } else {
  2405. break;
  2406. }
  2407. }
  2408. memdelete(string);
  2409. return Vector2i(utf32_cursor, 0);
  2410. }
  2411. String DisplayServerWindows::ime_get_text() const {
  2412. _THREAD_SAFE_METHOD_
  2413. DisplayServer::WindowID window_id = _get_focused_window_or_popup();
  2414. const WindowData &wd = windows[window_id];
  2415. if (!wd.ime_active) {
  2416. return String();
  2417. }
  2418. String ret;
  2419. int32_t length = ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, nullptr, 0);
  2420. wchar_t *string = reinterpret_cast<wchar_t *>(memalloc(length));
  2421. ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, string, length);
  2422. ret.append_utf16((char16_t *)string, length / sizeof(wchar_t));
  2423. memdelete(string);
  2424. return ret;
  2425. }
  2426. void DisplayServerWindows::window_set_ime_active(const bool p_active, WindowID p_window) {
  2427. _THREAD_SAFE_METHOD_
  2428. ERR_FAIL_COND(!windows.has(p_window));
  2429. WindowData &wd = windows[p_window];
  2430. if (p_active) {
  2431. wd.ime_active = true;
  2432. ImmAssociateContext(wd.hWnd, wd.im_himc);
  2433. CreateCaret(wd.hWnd, nullptr, 1, 1);
  2434. window_set_ime_position(wd.im_position, p_window);
  2435. } else {
  2436. ImmAssociateContext(wd.hWnd, (HIMC) nullptr);
  2437. DestroyCaret();
  2438. wd.ime_active = false;
  2439. }
  2440. }
  2441. void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowID p_window) {
  2442. _THREAD_SAFE_METHOD_
  2443. ERR_FAIL_COND(!windows.has(p_window));
  2444. WindowData &wd = windows[p_window];
  2445. wd.im_position = p_pos;
  2446. HIMC himc = ImmGetContext(wd.hWnd);
  2447. if (himc == (HIMC) nullptr) {
  2448. return;
  2449. }
  2450. COMPOSITIONFORM cps;
  2451. cps.dwStyle = CFS_POINT;
  2452. cps.ptCurrentPos.x = wd.im_position.x;
  2453. cps.ptCurrentPos.y = wd.im_position.y;
  2454. ImmSetCompositionWindow(himc, &cps);
  2455. ImmReleaseContext(wd.hWnd, himc);
  2456. }
  2457. void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) {
  2458. _THREAD_SAFE_METHOD_
  2459. ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
  2460. if (cursor_shape == p_shape) {
  2461. return;
  2462. }
  2463. if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) {
  2464. cursor_shape = p_shape;
  2465. return;
  2466. }
  2467. static const LPCTSTR win_cursors[CURSOR_MAX] = {
  2468. IDC_ARROW,
  2469. IDC_IBEAM,
  2470. IDC_HAND, // Finger.
  2471. IDC_CROSS,
  2472. IDC_WAIT,
  2473. IDC_APPSTARTING,
  2474. IDC_SIZEALL,
  2475. IDC_ARROW,
  2476. IDC_NO,
  2477. IDC_SIZENS,
  2478. IDC_SIZEWE,
  2479. IDC_SIZENESW,
  2480. IDC_SIZENWSE,
  2481. IDC_SIZEALL,
  2482. IDC_SIZENS,
  2483. IDC_SIZEWE,
  2484. IDC_HELP
  2485. };
  2486. if (cursors_cache.has(p_shape)) {
  2487. SetCursor(cursors[p_shape]);
  2488. } else {
  2489. SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
  2490. }
  2491. cursor_shape = p_shape;
  2492. }
  2493. DisplayServer::CursorShape DisplayServerWindows::cursor_get_shape() const {
  2494. return cursor_shape;
  2495. }
  2496. void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
  2497. _THREAD_SAFE_METHOD_
  2498. ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
  2499. if (p_cursor.is_valid()) {
  2500. RBMap<CursorShape, Vector<Variant>>::Element *cursor_c = cursors_cache.find(p_shape);
  2501. if (cursor_c) {
  2502. if (cursor_c->get()[0] == p_cursor && cursor_c->get()[1] == p_hotspot) {
  2503. cursor_set_shape(p_shape);
  2504. return;
  2505. }
  2506. cursors_cache.erase(p_shape);
  2507. }
  2508. Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
  2509. ERR_FAIL_COND(image.is_null());
  2510. Vector2i texture_size = image->get_size();
  2511. UINT image_size = texture_size.width * texture_size.height;
  2512. // Create the BITMAP with alpha channel.
  2513. COLORREF *buffer = nullptr;
  2514. BITMAPV5HEADER bi;
  2515. ZeroMemory(&bi, sizeof(bi));
  2516. bi.bV5Size = sizeof(bi);
  2517. bi.bV5Width = texture_size.width;
  2518. bi.bV5Height = -texture_size.height;
  2519. bi.bV5Planes = 1;
  2520. bi.bV5BitCount = 32;
  2521. bi.bV5Compression = BI_BITFIELDS;
  2522. bi.bV5RedMask = 0x00ff0000;
  2523. bi.bV5GreenMask = 0x0000ff00;
  2524. bi.bV5BlueMask = 0x000000ff;
  2525. bi.bV5AlphaMask = 0xff000000;
  2526. HDC dc = GetDC(nullptr);
  2527. HBITMAP bitmap = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO *>(&bi), DIB_RGB_COLORS, reinterpret_cast<void **>(&buffer), nullptr, 0);
  2528. HBITMAP mask = CreateBitmap(texture_size.width, texture_size.height, 1, 1, nullptr);
  2529. bool fully_transparent = true;
  2530. for (UINT index = 0; index < image_size; index++) {
  2531. int row_index = std::floor(index / texture_size.width);
  2532. int column_index = index % int(texture_size.width);
  2533. const Color &c = image->get_pixel(column_index, row_index);
  2534. fully_transparent = fully_transparent && (c.a == 0.f);
  2535. *(buffer + index) = c.to_argb32();
  2536. }
  2537. // Finally, create the icon.
  2538. if (cursors[p_shape]) {
  2539. DestroyIcon(cursors[p_shape]);
  2540. }
  2541. if (fully_transparent) {
  2542. cursors[p_shape] = nullptr;
  2543. } else {
  2544. ICONINFO iconinfo;
  2545. iconinfo.fIcon = FALSE;
  2546. iconinfo.xHotspot = p_hotspot.x;
  2547. iconinfo.yHotspot = p_hotspot.y;
  2548. iconinfo.hbmMask = mask;
  2549. iconinfo.hbmColor = bitmap;
  2550. cursors[p_shape] = CreateIconIndirect(&iconinfo);
  2551. }
  2552. Vector<Variant> params;
  2553. params.push_back(p_cursor);
  2554. params.push_back(p_hotspot);
  2555. cursors_cache.insert(p_shape, params);
  2556. if (p_shape == cursor_shape) {
  2557. if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
  2558. SetCursor(cursors[p_shape]);
  2559. }
  2560. }
  2561. DeleteObject(mask);
  2562. DeleteObject(bitmap);
  2563. ReleaseDC(nullptr, dc);
  2564. } else {
  2565. // Reset to default system cursor.
  2566. if (cursors[p_shape]) {
  2567. DestroyIcon(cursors[p_shape]);
  2568. }
  2569. cursors[p_shape] = nullptr;
  2570. cursors_cache.erase(p_shape);
  2571. CursorShape c = cursor_shape;
  2572. cursor_shape = CURSOR_MAX;
  2573. cursor_set_shape(c);
  2574. }
  2575. }
  2576. bool DisplayServerWindows::get_swap_cancel_ok() {
  2577. return true;
  2578. }
  2579. void DisplayServerWindows::enable_for_stealing_focus(OS::ProcessID pid) {
  2580. _THREAD_SAFE_METHOD_
  2581. AllowSetForegroundWindow(pid);
  2582. }
  2583. struct WindowEnumData {
  2584. DWORD process_id;
  2585. HWND parent_hWnd;
  2586. HWND hWnd;
  2587. };
  2588. static BOOL CALLBACK _enum_proc_find_window_from_process_id_callback(HWND hWnd, LPARAM lParam) {
  2589. WindowEnumData &ed = *(WindowEnumData *)lParam;
  2590. DWORD process_id = 0x0;
  2591. GetWindowThreadProcessId(hWnd, &process_id);
  2592. if (ed.process_id == process_id) {
  2593. if (GetParent(hWnd) != ed.parent_hWnd) {
  2594. return TRUE;
  2595. }
  2596. // Found it.
  2597. ed.hWnd = hWnd;
  2598. SetLastError(ERROR_SUCCESS);
  2599. return FALSE;
  2600. }
  2601. // Continue enumeration.
  2602. return TRUE;
  2603. }
  2604. HWND DisplayServerWindows::_find_window_from_process_id(OS::ProcessID p_pid, HWND p_current_hwnd) {
  2605. DWORD pid = p_pid;
  2606. WindowEnumData ed = { pid, p_current_hwnd, NULL };
  2607. // First, check our own child, maybe it's already embedded.
  2608. if (!EnumChildWindows(p_current_hwnd, _enum_proc_find_window_from_process_id_callback, (LPARAM)&ed) && (GetLastError() == ERROR_SUCCESS)) {
  2609. if (ed.hWnd) {
  2610. return ed.hWnd;
  2611. }
  2612. }
  2613. // Then check all the opened windows on the computer.
  2614. if (!EnumWindows(_enum_proc_find_window_from_process_id_callback, (LPARAM)&ed) && (GetLastError() == ERROR_SUCCESS)) {
  2615. return ed.hWnd;
  2616. }
  2617. return NULL;
  2618. }
  2619. Error DisplayServerWindows::embed_process(WindowID p_window, OS::ProcessID p_pid, const Rect2i &p_rect, bool p_visible, bool p_grab_focus) {
  2620. _THREAD_SAFE_METHOD_
  2621. ERR_FAIL_COND_V(!windows.has(p_window), FAILED);
  2622. const WindowData &wd = windows[p_window];
  2623. EmbeddedProcessData *ep = nullptr;
  2624. if (embedded_processes.has(p_pid)) {
  2625. ep = embedded_processes.get(p_pid);
  2626. } else {
  2627. // New process, trying to find the window.
  2628. HWND handle_to_embed = _find_window_from_process_id(p_pid, wd.hWnd);
  2629. if (!handle_to_embed) {
  2630. return ERR_DOES_NOT_EXIST;
  2631. }
  2632. const DWORD style = GetWindowLongPtr(handle_to_embed, GWL_STYLE);
  2633. ep = memnew(EmbeddedProcessData);
  2634. ep->window_handle = handle_to_embed;
  2635. ep->parent_window_handle = wd.hWnd;
  2636. ep->is_visible = (style & WS_VISIBLE) == WS_VISIBLE;
  2637. embedded_processes.insert(p_pid, ep);
  2638. }
  2639. if (p_rect.size.x <= 100 || p_rect.size.y <= 100) {
  2640. p_visible = false;
  2641. }
  2642. // In Godot, the window position is offset by the screen's origin coordinates.
  2643. // We need to adjust for this when a screen is positioned in the negative space
  2644. // (e.g., a screen to the left of the main screen).
  2645. const Rect2i adjusted_rect = Rect2i(p_rect.position + _get_screens_origin(), p_rect.size);
  2646. // Use HWND_BOTTOM to prevent reordering of the embedded window over another popup.
  2647. SetWindowPos(ep->window_handle, HWND_BOTTOM, adjusted_rect.position.x, adjusted_rect.position.y, adjusted_rect.size.x, adjusted_rect.size.y, SWP_NOZORDER | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
  2648. if (ep->is_visible != p_visible) {
  2649. if (p_visible) {
  2650. ShowWindow(ep->window_handle, SW_SHOWNA);
  2651. } else {
  2652. ShowWindow(ep->window_handle, SW_HIDE);
  2653. }
  2654. ep->is_visible = p_visible;
  2655. }
  2656. if (p_grab_focus) {
  2657. SetForegroundWindow(ep->window_handle);
  2658. SetFocus(ep->window_handle);
  2659. }
  2660. return OK;
  2661. }
  2662. Error DisplayServerWindows::request_close_embedded_process(OS::ProcessID p_pid) {
  2663. _THREAD_SAFE_METHOD_
  2664. if (!embedded_processes.has(p_pid)) {
  2665. return ERR_DOES_NOT_EXIST;
  2666. }
  2667. EmbeddedProcessData *ep = embedded_processes.get(p_pid);
  2668. // Send a close message to gracefully close the process.
  2669. PostMessage(ep->window_handle, WM_CLOSE, 0, 0);
  2670. return OK;
  2671. }
  2672. Error DisplayServerWindows::remove_embedded_process(OS::ProcessID p_pid) {
  2673. _THREAD_SAFE_METHOD_
  2674. if (!embedded_processes.has(p_pid)) {
  2675. return ERR_DOES_NOT_EXIST;
  2676. }
  2677. EmbeddedProcessData *ep = embedded_processes.get(p_pid);
  2678. request_close_embedded_process(p_pid);
  2679. // This is a workaround to ensure the parent window correctly regains focus after the
  2680. // embedded window is closed. When the embedded window is closed while it has focus,
  2681. // the parent window (the editor) does not become active. It appears focused but is not truly activated.
  2682. // Opening a new window and closing it forces Windows to set the focus and activation correctly.
  2683. DWORD style = WS_POPUP | WS_VISIBLE;
  2684. DWORD style_ex = WS_EX_TOPMOST;
  2685. WNDCLASSW wcTemp = {};
  2686. wcTemp.lpfnWndProc = DefWindowProcW;
  2687. wcTemp.hInstance = GetModuleHandle(nullptr);
  2688. wcTemp.lpszClassName = L"Engine temp window";
  2689. RegisterClassW(&wcTemp);
  2690. HWND hWnd = CreateWindowExW(
  2691. style_ex,
  2692. L"Engine temp window", L"",
  2693. style,
  2694. 0,
  2695. 0,
  2696. 1,
  2697. 1,
  2698. ep->parent_window_handle,
  2699. nullptr,
  2700. GetModuleHandle(nullptr),
  2701. nullptr);
  2702. SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
  2703. DestroyWindow(hWnd);
  2704. UnregisterClassW(L"Engine temp window", GetModuleHandle(nullptr));
  2705. SetForegroundWindow(ep->parent_window_handle);
  2706. embedded_processes.erase(p_pid);
  2707. memdelete(ep);
  2708. return OK;
  2709. }
  2710. OS::ProcessID DisplayServerWindows::get_focused_process_id() {
  2711. HWND hwnd = GetForegroundWindow();
  2712. if (!hwnd) {
  2713. return 0;
  2714. }
  2715. // Get the process ID of the window.
  2716. DWORD processID;
  2717. GetWindowThreadProcessId(hwnd, &processID);
  2718. return processID;
  2719. }
  2720. static HRESULT CALLBACK win32_task_dialog_callback(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData) {
  2721. if (msg == TDN_CREATED) {
  2722. // To match the input text dialog.
  2723. SendMessageW(hwnd, WM_SETICON, ICON_BIG, 0);
  2724. SendMessageW(hwnd, WM_SETICON, ICON_SMALL, 0);
  2725. }
  2726. return 0;
  2727. }
  2728. Error DisplayServerWindows::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) {
  2729. _THREAD_SAFE_METHOD_
  2730. TASKDIALOGCONFIG config;
  2731. ZeroMemory(&config, sizeof(TASKDIALOGCONFIG));
  2732. config.cbSize = sizeof(TASKDIALOGCONFIG);
  2733. Char16String title = p_title.utf16();
  2734. Char16String message = p_description.utf16();
  2735. LocalVector<Char16String> buttons;
  2736. for (String s : p_buttons) {
  2737. buttons.push_back(s.utf16());
  2738. }
  2739. WindowID window_id = _get_focused_window_or_popup();
  2740. if (!windows.has(window_id)) {
  2741. window_id = MAIN_WINDOW_ID;
  2742. }
  2743. config.pszWindowTitle = (LPCWSTR)(title.get_data());
  2744. config.pszContent = (LPCWSTR)(message.get_data());
  2745. config.hwndParent = windows[window_id].hWnd;
  2746. const int button_count = buttons.size();
  2747. config.cButtons = button_count;
  2748. // No dynamic stack array size :(
  2749. TASKDIALOG_BUTTON *tbuttons = button_count != 0 ? (TASKDIALOG_BUTTON *)alloca(sizeof(TASKDIALOG_BUTTON) * button_count) : nullptr;
  2750. if (tbuttons) {
  2751. for (int i = 0; i < button_count; i++) {
  2752. tbuttons[i].nButtonID = i + 100;
  2753. tbuttons[i].pszButtonText = (LPCWSTR)(buttons[i].get_data());
  2754. }
  2755. }
  2756. config.pButtons = tbuttons;
  2757. config.pfCallback = win32_task_dialog_callback;
  2758. Error result = FAILED;
  2759. HMODULE comctl = LoadLibraryW(L"comctl32.dll");
  2760. if (comctl) {
  2761. typedef HRESULT(WINAPI * TaskDialogIndirectPtr)(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton, int *pnRadioButton, BOOL *pfVerificationFlagChecked);
  2762. TaskDialogIndirectPtr task_dialog_indirect = (TaskDialogIndirectPtr)(void *)GetProcAddress(comctl, "TaskDialogIndirect");
  2763. int button_pressed;
  2764. if (task_dialog_indirect && SUCCEEDED(task_dialog_indirect(&config, &button_pressed, nullptr, nullptr))) {
  2765. if (p_callback.is_valid()) {
  2766. Variant button = button_pressed - 100;
  2767. const Variant *args[1] = { &button };
  2768. Variant ret;
  2769. Callable::CallError ce;
  2770. p_callback.callp(args, 1, ret, ce);
  2771. if (ce.error != Callable::CallError::CALL_OK) {
  2772. ERR_PRINT(vformat("Failed to execute dialog callback: %s.", Variant::get_callable_error_text(p_callback, args, 1, ce)));
  2773. }
  2774. }
  2775. result = OK;
  2776. }
  2777. FreeLibrary(comctl);
  2778. } else {
  2779. ERR_PRINT("Unable to create native dialog.");
  2780. }
  2781. return result;
  2782. }
  2783. struct Win32InputTextDialogInit {
  2784. const char16_t *title;
  2785. const char16_t *description;
  2786. const char16_t *partial;
  2787. const Callable &callback;
  2788. };
  2789. static int scale_with_dpi(int p_pos, int p_dpi) {
  2790. return IsProcessDPIAware() ? (p_pos * p_dpi / 96) : p_pos;
  2791. }
  2792. static INT_PTR input_text_dialog_init(HWND hWnd, UINT code, WPARAM wParam, LPARAM lParam) {
  2793. Win32InputTextDialogInit init = *(Win32InputTextDialogInit *)lParam;
  2794. SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)&init.callback); // Set dialog callback.
  2795. SetWindowTextW(hWnd, (LPCWSTR)init.title);
  2796. const int dpi = DisplayServerWindows::get_singleton()->screen_get_dpi();
  2797. const int margin = scale_with_dpi(7, dpi);
  2798. const SIZE dlg_size = { scale_with_dpi(300, dpi), scale_with_dpi(50, dpi) };
  2799. int str_len = lstrlenW((LPCWSTR)init.description);
  2800. SIZE str_size = { dlg_size.cx, 0 };
  2801. if (str_len > 0) {
  2802. HDC hdc = GetDC(nullptr);
  2803. RECT trect = { margin, margin, margin + dlg_size.cx, margin + dlg_size.cy };
  2804. SelectObject(hdc, (HFONT)SendMessageW(hWnd, WM_GETFONT, 0, 0));
  2805. // `+ margin` adds some space between the static text and the edit field.
  2806. // Don't scale this with DPI because DPI is already handled by DrawText.
  2807. str_size.cy = DrawTextW(hdc, (LPCWSTR)init.description, str_len, &trect, DT_LEFT | DT_WORDBREAK | DT_CALCRECT) + margin;
  2808. ReleaseDC(nullptr, hdc);
  2809. }
  2810. RECT crect, wrect;
  2811. GetClientRect(hWnd, &crect);
  2812. GetWindowRect(hWnd, &wrect);
  2813. int sw = GetSystemMetrics(SM_CXSCREEN);
  2814. int sh = GetSystemMetrics(SM_CYSCREEN);
  2815. int new_width = dlg_size.cx + margin * 2 + wrect.right - wrect.left - crect.right;
  2816. int new_height = dlg_size.cy + margin * 2 + wrect.bottom - wrect.top - crect.bottom + str_size.cy;
  2817. MoveWindow(hWnd, (sw - new_width) / 2, (sh - new_height) / 2, new_width, new_height, true);
  2818. HWND ok_button = GetDlgItem(hWnd, 1);
  2819. MoveWindow(ok_button,
  2820. dlg_size.cx + margin - scale_with_dpi(65, dpi),
  2821. dlg_size.cy + str_size.cy + margin - scale_with_dpi(20, dpi),
  2822. scale_with_dpi(65, dpi), scale_with_dpi(20, dpi), true);
  2823. HWND description = GetDlgItem(hWnd, 3);
  2824. MoveWindow(description, margin, margin, dlg_size.cx, str_size.cy, true);
  2825. SetWindowTextW(description, (LPCWSTR)init.description);
  2826. HWND text_edit = GetDlgItem(hWnd, 2);
  2827. MoveWindow(text_edit, margin, str_size.cy + margin, dlg_size.cx, scale_with_dpi(20, dpi), true);
  2828. SetWindowTextW(text_edit, (LPCWSTR)init.partial);
  2829. return TRUE;
  2830. }
  2831. static INT_PTR input_text_dialog_cmd_proc(HWND hWnd, UINT code, WPARAM wParam, LPARAM lParam) {
  2832. if (LOWORD(wParam) == 1) {
  2833. HWND text_edit = GetDlgItem(hWnd, 2);
  2834. ERR_FAIL_NULL_V(text_edit, false);
  2835. Char16String text;
  2836. text.resize(GetWindowTextLengthW(text_edit) + 1);
  2837. GetWindowTextW(text_edit, (LPWSTR)text.get_data(), text.size());
  2838. const Callable *callback = (const Callable *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
  2839. if (callback && callback->is_valid()) {
  2840. Variant v_result = String((const wchar_t *)text.get_data());
  2841. Variant ret;
  2842. Callable::CallError ce;
  2843. const Variant *args[1] = { &v_result };
  2844. callback->callp(args, 1, ret, ce);
  2845. if (ce.error != Callable::CallError::CALL_OK) {
  2846. ERR_PRINT(vformat("Failed to execute input dialog callback: %s.", Variant::get_callable_error_text(*callback, args, 1, ce)));
  2847. }
  2848. }
  2849. return EndDialog(hWnd, 0);
  2850. }
  2851. return false;
  2852. }
  2853. static INT_PTR CALLBACK input_text_dialog_proc(HWND hWnd, UINT code, WPARAM wParam, LPARAM lParam) {
  2854. switch (code) {
  2855. case WM_INITDIALOG:
  2856. return input_text_dialog_init(hWnd, code, wParam, lParam);
  2857. case WM_COMMAND:
  2858. return input_text_dialog_cmd_proc(hWnd, code, wParam, lParam);
  2859. default:
  2860. return FALSE;
  2861. }
  2862. }
  2863. Error DisplayServerWindows::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) {
  2864. #pragma pack(push, 1)
  2865. // NOTE: Use default/placeholder coordinates here. Windows uses its own coordinate system
  2866. // specifically for dialogs which relies on font sizes instead of pixels.
  2867. const struct {
  2868. WORD dlgVer; // must be 1
  2869. WORD signature; // must be 0xFFFF
  2870. DWORD helpID;
  2871. DWORD exStyle;
  2872. DWORD style;
  2873. WORD cDlgItems;
  2874. short x;
  2875. short y;
  2876. short cx;
  2877. short cy;
  2878. WCHAR menu[1]; // must be 0
  2879. WCHAR windowClass[7]; // must be "#32770" -- the default window class for dialogs
  2880. WCHAR title[1]; // must be 0
  2881. WORD pointsize;
  2882. WORD weight;
  2883. BYTE italic;
  2884. BYTE charset;
  2885. WCHAR font[13]; // must be "MS Shell Dlg"
  2886. } template_base = {
  2887. 1, 0xFFFF, 0, 0,
  2888. DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION,
  2889. 3, 0, 0, 20, 20, L"", L"#32770", L"", 8, FW_NORMAL, 0, DEFAULT_CHARSET, L"MS Shell Dlg"
  2890. };
  2891. const struct {
  2892. DWORD helpID;
  2893. DWORD exStyle;
  2894. DWORD style;
  2895. short x;
  2896. short y;
  2897. short cx;
  2898. short cy;
  2899. DWORD id;
  2900. WCHAR windowClass[7]; // must be "Button"
  2901. WCHAR title[3]; // must be "OK"
  2902. WORD extraCount;
  2903. } ok_button = {
  2904. 0, 0, WS_VISIBLE | BS_DEFPUSHBUTTON, 0, 0, 50, 14, 1, WC_BUTTONW, L"OK", 0
  2905. };
  2906. const struct {
  2907. DWORD helpID;
  2908. DWORD exStyle;
  2909. DWORD style;
  2910. short x;
  2911. short y;
  2912. short cx;
  2913. short cy;
  2914. DWORD id;
  2915. WCHAR windowClass[5]; // must be "Edit"
  2916. WCHAR title[1]; // must be 0
  2917. WORD extraCount;
  2918. } text_field = {
  2919. 0, 0, WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 0, 0, 250, 14, 2, WC_EDITW, L"", 0
  2920. };
  2921. const struct {
  2922. DWORD helpID;
  2923. DWORD exStyle;
  2924. DWORD style;
  2925. short x;
  2926. short y;
  2927. short cx;
  2928. short cy;
  2929. DWORD id;
  2930. WCHAR windowClass[7]; // must be "Static"
  2931. WCHAR title[1]; // must be 0
  2932. WORD extraCount;
  2933. } static_text = {
  2934. 0, 0, WS_VISIBLE, 0, 0, 250, 14, 3, WC_STATICW, L"", 0
  2935. };
  2936. #pragma pack(pop)
  2937. // Dialog template
  2938. const size_t data_size = sizeof(template_base) + (sizeof(template_base) % 4) +
  2939. sizeof(ok_button) + (sizeof(ok_button) % 4) +
  2940. sizeof(text_field) + (sizeof(text_field) % 4) +
  2941. sizeof(static_text) + (sizeof(static_text) % 4);
  2942. void *data_template = memalloc(data_size);
  2943. ERR_FAIL_NULL_V_MSG(data_template, FAILED, "Unable to allocate memory for the dialog template.");
  2944. ZeroMemory(data_template, data_size);
  2945. char *current_block = (char *)data_template;
  2946. CopyMemory(current_block, &template_base, sizeof(template_base));
  2947. current_block += sizeof(template_base) + (sizeof(template_base) % 4);
  2948. CopyMemory(current_block, &ok_button, sizeof(ok_button));
  2949. current_block += sizeof(ok_button) + (sizeof(ok_button) % 4);
  2950. CopyMemory(current_block, &text_field, sizeof(text_field));
  2951. current_block += sizeof(text_field) + (sizeof(text_field) % 4);
  2952. CopyMemory(current_block, &static_text, sizeof(static_text));
  2953. Char16String title16 = p_title.utf16();
  2954. Char16String description16 = p_description.utf16();
  2955. Char16String partial16 = p_partial.utf16();
  2956. Win32InputTextDialogInit init = {
  2957. title16.get_data(), description16.get_data(), partial16.get_data(), p_callback
  2958. };
  2959. // No modal dialogs for specific windows? Assume main window here.
  2960. INT_PTR ret = DialogBoxIndirectParamW(hInstance, (LPDLGTEMPLATEW)data_template, nullptr, (DLGPROC)input_text_dialog_proc, (LPARAM)(&init));
  2961. Error result = ret != -1 ? OK : FAILED;
  2962. memfree(data_template);
  2963. if (result == FAILED) {
  2964. ERR_PRINT("Unable to create native dialog.");
  2965. }
  2966. return result;
  2967. }
  2968. int DisplayServerWindows::keyboard_get_layout_count() const {
  2969. return GetKeyboardLayoutList(0, nullptr);
  2970. }
  2971. int DisplayServerWindows::keyboard_get_current_layout() const {
  2972. HKL cur_layout = GetKeyboardLayout(0);
  2973. int layout_count = GetKeyboardLayoutList(0, nullptr);
  2974. HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
  2975. GetKeyboardLayoutList(layout_count, layouts);
  2976. for (int i = 0; i < layout_count; i++) {
  2977. if (cur_layout == layouts[i]) {
  2978. memfree(layouts);
  2979. return i;
  2980. }
  2981. }
  2982. memfree(layouts);
  2983. return -1;
  2984. }
  2985. void DisplayServerWindows::keyboard_set_current_layout(int p_index) {
  2986. int layout_count = GetKeyboardLayoutList(0, nullptr);
  2987. ERR_FAIL_INDEX(p_index, layout_count);
  2988. HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
  2989. GetKeyboardLayoutList(layout_count, layouts);
  2990. ActivateKeyboardLayout(layouts[p_index], KLF_SETFORPROCESS);
  2991. memfree(layouts);
  2992. }
  2993. String DisplayServerWindows::keyboard_get_layout_language(int p_index) const {
  2994. int layout_count = GetKeyboardLayoutList(0, nullptr);
  2995. ERR_FAIL_INDEX_V(p_index, layout_count, "");
  2996. HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
  2997. GetKeyboardLayoutList(layout_count, layouts);
  2998. WCHAR buf[LOCALE_NAME_MAX_LENGTH];
  2999. memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(WCHAR));
  3000. LCIDToLocaleName(MAKELCID(LOWORD(layouts[p_index]), SORT_DEFAULT), buf, LOCALE_NAME_MAX_LENGTH, 0);
  3001. memfree(layouts);
  3002. return String::utf16((const char16_t *)buf).substr(0, 2);
  3003. }
  3004. Key DisplayServerWindows::keyboard_get_keycode_from_physical(Key p_keycode) const {
  3005. Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK;
  3006. Key keycode_no_mod = (Key)(p_keycode & KeyModifierMask::CODE_MASK);
  3007. if (keycode_no_mod == Key::PRINT ||
  3008. keycode_no_mod == Key::KP_ADD ||
  3009. keycode_no_mod == Key::KP_5 ||
  3010. (keycode_no_mod >= Key::KEY_0 && keycode_no_mod <= Key::KEY_9)) {
  3011. return p_keycode;
  3012. }
  3013. unsigned int scancode = KeyMappingWindows::get_scancode(keycode_no_mod);
  3014. if (scancode == 0) {
  3015. return p_keycode;
  3016. }
  3017. HKL current_layout = GetKeyboardLayout(0);
  3018. UINT vk = MapVirtualKeyEx(scancode, MAPVK_VSC_TO_VK, current_layout);
  3019. if (vk == 0) {
  3020. return p_keycode;
  3021. }
  3022. UINT char_code = MapVirtualKeyEx(vk, MAPVK_VK_TO_CHAR, current_layout) & 0x7FFF;
  3023. // Unlike a similar Linux/BSD check which matches full Latin-1 range,
  3024. // we limit these to ASCII to fix some layouts, including Arabic ones
  3025. if (char_code >= 32 && char_code <= 127) {
  3026. // Godot uses 'braces' instead of 'brackets'
  3027. if (char_code == (unsigned int)Key::BRACKETLEFT || char_code == (unsigned int)Key::BRACKETRIGHT) {
  3028. char_code += 32;
  3029. }
  3030. return (Key)(char_code | (unsigned int)modifiers);
  3031. }
  3032. return (Key)(KeyMappingWindows::get_keysym(vk) | modifiers);
  3033. }
  3034. Key DisplayServerWindows::keyboard_get_label_from_physical(Key p_keycode) const {
  3035. Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK;
  3036. Key keycode_no_mod = (Key)(p_keycode & KeyModifierMask::CODE_MASK);
  3037. if (keycode_no_mod == Key::PRINT ||
  3038. keycode_no_mod == Key::KP_ADD ||
  3039. keycode_no_mod == Key::KP_5 ||
  3040. (keycode_no_mod >= Key::KEY_0 && keycode_no_mod <= Key::KEY_9)) {
  3041. return p_keycode;
  3042. }
  3043. unsigned int scancode = KeyMappingWindows::get_scancode(keycode_no_mod);
  3044. if (scancode == 0) {
  3045. return p_keycode;
  3046. }
  3047. Key keycode = KeyMappingWindows::get_keysym(MapVirtualKey(scancode, MAPVK_VSC_TO_VK));
  3048. HKL current_layout = GetKeyboardLayout(0);
  3049. static BYTE keyboard_state[256];
  3050. memset(keyboard_state, 0, 256);
  3051. wchar_t chars[256] = {};
  3052. UINT extended_code = MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX);
  3053. if (ToUnicodeEx(extended_code, scancode, keyboard_state, chars, 255, 4, current_layout) > 0) {
  3054. String keysym = String::utf16((char16_t *)chars, 255);
  3055. if (!keysym.is_empty()) {
  3056. return fix_key_label(keysym[0], keycode) | modifiers;
  3057. }
  3058. }
  3059. return p_keycode;
  3060. }
  3061. void DisplayServerWindows::show_emoji_and_symbol_picker() const {
  3062. // Send Win + Period shortcut, there's no non-WinRT public API.
  3063. INPUT input[4] = {};
  3064. input[0].type = INPUT_KEYBOARD; // Win down.
  3065. input[0].ki.wVk = VK_LWIN;
  3066. input[1].type = INPUT_KEYBOARD; // Period down.
  3067. input[1].ki.wVk = VK_OEM_PERIOD;
  3068. input[2].type = INPUT_KEYBOARD; // Win up.
  3069. input[2].ki.wVk = VK_LWIN;
  3070. input[2].ki.dwFlags = KEYEVENTF_KEYUP;
  3071. input[3].type = INPUT_KEYBOARD; // Period up.
  3072. input[3].ki.wVk = VK_OEM_PERIOD;
  3073. input[3].ki.dwFlags = KEYEVENTF_KEYUP;
  3074. SendInput(4, input, sizeof(INPUT));
  3075. }
  3076. String DisplayServerWindows::_get_keyboard_layout_display_name(const String &p_klid) const {
  3077. String ret;
  3078. HKEY key;
  3079. if (RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", &key) != ERROR_SUCCESS) {
  3080. return String();
  3081. }
  3082. WCHAR buffer[MAX_PATH] = {};
  3083. DWORD buffer_size = MAX_PATH;
  3084. if (RegGetValueW(key, (LPCWSTR)p_klid.utf16().get_data(), L"Layout Display Name", RRF_RT_REG_SZ, nullptr, buffer, &buffer_size) == ERROR_SUCCESS) {
  3085. if (load_indirect_string) {
  3086. if (load_indirect_string(buffer, buffer, buffer_size, nullptr) == S_OK) {
  3087. ret = String::utf16((const char16_t *)buffer, buffer_size);
  3088. }
  3089. }
  3090. } else {
  3091. if (RegGetValueW(key, (LPCWSTR)p_klid.utf16().get_data(), L"Layout Text", RRF_RT_REG_SZ, nullptr, buffer, &buffer_size) == ERROR_SUCCESS) {
  3092. ret = String::utf16((const char16_t *)buffer, buffer_size);
  3093. }
  3094. }
  3095. RegCloseKey(key);
  3096. return ret;
  3097. }
  3098. String DisplayServerWindows::_get_klid(HKL p_hkl) const {
  3099. String ret;
  3100. WORD device = HIWORD(p_hkl);
  3101. if ((device & 0xf000) == 0xf000) {
  3102. WORD layout_id = device & 0x0fff;
  3103. HKEY key;
  3104. if (RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", &key) != ERROR_SUCCESS) {
  3105. return String();
  3106. }
  3107. DWORD index = 0;
  3108. wchar_t klid_buffer[KL_NAMELENGTH];
  3109. DWORD klid_buffer_size = KL_NAMELENGTH;
  3110. while (RegEnumKeyExW(key, index, klid_buffer, &klid_buffer_size, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS) {
  3111. wchar_t layout_id_buf[MAX_PATH] = {};
  3112. DWORD layout_id_size = MAX_PATH;
  3113. if (RegGetValueW(key, klid_buffer, L"Layout Id", RRF_RT_REG_SZ, nullptr, layout_id_buf, &layout_id_size) == ERROR_SUCCESS) {
  3114. if (layout_id == String::utf16((char16_t *)layout_id_buf, layout_id_size).hex_to_int()) {
  3115. ret = String::utf16((const char16_t *)klid_buffer, klid_buffer_size).lpad(8, "0");
  3116. break;
  3117. }
  3118. }
  3119. klid_buffer_size = KL_NAMELENGTH;
  3120. ++index;
  3121. }
  3122. RegCloseKey(key);
  3123. } else {
  3124. if (device == 0) {
  3125. device = LOWORD(p_hkl);
  3126. }
  3127. ret = (String::num_uint64((uint64_t)device, 16, false)).lpad(8, "0");
  3128. }
  3129. return ret;
  3130. }
  3131. String DisplayServerWindows::keyboard_get_layout_name(int p_index) const {
  3132. int layout_count = GetKeyboardLayoutList(0, nullptr);
  3133. ERR_FAIL_INDEX_V(p_index, layout_count, "");
  3134. HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
  3135. GetKeyboardLayoutList(layout_count, layouts);
  3136. String ret = _get_keyboard_layout_display_name(_get_klid(layouts[p_index])); // Try reading full name from Windows registry, fallback to locale name if failed (e.g. on Wine).
  3137. if (ret.is_empty()) {
  3138. WCHAR buf[LOCALE_NAME_MAX_LENGTH];
  3139. memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(WCHAR));
  3140. LCIDToLocaleName(MAKELCID(LOWORD(layouts[p_index]), SORT_DEFAULT), buf, LOCALE_NAME_MAX_LENGTH, 0);
  3141. WCHAR name[1024];
  3142. memset(name, 0, 1024 * sizeof(WCHAR));
  3143. GetLocaleInfoEx(buf, LOCALE_SLOCALIZEDDISPLAYNAME, (LPWSTR)&name, 1024);
  3144. ret = String::utf16((const char16_t *)name);
  3145. }
  3146. memfree(layouts);
  3147. return ret;
  3148. }
  3149. void DisplayServerWindows::process_events() {
  3150. ERR_FAIL_COND(!Thread::is_main_thread());
  3151. if (!drop_events) {
  3152. joypad->process_joypads();
  3153. }
  3154. _THREAD_SAFE_LOCK_
  3155. MSG msg = {};
  3156. while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
  3157. TranslateMessage(&msg);
  3158. DispatchMessageW(&msg);
  3159. }
  3160. _THREAD_SAFE_UNLOCK_
  3161. if (tts) {
  3162. tts->process_events();
  3163. }
  3164. if (!drop_events) {
  3165. _process_key_events();
  3166. Input::get_singleton()->flush_buffered_events();
  3167. }
  3168. LocalVector<List<FileDialogData *>::Element *> to_remove;
  3169. for (List<FileDialogData *>::Element *E = file_dialogs.front(); E; E = E->next()) {
  3170. FileDialogData *fd = E->get();
  3171. if (fd->finished.is_set()) {
  3172. if (fd->listener_thread.is_started()) {
  3173. fd->listener_thread.wait_to_finish();
  3174. }
  3175. to_remove.push_back(E);
  3176. }
  3177. }
  3178. for (List<FileDialogData *>::Element *E : to_remove) {
  3179. memdelete(E->get());
  3180. E->erase();
  3181. }
  3182. process_file_dialog_callbacks();
  3183. }
  3184. void DisplayServerWindows::force_process_and_drop_events() {
  3185. ERR_FAIL_COND(!Thread::is_main_thread());
  3186. drop_events = true;
  3187. process_events();
  3188. drop_events = false;
  3189. }
  3190. void DisplayServerWindows::release_rendering_thread() {
  3191. #if defined(GLES3_ENABLED)
  3192. if (gl_manager_angle) {
  3193. gl_manager_angle->release_current();
  3194. }
  3195. if (gl_manager_native) {
  3196. gl_manager_native->release_current();
  3197. }
  3198. #endif
  3199. }
  3200. void DisplayServerWindows::swap_buffers() {
  3201. #if defined(GLES3_ENABLED)
  3202. if (gl_manager_angle) {
  3203. gl_manager_angle->swap_buffers();
  3204. }
  3205. if (gl_manager_native) {
  3206. gl_manager_native->swap_buffers();
  3207. }
  3208. #endif
  3209. }
  3210. void DisplayServerWindows::set_native_icon(const String &p_filename) {
  3211. _THREAD_SAFE_METHOD_
  3212. Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::READ);
  3213. ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file with icon '" + p_filename + "'.");
  3214. ICONDIR *icon_dir = (ICONDIR *)memalloc(sizeof(ICONDIR));
  3215. int pos = 0;
  3216. icon_dir->idReserved = f->get_32();
  3217. pos += sizeof(WORD);
  3218. f->seek(pos);
  3219. icon_dir->idType = f->get_32();
  3220. pos += sizeof(WORD);
  3221. f->seek(pos);
  3222. ERR_FAIL_COND_MSG(icon_dir->idType != 1, "Invalid icon file format!");
  3223. icon_dir->idCount = f->get_32();
  3224. pos += sizeof(WORD);
  3225. f->seek(pos);
  3226. icon_dir = (ICONDIR *)memrealloc(icon_dir, sizeof(ICONDIR) - sizeof(ICONDIRENTRY) + icon_dir->idCount * sizeof(ICONDIRENTRY));
  3227. f->get_buffer((uint8_t *)&icon_dir->idEntries[0], icon_dir->idCount * sizeof(ICONDIRENTRY));
  3228. int small_icon_index = -1; // Select 16x16 with largest color count.
  3229. int small_icon_cc = 0;
  3230. int big_icon_index = -1; // Select largest.
  3231. int big_icon_width = 16;
  3232. int big_icon_cc = 0;
  3233. for (int i = 0; i < icon_dir->idCount; i++) {
  3234. int colors = (icon_dir->idEntries[i].bColorCount == 0) ? 32768 : icon_dir->idEntries[i].bColorCount;
  3235. int width = (icon_dir->idEntries[i].bWidth == 0) ? 256 : icon_dir->idEntries[i].bWidth;
  3236. if (width == 16) {
  3237. if (colors >= small_icon_cc) {
  3238. small_icon_index = i;
  3239. small_icon_cc = colors;
  3240. }
  3241. }
  3242. if (width >= big_icon_width) {
  3243. if (colors >= big_icon_cc) {
  3244. big_icon_index = i;
  3245. big_icon_width = width;
  3246. big_icon_cc = colors;
  3247. }
  3248. }
  3249. }
  3250. ERR_FAIL_COND_MSG(big_icon_index == -1, "No valid icons found!");
  3251. if (small_icon_index == -1) {
  3252. WARN_PRINT("No small icon found, reusing " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon!");
  3253. small_icon_index = big_icon_index;
  3254. small_icon_cc = big_icon_cc;
  3255. }
  3256. // Read the big icon.
  3257. DWORD bytecount_big = icon_dir->idEntries[big_icon_index].dwBytesInRes;
  3258. Vector<uint8_t> data_big;
  3259. data_big.resize(bytecount_big);
  3260. pos = icon_dir->idEntries[big_icon_index].dwImageOffset;
  3261. f->seek(pos);
  3262. f->get_buffer((uint8_t *)&data_big.write[0], bytecount_big);
  3263. HICON icon_big = CreateIconFromResource((PBYTE)&data_big.write[0], bytecount_big, TRUE, 0x00030000);
  3264. ERR_FAIL_NULL_MSG(icon_big, "Could not create " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
  3265. // Read the small icon.
  3266. DWORD bytecount_small = icon_dir->idEntries[small_icon_index].dwBytesInRes;
  3267. Vector<uint8_t> data_small;
  3268. data_small.resize(bytecount_small);
  3269. pos = icon_dir->idEntries[small_icon_index].dwImageOffset;
  3270. f->seek(pos);
  3271. f->get_buffer((uint8_t *)&data_small.write[0], bytecount_small);
  3272. HICON icon_small = CreateIconFromResource((PBYTE)&data_small.write[0], bytecount_small, TRUE, 0x00030000);
  3273. ERR_FAIL_NULL_MSG(icon_small, "Could not create 16x16 @" + itos(small_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
  3274. // Online tradition says to be sure last error is cleared and set the small icon first.
  3275. int err = 0;
  3276. SetLastError(err);
  3277. SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon_small);
  3278. err = GetLastError();
  3279. ERR_FAIL_COND_MSG(err, "Error setting ICON_SMALL: " + format_error_message(err) + ".");
  3280. SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon_big);
  3281. err = GetLastError();
  3282. ERR_FAIL_COND_MSG(err, "Error setting ICON_BIG: " + format_error_message(err) + ".");
  3283. memdelete(icon_dir);
  3284. }
  3285. void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
  3286. _THREAD_SAFE_METHOD_
  3287. if (p_icon.is_valid()) {
  3288. ERR_FAIL_COND(p_icon->get_width() <= 0 || p_icon->get_height() <= 0);
  3289. Ref<Image> img = p_icon;
  3290. if (img != icon) {
  3291. img = img->duplicate();
  3292. img->convert(Image::FORMAT_RGBA8);
  3293. }
  3294. int w = img->get_width();
  3295. int h = img->get_height();
  3296. // Create temporary bitmap buffer.
  3297. int icon_len = 40 + h * w * 4;
  3298. Vector<BYTE> v;
  3299. v.resize(icon_len);
  3300. BYTE *icon_bmp = v.ptrw();
  3301. encode_uint32(40, &icon_bmp[0]);
  3302. encode_uint32(w, &icon_bmp[4]);
  3303. encode_uint32(h * 2, &icon_bmp[8]);
  3304. encode_uint16(1, &icon_bmp[12]);
  3305. encode_uint16(32, &icon_bmp[14]);
  3306. encode_uint32(BI_RGB, &icon_bmp[16]);
  3307. encode_uint32(w * h * 4, &icon_bmp[20]);
  3308. encode_uint32(0, &icon_bmp[24]);
  3309. encode_uint32(0, &icon_bmp[28]);
  3310. encode_uint32(0, &icon_bmp[32]);
  3311. encode_uint32(0, &icon_bmp[36]);
  3312. uint8_t *wr = &icon_bmp[40];
  3313. const uint8_t *r = img->get_data().ptr();
  3314. for (int i = 0; i < h; i++) {
  3315. for (int j = 0; j < w; j++) {
  3316. const uint8_t *rpx = &r[((h - i - 1) * w + j) * 4];
  3317. uint8_t *wpx = &wr[(i * w + j) * 4];
  3318. wpx[0] = rpx[2];
  3319. wpx[1] = rpx[1];
  3320. wpx[2] = rpx[0];
  3321. wpx[3] = rpx[3];
  3322. }
  3323. }
  3324. HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
  3325. ERR_FAIL_NULL(hicon);
  3326. icon = img;
  3327. // Set the icon for the window.
  3328. SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon);
  3329. // Set the icon in the task manager (should we do this?).
  3330. SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
  3331. } else {
  3332. icon = Ref<Image>();
  3333. SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, 0);
  3334. SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, 0);
  3335. }
  3336. }
  3337. DisplayServer::IndicatorID DisplayServerWindows::create_status_indicator(const Ref<Texture2D> &p_icon, const String &p_tooltip, const Callable &p_callback) {
  3338. HICON hicon = nullptr;
  3339. if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
  3340. Ref<Image> img = p_icon->get_image();
  3341. img = img->duplicate();
  3342. if (img->is_compressed()) {
  3343. img->decompress();
  3344. }
  3345. img->convert(Image::FORMAT_RGBA8);
  3346. int w = img->get_width();
  3347. int h = img->get_height();
  3348. // Create temporary bitmap buffer.
  3349. int icon_len = 40 + h * w * 4;
  3350. Vector<BYTE> v;
  3351. v.resize(icon_len);
  3352. BYTE *icon_bmp = v.ptrw();
  3353. encode_uint32(40, &icon_bmp[0]);
  3354. encode_uint32(w, &icon_bmp[4]);
  3355. encode_uint32(h * 2, &icon_bmp[8]);
  3356. encode_uint16(1, &icon_bmp[12]);
  3357. encode_uint16(32, &icon_bmp[14]);
  3358. encode_uint32(BI_RGB, &icon_bmp[16]);
  3359. encode_uint32(w * h * 4, &icon_bmp[20]);
  3360. encode_uint32(0, &icon_bmp[24]);
  3361. encode_uint32(0, &icon_bmp[28]);
  3362. encode_uint32(0, &icon_bmp[32]);
  3363. encode_uint32(0, &icon_bmp[36]);
  3364. uint8_t *wr = &icon_bmp[40];
  3365. const uint8_t *r = img->get_data().ptr();
  3366. for (int i = 0; i < h; i++) {
  3367. for (int j = 0; j < w; j++) {
  3368. const uint8_t *rpx = &r[((h - i - 1) * w + j) * 4];
  3369. uint8_t *wpx = &wr[(i * w + j) * 4];
  3370. wpx[0] = rpx[2];
  3371. wpx[1] = rpx[1];
  3372. wpx[2] = rpx[0];
  3373. wpx[3] = rpx[3];
  3374. }
  3375. }
  3376. hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
  3377. }
  3378. IndicatorData idat;
  3379. idat.callback = p_callback;
  3380. NOTIFYICONDATAW ndat;
  3381. ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW));
  3382. ndat.cbSize = sizeof(NOTIFYICONDATAW);
  3383. ndat.hWnd = windows[MAIN_WINDOW_ID].hWnd;
  3384. ndat.uID = indicator_id_counter;
  3385. ndat.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
  3386. ndat.uCallbackMessage = WM_INDICATOR_CALLBACK_MESSAGE;
  3387. ndat.hIcon = hicon;
  3388. memcpy(ndat.szTip, p_tooltip.utf16().get_data(), MIN(p_tooltip.utf16().length(), 127) * sizeof(WCHAR));
  3389. ndat.uVersion = NOTIFYICON_VERSION;
  3390. Shell_NotifyIconW(NIM_ADD, &ndat);
  3391. Shell_NotifyIconW(NIM_SETVERSION, &ndat);
  3392. IndicatorID iid = indicator_id_counter++;
  3393. indicators[iid] = idat;
  3394. return iid;
  3395. }
  3396. void DisplayServerWindows::status_indicator_set_icon(IndicatorID p_id, const Ref<Texture2D> &p_icon) {
  3397. ERR_FAIL_COND(!indicators.has(p_id));
  3398. HICON hicon = nullptr;
  3399. if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0 && p_icon->get_image().is_valid()) {
  3400. Ref<Image> img = p_icon->get_image();
  3401. img = img->duplicate();
  3402. if (img->is_compressed()) {
  3403. img->decompress();
  3404. }
  3405. img->convert(Image::FORMAT_RGBA8);
  3406. int w = img->get_width();
  3407. int h = img->get_height();
  3408. // Create temporary bitmap buffer.
  3409. int icon_len = 40 + h * w * 4;
  3410. Vector<BYTE> v;
  3411. v.resize(icon_len);
  3412. BYTE *icon_bmp = v.ptrw();
  3413. encode_uint32(40, &icon_bmp[0]);
  3414. encode_uint32(w, &icon_bmp[4]);
  3415. encode_uint32(h * 2, &icon_bmp[8]);
  3416. encode_uint16(1, &icon_bmp[12]);
  3417. encode_uint16(32, &icon_bmp[14]);
  3418. encode_uint32(BI_RGB, &icon_bmp[16]);
  3419. encode_uint32(w * h * 4, &icon_bmp[20]);
  3420. encode_uint32(0, &icon_bmp[24]);
  3421. encode_uint32(0, &icon_bmp[28]);
  3422. encode_uint32(0, &icon_bmp[32]);
  3423. encode_uint32(0, &icon_bmp[36]);
  3424. uint8_t *wr = &icon_bmp[40];
  3425. const uint8_t *r = img->get_data().ptr();
  3426. for (int i = 0; i < h; i++) {
  3427. for (int j = 0; j < w; j++) {
  3428. const uint8_t *rpx = &r[((h - i - 1) * w + j) * 4];
  3429. uint8_t *wpx = &wr[(i * w + j) * 4];
  3430. wpx[0] = rpx[2];
  3431. wpx[1] = rpx[1];
  3432. wpx[2] = rpx[0];
  3433. wpx[3] = rpx[3];
  3434. }
  3435. }
  3436. hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
  3437. }
  3438. NOTIFYICONDATAW ndat;
  3439. ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW));
  3440. ndat.cbSize = sizeof(NOTIFYICONDATAW);
  3441. ndat.hWnd = windows[MAIN_WINDOW_ID].hWnd;
  3442. ndat.uID = p_id;
  3443. ndat.uFlags = NIF_ICON;
  3444. ndat.hIcon = hicon;
  3445. ndat.uVersion = NOTIFYICON_VERSION;
  3446. Shell_NotifyIconW(NIM_MODIFY, &ndat);
  3447. }
  3448. void DisplayServerWindows::status_indicator_set_tooltip(IndicatorID p_id, const String &p_tooltip) {
  3449. ERR_FAIL_COND(!indicators.has(p_id));
  3450. NOTIFYICONDATAW ndat;
  3451. ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW));
  3452. ndat.cbSize = sizeof(NOTIFYICONDATAW);
  3453. ndat.hWnd = windows[MAIN_WINDOW_ID].hWnd;
  3454. ndat.uID = p_id;
  3455. ndat.uFlags = NIF_TIP;
  3456. memcpy(ndat.szTip, p_tooltip.utf16().get_data(), MIN(p_tooltip.utf16().length(), 127) * sizeof(WCHAR));
  3457. ndat.uVersion = NOTIFYICON_VERSION;
  3458. Shell_NotifyIconW(NIM_MODIFY, &ndat);
  3459. }
  3460. void DisplayServerWindows::status_indicator_set_menu(IndicatorID p_id, const RID &p_menu_rid) {
  3461. ERR_FAIL_COND(!indicators.has(p_id));
  3462. indicators[p_id].menu_rid = p_menu_rid;
  3463. }
  3464. void DisplayServerWindows::status_indicator_set_callback(IndicatorID p_id, const Callable &p_callback) {
  3465. ERR_FAIL_COND(!indicators.has(p_id));
  3466. indicators[p_id].callback = p_callback;
  3467. }
  3468. Rect2 DisplayServerWindows::status_indicator_get_rect(IndicatorID p_id) const {
  3469. ERR_FAIL_COND_V(!indicators.has(p_id), Rect2());
  3470. NOTIFYICONIDENTIFIER nid;
  3471. ZeroMemory(&nid, sizeof(NOTIFYICONIDENTIFIER));
  3472. nid.cbSize = sizeof(NOTIFYICONIDENTIFIER);
  3473. nid.hWnd = windows[MAIN_WINDOW_ID].hWnd;
  3474. nid.uID = p_id;
  3475. nid.guidItem = GUID_NULL;
  3476. RECT rect;
  3477. if (Shell_NotifyIconGetRect(&nid, &rect) != S_OK) {
  3478. return Rect2();
  3479. }
  3480. Rect2 ind_rect = Rect2(Point2(rect.left, rect.top) - _get_screens_origin(), Size2(rect.right - rect.left, rect.bottom - rect.top));
  3481. for (int i = 0; i < get_screen_count(); i++) {
  3482. Rect2 screen_rect = Rect2(screen_get_position(i), screen_get_size(i));
  3483. if (screen_rect.encloses(ind_rect)) {
  3484. return ind_rect;
  3485. }
  3486. }
  3487. return Rect2();
  3488. }
  3489. void DisplayServerWindows::delete_status_indicator(IndicatorID p_id) {
  3490. ERR_FAIL_COND(!indicators.has(p_id));
  3491. NOTIFYICONDATAW ndat;
  3492. ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW));
  3493. ndat.cbSize = sizeof(NOTIFYICONDATAW);
  3494. ndat.hWnd = windows[MAIN_WINDOW_ID].hWnd;
  3495. ndat.uID = p_id;
  3496. ndat.uVersion = NOTIFYICON_VERSION;
  3497. Shell_NotifyIconW(NIM_DELETE, &ndat);
  3498. indicators.erase(p_id);
  3499. }
  3500. void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
  3501. _THREAD_SAFE_METHOD_
  3502. #if defined(RD_ENABLED)
  3503. if (rendering_context) {
  3504. rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
  3505. }
  3506. #endif
  3507. #if defined(GLES3_ENABLED)
  3508. if (gl_manager_native) {
  3509. gl_manager_native->set_use_vsync(p_window, p_vsync_mode != DisplayServer::VSYNC_DISABLED);
  3510. }
  3511. if (gl_manager_angle) {
  3512. gl_manager_angle->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
  3513. }
  3514. #endif
  3515. }
  3516. DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
  3517. _THREAD_SAFE_METHOD_
  3518. #if defined(RD_ENABLED)
  3519. if (rendering_context) {
  3520. return rendering_context->window_get_vsync_mode(p_window);
  3521. }
  3522. #endif
  3523. #if defined(GLES3_ENABLED)
  3524. if (gl_manager_native) {
  3525. return gl_manager_native->is_using_vsync(p_window) ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
  3526. }
  3527. if (gl_manager_angle) {
  3528. return gl_manager_angle->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
  3529. }
  3530. #endif
  3531. return DisplayServer::VSYNC_ENABLED;
  3532. }
  3533. void DisplayServerWindows::window_start_drag(WindowID p_window) {
  3534. _THREAD_SAFE_METHOD_
  3535. ERR_FAIL_COND(!windows.has(p_window));
  3536. WindowData &wd = windows[p_window];
  3537. if (wd.parent_hwnd) {
  3538. return; // Embedded window.
  3539. }
  3540. ReleaseCapture();
  3541. POINT coords;
  3542. GetCursorPos(&coords);
  3543. ScreenToClient(wd.hWnd, &coords);
  3544. SendMessage(wd.hWnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(coords.x, coords.y));
  3545. }
  3546. void DisplayServerWindows::window_start_resize(WindowResizeEdge p_edge, WindowID p_window) {
  3547. _THREAD_SAFE_METHOD_
  3548. ERR_FAIL_INDEX(int(p_edge), WINDOW_EDGE_MAX);
  3549. ERR_FAIL_COND(!windows.has(p_window));
  3550. WindowData &wd = windows[p_window];
  3551. if (wd.parent_hwnd) {
  3552. return; // Embedded window.
  3553. }
  3554. ReleaseCapture();
  3555. POINT coords;
  3556. GetCursorPos(&coords);
  3557. ScreenToClient(wd.hWnd, &coords);
  3558. DWORD op = 0;
  3559. switch (p_edge) {
  3560. case DisplayServer::WINDOW_EDGE_TOP_LEFT: {
  3561. op = WMSZ_TOPLEFT;
  3562. } break;
  3563. case DisplayServer::WINDOW_EDGE_TOP: {
  3564. op = WMSZ_TOP;
  3565. } break;
  3566. case DisplayServer::WINDOW_EDGE_TOP_RIGHT: {
  3567. op = WMSZ_TOPRIGHT;
  3568. } break;
  3569. case DisplayServer::WINDOW_EDGE_LEFT: {
  3570. op = WMSZ_LEFT;
  3571. } break;
  3572. case DisplayServer::WINDOW_EDGE_RIGHT: {
  3573. op = WMSZ_RIGHT;
  3574. } break;
  3575. case DisplayServer::WINDOW_EDGE_BOTTOM_LEFT: {
  3576. op = WMSZ_BOTTOMLEFT;
  3577. } break;
  3578. case DisplayServer::WINDOW_EDGE_BOTTOM: {
  3579. op = WMSZ_BOTTOM;
  3580. } break;
  3581. case DisplayServer::WINDOW_EDGE_BOTTOM_RIGHT: {
  3582. op = WMSZ_BOTTOMRIGHT;
  3583. } break;
  3584. default:
  3585. break;
  3586. }
  3587. SendMessage(wd.hWnd, WM_SYSCOMMAND, SC_SIZE | op, MAKELPARAM(coords.x, coords.y));
  3588. }
  3589. void DisplayServerWindows::set_context(Context p_context) {
  3590. }
  3591. bool DisplayServerWindows::is_window_transparency_available() const {
  3592. BOOL dwm_enabled = true;
  3593. if (DwmIsCompositionEnabled(&dwm_enabled) == S_OK) { // Note: Always enabled on Windows 8+, this check can be removed after Windows 7 support is dropped.
  3594. if (!dwm_enabled) {
  3595. return false;
  3596. }
  3597. }
  3598. #if defined(RD_ENABLED)
  3599. if (rendering_device && !rendering_device->is_composite_alpha_supported()) {
  3600. return false;
  3601. }
  3602. #endif
  3603. return OS::get_singleton()->is_layered_allowed();
  3604. }
  3605. #define MI_WP_SIGNATURE 0xFF515700
  3606. #define SIGNATURE_MASK 0xFFFFFF00
  3607. // Keeping the name suggested by Microsoft, but this macro really answers:
  3608. // Is this mouse event emulated from touch or pen input?
  3609. #define IsPenEvent(dw) (((dw) & SIGNATURE_MASK) == MI_WP_SIGNATURE)
  3610. // This one tells whether the event comes from touchscreen (and not from pen).
  3611. #define IsTouchEvent(dw) (IsPenEvent(dw) && ((dw) & 0x80))
  3612. void DisplayServerWindows::_touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx) {
  3613. if (touch_state.has(idx) == p_pressed) {
  3614. return;
  3615. }
  3616. if (p_pressed) {
  3617. touch_state.insert(idx, Vector2(p_x, p_y));
  3618. } else {
  3619. touch_state.erase(idx);
  3620. }
  3621. Ref<InputEventScreenTouch> event;
  3622. event.instantiate();
  3623. event->set_index(idx);
  3624. event->set_window_id(p_window);
  3625. event->set_pressed(p_pressed);
  3626. event->set_position(Vector2(p_x, p_y));
  3627. Input::get_singleton()->parse_input_event(event);
  3628. }
  3629. void DisplayServerWindows::_drag_event(WindowID p_window, float p_x, float p_y, int idx) {
  3630. RBMap<int, Vector2>::Element *curr = touch_state.find(idx);
  3631. if (!curr) {
  3632. return;
  3633. }
  3634. if (curr->get() == Vector2(p_x, p_y)) {
  3635. return;
  3636. }
  3637. Ref<InputEventScreenDrag> event;
  3638. event.instantiate();
  3639. event->set_window_id(p_window);
  3640. event->set_index(idx);
  3641. event->set_position(Vector2(p_x, p_y));
  3642. event->set_relative(Vector2(p_x, p_y) - curr->get());
  3643. event->set_relative_screen_position(event->get_relative());
  3644. Input::get_singleton()->parse_input_event(event);
  3645. curr->get() = Vector2(p_x, p_y);
  3646. }
  3647. void DisplayServerWindows::_send_window_event(const WindowData &wd, WindowEvent p_event) {
  3648. if (wd.event_callback.is_valid()) {
  3649. Variant event = int(p_event);
  3650. wd.event_callback.call(event);
  3651. }
  3652. }
  3653. void DisplayServerWindows::_dispatch_input_events(const Ref<InputEvent> &p_event) {
  3654. static_cast<DisplayServerWindows *>(get_singleton())->_dispatch_input_event(p_event);
  3655. }
  3656. void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) {
  3657. if (in_dispatch_input_event) {
  3658. return;
  3659. }
  3660. in_dispatch_input_event = true;
  3661. {
  3662. List<WindowID>::Element *E = popup_list.back();
  3663. if (E && Object::cast_to<InputEventKey>(*p_event)) {
  3664. // Redirect keyboard input to active popup.
  3665. if (windows.has(E->get())) {
  3666. Callable callable = windows[E->get()].input_event_callback;
  3667. if (callable.is_valid()) {
  3668. callable.call(p_event);
  3669. }
  3670. }
  3671. in_dispatch_input_event = false;
  3672. return;
  3673. }
  3674. }
  3675. Ref<InputEventFromWindow> event_from_window = p_event;
  3676. if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
  3677. // Send to a single window.
  3678. if (windows.has(event_from_window->get_window_id())) {
  3679. Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
  3680. if (callable.is_valid()) {
  3681. callable.call(p_event);
  3682. }
  3683. }
  3684. } else {
  3685. // Send to all windows. Copy all pending callbacks, since callback can erase window.
  3686. Vector<Callable> cbs;
  3687. for (KeyValue<WindowID, WindowData> &E : windows) {
  3688. Callable callable = E.value.input_event_callback;
  3689. if (callable.is_valid()) {
  3690. cbs.push_back(callable);
  3691. }
  3692. }
  3693. for (const Callable &cb : cbs) {
  3694. cb.call(p_event);
  3695. }
  3696. }
  3697. in_dispatch_input_event = false;
  3698. }
  3699. LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) {
  3700. DisplayServerWindows *ds_win = static_cast<DisplayServerWindows *>(DisplayServer::get_singleton());
  3701. if (ds_win) {
  3702. return ds_win->MouseProc(code, wParam, lParam);
  3703. } else {
  3704. return ::CallNextHookEx(nullptr, code, wParam, lParam);
  3705. }
  3706. }
  3707. DisplayServer::WindowID DisplayServerWindows::window_get_active_popup() const {
  3708. const List<WindowID>::Element *E = popup_list.back();
  3709. if (E) {
  3710. return E->get();
  3711. } else {
  3712. return INVALID_WINDOW_ID;
  3713. }
  3714. }
  3715. void DisplayServerWindows::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) {
  3716. _THREAD_SAFE_METHOD_
  3717. ERR_FAIL_COND(!windows.has(p_window));
  3718. WindowData &wd = windows[p_window];
  3719. wd.parent_safe_rect = p_rect;
  3720. }
  3721. Rect2i DisplayServerWindows::window_get_popup_safe_rect(WindowID p_window) const {
  3722. _THREAD_SAFE_METHOD_
  3723. ERR_FAIL_COND_V(!windows.has(p_window), Rect2i());
  3724. const WindowData &wd = windows[p_window];
  3725. return wd.parent_safe_rect;
  3726. }
  3727. void DisplayServerWindows::popup_open(WindowID p_window) {
  3728. _THREAD_SAFE_METHOD_
  3729. bool has_popup_ancestor = false;
  3730. WindowID transient_root = p_window;
  3731. while (true) {
  3732. WindowID parent = windows[transient_root].transient_parent;
  3733. if (parent == INVALID_WINDOW_ID) {
  3734. break;
  3735. } else {
  3736. transient_root = parent;
  3737. if (windows[parent].is_popup) {
  3738. has_popup_ancestor = true;
  3739. break;
  3740. }
  3741. }
  3742. }
  3743. // Detect tooltips and other similar popups that shouldn't block input to their parent.
  3744. bool ignores_input = window_get_flag(WINDOW_FLAG_NO_FOCUS, p_window) && window_get_flag(WINDOW_FLAG_MOUSE_PASSTHROUGH, p_window);
  3745. WindowData &wd = windows[p_window];
  3746. if (wd.is_popup || (has_popup_ancestor && !ignores_input)) {
  3747. // Find current popup parent, or root popup if new window is not transient.
  3748. List<WindowID>::Element *C = nullptr;
  3749. List<WindowID>::Element *E = popup_list.back();
  3750. while (E) {
  3751. if (wd.transient_parent != E->get() || wd.transient_parent == INVALID_WINDOW_ID) {
  3752. C = E;
  3753. E = E->prev();
  3754. } else {
  3755. break;
  3756. }
  3757. }
  3758. if (C) {
  3759. _send_window_event(windows[C->get()], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST);
  3760. }
  3761. time_since_popup = OS::get_singleton()->get_ticks_msec();
  3762. popup_list.push_back(p_window);
  3763. }
  3764. }
  3765. void DisplayServerWindows::popup_close(WindowID p_window) {
  3766. _THREAD_SAFE_METHOD_
  3767. List<WindowID>::Element *E = popup_list.find(p_window);
  3768. while (E) {
  3769. List<WindowID>::Element *F = E->next();
  3770. WindowID win_id = E->get();
  3771. popup_list.erase(E);
  3772. if (win_id != p_window) {
  3773. // Only request close on related windows, not this window. We are already processing it.
  3774. _send_window_event(windows[win_id], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST);
  3775. }
  3776. E = F;
  3777. }
  3778. }
  3779. BitField<DisplayServerWindows::WinKeyModifierMask> DisplayServerWindows::_get_mods() const {
  3780. BitField<WinKeyModifierMask> mask = {};
  3781. static unsigned char keyboard_state[256];
  3782. if (GetKeyboardState((PBYTE)&keyboard_state)) {
  3783. if ((keyboard_state[VK_LSHIFT] & 0x80) || (keyboard_state[VK_RSHIFT] & 0x80)) {
  3784. mask.set_flag(WinKeyModifierMask::SHIFT);
  3785. }
  3786. if ((keyboard_state[VK_LCONTROL] & 0x80) || (keyboard_state[VK_RCONTROL] & 0x80)) {
  3787. mask.set_flag(WinKeyModifierMask::CTRL);
  3788. }
  3789. if ((keyboard_state[VK_LMENU] & 0x80) || (keyboard_state[VK_RMENU] & 0x80)) {
  3790. mask.set_flag(WinKeyModifierMask::ALT);
  3791. }
  3792. if ((keyboard_state[VK_RMENU] & 0x80)) {
  3793. mask.set_flag(WinKeyModifierMask::ALT_GR);
  3794. }
  3795. if ((keyboard_state[VK_LWIN] & 0x80) || (keyboard_state[VK_RWIN] & 0x80)) {
  3796. mask.set_flag(WinKeyModifierMask::META);
  3797. }
  3798. }
  3799. return mask;
  3800. }
  3801. LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam) {
  3802. _THREAD_SAFE_METHOD_
  3803. uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup;
  3804. if (delta > 250) {
  3805. switch (wParam) {
  3806. case WM_NCLBUTTONDOWN:
  3807. case WM_NCRBUTTONDOWN:
  3808. case WM_NCMBUTTONDOWN:
  3809. case WM_LBUTTONDOWN:
  3810. case WM_RBUTTONDOWN:
  3811. case WM_MBUTTONDOWN: {
  3812. MOUSEHOOKSTRUCT *ms = (MOUSEHOOKSTRUCT *)lParam;
  3813. Point2i pos = Point2i(ms->pt.x, ms->pt.y) - _get_screens_origin();
  3814. List<WindowID>::Element *C = nullptr;
  3815. List<WindowID>::Element *E = popup_list.back();
  3816. // Find top popup to close.
  3817. while (E) {
  3818. // Popup window area.
  3819. Rect2i win_rect = Rect2i(window_get_position_with_decorations(E->get()), window_get_size_with_decorations(E->get()));
  3820. // Area of the parent window, which responsible for opening sub-menu.
  3821. Rect2i safe_rect = window_get_popup_safe_rect(E->get());
  3822. if (win_rect.has_point(pos)) {
  3823. break;
  3824. } else if (safe_rect != Rect2i() && safe_rect.has_point(pos)) {
  3825. break;
  3826. } else {
  3827. C = E;
  3828. E = E->prev();
  3829. }
  3830. }
  3831. if (C) {
  3832. _send_window_event(windows[C->get()], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST);
  3833. return 1;
  3834. }
  3835. } break;
  3836. }
  3837. }
  3838. return ::CallNextHookEx(mouse_monitor, code, wParam, lParam);
  3839. }
  3840. // Handle a single window message received while CreateWindowEx is still on the stack and our data
  3841. // structures are not fully initialized.
  3842. LRESULT DisplayServerWindows::_handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  3843. switch (uMsg) {
  3844. case WM_GETMINMAXINFO: {
  3845. // We receive this during CreateWindowEx and we haven't initialized the window
  3846. // struct, so let Windows figure out the maximized size.
  3847. // Silently forward to user/default.
  3848. } break;
  3849. case WM_NCCREATE: {
  3850. // We tunnel an unowned pointer to our window context (WindowData) through the
  3851. // first possible message (WM_NCCREATE) to fix up our window context collection.
  3852. CREATESTRUCTW *pCreate = (CREATESTRUCTW *)lParam;
  3853. WindowData *pWindowData = reinterpret_cast<WindowData *>(pCreate->lpCreateParams);
  3854. // Fix this up so we can recognize the remaining messages.
  3855. pWindowData->hWnd = hWnd;
  3856. #ifdef ACCESSKIT_ENABLED
  3857. if (accessibility_driver && !accessibility_driver->window_create(pWindowData->id, (void *)hWnd)) {
  3858. if (OS::get_singleton()->is_stdout_verbose()) {
  3859. ERR_PRINT("Can't create an accessibility adapter for window, accessibility support disabled!");
  3860. }
  3861. memdelete(accessibility_driver);
  3862. accessibility_driver = nullptr;
  3863. }
  3864. #endif
  3865. } break;
  3866. default: {
  3867. // Additional messages during window creation should happen after we fixed
  3868. // up the data structures on WM_NCCREATE, but this might change in the future,
  3869. // so report an error here and then we can implement them.
  3870. ERR_PRINT_ONCE(vformat("Unexpected window message 0x%x received for window we cannot recognize in our collection; sequence error.", uMsg));
  3871. } break;
  3872. }
  3873. if (user_proc) {
  3874. return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
  3875. }
  3876. return DefWindowProcW(hWnd, uMsg, wParam, lParam);
  3877. }
  3878. // The window procedure for our window class "Engine", used to handle processing of window-related system messages/events.
  3879. // See: https://docs.microsoft.com/en-us/windows/win32/winmsg/window-procedures
  3880. LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  3881. if (drop_events) {
  3882. if (user_proc) {
  3883. return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
  3884. } else {
  3885. return DefWindowProcW(hWnd, uMsg, wParam, lParam);
  3886. }
  3887. }
  3888. WindowID window_id = INVALID_WINDOW_ID;
  3889. bool window_created = false;
  3890. // Check whether window exists
  3891. // FIXME this is O(n), where n is the set of currently open windows and subwindows
  3892. // we should have a secondary map from HWND to WindowID or even WindowData* alias, if we want to eliminate all the map lookups below
  3893. for (const KeyValue<WindowID, WindowData> &E : windows) {
  3894. if (E.value.hWnd == hWnd) {
  3895. window_id = E.key;
  3896. window_created = true;
  3897. break;
  3898. }
  3899. }
  3900. // WARNING: We get called with events before the window is registered in our collection
  3901. // specifically, even the call to CreateWindowEx already calls here while still on the stack,
  3902. // so there is no way to store the window handle in our collection before we get here.
  3903. if (!window_created) {
  3904. // don't let code below operate on incompletely initialized window objects or missing window_id
  3905. return _handle_early_window_message(hWnd, uMsg, wParam, lParam);
  3906. }
  3907. // Process window messages.
  3908. switch (uMsg) {
  3909. case WM_GETOBJECT: {
  3910. get_object_recieved = true;
  3911. } break;
  3912. case WM_MENUCOMMAND: {
  3913. native_menu->_menu_activate(HMENU(lParam), (int)wParam);
  3914. } break;
  3915. case WM_CREATE: {
  3916. {
  3917. DWORD value = windows[window_id].sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT;
  3918. ::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value));
  3919. }
  3920. if (is_dark_mode_supported() && dark_title_available) {
  3921. BOOL value = is_dark_mode();
  3922. ::DwmSetWindowAttribute(windows[window_id].hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
  3923. SendMessageW(windows[window_id].hWnd, WM_PAINT, 0, 0);
  3924. }
  3925. } break;
  3926. case WM_NCHITTEST: {
  3927. if (windows[window_id].mpass) {
  3928. return HTTRANSPARENT;
  3929. }
  3930. } break;
  3931. case WM_MOUSEACTIVATE: {
  3932. if (windows[window_id].no_focus || windows[window_id].is_popup) {
  3933. return MA_NOACTIVATE; // Do not activate, but process mouse messages.
  3934. }
  3935. // When embedded, the window is a child of the parent and is not activated
  3936. // by default because it lacks native controls.
  3937. if (windows[window_id].parent_hwnd) {
  3938. SetFocus(windows[window_id].hWnd);
  3939. return MA_ACTIVATE;
  3940. }
  3941. } break;
  3942. case WM_ACTIVATEAPP: {
  3943. bool new_app_focused = (bool)wParam;
  3944. if (new_app_focused == app_focused) {
  3945. break;
  3946. }
  3947. app_focused = new_app_focused;
  3948. if (OS::get_singleton()->get_main_loop()) {
  3949. OS::get_singleton()->get_main_loop()->notification(app_focused ? MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN : MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
  3950. }
  3951. } break;
  3952. case WM_ACTIVATE: {
  3953. // Activation can happen just after the window has been created, even before the callbacks are set.
  3954. // Therefore, it's safer to defer the delivery of the event.
  3955. // It's important to set an nIDEvent different from the SetTimer for move_timer_id because
  3956. // if the same nIDEvent is passed, the timer is replaced and the same timer_id is returned.
  3957. // The problem with the timer is that the window cannot be resized or the buttons cannot be used correctly
  3958. // if the window is not activated first. This happens because the code in the activation process runs
  3959. // after the mouse click is handled. To address this, the timer is now used only when the window is created.
  3960. windows[window_id].activate_state = GET_WM_ACTIVATE_STATE(wParam, lParam);
  3961. if (windows[window_id].first_activation_done) {
  3962. _process_activate_event(window_id);
  3963. } else {
  3964. windows[window_id].activate_timer_id = SetTimer(windows[window_id].hWnd, DisplayServerWindows::TIMER_ID_WINDOW_ACTIVATION, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
  3965. }
  3966. return 0;
  3967. } break;
  3968. case WM_GETMINMAXINFO: {
  3969. if (windows[window_id].resizable && !windows[window_id].fullscreen) {
  3970. // Size of window decorations.
  3971. Size2 decor = window_get_size_with_decorations(window_id) - window_get_size(window_id);
  3972. MINMAXINFO *min_max_info = (MINMAXINFO *)lParam;
  3973. if (windows[window_id].min_size != Size2()) {
  3974. min_max_info->ptMinTrackSize.x = windows[window_id].min_size.x + decor.x;
  3975. min_max_info->ptMinTrackSize.y = windows[window_id].min_size.y + decor.y;
  3976. }
  3977. if (windows[window_id].max_size != Size2()) {
  3978. min_max_info->ptMaxTrackSize.x = windows[window_id].max_size.x + decor.x;
  3979. min_max_info->ptMaxTrackSize.y = windows[window_id].max_size.y + decor.y;
  3980. }
  3981. if (windows[window_id].borderless) {
  3982. Rect2i screen_rect = screen_get_usable_rect(window_get_current_screen(window_id));
  3983. // Set the size of (borderless) maximized mode to exclude taskbar (or any other panel) if present.
  3984. min_max_info->ptMaxPosition.x = screen_rect.position.x;
  3985. min_max_info->ptMaxPosition.y = screen_rect.position.y;
  3986. min_max_info->ptMaxSize.x = screen_rect.size.x;
  3987. min_max_info->ptMaxSize.y = screen_rect.size.y;
  3988. }
  3989. return 0;
  3990. }
  3991. } break;
  3992. case WM_ERASEBKGND: {
  3993. Color early_color;
  3994. if (!_get_window_early_clear_override(early_color)) {
  3995. break;
  3996. }
  3997. bool must_recreate_brush = !window_bkg_brush || window_bkg_brush_color != early_color.to_argb32();
  3998. if (must_recreate_brush) {
  3999. if (window_bkg_brush) {
  4000. DeleteObject(window_bkg_brush);
  4001. }
  4002. window_bkg_brush = CreateSolidBrush(RGB(early_color.get_r8(), early_color.get_g8(), early_color.get_b8()));
  4003. }
  4004. HDC hdc = (HDC)wParam;
  4005. RECT rect = {};
  4006. if (GetUpdateRect(hWnd, &rect, true)) {
  4007. FillRect(hdc, &rect, window_bkg_brush);
  4008. }
  4009. return 1;
  4010. } break;
  4011. case WM_PAINT: {
  4012. Main::force_redraw();
  4013. } break;
  4014. case WM_SETTINGCHANGE:
  4015. case WM_SYSCOLORCHANGE: {
  4016. if (lParam && CompareStringOrdinal(reinterpret_cast<LPCWCH>(lParam), -1, L"ImmersiveColorSet", -1, true) == CSTR_EQUAL) {
  4017. if (is_dark_mode_supported() && dark_title_available) {
  4018. BOOL value = is_dark_mode();
  4019. ::DwmSetWindowAttribute(windows[window_id].hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
  4020. }
  4021. }
  4022. if (system_theme_changed.is_valid()) {
  4023. Variant ret;
  4024. Callable::CallError ce;
  4025. system_theme_changed.callp(nullptr, 0, ret, ce);
  4026. if (ce.error != Callable::CallError::CALL_OK) {
  4027. ERR_PRINT(vformat("Failed to execute system theme changed callback: %s.", Variant::get_callable_error_text(system_theme_changed, nullptr, 0, ce)));
  4028. }
  4029. }
  4030. } break;
  4031. case WM_THEMECHANGED: {
  4032. if (is_dark_mode_supported() && dark_title_available) {
  4033. BOOL value = is_dark_mode();
  4034. ::DwmSetWindowAttribute(windows[window_id].hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
  4035. }
  4036. } break;
  4037. case WM_SYSCOMMAND: // Intercept system commands.
  4038. {
  4039. switch (wParam) // Check system calls.
  4040. {
  4041. case SC_SCREENSAVE: // Screensaver trying to start?
  4042. case SC_MONITORPOWER: // Monitor trying to enter powersave?
  4043. return 0; // Prevent from happening.
  4044. case SC_KEYMENU:
  4045. Engine *engine = Engine::get_singleton();
  4046. if (((lParam >> 16) <= 0) && !engine->is_project_manager_hint() && !engine->is_editor_hint() && !GLOBAL_GET_CACHED(bool, "application/run/enable_alt_space_menu")) {
  4047. return 0;
  4048. }
  4049. if (!_get_mods().has_flag(WinKeyModifierMask::ALT) || !(GetAsyncKeyState(VK_SPACE) & (1 << 15))) {
  4050. return 0;
  4051. }
  4052. SendMessage(windows[window_id].hWnd, WM_SYSKEYUP, VK_SPACE, 0);
  4053. SendMessage(windows[window_id].hWnd, WM_SYSKEYUP, VK_MENU, 0);
  4054. }
  4055. } break;
  4056. case WM_INDICATOR_CALLBACK_MESSAGE: {
  4057. if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN || lParam == WM_MBUTTONDOWN || lParam == WM_XBUTTONDOWN) {
  4058. IndicatorID iid = (IndicatorID)wParam;
  4059. MouseButton mb = MouseButton::LEFT;
  4060. if (lParam == WM_RBUTTONDOWN) {
  4061. mb = MouseButton::RIGHT;
  4062. } else if (lParam == WM_MBUTTONDOWN) {
  4063. mb = MouseButton::MIDDLE;
  4064. } else if (lParam == WM_XBUTTONDOWN) {
  4065. mb = MouseButton::MB_XBUTTON1;
  4066. }
  4067. if (indicators.has(iid)) {
  4068. if (lParam == WM_RBUTTONDOWN && indicators[iid].menu_rid.is_valid() && native_menu->has_menu(indicators[iid].menu_rid)) {
  4069. NOTIFYICONIDENTIFIER nid;
  4070. ZeroMemory(&nid, sizeof(NOTIFYICONIDENTIFIER));
  4071. nid.cbSize = sizeof(NOTIFYICONIDENTIFIER);
  4072. nid.hWnd = windows[MAIN_WINDOW_ID].hWnd;
  4073. nid.uID = iid;
  4074. nid.guidItem = GUID_NULL;
  4075. RECT rect;
  4076. if (Shell_NotifyIconGetRect(&nid, &rect) == S_OK) {
  4077. native_menu->popup(indicators[iid].menu_rid, Vector2i((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2));
  4078. }
  4079. } else if (indicators[iid].callback.is_valid()) {
  4080. Variant v_button = mb;
  4081. Variant v_pos = mouse_get_position();
  4082. const Variant *v_args[2] = { &v_button, &v_pos };
  4083. Variant ret;
  4084. Callable::CallError ce;
  4085. indicators[iid].callback.callp((const Variant **)&v_args, 2, ret, ce);
  4086. if (ce.error != Callable::CallError::CALL_OK) {
  4087. ERR_PRINT(vformat("Failed to execute status indicator callback: %s.", Variant::get_callable_error_text(indicators[iid].callback, v_args, 2, ce)));
  4088. }
  4089. }
  4090. }
  4091. return 0;
  4092. }
  4093. } break;
  4094. case WM_CLOSE: {
  4095. if (windows[window_id].activate_timer_id) {
  4096. KillTimer(windows[window_id].hWnd, windows[window_id].activate_timer_id);
  4097. windows[window_id].activate_timer_id = 0;
  4098. }
  4099. _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST);
  4100. return 0;
  4101. }
  4102. case WM_MOUSELEAVE: {
  4103. if (window_mouseover_id == window_id) {
  4104. old_invalid = true;
  4105. window_mouseover_id = INVALID_WINDOW_ID;
  4106. _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
  4107. } else if (window_mouseover_id != INVALID_WINDOW_ID && windows.has(window_mouseover_id)) {
  4108. // This is reached during drag and drop, after dropping in a different window.
  4109. // Once-off notification, must call again.
  4110. track_mouse_leave_event(windows[window_mouseover_id].hWnd);
  4111. }
  4112. } break;
  4113. case WM_INPUT: {
  4114. if (!use_raw_input) {
  4115. break;
  4116. }
  4117. UINT dwSize;
  4118. GetRawInputData((HRAWINPUT)lParam, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER));
  4119. LPBYTE lpb = new BYTE[dwSize];
  4120. if (lpb == nullptr) {
  4121. return 0;
  4122. }
  4123. if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize) {
  4124. OutputDebugString(TEXT("GetRawInputData does not return correct size !\n"));
  4125. }
  4126. RAWINPUT *raw = (RAWINPUT *)lpb;
  4127. const BitField<WinKeyModifierMask> &mods = _get_mods();
  4128. if (raw->header.dwType == RIM_TYPEKEYBOARD) {
  4129. if (raw->data.keyboard.VKey == VK_SHIFT) {
  4130. // If multiple Shifts are held down at the same time,
  4131. // Windows natively only sends a KEYUP for the last one to be released.
  4132. if (raw->data.keyboard.Flags & RI_KEY_BREAK) {
  4133. // Make sure to check the latest key state since
  4134. // we're in the middle of the message queue.
  4135. if (GetAsyncKeyState(VK_SHIFT) < 0) {
  4136. // A Shift is released, but another Shift is still held
  4137. ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
  4138. KeyEvent ke;
  4139. ke.shift = false;
  4140. ke.altgr = mods.has_flag(WinKeyModifierMask::ALT_GR);
  4141. ke.alt = mods.has_flag(WinKeyModifierMask::ALT);
  4142. ke.control = mods.has_flag(WinKeyModifierMask::CTRL);
  4143. ke.meta = mods.has_flag(WinKeyModifierMask::META);
  4144. ke.uMsg = WM_KEYUP;
  4145. ke.window_id = window_id;
  4146. ke.wParam = VK_SHIFT;
  4147. // data.keyboard.MakeCode -> 0x2A - left shift, 0x36 - right shift.
  4148. // Bit 30 -> key was previously down, bit 31 -> key is being released.
  4149. ke.lParam = raw->data.keyboard.MakeCode << 16 | 1 << 30 | 1 << 31;
  4150. key_event_buffer[key_event_pos++] = ke;
  4151. }
  4152. }
  4153. }
  4154. } else if (mouse_mode == MOUSE_MODE_CAPTURED && raw->header.dwType == RIM_TYPEMOUSE) {
  4155. Ref<InputEventMouseMotion> mm;
  4156. mm.instantiate();
  4157. mm->set_window_id(window_id);
  4158. mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL));
  4159. mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT));
  4160. mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT));
  4161. mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META));
  4162. mm->set_pressure((raw->data.mouse.ulButtons & RI_MOUSE_LEFT_BUTTON_DOWN) ? 1.0f : 0.0f);
  4163. mm->set_button_mask(mouse_get_button_state());
  4164. Point2i c(windows[window_id].width / 2, windows[window_id].height / 2);
  4165. // Centering just so it works as before.
  4166. POINT pos = { (int)c.x, (int)c.y };
  4167. ClientToScreen(windows[window_id].hWnd, &pos);
  4168. SetCursorPos(pos.x, pos.y);
  4169. mm->set_position(c);
  4170. mm->set_global_position(c);
  4171. mm->set_velocity(Vector2(0, 0));
  4172. mm->set_screen_velocity(Vector2(0, 0));
  4173. if (raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE) {
  4174. mm->set_relative(Vector2(raw->data.mouse.lLastX, raw->data.mouse.lLastY));
  4175. } else if (raw->data.mouse.usFlags == MOUSE_MOVE_ABSOLUTE) {
  4176. int nScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
  4177. int nScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
  4178. int nScreenLeft = GetSystemMetrics(SM_XVIRTUALSCREEN);
  4179. int nScreenTop = GetSystemMetrics(SM_YVIRTUALSCREEN);
  4180. Vector2 abs_pos(
  4181. (double(raw->data.mouse.lLastX) - 65536.0 / (nScreenWidth)) * nScreenWidth / 65536.0 + nScreenLeft,
  4182. (double(raw->data.mouse.lLastY) - 65536.0 / (nScreenHeight)) * nScreenHeight / 65536.0 + nScreenTop);
  4183. POINT coords; // Client coords.
  4184. coords.x = abs_pos.x;
  4185. coords.y = abs_pos.y;
  4186. ScreenToClient(hWnd, &coords);
  4187. mm->set_relative(Vector2(coords.x - old_x, coords.y - old_y));
  4188. old_x = coords.x;
  4189. old_y = coords.y;
  4190. }
  4191. mm->set_relative_screen_position(mm->get_relative());
  4192. if ((windows[window_id].window_focused || windows[window_id].is_popup) && mm->get_relative() != Vector2()) {
  4193. Input::get_singleton()->parse_input_event(mm);
  4194. }
  4195. }
  4196. delete[] lpb;
  4197. } break;
  4198. case WT_CSRCHANGE:
  4199. case WT_PROXIMITY: {
  4200. if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
  4201. AXIS pressure;
  4202. if (wintab_WTInfo(WTI_DEVICES + windows[window_id].wtlc.lcDevice, DVC_NPRESSURE, &pressure)) {
  4203. windows[window_id].min_pressure = int(pressure.axMin);
  4204. windows[window_id].max_pressure = int(pressure.axMax);
  4205. }
  4206. AXIS orientation[3];
  4207. if (wintab_WTInfo(WTI_DEVICES + windows[window_id].wtlc.lcDevice, DVC_ORIENTATION, &orientation)) {
  4208. windows[window_id].tilt_supported = orientation[0].axResolution && orientation[1].axResolution;
  4209. }
  4210. return 0;
  4211. }
  4212. } break;
  4213. case WT_PACKET: {
  4214. if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
  4215. PACKET packet;
  4216. if (wintab_WTPacket(windows[window_id].wtctx, wParam, &packet)) {
  4217. POINT coords;
  4218. GetCursorPos(&coords);
  4219. ScreenToClient(windows[window_id].hWnd, &coords);
  4220. windows[window_id].last_pressure_update = 0;
  4221. float pressure = float(packet.pkNormalPressure - windows[window_id].min_pressure) / float(windows[window_id].max_pressure - windows[window_id].min_pressure);
  4222. double azim = (packet.pkOrientation.orAzimuth / 10.0f) * (Math::PI / 180);
  4223. double alt = Math::tan((Math::abs(packet.pkOrientation.orAltitude / 10.0f)) * (Math::PI / 180));
  4224. bool inverted = packet.pkStatus & TPS_INVERT;
  4225. Vector2 tilt = (windows[window_id].tilt_supported) ? Vector2(Math::atan(Math::sin(azim) / alt), Math::atan(Math::cos(azim) / alt)) : Vector2();
  4226. // Nothing changed, ignore event.
  4227. if (!old_invalid && coords.x == old_x && coords.y == old_y && windows[window_id].last_pressure == pressure && windows[window_id].last_tilt == tilt && windows[window_id].last_pen_inverted == inverted) {
  4228. break;
  4229. }
  4230. windows[window_id].last_pressure = pressure;
  4231. windows[window_id].last_tilt = tilt;
  4232. windows[window_id].last_pen_inverted = inverted;
  4233. // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
  4234. if (!windows[window_id].window_focused && mouse_mode == MOUSE_MODE_CAPTURED) {
  4235. break;
  4236. }
  4237. const BitField<WinKeyModifierMask> &mods = _get_mods();
  4238. Ref<InputEventMouseMotion> mm;
  4239. mm.instantiate();
  4240. mm->set_window_id(window_id);
  4241. mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL));
  4242. mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT));
  4243. mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT));
  4244. mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META));
  4245. mm->set_pressure(windows[window_id].last_pressure);
  4246. mm->set_tilt(windows[window_id].last_tilt);
  4247. mm->set_pen_inverted(windows[window_id].last_pen_inverted);
  4248. mm->set_button_mask(mouse_get_button_state());
  4249. mm->set_position(Vector2(coords.x, coords.y));
  4250. mm->set_global_position(Vector2(coords.x, coords.y));
  4251. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  4252. Point2i c(windows[window_id].width / 2, windows[window_id].height / 2);
  4253. old_x = c.x;
  4254. old_y = c.y;
  4255. if (mm->get_position() == c) {
  4256. center = c;
  4257. return 0;
  4258. }
  4259. Point2i ncenter = mm->get_position();
  4260. center = ncenter;
  4261. POINT pos = { (int)c.x, (int)c.y };
  4262. ClientToScreen(windows[window_id].hWnd, &pos);
  4263. SetCursorPos(pos.x, pos.y);
  4264. }
  4265. mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
  4266. mm->set_screen_velocity(mm->get_velocity());
  4267. if (old_invalid) {
  4268. old_x = mm->get_position().x;
  4269. old_y = mm->get_position().y;
  4270. old_invalid = false;
  4271. }
  4272. mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
  4273. mm->set_relative_screen_position(mm->get_relative());
  4274. old_x = mm->get_position().x;
  4275. old_y = mm->get_position().y;
  4276. if (windows[window_id].window_focused || window_get_active_popup() == window_id) {
  4277. Input::get_singleton()->parse_input_event(mm);
  4278. }
  4279. }
  4280. return 0;
  4281. }
  4282. } break;
  4283. case WM_POINTERENTER: {
  4284. if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) {
  4285. break;
  4286. }
  4287. if ((tablet_get_current_driver() != "winink") || !winink_available) {
  4288. break;
  4289. }
  4290. uint32_t pointer_id = LOWORD(wParam);
  4291. POINTER_INPUT_TYPE pointer_type = PT_POINTER;
  4292. if (!win8p_GetPointerType(pointer_id, &pointer_type)) {
  4293. break;
  4294. }
  4295. if (pointer_type != PT_PEN) {
  4296. break;
  4297. }
  4298. pointer_button[GET_POINTERID_WPARAM(wParam)] = MouseButton::NONE;
  4299. windows[window_id].block_mm = true;
  4300. return 0;
  4301. } break;
  4302. case WM_POINTERLEAVE: {
  4303. pointer_button[GET_POINTERID_WPARAM(wParam)] = MouseButton::NONE;
  4304. windows[window_id].block_mm = false;
  4305. return 0;
  4306. } break;
  4307. case WM_POINTERDOWN:
  4308. case WM_POINTERUP: {
  4309. if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) {
  4310. break;
  4311. }
  4312. if ((tablet_get_current_driver() != "winink") || !winink_available) {
  4313. break;
  4314. }
  4315. uint32_t pointer_id = LOWORD(wParam);
  4316. POINTER_INPUT_TYPE pointer_type = PT_POINTER;
  4317. if (!win8p_GetPointerType(pointer_id, &pointer_type)) {
  4318. break;
  4319. }
  4320. if (pointer_type != PT_PEN) {
  4321. break;
  4322. }
  4323. Ref<InputEventMouseButton> mb;
  4324. mb.instantiate();
  4325. mb->set_window_id(window_id);
  4326. BitField<MouseButtonMask> last_button_state = MouseButtonMask::NONE;
  4327. if (IS_POINTER_FIRSTBUTTON_WPARAM(wParam)) {
  4328. last_button_state.set_flag(MouseButtonMask::LEFT);
  4329. mb->set_button_index(MouseButton::LEFT);
  4330. }
  4331. if (IS_POINTER_SECONDBUTTON_WPARAM(wParam)) {
  4332. last_button_state.set_flag(MouseButtonMask::RIGHT);
  4333. mb->set_button_index(MouseButton::RIGHT);
  4334. }
  4335. if (IS_POINTER_THIRDBUTTON_WPARAM(wParam)) {
  4336. last_button_state.set_flag(MouseButtonMask::MIDDLE);
  4337. mb->set_button_index(MouseButton::MIDDLE);
  4338. }
  4339. if (IS_POINTER_FOURTHBUTTON_WPARAM(wParam)) {
  4340. last_button_state.set_flag(MouseButtonMask::MB_XBUTTON1);
  4341. mb->set_button_index(MouseButton::MB_XBUTTON1);
  4342. }
  4343. if (IS_POINTER_FIFTHBUTTON_WPARAM(wParam)) {
  4344. last_button_state.set_flag(MouseButtonMask::MB_XBUTTON2);
  4345. mb->set_button_index(MouseButton::MB_XBUTTON2);
  4346. }
  4347. mb->set_button_mask(last_button_state);
  4348. const BitField<WinKeyModifierMask> &mods = _get_mods();
  4349. mb->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL));
  4350. mb->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT));
  4351. mb->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT));
  4352. mb->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META));
  4353. POINT coords; // Client coords.
  4354. coords.x = GET_X_LPARAM(lParam);
  4355. coords.y = GET_Y_LPARAM(lParam);
  4356. // Note: Handle popup closing here, since mouse event is not emulated and hook will not be called.
  4357. uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup;
  4358. if (delta > 250) {
  4359. Point2i pos = Point2i(coords.x, coords.y) - _get_screens_origin();
  4360. List<WindowID>::Element *C = nullptr;
  4361. List<WindowID>::Element *E = popup_list.back();
  4362. // Find top popup to close.
  4363. while (E) {
  4364. // Popup window area.
  4365. Rect2i win_rect = Rect2i(window_get_position_with_decorations(E->get()), window_get_size_with_decorations(E->get()));
  4366. // Area of the parent window, which responsible for opening sub-menu.
  4367. Rect2i safe_rect = window_get_popup_safe_rect(E->get());
  4368. if (win_rect.has_point(pos)) {
  4369. break;
  4370. } else if (safe_rect != Rect2i() && safe_rect.has_point(pos)) {
  4371. break;
  4372. } else {
  4373. C = E;
  4374. E = E->prev();
  4375. }
  4376. }
  4377. if (C) {
  4378. _send_window_event(windows[C->get()], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST);
  4379. }
  4380. }
  4381. int64_t pen_id = GET_POINTERID_WPARAM(wParam);
  4382. if (uMsg == WM_POINTERDOWN) {
  4383. mb->set_pressed(true);
  4384. if (pointer_down_time.has(pen_id) && (pointer_prev_button[pen_id] == mb->get_button_index()) && (Math::abs(coords.y - pointer_last_pos[pen_id].y) < GetSystemMetrics(SM_CYDOUBLECLK)) && GetMessageTime() - pointer_down_time[pen_id] < (LONG)GetDoubleClickTime()) {
  4385. mb->set_double_click(true);
  4386. pointer_down_time[pen_id] = 0;
  4387. } else {
  4388. pointer_down_time[pen_id] = GetMessageTime();
  4389. pointer_prev_button[pen_id] = mb->get_button_index();
  4390. pointer_last_pos[pen_id] = Vector2(coords.x, coords.y);
  4391. }
  4392. pointer_button[pen_id] = mb->get_button_index();
  4393. } else {
  4394. if (!pointer_button.has(pen_id)) {
  4395. return 0;
  4396. }
  4397. mb->set_pressed(false);
  4398. mb->set_button_index(pointer_button[pen_id]);
  4399. pointer_button[pen_id] = MouseButton::NONE;
  4400. }
  4401. ScreenToClient(windows[window_id].hWnd, &coords);
  4402. mb->set_position(Vector2(coords.x, coords.y));
  4403. mb->set_global_position(Vector2(coords.x, coords.y));
  4404. Input::get_singleton()->parse_input_event(mb);
  4405. return 0;
  4406. } break;
  4407. case WM_POINTERUPDATE: {
  4408. if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) {
  4409. break;
  4410. }
  4411. if ((tablet_get_current_driver() != "winink") || !winink_available) {
  4412. break;
  4413. }
  4414. uint32_t pointer_id = LOWORD(wParam);
  4415. POINTER_INPUT_TYPE pointer_type = PT_POINTER;
  4416. if (!win8p_GetPointerType(pointer_id, &pointer_type)) {
  4417. break;
  4418. }
  4419. if (pointer_type != PT_PEN) {
  4420. break;
  4421. }
  4422. POINTER_PEN_INFO pen_info;
  4423. if (!win8p_GetPointerPenInfo(pointer_id, &pen_info)) {
  4424. break;
  4425. }
  4426. if (Input::get_singleton()->is_emulating_mouse_from_touch()) {
  4427. // Universal translation enabled; ignore OS translation.
  4428. LPARAM extra = GetMessageExtraInfo();
  4429. if (IsTouchEvent(extra)) {
  4430. break;
  4431. }
  4432. }
  4433. if (window_mouseover_id != window_id) {
  4434. // Mouse enter.
  4435. if (mouse_mode != MOUSE_MODE_CAPTURED) {
  4436. if (window_mouseover_id != INVALID_WINDOW_ID && windows.has(window_mouseover_id)) {
  4437. // Leave previous window.
  4438. _send_window_event(windows[window_mouseover_id], WINDOW_EVENT_MOUSE_EXIT);
  4439. }
  4440. _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
  4441. }
  4442. CursorShape c = cursor_shape;
  4443. cursor_shape = CURSOR_MAX;
  4444. cursor_set_shape(c);
  4445. window_mouseover_id = window_id;
  4446. // Once-off notification, must call again.
  4447. track_mouse_leave_event(hWnd);
  4448. }
  4449. // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
  4450. if (!windows[window_id].window_focused && mouse_mode == MOUSE_MODE_CAPTURED) {
  4451. break;
  4452. }
  4453. Ref<InputEventMouseMotion> mm;
  4454. mm.instantiate();
  4455. mm->set_window_id(window_id);
  4456. if (pen_info.penMask & PEN_MASK_PRESSURE) {
  4457. mm->set_pressure((float)pen_info.pressure / 1024);
  4458. } else {
  4459. mm->set_pressure((HIWORD(wParam) & POINTER_MESSAGE_FLAG_FIRSTBUTTON) ? 1.0f : 0.0f);
  4460. }
  4461. if ((pen_info.penMask & PEN_MASK_TILT_X) && (pen_info.penMask & PEN_MASK_TILT_Y)) {
  4462. mm->set_tilt(Vector2((float)pen_info.tiltX / 90, (float)pen_info.tiltY / 90));
  4463. }
  4464. mm->set_pen_inverted(pen_info.penFlags & (PEN_FLAG_INVERTED | PEN_FLAG_ERASER));
  4465. const BitField<WinKeyModifierMask> &mods = _get_mods();
  4466. mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL));
  4467. mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT));
  4468. mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT));
  4469. mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META));
  4470. BitField<MouseButtonMask> last_button_state = MouseButtonMask::NONE;
  4471. if (IS_POINTER_FIRSTBUTTON_WPARAM(wParam)) {
  4472. last_button_state.set_flag(MouseButtonMask::LEFT);
  4473. }
  4474. if (IS_POINTER_SECONDBUTTON_WPARAM(wParam)) {
  4475. last_button_state.set_flag(MouseButtonMask::RIGHT);
  4476. }
  4477. if (IS_POINTER_THIRDBUTTON_WPARAM(wParam)) {
  4478. last_button_state.set_flag(MouseButtonMask::MIDDLE);
  4479. }
  4480. if (IS_POINTER_FOURTHBUTTON_WPARAM(wParam)) {
  4481. last_button_state.set_flag(MouseButtonMask::MB_XBUTTON1);
  4482. }
  4483. if (IS_POINTER_FIFTHBUTTON_WPARAM(wParam)) {
  4484. last_button_state.set_flag(MouseButtonMask::MB_XBUTTON2);
  4485. }
  4486. mm->set_button_mask(last_button_state);
  4487. POINT coords; // Client coords.
  4488. coords.x = GET_X_LPARAM(lParam);
  4489. coords.y = GET_Y_LPARAM(lParam);
  4490. ScreenToClient(windows[window_id].hWnd, &coords);
  4491. mm->set_position(Vector2(coords.x, coords.y));
  4492. mm->set_global_position(Vector2(coords.x, coords.y));
  4493. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  4494. Point2i c(windows[window_id].width / 2, windows[window_id].height / 2);
  4495. old_x = c.x;
  4496. old_y = c.y;
  4497. if (mm->get_position() == c) {
  4498. center = c;
  4499. return 0;
  4500. }
  4501. Point2i ncenter = mm->get_position();
  4502. center = ncenter;
  4503. POINT pos = { (int)c.x, (int)c.y };
  4504. ClientToScreen(hWnd, &pos);
  4505. SetCursorPos(pos.x, pos.y);
  4506. }
  4507. mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
  4508. mm->set_screen_velocity(mm->get_velocity());
  4509. if (old_invalid) {
  4510. old_x = mm->get_position().x;
  4511. old_y = mm->get_position().y;
  4512. old_invalid = false;
  4513. }
  4514. mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
  4515. mm->set_relative_screen_position(mm->get_relative());
  4516. old_x = mm->get_position().x;
  4517. old_y = mm->get_position().y;
  4518. if (windows[window_id].window_focused || window_get_active_popup() == window_id) {
  4519. Input::get_singleton()->parse_input_event(mm);
  4520. }
  4521. return 0; // Pointer event handled return 0 to avoid duplicate WM_MOUSEMOVE event.
  4522. } break;
  4523. case WM_MOUSEMOVE: {
  4524. if (windows[window_id].block_mm) {
  4525. break;
  4526. }
  4527. if (mouse_mode == MOUSE_MODE_CAPTURED && use_raw_input) {
  4528. break;
  4529. }
  4530. if (Input::get_singleton()->is_emulating_mouse_from_touch()) {
  4531. // Universal translation enabled; ignore OS translation.
  4532. LPARAM extra = GetMessageExtraInfo();
  4533. if (IsTouchEvent(extra)) {
  4534. break;
  4535. }
  4536. }
  4537. DisplayServer::WindowID over_id = get_window_at_screen_position(mouse_get_position());
  4538. if (windows.has(over_id) && !Rect2(window_get_position(over_id), Point2(windows[over_id].width, windows[over_id].height)).has_point(mouse_get_position())) {
  4539. // Don't consider the windowborder as part of the window.
  4540. over_id = INVALID_WINDOW_ID;
  4541. }
  4542. if (window_mouseover_id != over_id) {
  4543. // Mouse enter.
  4544. if (mouse_mode != MOUSE_MODE_CAPTURED) {
  4545. if (window_mouseover_id != INVALID_WINDOW_ID && windows.has(window_mouseover_id)) {
  4546. // Leave previous window.
  4547. _send_window_event(windows[window_mouseover_id], WINDOW_EVENT_MOUSE_EXIT);
  4548. }
  4549. if (over_id != INVALID_WINDOW_ID && windows.has(over_id)) {
  4550. _send_window_event(windows[over_id], WINDOW_EVENT_MOUSE_ENTER);
  4551. }
  4552. }
  4553. CursorShape c = cursor_shape;
  4554. cursor_shape = CURSOR_MAX;
  4555. cursor_set_shape(c);
  4556. window_mouseover_id = over_id;
  4557. // Once-off notification, must call again.
  4558. track_mouse_leave_event(hWnd);
  4559. }
  4560. // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode.
  4561. if (!windows[window_id].window_focused && mouse_mode == MOUSE_MODE_CAPTURED) {
  4562. break;
  4563. }
  4564. DisplayServer::WindowID receiving_window_id = window_id;
  4565. if (!windows[window_id].no_focus) {
  4566. receiving_window_id = _get_focused_window_or_popup();
  4567. if (receiving_window_id == INVALID_WINDOW_ID) {
  4568. receiving_window_id = window_id;
  4569. }
  4570. }
  4571. const BitField<WinKeyModifierMask> &mods = _get_mods();
  4572. Ref<InputEventMouseMotion> mm;
  4573. mm.instantiate();
  4574. mm->set_window_id(receiving_window_id);
  4575. mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL));
  4576. mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT));
  4577. mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT));
  4578. mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META));
  4579. if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) {
  4580. // Note: WinTab sends both WT_PACKET and WM_xBUTTONDOWN/UP/MOUSEMOVE events, use mouse 1/0 pressure only when last_pressure was not updated recently.
  4581. if (windows[window_id].last_pressure_update < 10) {
  4582. windows[window_id].last_pressure_update++;
  4583. } else {
  4584. windows[window_id].last_tilt = Vector2();
  4585. windows[window_id].last_pressure = (wParam & MK_LBUTTON) ? 1.0f : 0.0f;
  4586. windows[window_id].last_pen_inverted = false;
  4587. }
  4588. } else {
  4589. windows[window_id].last_tilt = Vector2();
  4590. windows[window_id].last_pressure = (wParam & MK_LBUTTON) ? 1.0f : 0.0f;
  4591. windows[window_id].last_pen_inverted = false;
  4592. }
  4593. mm->set_pressure(windows[window_id].last_pressure);
  4594. mm->set_tilt(windows[window_id].last_tilt);
  4595. mm->set_pen_inverted(windows[window_id].last_pen_inverted);
  4596. mm->set_button_mask(mouse_get_button_state());
  4597. mm->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
  4598. mm->set_global_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
  4599. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  4600. Point2i c(windows[window_id].width / 2, windows[window_id].height / 2);
  4601. old_x = c.x;
  4602. old_y = c.y;
  4603. if (mm->get_position() == c) {
  4604. center = c;
  4605. return 0;
  4606. }
  4607. Point2i ncenter = mm->get_position();
  4608. center = ncenter;
  4609. POINT pos = { (int)c.x, (int)c.y };
  4610. ClientToScreen(windows[window_id].hWnd, &pos);
  4611. SetCursorPos(pos.x, pos.y);
  4612. }
  4613. mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
  4614. mm->set_screen_velocity(mm->get_velocity());
  4615. if (old_invalid) {
  4616. old_x = mm->get_position().x;
  4617. old_y = mm->get_position().y;
  4618. old_invalid = false;
  4619. }
  4620. mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
  4621. mm->set_relative_screen_position(mm->get_relative());
  4622. old_x = mm->get_position().x;
  4623. old_y = mm->get_position().y;
  4624. if (receiving_window_id != window_id) {
  4625. // Adjust event position relative to window distance when event is sent to a different window.
  4626. mm->set_position(mm->get_position() - window_get_position(receiving_window_id) + window_get_position(window_id));
  4627. mm->set_global_position(mm->get_position());
  4628. }
  4629. Input::get_singleton()->parse_input_event(mm);
  4630. } break;
  4631. case WM_LBUTTONDOWN:
  4632. case WM_LBUTTONUP:
  4633. if (Input::get_singleton()->is_emulating_mouse_from_touch()) {
  4634. // Universal translation enabled; ignore OS translations for left button.
  4635. LPARAM extra = GetMessageExtraInfo();
  4636. if (IsTouchEvent(extra)) {
  4637. break;
  4638. }
  4639. }
  4640. [[fallthrough]];
  4641. case WM_MBUTTONDOWN:
  4642. case WM_MBUTTONUP:
  4643. case WM_RBUTTONDOWN:
  4644. case WM_RBUTTONUP:
  4645. case WM_MOUSEWHEEL:
  4646. case WM_MOUSEHWHEEL:
  4647. case WM_LBUTTONDBLCLK:
  4648. case WM_MBUTTONDBLCLK:
  4649. case WM_RBUTTONDBLCLK:
  4650. case WM_XBUTTONDBLCLK:
  4651. case WM_XBUTTONDOWN:
  4652. case WM_XBUTTONUP: {
  4653. Ref<InputEventMouseButton> mb;
  4654. mb.instantiate();
  4655. mb->set_window_id(window_id);
  4656. switch (uMsg) {
  4657. case WM_LBUTTONDOWN: {
  4658. mb->set_pressed(true);
  4659. mb->set_button_index(MouseButton::LEFT);
  4660. } break;
  4661. case WM_LBUTTONUP: {
  4662. mb->set_pressed(false);
  4663. mb->set_button_index(MouseButton::LEFT);
  4664. } break;
  4665. case WM_MBUTTONDOWN: {
  4666. mb->set_pressed(true);
  4667. mb->set_button_index(MouseButton::MIDDLE);
  4668. } break;
  4669. case WM_MBUTTONUP: {
  4670. mb->set_pressed(false);
  4671. mb->set_button_index(MouseButton::MIDDLE);
  4672. } break;
  4673. case WM_RBUTTONDOWN: {
  4674. mb->set_pressed(true);
  4675. mb->set_button_index(MouseButton::RIGHT);
  4676. } break;
  4677. case WM_RBUTTONUP: {
  4678. mb->set_pressed(false);
  4679. mb->set_button_index(MouseButton::RIGHT);
  4680. } break;
  4681. case WM_LBUTTONDBLCLK: {
  4682. mb->set_pressed(true);
  4683. mb->set_button_index(MouseButton::LEFT);
  4684. mb->set_double_click(true);
  4685. } break;
  4686. case WM_RBUTTONDBLCLK: {
  4687. mb->set_pressed(true);
  4688. mb->set_button_index(MouseButton::RIGHT);
  4689. mb->set_double_click(true);
  4690. } break;
  4691. case WM_MBUTTONDBLCLK: {
  4692. mb->set_pressed(true);
  4693. mb->set_button_index(MouseButton::MIDDLE);
  4694. mb->set_double_click(true);
  4695. } break;
  4696. case WM_MOUSEWHEEL: {
  4697. mb->set_pressed(true);
  4698. int motion = (short)HIWORD(wParam);
  4699. if (!motion) {
  4700. return 0;
  4701. }
  4702. if (motion > 0) {
  4703. mb->set_button_index(MouseButton::WHEEL_UP);
  4704. } else {
  4705. mb->set_button_index(MouseButton::WHEEL_DOWN);
  4706. }
  4707. mb->set_factor(std::fabs((double)motion / (double)WHEEL_DELTA));
  4708. } break;
  4709. case WM_MOUSEHWHEEL: {
  4710. mb->set_pressed(true);
  4711. int motion = (short)HIWORD(wParam);
  4712. if (!motion) {
  4713. return 0;
  4714. }
  4715. if (motion < 0) {
  4716. mb->set_button_index(MouseButton::WHEEL_LEFT);
  4717. } else {
  4718. mb->set_button_index(MouseButton::WHEEL_RIGHT);
  4719. }
  4720. mb->set_factor(std::fabs((double)motion / (double)WHEEL_DELTA));
  4721. } break;
  4722. case WM_XBUTTONDOWN: {
  4723. mb->set_pressed(true);
  4724. if (HIWORD(wParam) == XBUTTON1) {
  4725. mb->set_button_index(MouseButton::MB_XBUTTON1);
  4726. } else {
  4727. mb->set_button_index(MouseButton::MB_XBUTTON2);
  4728. }
  4729. } break;
  4730. case WM_XBUTTONUP: {
  4731. mb->set_pressed(false);
  4732. if (HIWORD(wParam) == XBUTTON1) {
  4733. mb->set_button_index(MouseButton::MB_XBUTTON1);
  4734. } else {
  4735. mb->set_button_index(MouseButton::MB_XBUTTON2);
  4736. }
  4737. } break;
  4738. case WM_XBUTTONDBLCLK: {
  4739. mb->set_pressed(true);
  4740. if (HIWORD(wParam) == XBUTTON1) {
  4741. mb->set_button_index(MouseButton::MB_XBUTTON1);
  4742. } else {
  4743. mb->set_button_index(MouseButton::MB_XBUTTON2);
  4744. }
  4745. mb->set_double_click(true);
  4746. } break;
  4747. default: {
  4748. return 0;
  4749. }
  4750. }
  4751. const BitField<WinKeyModifierMask> &mods = _get_mods();
  4752. mb->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL));
  4753. mb->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT));
  4754. mb->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT));
  4755. mb->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META));
  4756. if (mb->is_pressed() && mb->get_button_index() >= MouseButton::WHEEL_UP && mb->get_button_index() <= MouseButton::WHEEL_RIGHT) {
  4757. MouseButtonMask mask = mouse_button_to_mask(mb->get_button_index());
  4758. BitField<MouseButtonMask> scroll_mask = mouse_get_button_state();
  4759. scroll_mask.set_flag(mask);
  4760. mb->set_button_mask(scroll_mask);
  4761. } else {
  4762. mb->set_button_mask(mouse_get_button_state());
  4763. }
  4764. mb->set_position(Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
  4765. if (mouse_mode == MOUSE_MODE_CAPTURED && !use_raw_input) {
  4766. mb->set_position(Vector2(old_x, old_y));
  4767. }
  4768. if (uMsg != WM_MOUSEWHEEL && uMsg != WM_MOUSEHWHEEL) {
  4769. if (mb->is_pressed()) {
  4770. if (++pressrc > 0 && mouse_mode != MOUSE_MODE_CAPTURED) {
  4771. SetCapture(hWnd);
  4772. }
  4773. } else {
  4774. if (--pressrc <= 0 || mouse_get_button_state().is_empty()) {
  4775. if (mouse_mode != MOUSE_MODE_CAPTURED) {
  4776. ReleaseCapture();
  4777. }
  4778. pressrc = 0;
  4779. }
  4780. }
  4781. } else {
  4782. // For reasons unknown to humanity, wheel comes in screen coordinates.
  4783. POINT coords;
  4784. coords.x = mb->get_position().x;
  4785. coords.y = mb->get_position().y;
  4786. ScreenToClient(hWnd, &coords);
  4787. mb->set_position(Vector2(coords.x, coords.y));
  4788. }
  4789. mb->set_global_position(mb->get_position());
  4790. Input::get_singleton()->parse_input_event(mb);
  4791. if (mb->is_pressed() && mb->get_button_index() >= MouseButton::WHEEL_UP && mb->get_button_index() <= MouseButton::WHEEL_RIGHT) {
  4792. // Send release for mouse wheel.
  4793. Ref<InputEventMouseButton> mbd = mb->duplicate();
  4794. mbd->set_window_id(window_id);
  4795. mbd->set_button_mask(mouse_get_button_state());
  4796. mbd->set_pressed(false);
  4797. Input::get_singleton()->parse_input_event(mbd);
  4798. }
  4799. // Propagate the button up event to the window on which the button down
  4800. // event was triggered. This is needed for drag & drop to work between windows,
  4801. // because the engine expects events to keep being processed
  4802. // on the same window dragging started.
  4803. if (mb->is_pressed()) {
  4804. last_mouse_button_down_window = window_id;
  4805. } else if (last_mouse_button_down_window != INVALID_WINDOW_ID) {
  4806. mb->set_window_id(last_mouse_button_down_window);
  4807. last_mouse_button_down_window = INVALID_WINDOW_ID;
  4808. }
  4809. } break;
  4810. case WM_WINDOWPOSCHANGED: {
  4811. WindowData &window = windows[window_id];
  4812. int off_x = (window.multiwindow_fs || (!window.fullscreen && window.borderless && IsZoomed(hWnd))) ? FS_TRANSP_BORDER : 0;
  4813. Rect2i window_client_rect;
  4814. Rect2i window_rect;
  4815. {
  4816. RECT rect;
  4817. GetClientRect(hWnd, &rect);
  4818. ClientToScreen(hWnd, (POINT *)&rect.left);
  4819. ClientToScreen(hWnd, (POINT *)&rect.right);
  4820. window_client_rect = Rect2i(rect.left, rect.top, rect.right - rect.left - off_x, rect.bottom - rect.top);
  4821. window_client_rect.position -= _get_screens_origin();
  4822. RECT wrect;
  4823. GetWindowRect(hWnd, &wrect);
  4824. window_rect = Rect2i(wrect.left, wrect.top, wrect.right - wrect.left - off_x, wrect.bottom - wrect.top);
  4825. window_rect.position -= _get_screens_origin();
  4826. }
  4827. WINDOWPOS *window_pos_params = (WINDOWPOS *)lParam;
  4828. bool rect_changed = false;
  4829. if (!(window_pos_params->flags & SWP_NOSIZE) || window_pos_params->flags & SWP_FRAMECHANGED) {
  4830. int screen_id = window_get_current_screen(window_id);
  4831. Size2i screen_size = screen_get_size(screen_id);
  4832. Point2i screen_position = screen_get_position(screen_id);
  4833. window.maximized = false;
  4834. window.minimized = false;
  4835. window.fullscreen = false;
  4836. if (IsIconic(hWnd)) {
  4837. window.minimized = true;
  4838. } else if (IsZoomed(hWnd)) {
  4839. window.maximized = true;
  4840. // If maximized_window_size == screen_size add 1px border to prevent switching to exclusive_fs.
  4841. if (!window.maximized_fs && window.borderless && window_rect.position == screen_position && window_rect.size == screen_size) {
  4842. // Window (borderless) was just maximized and the covers the entire screen.
  4843. window.maximized_fs = true;
  4844. _update_window_style(window_id, false);
  4845. }
  4846. } else if (window_rect.position == screen_position && window_rect.size == screen_size) {
  4847. window.fullscreen = true;
  4848. }
  4849. if (window.maximized_fs && !window.maximized) {
  4850. // Window (maximized and covering fullscreen) was just non-maximized.
  4851. window.maximized_fs = false;
  4852. _update_window_style(window_id, false);
  4853. }
  4854. if (!window.minimized) {
  4855. window.width = window_client_rect.size.width;
  4856. window.height = window_client_rect.size.height;
  4857. rect_changed = true;
  4858. }
  4859. #if defined(RD_ENABLED)
  4860. if (window.create_completed && rendering_context && window.context_created) {
  4861. // Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed.
  4862. rendering_context->window_set_size(window_id, window.width, window.height);
  4863. }
  4864. #endif
  4865. #if defined(GLES3_ENABLED)
  4866. if (window.create_completed && gl_manager_native) {
  4867. gl_manager_native->window_resize(window_id, window.width, window.height);
  4868. }
  4869. if (window.create_completed && gl_manager_angle) {
  4870. gl_manager_angle->window_resize(window_id, window.width, window.height);
  4871. }
  4872. #endif
  4873. }
  4874. if (!window.minimized && (!(window_pos_params->flags & SWP_NOMOVE) || window_pos_params->flags & SWP_FRAMECHANGED)) {
  4875. window.last_pos = window_client_rect.position;
  4876. rect_changed = true;
  4877. }
  4878. if (rect_changed) {
  4879. if (window.rect_changed_callback.is_valid()) {
  4880. window.rect_changed_callback.call(Rect2i(window.last_pos.x, window.last_pos.y, window.width, window.height));
  4881. }
  4882. // Update cursor clip region after window rect has changed.
  4883. if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
  4884. RECT crect;
  4885. GetClientRect(window.hWnd, &crect);
  4886. crect.right -= off_x;
  4887. ClientToScreen(window.hWnd, (POINT *)&crect.left);
  4888. ClientToScreen(window.hWnd, (POINT *)&crect.right);
  4889. ClipCursor(&crect);
  4890. }
  4891. if (!window.minimized && window.was_fullscreen_pre_min) {
  4892. // Restore fullscreen mode if window was in fullscreen before it was minimized.
  4893. int cs = window_get_current_screen(window_id);
  4894. Point2 pos = screen_get_position(cs) + _get_screens_origin();
  4895. Size2 size = screen_get_size(cs);
  4896. window.was_fullscreen_pre_min = false;
  4897. window.fullscreen = true;
  4898. window.maximized = false;
  4899. window.minimized = false;
  4900. _update_window_style(window_id, false);
  4901. MoveWindow(window.hWnd, pos.x, pos.y, size.width, size.height, TRUE);
  4902. }
  4903. } else {
  4904. if (window.parent_hwnd) {
  4905. // WM_WINDOWPOSCHANGED is sent when the parent changes.
  4906. // If we are supposed to have a parent and now we don't, it's likely
  4907. // because the parent was closed. We will close our window as well.
  4908. // This prevents an embedded game from staying alive when the editor is closed or crashes.
  4909. if (!GetParent(window.hWnd)) {
  4910. SendMessage(window.hWnd, WM_CLOSE, 0, 0);
  4911. }
  4912. }
  4913. }
  4914. // Return here to prevent WM_MOVE and WM_SIZE from being sent
  4915. // See: https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-windowposchanged#remarks
  4916. return 0;
  4917. } break;
  4918. case WM_ENTERSIZEMOVE: {
  4919. Input::get_singleton()->release_pressed_events();
  4920. windows[window_id].move_timer_id = SetTimer(windows[window_id].hWnd, DisplayServerWindows::TIMER_ID_MOVE_REDRAW, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
  4921. } break;
  4922. case WM_EXITSIZEMOVE: {
  4923. KillTimer(windows[window_id].hWnd, windows[window_id].move_timer_id);
  4924. windows[window_id].move_timer_id = 0;
  4925. // Reset the correct mouse mode because we couldn't call ReleaseCapture in
  4926. // _set_mouse_mode_impl while in _process_activate_event (because the user was moving a window).
  4927. _set_mouse_mode_impl(mouse_mode);
  4928. } break;
  4929. case WM_TIMER: {
  4930. if (wParam == windows[window_id].move_timer_id) {
  4931. _THREAD_SAFE_UNLOCK_
  4932. _process_key_events();
  4933. if (!Main::is_iterating()) {
  4934. Main::iteration();
  4935. }
  4936. _THREAD_SAFE_LOCK_
  4937. } else if (wParam == windows[window_id].activate_timer_id) {
  4938. _process_activate_event(window_id);
  4939. KillTimer(windows[window_id].hWnd, windows[window_id].activate_timer_id);
  4940. windows[window_id].activate_timer_id = 0;
  4941. windows[window_id].first_activation_done = true;
  4942. }
  4943. } break;
  4944. case WM_SYSKEYUP:
  4945. case WM_KEYUP:
  4946. case WM_SYSKEYDOWN:
  4947. case WM_KEYDOWN: {
  4948. if (windows[window_id].ime_suppress_next_keyup && (uMsg == WM_KEYUP || uMsg == WM_SYSKEYUP)) {
  4949. windows[window_id].ime_suppress_next_keyup = false;
  4950. break;
  4951. }
  4952. if (windows[window_id].ime_in_progress) {
  4953. break;
  4954. }
  4955. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  4956. // When SetCapture is used, ALT+F4 hotkey is ignored by Windows, so handle it ourselves
  4957. if (wParam == VK_F4 && _get_mods().has_flag(WinKeyModifierMask::ALT) && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN)) {
  4958. _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST);
  4959. }
  4960. }
  4961. [[fallthrough]];
  4962. }
  4963. case WM_CHAR: {
  4964. ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
  4965. const BitField<WinKeyModifierMask> &mods = _get_mods();
  4966. KeyEvent ke;
  4967. ke.shift = mods.has_flag(WinKeyModifierMask::SHIFT);
  4968. ke.alt = mods.has_flag(WinKeyModifierMask::ALT);
  4969. ke.altgr = mods.has_flag(WinKeyModifierMask::ALT_GR);
  4970. ke.control = mods.has_flag(WinKeyModifierMask::CTRL);
  4971. ke.meta = mods.has_flag(WinKeyModifierMask::META);
  4972. ke.uMsg = uMsg;
  4973. ke.window_id = window_id;
  4974. if (ke.uMsg == WM_SYSKEYDOWN) {
  4975. ke.uMsg = WM_KEYDOWN;
  4976. }
  4977. if (ke.uMsg == WM_SYSKEYUP) {
  4978. ke.uMsg = WM_KEYUP;
  4979. }
  4980. ke.wParam = wParam;
  4981. ke.lParam = lParam;
  4982. key_event_buffer[key_event_pos++] = ke;
  4983. } break;
  4984. case WM_IME_COMPOSITION: {
  4985. CANDIDATEFORM cf;
  4986. cf.dwIndex = 0;
  4987. cf.dwStyle = CFS_CANDIDATEPOS;
  4988. cf.ptCurrentPos.x = windows[window_id].im_position.x;
  4989. cf.ptCurrentPos.y = windows[window_id].im_position.y;
  4990. ImmSetCandidateWindow(windows[window_id].im_himc, &cf);
  4991. cf.dwStyle = CFS_EXCLUDE;
  4992. cf.rcArea.left = windows[window_id].im_position.x;
  4993. cf.rcArea.right = windows[window_id].im_position.x;
  4994. cf.rcArea.top = windows[window_id].im_position.y;
  4995. cf.rcArea.bottom = windows[window_id].im_position.y;
  4996. ImmSetCandidateWindow(windows[window_id].im_himc, &cf);
  4997. if (windows[window_id].ime_active) {
  4998. SetCaretPos(windows[window_id].im_position.x, windows[window_id].im_position.y);
  4999. OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
  5000. }
  5001. } break;
  5002. case WM_INPUTLANGCHANGEREQUEST: {
  5003. // FIXME: Do something?
  5004. } break;
  5005. case WM_IME_STARTCOMPOSITION: {
  5006. if (windows[window_id].ime_active) {
  5007. windows[window_id].ime_in_progress = true;
  5008. if (key_event_pos > 0) {
  5009. key_event_pos--;
  5010. }
  5011. }
  5012. return 0;
  5013. } break;
  5014. case WM_IME_ENDCOMPOSITION: {
  5015. if (windows[window_id].ime_active) {
  5016. windows[window_id].ime_in_progress = false;
  5017. windows[window_id].ime_suppress_next_keyup = true;
  5018. }
  5019. return 0;
  5020. } break;
  5021. case WM_IME_NOTIFY: {
  5022. return 0;
  5023. } break;
  5024. case WM_TOUCH: {
  5025. BOOL bHandled = FALSE;
  5026. UINT cInputs = LOWORD(wParam);
  5027. PTOUCHINPUT pInputs = memnew_arr(TOUCHINPUT, cInputs);
  5028. if (pInputs) {
  5029. if (GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT))) {
  5030. for (UINT i = 0; i < cInputs; i++) {
  5031. TOUCHINPUT ti = pInputs[i];
  5032. POINT touch_pos = {
  5033. TOUCH_COORD_TO_PIXEL(ti.x),
  5034. TOUCH_COORD_TO_PIXEL(ti.y),
  5035. };
  5036. ScreenToClient(hWnd, &touch_pos);
  5037. // Do something with each touch input entry.
  5038. if (ti.dwFlags & TOUCHEVENTF_MOVE) {
  5039. _drag_event(window_id, touch_pos.x, touch_pos.y, ti.dwID);
  5040. } else if (ti.dwFlags & (TOUCHEVENTF_UP | TOUCHEVENTF_DOWN)) {
  5041. _touch_event(window_id, ti.dwFlags & TOUCHEVENTF_DOWN, touch_pos.x, touch_pos.y, ti.dwID);
  5042. }
  5043. }
  5044. bHandled = TRUE;
  5045. } else {
  5046. // TODO: Handle the error here.
  5047. }
  5048. memdelete_arr(pInputs);
  5049. } else {
  5050. // TODO: Handle the error here, probably out of memory.
  5051. }
  5052. if (bHandled) {
  5053. CloseTouchInputHandle((HTOUCHINPUT)lParam);
  5054. return 0;
  5055. }
  5056. } break;
  5057. case WM_DEVICECHANGE: {
  5058. joypad->probe_joypads();
  5059. } break;
  5060. case WM_DESTROY: {
  5061. #ifdef ACCESSKIT_ENABLED
  5062. if (accessibility_driver) {
  5063. accessibility_driver->window_destroy(window_id);
  5064. }
  5065. #endif
  5066. Input::get_singleton()->flush_buffered_events();
  5067. if (window_mouseover_id == window_id) {
  5068. window_mouseover_id = INVALID_WINDOW_ID;
  5069. _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
  5070. }
  5071. } break;
  5072. case WM_SETCURSOR: {
  5073. if (LOWORD(lParam) == HTCLIENT) {
  5074. if (windows[window_id].window_focused && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN)) {
  5075. // Hide the cursor.
  5076. if (hCursor == nullptr) {
  5077. hCursor = SetCursor(nullptr);
  5078. } else {
  5079. SetCursor(nullptr);
  5080. }
  5081. } else {
  5082. if (hCursor != nullptr) {
  5083. CursorShape c = cursor_shape;
  5084. cursor_shape = CURSOR_MAX;
  5085. cursor_set_shape(c);
  5086. hCursor = nullptr;
  5087. }
  5088. }
  5089. }
  5090. } break;
  5091. default: {
  5092. if (user_proc) {
  5093. return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
  5094. }
  5095. }
  5096. }
  5097. return DefWindowProcW(hWnd, uMsg, wParam, lParam);
  5098. }
  5099. LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  5100. DisplayServerWindows *ds_win = static_cast<DisplayServerWindows *>(DisplayServer::get_singleton());
  5101. if (ds_win) {
  5102. return ds_win->WndProc(hWnd, uMsg, wParam, lParam);
  5103. } else {
  5104. return DefWindowProcW(hWnd, uMsg, wParam, lParam);
  5105. }
  5106. }
  5107. void DisplayServerWindows::_process_activate_event(WindowID p_window_id) {
  5108. WindowData &wd = windows[p_window_id];
  5109. if (wd.activate_state == WA_ACTIVE || wd.activate_state == WA_CLICKACTIVE) {
  5110. last_focused_window = p_window_id;
  5111. _set_mouse_mode_impl(mouse_mode);
  5112. if (!IsIconic(wd.hWnd)) {
  5113. SetFocus(wd.hWnd);
  5114. }
  5115. wd.window_focused = true;
  5116. #ifdef ACCESSKIT_ENABLED
  5117. if (accessibility_driver) {
  5118. accessibility_driver->accessibility_set_window_focused(p_window_id, true);
  5119. }
  5120. #endif
  5121. _send_window_event(wd, WINDOW_EVENT_FOCUS_IN);
  5122. } else { // WM_INACTIVE.
  5123. Input::get_singleton()->release_pressed_events();
  5124. track_mouse_leave_event(wd.hWnd);
  5125. // Release capture unconditionally because it can be set due to dragging, in addition to captured mode.
  5126. // When the user is moving a window, it's important to not ReleaseCapture because it will cause
  5127. // the window movement to stop and if the user tries to move the Windows when it's not activated,
  5128. // it will prevent the window movement. If we are here and a window is moving, it's because we had multiple
  5129. // opened windows in the editor and we are definitively not in a middle of dragging.
  5130. if (!_has_moving_window()) {
  5131. ReleaseCapture();
  5132. }
  5133. wd.window_focused = false;
  5134. #ifdef ACCESSKIT_ENABLED
  5135. if (accessibility_driver) {
  5136. accessibility_driver->accessibility_set_window_focused(p_window_id, false);
  5137. }
  5138. #endif
  5139. _send_window_event(wd, WINDOW_EVENT_FOCUS_OUT);
  5140. }
  5141. if ((tablet_get_current_driver() == "wintab") && wintab_available && wd.wtctx) {
  5142. wintab_WTEnable(wd.wtctx, wd.activate_state);
  5143. }
  5144. }
  5145. void DisplayServerWindows::_process_key_events() {
  5146. for (int i = 0; i < key_event_pos; i++) {
  5147. KeyEvent &ke = key_event_buffer[i];
  5148. switch (ke.uMsg) {
  5149. case WM_CHAR: {
  5150. // Extended keys should only be processed as WM_KEYDOWN message.
  5151. if (!KeyMappingWindows::is_extended_key(ke.wParam) && ((i == 0 && ke.uMsg == WM_CHAR) || (i > 0 && key_event_buffer[i - 1].uMsg == WM_CHAR))) {
  5152. static char32_t prev_wc = 0;
  5153. char32_t unicode = ke.wParam;
  5154. if ((unicode & 0xfffffc00) == 0xd800) {
  5155. if (prev_wc != 0) {
  5156. ERR_PRINT("invalid utf16 surrogate input");
  5157. }
  5158. prev_wc = unicode;
  5159. break; // Skip surrogate.
  5160. } else if ((unicode & 0xfffffc00) == 0xdc00) {
  5161. if (prev_wc == 0) {
  5162. ERR_PRINT("invalid utf16 surrogate input");
  5163. break; // Skip invalid surrogate.
  5164. }
  5165. unicode = (prev_wc << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
  5166. prev_wc = 0;
  5167. } else {
  5168. prev_wc = 0;
  5169. }
  5170. Ref<InputEventKey> k;
  5171. k.instantiate();
  5172. UINT vk = MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK);
  5173. bool is_oem = (vk >= 0xB8) && (vk <= 0xE6);
  5174. Key keycode = KeyMappingWindows::get_keysym(vk);
  5175. Key key_label = keycode;
  5176. Key physical_keycode = KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24));
  5177. static BYTE keyboard_state[256];
  5178. memset(keyboard_state, 0, 256);
  5179. wchar_t chars[256] = {};
  5180. UINT extended_code = MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX);
  5181. if (!(ke.lParam & (1 << 24)) && ToUnicodeEx(extended_code, (ke.lParam >> 16) & 0xFF, keyboard_state, chars, 255, 4, GetKeyboardLayout(0)) > 0) {
  5182. String keysym = String::utf16((char16_t *)chars, 255);
  5183. if (!keysym.is_empty()) {
  5184. char32_t unicode_value = keysym[0];
  5185. // For printable ASCII characters (0x20-0x7E), override the original keycode with the character value.
  5186. if (is_oem && Key::SPACE <= (Key)unicode_value && (Key)unicode_value <= Key::ASCIITILDE) {
  5187. keycode = fix_keycode(unicode_value, (Key)unicode_value);
  5188. }
  5189. key_label = fix_key_label(unicode_value, keycode);
  5190. }
  5191. }
  5192. k->set_window_id(ke.window_id);
  5193. if (keycode != Key::SHIFT) {
  5194. k->set_shift_pressed(ke.shift);
  5195. }
  5196. if (keycode != Key::ALT) {
  5197. k->set_alt_pressed(ke.alt);
  5198. }
  5199. if (keycode != Key::CTRL) {
  5200. k->set_ctrl_pressed(ke.control);
  5201. }
  5202. if (keycode != Key::META) {
  5203. k->set_meta_pressed(ke.meta);
  5204. }
  5205. k->set_pressed(true);
  5206. k->set_keycode(keycode);
  5207. k->set_physical_keycode(physical_keycode);
  5208. k->set_key_label(key_label);
  5209. k->set_unicode(fix_unicode(unicode));
  5210. if (k->get_unicode() && ke.altgr && windows[ke.window_id].ime_active) {
  5211. k->set_alt_pressed(false);
  5212. k->set_ctrl_pressed(false);
  5213. }
  5214. Input::get_singleton()->parse_input_event(k);
  5215. } else {
  5216. // Do nothing.
  5217. }
  5218. } break;
  5219. case WM_KEYUP:
  5220. case WM_KEYDOWN: {
  5221. Ref<InputEventKey> k;
  5222. k.instantiate();
  5223. k->set_window_id(ke.window_id);
  5224. k->set_pressed(ke.uMsg == WM_KEYDOWN);
  5225. bool is_oem = (ke.wParam >= 0xB8) && (ke.wParam <= 0xE6);
  5226. Key keycode = KeyMappingWindows::get_keysym(ke.wParam);
  5227. if ((ke.lParam & (1 << 24)) && (ke.wParam == VK_RETURN)) {
  5228. // Special case for Numpad Enter key.
  5229. keycode = Key::KP_ENTER;
  5230. }
  5231. Key key_label = keycode;
  5232. Key physical_keycode = KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24));
  5233. KeyLocation location = KeyMappingWindows::get_location((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24));
  5234. static BYTE keyboard_state[256];
  5235. memset(keyboard_state, 0, 256);
  5236. wchar_t chars[256] = {};
  5237. UINT extended_code = MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX);
  5238. if (!(ke.lParam & (1 << 24)) && ToUnicodeEx(extended_code, (ke.lParam >> 16) & 0xFF, keyboard_state, chars, 255, 4, GetKeyboardLayout(0)) > 0) {
  5239. String keysym = String::utf16((char16_t *)chars, 255);
  5240. if (!keysym.is_empty()) {
  5241. char32_t unicode_value = keysym[0];
  5242. // For printable ASCII characters (0x20-0x7E), override the original keycode with the character value.
  5243. if (is_oem && Key::SPACE <= (Key)unicode_value && (Key)unicode_value <= Key::ASCIITILDE) {
  5244. keycode = fix_keycode(unicode_value, (Key)unicode_value);
  5245. }
  5246. key_label = fix_key_label(unicode_value, keycode);
  5247. }
  5248. }
  5249. if (keycode != Key::SHIFT) {
  5250. k->set_shift_pressed(ke.shift);
  5251. }
  5252. if (keycode != Key::ALT) {
  5253. k->set_alt_pressed(ke.alt);
  5254. }
  5255. if (keycode != Key::CTRL) {
  5256. k->set_ctrl_pressed(ke.control);
  5257. }
  5258. if (keycode != Key::META) {
  5259. k->set_meta_pressed(ke.meta);
  5260. }
  5261. k->set_keycode(keycode);
  5262. k->set_physical_keycode(physical_keycode);
  5263. k->set_location(location);
  5264. k->set_key_label(key_label);
  5265. if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) {
  5266. char32_t unicode = key_event_buffer[i + 1].wParam;
  5267. static char32_t prev_wck = 0;
  5268. if ((unicode & 0xfffffc00) == 0xd800) {
  5269. if (prev_wck != 0) {
  5270. ERR_PRINT("invalid utf16 surrogate input");
  5271. }
  5272. prev_wck = unicode;
  5273. break; // Skip surrogate.
  5274. } else if ((unicode & 0xfffffc00) == 0xdc00) {
  5275. if (prev_wck == 0) {
  5276. ERR_PRINT("invalid utf16 surrogate input");
  5277. break; // Skip invalid surrogate.
  5278. }
  5279. unicode = (prev_wck << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
  5280. prev_wck = 0;
  5281. } else {
  5282. prev_wck = 0;
  5283. }
  5284. k->set_unicode(fix_unicode(unicode));
  5285. }
  5286. if (k->get_unicode() && ke.altgr && windows[ke.window_id].ime_active) {
  5287. k->set_alt_pressed(false);
  5288. k->set_ctrl_pressed(false);
  5289. }
  5290. k->set_echo((ke.uMsg == WM_KEYDOWN && (ke.lParam & (1 << 30))));
  5291. Input::get_singleton()->parse_input_event(k);
  5292. } break;
  5293. }
  5294. }
  5295. key_event_pos = 0;
  5296. }
  5297. void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const String &p_new_driver) {
  5298. for (KeyValue<WindowID, WindowData> &E : windows) {
  5299. WindowData &wd = E.value;
  5300. wd.block_mm = false;
  5301. if ((p_old_driver == "wintab") && wintab_available && wd.wtctx) {
  5302. wintab_WTEnable(wd.wtctx, false);
  5303. wintab_WTClose(wd.wtctx);
  5304. wd.wtctx = nullptr;
  5305. }
  5306. if ((p_new_driver == "wintab") && wintab_available) {
  5307. wintab_WTInfo(WTI_DEFSYSCTX, 0, &wd.wtlc);
  5308. wd.wtlc.lcOptions |= CXO_MESSAGES;
  5309. wd.wtlc.lcPktData = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION;
  5310. wd.wtlc.lcMoveMask = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE;
  5311. wd.wtlc.lcPktMode = 0;
  5312. wd.wtlc.lcOutOrgX = 0;
  5313. wd.wtlc.lcOutExtX = wd.wtlc.lcInExtX;
  5314. wd.wtlc.lcOutOrgY = 0;
  5315. wd.wtlc.lcOutExtY = -wd.wtlc.lcInExtY;
  5316. wd.wtctx = wintab_WTOpen(wd.hWnd, &wd.wtlc, false);
  5317. if (wd.wtctx) {
  5318. wintab_WTEnable(wd.wtctx, true);
  5319. AXIS pressure;
  5320. if (wintab_WTInfo(WTI_DEVICES + wd.wtlc.lcDevice, DVC_NPRESSURE, &pressure)) {
  5321. wd.min_pressure = int(pressure.axMin);
  5322. wd.max_pressure = int(pressure.axMax);
  5323. }
  5324. AXIS orientation[3];
  5325. if (wintab_WTInfo(WTI_DEVICES + wd.wtlc.lcDevice, DVC_ORIENTATION, &orientation)) {
  5326. wd.tilt_supported = orientation[0].axResolution && orientation[1].axResolution;
  5327. }
  5328. wintab_WTEnable(wd.wtctx, true);
  5329. } else {
  5330. print_verbose("WinTab context creation failed.");
  5331. }
  5332. }
  5333. }
  5334. }
  5335. DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, bool p_exclusive, WindowID p_transient_parent, HWND p_parent_hwnd) {
  5336. DWORD dwExStyle;
  5337. DWORD dwStyle;
  5338. _get_window_style(window_id_counter == MAIN_WINDOW_ID, false, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_flags & WINDOW_FLAG_MINIMIZE_DISABLED_BIT, p_flags & WINDOW_FLAG_MAXIMIZE_DISABLED_BIT, p_mode == WINDOW_MODE_MINIMIZED, p_mode == WINDOW_MODE_MAXIMIZED, false, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP_BIT), p_parent_hwnd, dwStyle, dwExStyle);
  5339. int rq_screen = get_screen_from_rect(p_rect);
  5340. if (rq_screen < 0) {
  5341. rq_screen = get_primary_screen(); // Requested window rect is outside any screen bounds.
  5342. }
  5343. Rect2i usable_rect = screen_get_usable_rect(rq_screen);
  5344. Point2i offset = _get_screens_origin();
  5345. RECT WindowRect;
  5346. int off_x = (p_mode == WINDOW_MODE_FULLSCREEN || ((p_flags & WINDOW_FLAG_BORDERLESS_BIT) && p_mode == WINDOW_MODE_MAXIMIZED)) ? FS_TRANSP_BORDER : 0;
  5347. WindowRect.left = p_rect.position.x;
  5348. WindowRect.right = p_rect.position.x + p_rect.size.x + off_x;
  5349. WindowRect.top = p_rect.position.y;
  5350. WindowRect.bottom = p_rect.position.y + p_rect.size.y;
  5351. if (!p_parent_hwnd) {
  5352. if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
  5353. Rect2i screen_rect = Rect2i(screen_get_position(rq_screen), screen_get_size(rq_screen));
  5354. WindowRect.left = screen_rect.position.x;
  5355. WindowRect.right = screen_rect.position.x + screen_rect.size.x + off_x;
  5356. WindowRect.top = screen_rect.position.y;
  5357. WindowRect.bottom = screen_rect.position.y + screen_rect.size.y;
  5358. } else {
  5359. Rect2i srect = screen_get_usable_rect(rq_screen);
  5360. Point2i wpos = p_rect.position;
  5361. if (srect != Rect2i()) {
  5362. wpos = wpos.clamp(srect.position, srect.position + srect.size - p_rect.size / 3);
  5363. }
  5364. WindowRect.left = wpos.x;
  5365. WindowRect.right = wpos.x + p_rect.size.x + off_x;
  5366. WindowRect.top = wpos.y;
  5367. WindowRect.bottom = wpos.y + p_rect.size.y;
  5368. }
  5369. }
  5370. WindowRect.left += offset.x;
  5371. WindowRect.right += offset.x;
  5372. WindowRect.top += offset.y;
  5373. WindowRect.bottom += offset.y;
  5374. if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
  5375. AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
  5376. }
  5377. WindowID id = window_id_counter;
  5378. {
  5379. WindowData *wd_transient_parent = nullptr;
  5380. HWND owner_hwnd = nullptr;
  5381. if (p_parent_hwnd) {
  5382. owner_hwnd = p_parent_hwnd;
  5383. } else if (p_transient_parent != INVALID_WINDOW_ID) {
  5384. if (!windows.has(p_transient_parent)) {
  5385. ERR_PRINT("Condition \"!windows.has(p_transient_parent)\" is true.");
  5386. p_transient_parent = INVALID_WINDOW_ID;
  5387. } else {
  5388. wd_transient_parent = &windows[p_transient_parent];
  5389. if (p_exclusive) {
  5390. owner_hwnd = wd_transient_parent->hWnd;
  5391. }
  5392. }
  5393. }
  5394. WindowData &wd = windows[id];
  5395. wd.id = id;
  5396. wd.hWnd = CreateWindowExW(
  5397. dwExStyle,
  5398. L"Engine", L"",
  5399. dwStyle,
  5400. WindowRect.left,
  5401. WindowRect.top,
  5402. WindowRect.right - WindowRect.left,
  5403. WindowRect.bottom - WindowRect.top,
  5404. owner_hwnd,
  5405. nullptr,
  5406. hInstance,
  5407. // tunnel the WindowData we need to handle creation message
  5408. // lifetime is ensured because we are still on the stack when this is
  5409. // processed in the window proc
  5410. reinterpret_cast<void *>(&wd));
  5411. if (!wd.hWnd) {
  5412. MessageBoxW(nullptr, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
  5413. windows.erase(id);
  5414. ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Windows OS window.");
  5415. }
  5416. wd.parent_hwnd = p_parent_hwnd;
  5417. // Detach the input queue from the parent window.
  5418. // This prevents the embedded window from waiting on the main window's input queue,
  5419. // causing lags input lags when resizing or moving the main window.
  5420. if (p_parent_hwnd) {
  5421. DWORD mainThreadId = GetWindowThreadProcessId(owner_hwnd, nullptr);
  5422. DWORD embeddedThreadId = GetCurrentThreadId();
  5423. AttachThreadInput(embeddedThreadId, mainThreadId, FALSE);
  5424. }
  5425. if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
  5426. wd.fullscreen = true;
  5427. if (p_mode == WINDOW_MODE_FULLSCREEN) {
  5428. wd.multiwindow_fs = true;
  5429. }
  5430. }
  5431. if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
  5432. // Save initial non-fullscreen rect.
  5433. Rect2i srect = screen_get_usable_rect(rq_screen);
  5434. Point2i wpos = p_rect.position;
  5435. if (srect != Rect2i()) {
  5436. wpos = wpos.clamp(srect.position, srect.position + srect.size - p_rect.size / 3);
  5437. }
  5438. wd.pre_fs_rect.left = wpos.x + offset.x;
  5439. wd.pre_fs_rect.right = wpos.x + p_rect.size.x + offset.x;
  5440. wd.pre_fs_rect.top = wpos.y + offset.y;
  5441. wd.pre_fs_rect.bottom = wpos.y + p_rect.size.y + offset.y;
  5442. wd.pre_fs_valid = true;
  5443. }
  5444. wd.exclusive = p_exclusive;
  5445. if (wd_transient_parent) {
  5446. wd.transient_parent = p_transient_parent;
  5447. wd_transient_parent->transient_children.insert(id);
  5448. }
  5449. wd.sharp_corners = p_flags & WINDOW_FLAG_SHARP_CORNERS_BIT;
  5450. {
  5451. DWORD value = wd.sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT;
  5452. ::DwmSetWindowAttribute(wd.hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value));
  5453. }
  5454. if (is_dark_mode_supported() && dark_title_available) {
  5455. BOOL value = is_dark_mode();
  5456. ::DwmSetWindowAttribute(wd.hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
  5457. }
  5458. RECT real_client_rect;
  5459. GetClientRect(wd.hWnd, &real_client_rect);
  5460. #ifdef RD_ENABLED
  5461. if (rendering_context) {
  5462. union {
  5463. #ifdef VULKAN_ENABLED
  5464. RenderingContextDriverVulkanWindows::WindowPlatformData vulkan;
  5465. #endif
  5466. #ifdef D3D12_ENABLED
  5467. RenderingContextDriverD3D12::WindowPlatformData d3d12;
  5468. #endif
  5469. } wpd;
  5470. #ifdef VULKAN_ENABLED
  5471. if (rendering_driver == "vulkan") {
  5472. wpd.vulkan.window = wd.hWnd;
  5473. wpd.vulkan.instance = hInstance;
  5474. }
  5475. #endif
  5476. #ifdef D3D12_ENABLED
  5477. if (rendering_driver == "d3d12") {
  5478. wpd.d3d12.window = wd.hWnd;
  5479. }
  5480. #endif
  5481. if (rendering_context->window_create(id, &wpd) != OK) {
  5482. ERR_PRINT(vformat("Failed to create %s window.", rendering_driver));
  5483. memdelete(rendering_context);
  5484. rendering_context = nullptr;
  5485. windows.erase(id);
  5486. return INVALID_WINDOW_ID;
  5487. }
  5488. rendering_context->window_set_size(id, real_client_rect.right - real_client_rect.left - off_x, real_client_rect.bottom - real_client_rect.top);
  5489. rendering_context->window_set_vsync_mode(id, p_vsync_mode);
  5490. wd.context_created = true;
  5491. }
  5492. #endif
  5493. #ifdef GLES3_ENABLED
  5494. if (gl_manager_native) {
  5495. if (gl_manager_native->window_create(id, wd.hWnd, hInstance, real_client_rect.right - real_client_rect.left - off_x, real_client_rect.bottom - real_client_rect.top) != OK) {
  5496. memdelete(gl_manager_native);
  5497. gl_manager_native = nullptr;
  5498. windows.erase(id);
  5499. ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window.");
  5500. }
  5501. window_set_vsync_mode(p_vsync_mode, id);
  5502. }
  5503. if (gl_manager_angle) {
  5504. if (gl_manager_angle->window_create(id, nullptr, wd.hWnd, real_client_rect.right - real_client_rect.left - off_x, real_client_rect.bottom - real_client_rect.top) != OK) {
  5505. memdelete(gl_manager_angle);
  5506. gl_manager_angle = nullptr;
  5507. windows.erase(id);
  5508. ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window.");
  5509. }
  5510. window_set_vsync_mode(p_vsync_mode, id);
  5511. }
  5512. #endif
  5513. RegisterTouchWindow(wd.hWnd, 0);
  5514. DragAcceptFiles(wd.hWnd, true);
  5515. if ((tablet_get_current_driver() == "wintab") && wintab_available) {
  5516. wintab_WTInfo(WTI_DEFSYSCTX, 0, &wd.wtlc);
  5517. wd.wtlc.lcOptions |= CXO_MESSAGES;
  5518. wd.wtlc.lcPktData = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION;
  5519. wd.wtlc.lcMoveMask = PK_STATUS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE;
  5520. wd.wtlc.lcPktMode = 0;
  5521. wd.wtlc.lcOutOrgX = 0;
  5522. wd.wtlc.lcOutExtX = wd.wtlc.lcInExtX;
  5523. wd.wtlc.lcOutOrgY = 0;
  5524. wd.wtlc.lcOutExtY = -wd.wtlc.lcInExtY;
  5525. wd.wtctx = wintab_WTOpen(wd.hWnd, &wd.wtlc, false);
  5526. if (wd.wtctx) {
  5527. wintab_WTEnable(wd.wtctx, true);
  5528. AXIS pressure;
  5529. if (wintab_WTInfo(WTI_DEVICES + wd.wtlc.lcDevice, DVC_NPRESSURE, &pressure)) {
  5530. wd.min_pressure = int(pressure.axMin);
  5531. wd.max_pressure = int(pressure.axMax);
  5532. }
  5533. AXIS orientation[3];
  5534. if (wintab_WTInfo(WTI_DEVICES + wd.wtlc.lcDevice, DVC_ORIENTATION, &orientation)) {
  5535. wd.tilt_supported = orientation[0].axResolution && orientation[1].axResolution;
  5536. }
  5537. } else {
  5538. print_verbose("WinTab context creation failed.");
  5539. }
  5540. } else {
  5541. wd.wtctx = nullptr;
  5542. }
  5543. if (p_mode == WINDOW_MODE_MAXIMIZED) {
  5544. wd.maximized = true;
  5545. wd.minimized = false;
  5546. }
  5547. if (p_mode == WINDOW_MODE_MINIMIZED) {
  5548. wd.maximized = false;
  5549. wd.minimized = true;
  5550. }
  5551. wd.last_pressure = 0;
  5552. wd.last_pressure_update = 0;
  5553. wd.last_tilt = Vector2();
  5554. IPropertyStore *prop_store;
  5555. HRESULT hr = SHGetPropertyStoreForWindow(wd.hWnd, IID_IPropertyStore, (void **)&prop_store);
  5556. if (hr == S_OK) {
  5557. PROPVARIANT val;
  5558. String appname;
  5559. if (Engine::get_singleton()->is_editor_hint()) {
  5560. appname = "Godot.GodotEditor." + String(GODOT_VERSION_FULL_CONFIG);
  5561. } else {
  5562. String name = GLOBAL_GET("application/config/name");
  5563. String version = GLOBAL_GET("application/config/version");
  5564. if (version.is_empty()) {
  5565. version = "0";
  5566. }
  5567. String clean_app_name = name.to_pascal_case();
  5568. for (int i = 0; i < clean_app_name.length(); i++) {
  5569. if (!is_ascii_alphanumeric_char(clean_app_name[i]) && clean_app_name[i] != '_' && clean_app_name[i] != '.') {
  5570. clean_app_name[i] = '_';
  5571. }
  5572. }
  5573. clean_app_name = clean_app_name.substr(0, 120 - version.length()).trim_suffix(".");
  5574. appname = "Godot." + clean_app_name + "." + version;
  5575. }
  5576. InitPropVariantFromString((PCWSTR)appname.utf16().get_data(), &val);
  5577. prop_store->SetValue(PKEY_AppUserModel_ID, val);
  5578. prop_store->Release();
  5579. }
  5580. // IME.
  5581. wd.im_himc = ImmGetContext(wd.hWnd);
  5582. ImmAssociateContext(wd.hWnd, (HIMC) nullptr);
  5583. wd.im_position = Vector2();
  5584. if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN || p_mode == WINDOW_MODE_MAXIMIZED) {
  5585. RECT r;
  5586. GetClientRect(wd.hWnd, &r);
  5587. ClientToScreen(wd.hWnd, (POINT *)&r.left);
  5588. ClientToScreen(wd.hWnd, (POINT *)&r.right);
  5589. wd.last_pos = Point2i(r.left, r.top) - _get_screens_origin();
  5590. wd.width = r.right - r.left - off_x;
  5591. wd.height = r.bottom - r.top;
  5592. } else {
  5593. wd.last_pos = p_rect.position;
  5594. wd.width = p_rect.size.width;
  5595. wd.height = p_rect.size.height;
  5596. }
  5597. wd.create_completed = true;
  5598. // Set size of maximized borderless window (by default it covers the entire screen).
  5599. if (!p_parent_hwnd && p_mode == WINDOW_MODE_MAXIMIZED && (p_flags & WINDOW_FLAG_BORDERLESS_BIT)) {
  5600. SetWindowPos(wd.hWnd, HWND_TOP, usable_rect.position.x - off_x, usable_rect.position.y, usable_rect.size.width + off_x, usable_rect.size.height, SWP_NOZORDER | SWP_NOACTIVATE);
  5601. }
  5602. _update_window_mouse_passthrough(id);
  5603. window_id_counter++;
  5604. }
  5605. return id;
  5606. }
  5607. BitField<DisplayServerWindows::DriverID> DisplayServerWindows::tested_drivers = 0;
  5608. // WinTab API.
  5609. bool DisplayServerWindows::wintab_available = false;
  5610. WTOpenPtr DisplayServerWindows::wintab_WTOpen = nullptr;
  5611. WTClosePtr DisplayServerWindows::wintab_WTClose = nullptr;
  5612. WTInfoPtr DisplayServerWindows::wintab_WTInfo = nullptr;
  5613. WTPacketPtr DisplayServerWindows::wintab_WTPacket = nullptr;
  5614. WTEnablePtr DisplayServerWindows::wintab_WTEnable = nullptr;
  5615. // UXTheme API.
  5616. bool DisplayServerWindows::dark_title_available = false;
  5617. bool DisplayServerWindows::use_legacy_dark_mode_before_20H1 = false;
  5618. bool DisplayServerWindows::ux_theme_available = false;
  5619. ShouldAppsUseDarkModePtr DisplayServerWindows::ShouldAppsUseDarkMode = nullptr;
  5620. GetImmersiveColorFromColorSetExPtr DisplayServerWindows::GetImmersiveColorFromColorSetEx = nullptr;
  5621. GetImmersiveColorTypeFromNamePtr DisplayServerWindows::GetImmersiveColorTypeFromName = nullptr;
  5622. GetImmersiveUserColorSetPreferencePtr DisplayServerWindows::GetImmersiveUserColorSetPreference = nullptr;
  5623. // Windows Ink API.
  5624. bool DisplayServerWindows::winink_available = false;
  5625. GetPointerTypePtr DisplayServerWindows::win8p_GetPointerType = nullptr;
  5626. GetPointerPenInfoPtr DisplayServerWindows::win8p_GetPointerPenInfo = nullptr;
  5627. LogicalToPhysicalPointForPerMonitorDPIPtr DisplayServerWindows::win81p_LogicalToPhysicalPointForPerMonitorDPI = nullptr;
  5628. PhysicalToLogicalPointForPerMonitorDPIPtr DisplayServerWindows::win81p_PhysicalToLogicalPointForPerMonitorDPI = nullptr;
  5629. // Shell API,
  5630. SHLoadIndirectStringPtr DisplayServerWindows::load_indirect_string = nullptr;
  5631. Vector2i _get_device_ids(const String &p_device_name) {
  5632. if (p_device_name.is_empty()) {
  5633. return Vector2i();
  5634. }
  5635. REFCLSID clsid = CLSID_WbemLocator; // Unmarshaler CLSID
  5636. REFIID uuid = IID_IWbemLocator; // Interface UUID
  5637. IWbemLocator *wbemLocator = nullptr; // to get the services
  5638. IWbemServices *wbemServices = nullptr; // to get the class
  5639. IEnumWbemClassObject *iter = nullptr;
  5640. IWbemClassObject *pnpSDriverObject[1]; // contains driver name, version, etc.
  5641. HRESULT hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, uuid, (LPVOID *)&wbemLocator);
  5642. if (hr != S_OK) {
  5643. return Vector2i();
  5644. }
  5645. BSTR resource_name = SysAllocString(L"root\\CIMV2");
  5646. hr = wbemLocator->ConnectServer(resource_name, nullptr, nullptr, nullptr, 0, nullptr, nullptr, &wbemServices);
  5647. SysFreeString(resource_name);
  5648. SAFE_RELEASE(wbemLocator) // from now on, use `wbemServices`
  5649. if (hr != S_OK) {
  5650. SAFE_RELEASE(wbemServices)
  5651. return Vector2i();
  5652. }
  5653. Vector2i ids;
  5654. const String gpu_device_class_query = vformat("SELECT * FROM Win32_PnPSignedDriver WHERE DeviceName = \"%s\"", p_device_name);
  5655. BSTR query = SysAllocString((const WCHAR *)gpu_device_class_query.utf16().get_data());
  5656. BSTR query_lang = SysAllocString(L"WQL");
  5657. hr = wbemServices->ExecQuery(query_lang, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, nullptr, &iter);
  5658. SysFreeString(query_lang);
  5659. SysFreeString(query);
  5660. if (hr == S_OK) {
  5661. ULONG resultCount;
  5662. hr = iter->Next(5000, 1, pnpSDriverObject, &resultCount); // Get exactly 1. Wait max 5 seconds.
  5663. if (hr == S_OK && resultCount > 0) {
  5664. VARIANT did;
  5665. VariantInit(&did);
  5666. BSTR object_name = SysAllocString(L"DeviceID");
  5667. hr = pnpSDriverObject[0]->Get(object_name, 0, &did, nullptr, nullptr);
  5668. SysFreeString(object_name);
  5669. if (hr == S_OK) {
  5670. String device_id = String(V_BSTR(&did));
  5671. ids.x = device_id.get_slicec('&', 0).lstrip("PCI\\VEN_").hex_to_int();
  5672. ids.y = device_id.get_slicec('&', 1).lstrip("DEV_").hex_to_int();
  5673. }
  5674. for (ULONG i = 0; i < resultCount; i++) {
  5675. SAFE_RELEASE(pnpSDriverObject[i])
  5676. }
  5677. }
  5678. }
  5679. SAFE_RELEASE(wbemServices)
  5680. SAFE_RELEASE(iter)
  5681. return ids;
  5682. }
  5683. bool DisplayServerWindows::is_dark_mode_supported() const {
  5684. return ux_theme_available;
  5685. }
  5686. bool DisplayServerWindows::is_dark_mode() const {
  5687. return ux_theme_available && ShouldAppsUseDarkMode();
  5688. }
  5689. Color DisplayServerWindows::get_accent_color() const {
  5690. if (!ux_theme_available) {
  5691. return Color(0, 0, 0, 0);
  5692. }
  5693. int argb = GetImmersiveColorFromColorSetEx((UINT)GetImmersiveUserColorSetPreference(false, false), GetImmersiveColorTypeFromName(L"ImmersiveSystemAccent"), false, 0);
  5694. return Color((argb & 0xFF) / 255.f, ((argb & 0xFF00) >> 8) / 255.f, ((argb & 0xFF0000) >> 16) / 255.f, ((argb & 0xFF000000) >> 24) / 255.f);
  5695. }
  5696. Color DisplayServerWindows::get_base_color() const {
  5697. if (!ux_theme_available) {
  5698. return Color(0, 0, 0, 0);
  5699. }
  5700. int argb = GetImmersiveColorFromColorSetEx((UINT)GetImmersiveUserColorSetPreference(false, false), GetImmersiveColorTypeFromName(ShouldAppsUseDarkMode() ? L"ImmersiveDarkChromeMediumLow" : L"ImmersiveLightChromeMediumLow"), false, 0);
  5701. return Color((argb & 0xFF) / 255.f, ((argb & 0xFF00) >> 8) / 255.f, ((argb & 0xFF0000) >> 16) / 255.f, ((argb & 0xFF000000) >> 24) / 255.f);
  5702. }
  5703. void DisplayServerWindows::set_system_theme_change_callback(const Callable &p_callable) {
  5704. system_theme_changed = p_callable;
  5705. }
  5706. int DisplayServerWindows::tablet_get_driver_count() const {
  5707. return tablet_drivers.size();
  5708. }
  5709. String DisplayServerWindows::tablet_get_driver_name(int p_driver) const {
  5710. if (p_driver < 0 || p_driver >= tablet_drivers.size()) {
  5711. return "";
  5712. } else {
  5713. return tablet_drivers[p_driver];
  5714. }
  5715. }
  5716. String DisplayServerWindows::tablet_get_current_driver() const {
  5717. return tablet_driver;
  5718. }
  5719. void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) {
  5720. if (tablet_get_driver_count() == 0) {
  5721. return;
  5722. }
  5723. String driver = p_driver;
  5724. if (driver == "auto") {
  5725. if (winink_available && !winink_disabled) {
  5726. driver = "winink";
  5727. } else if (wintab_available) {
  5728. driver = "wintab";
  5729. } else {
  5730. driver = "dummy";
  5731. }
  5732. }
  5733. bool found = false;
  5734. for (int i = 0; i < tablet_get_driver_count(); i++) {
  5735. if (driver == tablet_get_driver_name(i)) {
  5736. found = true;
  5737. }
  5738. }
  5739. if (found) {
  5740. _update_tablet_ctx(tablet_driver, driver);
  5741. tablet_driver = driver;
  5742. } else {
  5743. ERR_PRINT("Unknown tablet driver " + p_driver + ".");
  5744. }
  5745. }
  5746. DisplayServerWindows::DisplayServerWindows(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) {
  5747. KeyMappingWindows::initialize();
  5748. tested_drivers.clear();
  5749. drop_events = false;
  5750. key_event_pos = 0;
  5751. hInstance = static_cast<OS_Windows *>(OS::get_singleton())->get_hinstance();
  5752. pressrc = 0;
  5753. old_invalid = true;
  5754. mouse_mode = MOUSE_MODE_VISIBLE;
  5755. rendering_driver = p_rendering_driver;
  5756. // Init TTS
  5757. bool tts_enabled = GLOBAL_GET("audio/general/text_to_speech");
  5758. if (tts_enabled) {
  5759. initialize_tts();
  5760. }
  5761. native_menu = memnew(NativeMenuWindows);
  5762. #ifdef ACCESSKIT_ENABLED
  5763. if (accessibility_get_mode() != DisplayServer::AccessibilityMode::ACCESSIBILITY_DISABLED) {
  5764. accessibility_driver = memnew(AccessibilityDriverAccessKit);
  5765. if (accessibility_driver->init() != OK) {
  5766. if (OS::get_singleton()->is_stdout_verbose()) {
  5767. ERR_PRINT("Can't create an accessibility driver, accessibility support disabled!");
  5768. }
  5769. memdelete(accessibility_driver);
  5770. accessibility_driver = nullptr;
  5771. }
  5772. }
  5773. #endif
  5774. // Enforce default keep screen on value.
  5775. screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
  5776. // Load Windows version info.
  5777. ZeroMemory(&os_ver, sizeof(OSVERSIONINFOW));
  5778. os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
  5779. HMODULE nt_lib = LoadLibraryW(L"ntdll.dll");
  5780. if (nt_lib) {
  5781. WineGetVersionPtr wine_get_version = (WineGetVersionPtr)(void *)GetProcAddress(nt_lib, "wine_get_version"); // Do not read Windows build number under Wine, it can be set to arbitrary value.
  5782. if (!wine_get_version) {
  5783. RtlGetVersionPtr RtlGetVersion = (RtlGetVersionPtr)(void *)GetProcAddress(nt_lib, "RtlGetVersion");
  5784. if (RtlGetVersion) {
  5785. RtlGetVersion(&os_ver);
  5786. }
  5787. }
  5788. FreeLibrary(nt_lib);
  5789. }
  5790. // Load Shell API.
  5791. HMODULE shellapi_lib = LoadLibraryW(L"shlwapi.dll");
  5792. if (shellapi_lib) {
  5793. load_indirect_string = (SHLoadIndirectStringPtr)(void *)GetProcAddress(shellapi_lib, "SHLoadIndirectString");
  5794. }
  5795. // Load UXTheme, available on Windows 10+ only.
  5796. if (os_ver.dwBuildNumber >= 10240) {
  5797. HMODULE ux_theme_lib = LoadLibraryW(L"uxtheme.dll");
  5798. if (ux_theme_lib) {
  5799. ShouldAppsUseDarkMode = (ShouldAppsUseDarkModePtr)(void *)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(132));
  5800. GetImmersiveColorFromColorSetEx = (GetImmersiveColorFromColorSetExPtr)(void *)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(95));
  5801. GetImmersiveColorTypeFromName = (GetImmersiveColorTypeFromNamePtr)(void *)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(96));
  5802. GetImmersiveUserColorSetPreference = (GetImmersiveUserColorSetPreferencePtr)(void *)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(98));
  5803. if (os_ver.dwBuildNumber >= 17763) { // Windows 10 Redstone 5 (1809)+ only.
  5804. AllowDarkModeForAppPtr AllowDarkModeForApp = nullptr;
  5805. SetPreferredAppModePtr SetPreferredAppMode = nullptr;
  5806. FlushMenuThemesPtr FlushMenuThemes = nullptr;
  5807. if (os_ver.dwBuildNumber < 18362) { // Windows 10 Redstone 5 (1809) and 19H1 (1903) only.
  5808. AllowDarkModeForApp = (AllowDarkModeForAppPtr)(void *)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(135));
  5809. } else { // Windows 10 19H2 (1909)+ only.
  5810. SetPreferredAppMode = (SetPreferredAppModePtr)(void *)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(135));
  5811. FlushMenuThemes = (FlushMenuThemesPtr)(void *)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(136));
  5812. }
  5813. RefreshImmersiveColorPolicyStatePtr RefreshImmersiveColorPolicyState = (RefreshImmersiveColorPolicyStatePtr)(void *)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(104));
  5814. if (ShouldAppsUseDarkMode) {
  5815. bool dark_mode = ShouldAppsUseDarkMode();
  5816. if (SetPreferredAppMode) {
  5817. SetPreferredAppMode(dark_mode ? APPMODE_ALLOWDARK : APPMODE_DEFAULT);
  5818. } else if (AllowDarkModeForApp) {
  5819. AllowDarkModeForApp(dark_mode);
  5820. }
  5821. if (RefreshImmersiveColorPolicyState) {
  5822. RefreshImmersiveColorPolicyState();
  5823. }
  5824. if (FlushMenuThemes) {
  5825. FlushMenuThemes();
  5826. }
  5827. }
  5828. }
  5829. ux_theme_available = ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference;
  5830. if (os_ver.dwBuildNumber >= 18363) {
  5831. dark_title_available = true;
  5832. if (os_ver.dwBuildNumber < 19041) {
  5833. use_legacy_dark_mode_before_20H1 = true;
  5834. }
  5835. }
  5836. }
  5837. }
  5838. tablet_drivers.push_back("auto");
  5839. // Note: Windows Ink API for pen input, available on Windows 8+ only.
  5840. // Note: DPI conversion API, available on Windows 8.1+ only.
  5841. HMODULE user32_lib = LoadLibraryW(L"user32.dll");
  5842. if (user32_lib) {
  5843. win8p_GetPointerType = (GetPointerTypePtr)(void *)GetProcAddress(user32_lib, "GetPointerType");
  5844. win8p_GetPointerPenInfo = (GetPointerPenInfoPtr)(void *)GetProcAddress(user32_lib, "GetPointerPenInfo");
  5845. win81p_LogicalToPhysicalPointForPerMonitorDPI = (LogicalToPhysicalPointForPerMonitorDPIPtr)(void *)GetProcAddress(user32_lib, "LogicalToPhysicalPointForPerMonitorDPI");
  5846. win81p_PhysicalToLogicalPointForPerMonitorDPI = (PhysicalToLogicalPointForPerMonitorDPIPtr)(void *)GetProcAddress(user32_lib, "PhysicalToLogicalPointForPerMonitorDPI");
  5847. winink_available = win8p_GetPointerType && win8p_GetPointerPenInfo;
  5848. }
  5849. if (winink_available) {
  5850. tablet_drivers.push_back("winink");
  5851. }
  5852. // Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
  5853. HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll");
  5854. if (wintab_lib) {
  5855. wintab_WTOpen = (WTOpenPtr)(void *)GetProcAddress(wintab_lib, "WTOpenW");
  5856. wintab_WTClose = (WTClosePtr)(void *)GetProcAddress(wintab_lib, "WTClose");
  5857. wintab_WTInfo = (WTInfoPtr)(void *)GetProcAddress(wintab_lib, "WTInfoW");
  5858. wintab_WTPacket = (WTPacketPtr)(void *)GetProcAddress(wintab_lib, "WTPacket");
  5859. wintab_WTEnable = (WTEnablePtr)(void *)GetProcAddress(wintab_lib, "WTEnable");
  5860. wintab_available = wintab_WTOpen && wintab_WTClose && wintab_WTInfo && wintab_WTPacket && wintab_WTEnable;
  5861. }
  5862. if (wintab_available) {
  5863. tablet_drivers.push_back("wintab");
  5864. }
  5865. tablet_drivers.push_back("dummy");
  5866. String wacom_cfg = OS::get_singleton()->get_config_path().path_join("WTablet").path_join("Wacom_Tablet.dat");
  5867. if (FileAccess::exists(wacom_cfg)) {
  5868. Ref<XMLParser> parser;
  5869. parser.instantiate();
  5870. if (parser->open(wacom_cfg) == OK) {
  5871. while (parser->read() == OK) {
  5872. if (parser->get_node_type() != XMLParser::NODE_ELEMENT) {
  5873. continue;
  5874. }
  5875. if (parser->get_node_name() == "WinUseInk") {
  5876. parser->read();
  5877. if (parser->get_node_type() == XMLParser::NODE_TEXT) {
  5878. winink_disabled = (parser->get_node_data().to_lower().strip_edges() != "true");
  5879. print_verbose(vformat("Wacom tablet config found at \"%s\", Windows Ink support is %s.", wacom_cfg, winink_disabled ? "disabled" : "enabled"));
  5880. break;
  5881. }
  5882. }
  5883. }
  5884. }
  5885. }
  5886. if (OS::get_singleton()->is_hidpi_allowed()) {
  5887. HMODULE Shcore = LoadLibraryW(L"Shcore.dll");
  5888. if (Shcore != nullptr) {
  5889. typedef HRESULT(WINAPI * SetProcessDpiAwareness_t)(SHC_PROCESS_DPI_AWARENESS);
  5890. SetProcessDpiAwareness_t SetProcessDpiAwareness = (SetProcessDpiAwareness_t)(void *)GetProcAddress(Shcore, "SetProcessDpiAwareness");
  5891. if (SetProcessDpiAwareness) {
  5892. SetProcessDpiAwareness(SHC_PROCESS_SYSTEM_DPI_AWARE);
  5893. }
  5894. }
  5895. }
  5896. HMODULE comctl32 = LoadLibraryW(L"comctl32.dll");
  5897. if (comctl32) {
  5898. typedef BOOL(WINAPI * InitCommonControlsExPtr)(_In_ const INITCOMMONCONTROLSEX *picce);
  5899. InitCommonControlsExPtr init_common_controls_ex = (InitCommonControlsExPtr)(void *)GetProcAddress(comctl32, "InitCommonControlsEx");
  5900. // Fails if the incorrect version was loaded. Probably not a big enough deal to print an error about.
  5901. if (init_common_controls_ex) {
  5902. INITCOMMONCONTROLSEX icc = {};
  5903. icc.dwICC = ICC_STANDARD_CLASSES;
  5904. icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
  5905. if (!init_common_controls_ex(&icc)) {
  5906. WARN_PRINT("Unable to initialize Windows common controls. Native dialogs may not work properly.");
  5907. }
  5908. }
  5909. FreeLibrary(comctl32);
  5910. }
  5911. OleInitialize(nullptr);
  5912. memset(&wc, 0, sizeof(WNDCLASSEXW));
  5913. wc.cbSize = sizeof(WNDCLASSEXW);
  5914. wc.style = CS_OWNDC | CS_DBLCLKS;
  5915. wc.lpfnWndProc = (WNDPROC)::WndProc;
  5916. wc.cbClsExtra = 0;
  5917. wc.cbWndExtra = 0;
  5918. wc.hInstance = hInstance ? hInstance : GetModuleHandle(nullptr);
  5919. wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
  5920. wc.hCursor = nullptr;
  5921. wc.hbrBackground = nullptr;
  5922. wc.lpszMenuName = nullptr;
  5923. wc.lpszClassName = L"Engine";
  5924. if (!RegisterClassExW(&wc)) {
  5925. r_error = ERR_UNAVAILABLE;
  5926. return;
  5927. }
  5928. _register_raw_input_devices(INVALID_WINDOW_ID);
  5929. // Init context and rendering device.
  5930. if (rendering_driver == "dummy") {
  5931. RasterizerDummy::make_current();
  5932. }
  5933. #if defined(RD_ENABLED)
  5934. [[maybe_unused]] bool fallback_to_vulkan = GLOBAL_GET("rendering/rendering_device/fallback_to_vulkan");
  5935. [[maybe_unused]] bool fallback_to_d3d12 = GLOBAL_GET("rendering/rendering_device/fallback_to_d3d12");
  5936. #if defined(VULKAN_ENABLED)
  5937. if (rendering_driver == "vulkan") {
  5938. rendering_context = memnew(RenderingContextDriverVulkanWindows);
  5939. tested_drivers.set_flag(DRIVER_ID_RD_VULKAN);
  5940. }
  5941. #else
  5942. fallback_to_d3d12 = true; // Always enable fallback if engine was built w/o other driver support.
  5943. #endif
  5944. #if defined(D3D12_ENABLED)
  5945. if (rendering_driver == "d3d12") {
  5946. rendering_context = memnew(RenderingContextDriverD3D12);
  5947. tested_drivers.set_flag(DRIVER_ID_RD_D3D12);
  5948. }
  5949. #else
  5950. fallback_to_vulkan = true; // Always enable fallback if engine was built w/o other driver support.
  5951. #endif
  5952. if (rendering_context) {
  5953. if (rendering_context->initialize() != OK) {
  5954. bool failed = true;
  5955. #if defined(VULKAN_ENABLED)
  5956. if (failed && fallback_to_vulkan && rendering_driver != "vulkan") {
  5957. memdelete(rendering_context);
  5958. rendering_context = memnew(RenderingContextDriverVulkanWindows);
  5959. tested_drivers.set_flag(DRIVER_ID_RD_VULKAN);
  5960. if (rendering_context->initialize() == OK) {
  5961. WARN_PRINT("Your video card drivers seem not to support Direct3D 12, switching to Vulkan.");
  5962. rendering_driver = "vulkan";
  5963. OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
  5964. failed = false;
  5965. }
  5966. }
  5967. #endif
  5968. #if defined(D3D12_ENABLED)
  5969. if (failed && fallback_to_d3d12 && rendering_driver != "d3d12") {
  5970. memdelete(rendering_context);
  5971. rendering_context = memnew(RenderingContextDriverD3D12);
  5972. tested_drivers.set_flag(DRIVER_ID_RD_D3D12);
  5973. if (rendering_context->initialize() == OK) {
  5974. WARN_PRINT("Your video card drivers seem not to support Vulkan, switching to Direct3D 12.");
  5975. rendering_driver = "d3d12";
  5976. OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
  5977. failed = false;
  5978. }
  5979. }
  5980. #endif
  5981. #if defined(GLES3_ENABLED)
  5982. bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3");
  5983. if (failed && fallback_to_opengl3 && rendering_driver != "opengl3") {
  5984. memdelete(rendering_context);
  5985. rendering_context = nullptr;
  5986. tested_drivers.set_flag(DRIVER_ID_COMPAT_OPENGL3);
  5987. WARN_PRINT("Your video card drivers seem not to support Direct3D 12 or Vulkan, switching to OpenGL 3.");
  5988. rendering_driver = "opengl3";
  5989. OS::get_singleton()->set_current_rendering_method("gl_compatibility");
  5990. OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
  5991. failed = false;
  5992. }
  5993. #endif
  5994. if (failed) {
  5995. memdelete(rendering_context);
  5996. rendering_context = nullptr;
  5997. r_error = ERR_UNAVAILABLE;
  5998. return;
  5999. }
  6000. }
  6001. }
  6002. #endif
  6003. #if defined(GLES3_ENABLED)
  6004. bool fallback = GLOBAL_GET("rendering/gl_compatibility/fallback_to_angle");
  6005. bool show_warning = true;
  6006. if (rendering_driver == "opengl3") {
  6007. // There's no native OpenGL drivers on Windows for ARM, always enable fallback.
  6008. #if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
  6009. fallback = true;
  6010. show_warning = false;
  6011. #else
  6012. typedef BOOL(WINAPI * IsWow64Process2Ptr)(HANDLE, USHORT *, USHORT *);
  6013. IsWow64Process2Ptr IsWow64Process2 = (IsWow64Process2Ptr)(void *)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process2");
  6014. if (IsWow64Process2) {
  6015. USHORT process_arch = 0;
  6016. USHORT machine_arch = 0;
  6017. if (!IsWow64Process2(GetCurrentProcess(), &process_arch, &machine_arch)) {
  6018. machine_arch = 0;
  6019. }
  6020. if (machine_arch == 0xAA64) {
  6021. fallback = true;
  6022. show_warning = false;
  6023. }
  6024. }
  6025. #endif
  6026. }
  6027. bool gl_supported = true;
  6028. if (fallback && (rendering_driver == "opengl3")) {
  6029. Dictionary gl_info = detect_wgl();
  6030. bool force_angle = false;
  6031. gl_supported = gl_info["version"].operator int() >= 30003;
  6032. Vector2i device_id = _get_device_ids(gl_info["name"]);
  6033. Array device_list = GLOBAL_GET("rendering/gl_compatibility/force_angle_on_devices");
  6034. for (int i = 0; i < device_list.size(); i++) {
  6035. const Dictionary &device = device_list[i];
  6036. if (device.has("vendor") && device.has("name")) {
  6037. const String &vendor = device["vendor"];
  6038. const String &name = device["name"];
  6039. if (device_id != Vector2i() && vendor.begins_with("0x") && name.begins_with("0x") && device_id.x == vendor.lstrip("0x").hex_to_int() && device_id.y == name.lstrip("0x").hex_to_int()) {
  6040. // Check vendor/device IDs.
  6041. force_angle = true;
  6042. break;
  6043. } else if (gl_info["vendor"].operator String().to_upper().contains(vendor.to_upper()) && (name == "*" || gl_info["name"].operator String().to_upper().contains(name.to_upper()))) {
  6044. // Check vendor/device names.
  6045. force_angle = true;
  6046. break;
  6047. }
  6048. }
  6049. }
  6050. if (force_angle || (gl_info["version"].operator int() < 30003)) {
  6051. tested_drivers.set_flag(DRIVER_ID_COMPAT_OPENGL3);
  6052. if (show_warning) {
  6053. if (gl_info["version"].operator int() < 30003) {
  6054. WARN_PRINT("Your video card drivers seem not to support the required OpenGL 3.3 version, switching to ANGLE.");
  6055. } else {
  6056. WARN_PRINT("Your video card drivers are known to have low quality OpenGL 3.3 support, switching to ANGLE.");
  6057. }
  6058. }
  6059. rendering_driver = "opengl3_angle";
  6060. OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
  6061. }
  6062. }
  6063. if (rendering_driver == "opengl3_angle") {
  6064. gl_manager_angle = memnew(GLManagerANGLE_Windows);
  6065. tested_drivers.set_flag(DRIVER_ID_COMPAT_ANGLE_D3D11);
  6066. if (gl_manager_angle->initialize() != OK) {
  6067. memdelete(gl_manager_angle);
  6068. gl_manager_angle = nullptr;
  6069. bool fallback_to_native = GLOBAL_GET("rendering/gl_compatibility/fallback_to_native");
  6070. if (fallback_to_native && gl_supported) {
  6071. #ifdef EGL_STATIC
  6072. WARN_PRINT("Your video card drivers seem not to support GLES3 / ANGLE, switching to native OpenGL.");
  6073. #else
  6074. WARN_PRINT("Your video card drivers seem not to support GLES3 / ANGLE or ANGLE dynamic libraries (libEGL.dll and libGLESv2.dll) are missing, switching to native OpenGL.");
  6075. #endif
  6076. rendering_driver = "opengl3";
  6077. } else {
  6078. r_error = ERR_UNAVAILABLE;
  6079. ERR_FAIL_MSG("Could not initialize ANGLE OpenGL.");
  6080. }
  6081. }
  6082. }
  6083. if (rendering_driver == "opengl3") {
  6084. gl_manager_native = memnew(GLManagerNative_Windows);
  6085. tested_drivers.set_flag(DRIVER_ID_COMPAT_OPENGL3);
  6086. if (gl_manager_native->initialize() != OK) {
  6087. memdelete(gl_manager_native);
  6088. gl_manager_native = nullptr;
  6089. r_error = ERR_UNAVAILABLE;
  6090. ERR_FAIL_MSG("Could not initialize native OpenGL.");
  6091. }
  6092. }
  6093. if (rendering_driver == "opengl3") {
  6094. RasterizerGLES3::make_current(true);
  6095. }
  6096. if (rendering_driver == "opengl3_angle") {
  6097. RasterizerGLES3::make_current(false);
  6098. }
  6099. #endif
  6100. String appname;
  6101. if (Engine::get_singleton()->is_editor_hint()) {
  6102. appname = "Godot.GodotEditor." + String(GODOT_VERSION_FULL_CONFIG);
  6103. } else {
  6104. String name = GLOBAL_GET("application/config/name");
  6105. String version = GLOBAL_GET("application/config/version");
  6106. if (version.is_empty()) {
  6107. version = "0";
  6108. }
  6109. String clean_app_name = name.to_pascal_case();
  6110. for (int i = 0; i < clean_app_name.length(); i++) {
  6111. if (!is_ascii_alphanumeric_char(clean_app_name[i]) && clean_app_name[i] != '_' && clean_app_name[i] != '.') {
  6112. clean_app_name[i] = '_';
  6113. }
  6114. }
  6115. clean_app_name = clean_app_name.substr(0, 120 - version.length()).trim_suffix(".");
  6116. appname = "Godot." + clean_app_name + "." + version;
  6117. #ifndef TOOLS_ENABLED
  6118. // Set for exported projects only.
  6119. HKEY key;
  6120. if (RegOpenKeyW(HKEY_CURRENT_USER_LOCAL_SETTINGS, L"Software\\Microsoft\\Windows\\Shell\\MuiCache", &key) == ERROR_SUCCESS) {
  6121. Char16String cs_name = name.utf16();
  6122. String value_name = OS::get_singleton()->get_executable_path().replace_char('/', '\\') + ".FriendlyAppName";
  6123. RegSetValueExW(key, (LPCWSTR)value_name.utf16().get_data(), 0, REG_SZ, (const BYTE *)cs_name.get_data(), cs_name.size() * sizeof(WCHAR));
  6124. RegCloseKey(key);
  6125. }
  6126. #endif
  6127. }
  6128. SetCurrentProcessExplicitAppUserModelID((PCWSTR)appname.utf16().get_data());
  6129. mouse_monitor = SetWindowsHookEx(WH_MOUSE, ::MouseProc, nullptr, GetCurrentThreadId());
  6130. Point2i window_position;
  6131. if (p_position != nullptr) {
  6132. window_position = *p_position;
  6133. } else {
  6134. if (p_screen == SCREEN_OF_MAIN_WINDOW) {
  6135. p_screen = SCREEN_PRIMARY;
  6136. }
  6137. Rect2i scr_rect = screen_get_usable_rect(p_screen);
  6138. window_position = scr_rect.position + (scr_rect.size - p_resolution) / 2;
  6139. }
  6140. HWND parent_hwnd = NULL;
  6141. if (p_parent_window) {
  6142. // Parented window.
  6143. parent_hwnd = (HWND)p_parent_window;
  6144. }
  6145. WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution), false, INVALID_WINDOW_ID, parent_hwnd);
  6146. if (main_window == INVALID_WINDOW_ID) {
  6147. r_error = ERR_UNAVAILABLE;
  6148. ERR_FAIL_MSG("Failed to create main window.");
  6149. }
  6150. joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd);
  6151. for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
  6152. if (p_flags & (1 << i)) {
  6153. window_set_flag(WindowFlags(i), true, main_window);
  6154. }
  6155. }
  6156. windows[MAIN_WINDOW_ID].initialized = true;
  6157. #ifdef ACCESSKIT_ENABLED
  6158. if (accessibility_screen_reader_active()) {
  6159. _THREAD_SAFE_LOCK_
  6160. uint64_t time_wait = OS::get_singleton()->get_ticks_msec();
  6161. while (true) {
  6162. MSG msg = {};
  6163. while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
  6164. TranslateMessage(&msg);
  6165. DispatchMessageW(&msg);
  6166. }
  6167. uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_wait;
  6168. if (delta > 500 || get_object_recieved) {
  6169. break;
  6170. }
  6171. }
  6172. _THREAD_SAFE_UNLOCK_
  6173. }
  6174. #endif
  6175. #if defined(RD_ENABLED)
  6176. if (rendering_context) {
  6177. rendering_device = memnew(RenderingDevice);
  6178. if (rendering_device->initialize(rendering_context, MAIN_WINDOW_ID) != OK) {
  6179. memdelete(rendering_device);
  6180. rendering_device = nullptr;
  6181. memdelete(rendering_context);
  6182. rendering_context = nullptr;
  6183. r_error = ERR_UNAVAILABLE;
  6184. return;
  6185. }
  6186. rendering_device->screen_create(MAIN_WINDOW_ID);
  6187. RendererCompositorRD::make_current();
  6188. }
  6189. #endif
  6190. if (!Engine::get_singleton()->is_editor_hint() && !OS::get_singleton()->is_in_low_processor_usage_mode()) {
  6191. // Increase priority for projects that are not in low-processor mode (typically games)
  6192. // to reduce the risk of frame stuttering.
  6193. // This is not done for the editor to prevent importers or resource bakers
  6194. // from making the system unresponsive.
  6195. SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
  6196. DWORD index = 0;
  6197. HANDLE handle = AvSetMmThreadCharacteristicsW(L"Games", &index);
  6198. if (handle) {
  6199. AvSetMmThreadPriority(handle, AVRT_PRIORITY_CRITICAL);
  6200. }
  6201. // This is needed to make sure that background work does not starve the main thread.
  6202. // This is only setting the priority of this thread, not the whole process.
  6203. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  6204. }
  6205. cursor_shape = CURSOR_ARROW;
  6206. _update_real_mouse_position(MAIN_WINDOW_ID);
  6207. r_error = OK;
  6208. static_cast<OS_Windows *>(OS::get_singleton())->set_main_window(windows[MAIN_WINDOW_ID].hWnd);
  6209. Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
  6210. }
  6211. Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
  6212. Vector<String> drivers;
  6213. #ifdef VULKAN_ENABLED
  6214. drivers.push_back("vulkan");
  6215. #endif
  6216. #ifdef D3D12_ENABLED
  6217. drivers.push_back("d3d12");
  6218. #endif
  6219. #ifdef GLES3_ENABLED
  6220. drivers.push_back("opengl3");
  6221. drivers.push_back("opengl3_angle");
  6222. #endif
  6223. drivers.push_back("dummy");
  6224. return drivers;
  6225. }
  6226. DisplayServer *DisplayServerWindows::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) {
  6227. DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, p_parent_window, r_error));
  6228. if (r_error != OK) {
  6229. if (tested_drivers == 0) {
  6230. OS::get_singleton()->alert("Failed to register the window class.", "Unable to initialize DisplayServer");
  6231. } else if (tested_drivers.has_flag(DRIVER_ID_RD_VULKAN) || tested_drivers.has_flag(DRIVER_ID_RD_D3D12)) {
  6232. Vector<String> drivers;
  6233. if (tested_drivers.has_flag(DRIVER_ID_RD_VULKAN)) {
  6234. drivers.push_back("Vulkan");
  6235. }
  6236. if (tested_drivers.has_flag(DRIVER_ID_RD_D3D12)) {
  6237. drivers.push_back("Direct3D 12");
  6238. }
  6239. String executable_name = OS::get_singleton()->get_executable_path().get_file();
  6240. OS::get_singleton()->alert(
  6241. vformat("Your video card drivers seem not to support the required %s version.\n\n"
  6242. "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n"
  6243. "You can enable the OpenGL 3 driver by starting the engine from the\n"
  6244. "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n"
  6245. "If you have recently updated your video card drivers, try rebooting.",
  6246. String(" or ").join(drivers),
  6247. executable_name),
  6248. "Unable to initialize video driver");
  6249. } else {
  6250. Vector<String> drivers;
  6251. if (tested_drivers.has_flag(DRIVER_ID_COMPAT_OPENGL3)) {
  6252. drivers.push_back("OpenGL 3.3");
  6253. }
  6254. if (tested_drivers.has_flag(DRIVER_ID_COMPAT_ANGLE_D3D11)) {
  6255. drivers.push_back("Direct3D 11");
  6256. }
  6257. OS::get_singleton()->alert(
  6258. vformat(
  6259. "Your video card drivers seem not to support the required %s version.\n\n"
  6260. "If possible, consider updating your video card drivers.\n\n"
  6261. "If you have recently updated your video card drivers, try rebooting.",
  6262. String(" or ").join(drivers)),
  6263. "Unable to initialize video driver");
  6264. }
  6265. }
  6266. return ds;
  6267. }
  6268. void DisplayServerWindows::register_windows_driver() {
  6269. register_create_function("windows", create_func, get_rendering_drivers_func);
  6270. }
  6271. DisplayServerWindows::~DisplayServerWindows() {
  6272. LocalVector<List<FileDialogData *>::Element *> to_remove;
  6273. for (List<FileDialogData *>::Element *E = file_dialogs.front(); E; E = E->next()) {
  6274. FileDialogData *fd = E->get();
  6275. if (fd->listener_thread.is_started()) {
  6276. fd->close_requested.set();
  6277. fd->listener_thread.wait_to_finish();
  6278. }
  6279. to_remove.push_back(E);
  6280. }
  6281. for (List<FileDialogData *>::Element *E : to_remove) {
  6282. memdelete(E->get());
  6283. E->erase();
  6284. }
  6285. delete joypad;
  6286. touch_state.clear();
  6287. cursors_cache.clear();
  6288. // Destroy all status indicators.
  6289. for (HashMap<IndicatorID, IndicatorData>::Iterator E = indicators.begin(); E; ++E) {
  6290. NOTIFYICONDATAW ndat;
  6291. ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW));
  6292. ndat.cbSize = sizeof(NOTIFYICONDATAW);
  6293. ndat.hWnd = windows[MAIN_WINDOW_ID].hWnd;
  6294. ndat.uID = E->key;
  6295. ndat.uVersion = NOTIFYICON_VERSION;
  6296. Shell_NotifyIconW(NIM_DELETE, &ndat);
  6297. }
  6298. if (mouse_monitor) {
  6299. UnhookWindowsHookEx(mouse_monitor);
  6300. }
  6301. if (user_proc) {
  6302. SetWindowLongPtr(windows[MAIN_WINDOW_ID].hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc);
  6303. }
  6304. // Close power request handle.
  6305. screen_set_keep_on(false);
  6306. if (native_menu) {
  6307. memdelete(native_menu);
  6308. native_menu = nullptr;
  6309. }
  6310. #ifdef GLES3_ENABLED
  6311. // destroy windows .. NYI?
  6312. // FIXME wglDeleteContext is never called
  6313. #endif
  6314. if (windows.has(MAIN_WINDOW_ID)) {
  6315. #ifdef RD_ENABLED
  6316. if (rendering_device) {
  6317. rendering_device->screen_free(MAIN_WINDOW_ID);
  6318. }
  6319. if (rendering_context) {
  6320. rendering_context->window_destroy(MAIN_WINDOW_ID);
  6321. }
  6322. #endif
  6323. if (wintab_available && windows[MAIN_WINDOW_ID].wtctx) {
  6324. wintab_WTClose(windows[MAIN_WINDOW_ID].wtctx);
  6325. windows[MAIN_WINDOW_ID].wtctx = nullptr;
  6326. }
  6327. if (windows[MAIN_WINDOW_ID].drop_target != nullptr) {
  6328. RevokeDragDrop(windows[MAIN_WINDOW_ID].hWnd);
  6329. windows[MAIN_WINDOW_ID].drop_target->Release();
  6330. }
  6331. DestroyWindow(windows[MAIN_WINDOW_ID].hWnd);
  6332. }
  6333. #ifdef RD_ENABLED
  6334. if (rendering_device) {
  6335. memdelete(rendering_device);
  6336. rendering_device = nullptr;
  6337. }
  6338. if (rendering_context) {
  6339. memdelete(rendering_context);
  6340. rendering_context = nullptr;
  6341. }
  6342. #endif
  6343. if (restore_mouse_trails > 1) {
  6344. SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, nullptr, 0);
  6345. }
  6346. #ifdef GLES3_ENABLED
  6347. if (gl_manager_angle) {
  6348. memdelete(gl_manager_angle);
  6349. gl_manager_angle = nullptr;
  6350. }
  6351. if (gl_manager_native) {
  6352. memdelete(gl_manager_native);
  6353. gl_manager_native = nullptr;
  6354. }
  6355. #endif
  6356. #ifdef ACCESSKIT_ENABLED
  6357. if (accessibility_driver) {
  6358. memdelete(accessibility_driver);
  6359. }
  6360. #endif
  6361. if (tts) {
  6362. memdelete(tts);
  6363. }
  6364. OleUninitialize();
  6365. }