display_server_windows.cpp 206 KB

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