display_server_windows.cpp 231 KB

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