display_server_windows.cpp 245 KB

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