RGFW.h 382 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617
  1. /*
  2. *
  3. * RGFW 1.7
  4. *
  5. * Copyright (C) 2022-25 ColleagueRiley
  6. *
  7. * libpng license
  8. *
  9. * This software is provided 'as-is', without any express or implied
  10. * warranty. In no event will the authors be held liable for any damages
  11. * arising from the use of this software.
  12. * Permission is granted to anyone to use this software for any purpose,
  13. * including commercial applications, and to alter it and redistribute it
  14. * freely, subject to the following restrictions:
  15. *
  16. * 1. The origin of this software must not be misrepresented; you must not
  17. * claim that you wrote the original software. If you use this software
  18. * in a product, an acknowledgment in the product documentation would be
  19. * appreciated but is not required.
  20. * 2. Altered source versions must be plainly marked as such, and must not be
  21. * misrepresented as being the original software.
  22. * 3. This notice may not be removed or altered from any source distribution.
  23. *
  24. *
  25. */
  26. /*
  27. (MAKE SURE RGFW_IMPLEMENTATION is in exactly one header or you use -D RGFW_IMPLEMENTATION)
  28. #define RGFW_IMPLEMENTATION - makes it so source code is included with header
  29. */
  30. /*
  31. #define RGFW_IMPLEMENTATION - (required) makes it so the source code is included
  32. #define RGFW_DEBUG - (optional) makes it so RGFW prints debug messages and errors when they're found
  33. #define RGFW_OSMESA - (optional) use OSmesa as backend (instead of system's opengl api + regular opengl)
  34. #define RGFW_BUFFER - (optional) draw directly to (RGFW) window pixel buffer that is drawn to screen (the buffer is in the RGBA format)
  35. #define RGFW_EGL - (optional) use EGL for loading an OpenGL context (instead of the system's opengl api)
  36. #define RGFW_OPENGL_ES1 - (optional) use EGL to load and use Opengl ES (version 1) for backend rendering (instead of the system's opengl api)
  37. This version doesn't work for desktops (I'm pretty sure)
  38. #define RGFW_OPENGL_ES2 - (optional) use OpenGL ES (version 2)
  39. #define RGFW_OPENGL_ES3 - (optional) use OpenGL ES (version 3)
  40. #define RGFW_DIRECTX - (optional) include integration directX functions (windows only)
  41. #define RGFW_VULKAN - (optional) include helpful vulkan integration functions and macros
  42. #define RGFW_WEBGPU - (optional) use webGPU for rendering (Web ONLY)
  43. #define RGFW_NO_API - (optional) don't use any rendering API (no opengl, no vulkan, no directX)
  44. #define RGFW_LINK_EGL (optional) (windows only) if EGL is being used, if EGL functions should be defined dymanically (using GetProcAddress)
  45. #define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS
  46. #define RGFW_WAYLAND (optional) (unix only) use Wayland. (This can be used with X11)
  47. #define RGFW_NO_X11 (optional) (unix only) don't fallback to X11 when using Wayland
  48. #define RGFW_NO_LOAD_WGL (optional) (windows only) if WGL should be loaded dynamically during runtime
  49. #define RGFW_NO_X11_CURSOR (optional) (unix only) don't use XCursor
  50. #define RGFW_NO_X11_CURSOR_PRELOAD (optional) (unix only) use XCursor, but don't link it in code, (you'll have to link it with -lXcursor)
  51. #define RGFW_NO_X11_EXT_PRELOAD (optional) (unix only) use Xext, but don't link it in code, (you'll have to link it with -lXext)
  52. #define RGFW_NO_LOAD_WINMM (optional) (windows only) use winmm (timeBeginPeriod), but don't link it in code, (you'll have to link it with -lwinmm)
  53. #define RGFW_NO_WINMM (optional) (windows only) don't use winmm
  54. #define RGFW_NO_IOKIT (optional) (macOS) don't use IOKit
  55. #define RGFW_NO_UNIX_CLOCK (optional) (unix) don't link unix clock functions
  56. #define RGFW_NO_DWM (windows only) - do not use or link dwmapi
  57. #define RGFW_USE_XDL (optional) (X11) if XDL (XLib Dynamic Loader) should be used to load X11 dynamically during runtime (must include XDL.h along with RGFW)
  58. #define RGFW_COCOA_GRAPHICS_SWITCHING - (optional) (cocoa) use automatic graphics switching (allow the system to choose to use GPU or iGPU)
  59. #define RGFW_COCOA_FRAME_NAME (optional) (cocoa) set frame name
  60. #define RGFW_NO_DPI - do not calculate DPI (no XRM nor libShcore included)
  61. #define RGFW_BUFFER_BGR - use the BGR format for bufffers instead of RGB, saves processing time
  62. #define RGFW_ADVANCED_SMOOTH_RESIZE - use advanced methods for smooth resizing (may result in a spike in memory usage or worse performance) (eg. WM_TIMER and XSyncValue)
  63. #define RGFW_ALLOC x - choose the default allocation function (defaults to standard malloc)
  64. #define RGFW_FREE x - choose the default deallocation function (defaults to standard free)
  65. #define RGFW_USERPTR x - choose the default userptr sent to the malloc call, (NULL by default)
  66. #define RGFW_EXPORT - use when building RGFW
  67. #define RGFW_IMPORT - use when linking with RGFW (not as a single-header)
  68. #define RGFW_USE_INT - force the use c-types rather than stdint.h (for systems that might not have stdint.h (msvc))
  69. #define RGFW_bool x - choose what type to use for bool, by default u32 is used
  70. */
  71. /*
  72. Example to get you started :
  73. linux : gcc main.c -lX11 -lXrandr -lGL
  74. windows : gcc main.c -lopengl32 -lgdi32
  75. macos : gcc main.c -framework Cocoa -framework CoreVideo -framework OpenGL -framework IOKit
  76. #define RGFW_IMPLEMENTATION
  77. #include "RGFW.h"
  78. u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF};
  79. int main() {
  80. RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(100, 100, 500, 500), (u64)0);
  81. RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4);
  82. while (RGFW_window_shouldClose(win) == RGFW_FALSE) {
  83. while (RGFW_window_checkEvent(win)) {
  84. if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_escape))
  85. break;
  86. }
  87. RGFW_window_swapBuffers(win);
  88. glClearColor(1, 1, 1, 1);
  89. glClear(GL_COLOR_BUFFER_BIT);
  90. }
  91. RGFW_window_close(win);
  92. }
  93. compiling :
  94. if you wish to compile the library all you have to do is create a new file with this in it
  95. rgfw.c
  96. #define RGFW_IMPLEMENTATION
  97. #include "RGFW.h"
  98. You may also want to add
  99. `#define RGFW_EXPORT` when compiling and
  100. `#define RGFW_IMPORT`when linking RGFW on it's own:
  101. this reduces inline functions and prevents bloat in the object file
  102. then you can use gcc (or whatever compile you wish to use) to compile the library into object file
  103. ex. gcc -c RGFW.c -fPIC
  104. after you compile the library into an object file, you can also turn the object file into an static or shared library
  105. (commands ar and gcc can be replaced with whatever equivalent your system uses)
  106. static : ar rcs RGFW.a RGFW.o
  107. shared :
  108. windows:
  109. gcc -shared RGFW.o -lopengl32 -lgdi32 -o RGFW.dll
  110. linux:
  111. gcc -shared RGFW.o -lX11 -lGL -lXrandr -o RGFW.so
  112. macos:
  113. gcc -shared RGFW.o -framework CoreVideo -framework Cocoa -framework OpenGL -framework IOKit
  114. */
  115. /*
  116. Credits :
  117. EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support, siliapp.h -> referencing
  118. stb - This project is heavily inspired by the stb single header files
  119. GLFW:
  120. certain parts of winapi and X11 are very poorly documented,
  121. GLFW's source code was referenced and used throughout the project.
  122. contributors : (feel free to put yourself here if you contribute)
  123. krisvers -> code review
  124. EimaMei (SaCode) -> code review
  125. Code-Nycticebus -> bug fixes
  126. Rob Rohan -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs
  127. AICDG (@THISISAGOODNAME) -> vulkan support (example)
  128. @Easymode -> support, testing/debugging, bug fixes and reviews
  129. Joshua Rowe (omnisci3nce) - bug fix, review (macOS)
  130. @lesleyrs -> bug fix, review (OpenGL)
  131. Nick Porcino (meshula) - testing, organization, review (MacOS, examples)
  132. @DarekParodia -> code review (X11) (C++)
  133. */
  134. #if _MSC_VER
  135. #pragma comment(lib, "gdi32")
  136. #pragma comment(lib, "shell32")
  137. #pragma comment(lib, "User32")
  138. #pragma warning( push )
  139. #pragma warning( disable : 4996 4191 4127)
  140. #if _MSC_VER < 600
  141. #define RGFW_C89
  142. #endif
  143. #else
  144. #if defined(__STDC__) && !defined(__STDC_VERSION__)
  145. #define RGFW_C89
  146. #endif
  147. #endif
  148. #ifndef RGFW_USERPTR
  149. #define RGFW_USERPTR NULL
  150. #endif
  151. #ifndef RGFW_UNUSED
  152. #define RGFW_UNUSED(x) (void)(x)
  153. #endif
  154. #ifndef RGFW_ROUND
  155. #define RGFW_ROUND(x) (i32)((x) >= 0 ? (x) + 0.5f : (x) - 0.5f)
  156. #endif
  157. #ifndef RGFW_ALLOC
  158. #include <stdlib.h>
  159. #define RGFW_ALLOC malloc
  160. #define RGFW_FREE free
  161. #endif
  162. #ifndef RGFW_ASSERT
  163. #include <assert.h>
  164. #define RGFW_ASSERT assert
  165. #endif
  166. #if !defined(RGFW_MEMCPY) || !defined(RGFW_STRNCMP) || !defined(RGFW_STRNCPY)
  167. #include <string.h>
  168. #endif
  169. #ifndef RGFW_MEMCPY
  170. #define RGFW_MEMCPY(dist, src, len) memcpy(dist, src, len)
  171. #endif
  172. #ifndef RGFW_STRNCMP
  173. #define RGFW_STRNCMP(s1, s2, max) strncmp(s1, s2, max)
  174. #endif
  175. #ifndef RGFW_STRNCPY
  176. #define RGFW_STRNCPY(dist, src, len) strncpy(dist, src, len)
  177. #endif
  178. #ifndef RGFW_STRSTR
  179. #define RGFW_STRSTR(str, substr) strstr(str, substr)
  180. #endif
  181. #ifndef RGFW_STRTOL
  182. /* required for X11 XDnD and X11 Monitor DPI */
  183. #include <stdlib.h>
  184. #define RGFW_STRTOL(str, endptr, base) strtol(str, endptr, base)
  185. #define RGFW_ATOF(num) atof(num)
  186. #endif
  187. #if !_MSC_VER
  188. #ifndef inline
  189. #ifndef __APPLE__
  190. #define inline __inline
  191. #endif
  192. #endif
  193. #endif
  194. #ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */
  195. #define RGFW_NO_MONITOR
  196. #define RGFW_NO_PASSTHROUGH
  197. #endif
  198. #if defined(RGFW_EXPORT) || defined(RGFW_IMPORT)
  199. #if defined(_WIN32)
  200. #if defined(__TINYC__) && (defined(RGFW_EXPORT) || defined(RGFW_IMPORT))
  201. #define __declspec(x) __attribute__((x))
  202. #endif
  203. #if defined(RGFW_EXPORT)
  204. #define RGFWDEF __declspec(dllexport)
  205. #else
  206. #define RGFWDEF __declspec(dllimport)
  207. #endif
  208. #else
  209. #if defined(RGFW_EXPORT)
  210. #define RGFWDEF __attribute__((visibility("default")))
  211. #endif
  212. #endif
  213. #endif
  214. #ifndef RGFWDEF
  215. #ifdef RGFW_C89
  216. #define RGFWDEF __inline
  217. #else
  218. #define RGFWDEF inline
  219. #endif
  220. #endif
  221. #ifndef RGFW_ENUM
  222. #define RGFW_ENUM(type, name) type name; enum
  223. #endif
  224. #if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
  225. extern "C" {
  226. #endif
  227. /* makes sure the header file part is only defined once by default */
  228. #ifndef RGFW_HEADER
  229. #define RGFW_HEADER
  230. #include <stddef.h>
  231. #ifndef RGFW_INT_DEFINED
  232. #ifdef RGFW_USE_INT /* optional for any system that might not have stdint.h */
  233. typedef unsigned char u8;
  234. typedef signed char i8;
  235. typedef unsigned short u16;
  236. typedef signed short i16;
  237. typedef unsigned long int u32;
  238. typedef signed long int i32;
  239. typedef unsigned long long u64;
  240. typedef signed long long i64;
  241. #else /* use stdint standard types instead of c ""standard"" types */
  242. #include <stdint.h>
  243. typedef uint8_t u8;
  244. typedef int8_t i8;
  245. typedef uint16_t u16;
  246. typedef int16_t i16;
  247. typedef uint32_t u32;
  248. typedef int32_t i32;
  249. typedef uint64_t u64;
  250. typedef int64_t i64;
  251. #endif
  252. #define RGFW_INT_DEFINED
  253. #endif
  254. #ifndef RGFW_BOOL_DEFINED
  255. #define RGFW_BOOL_DEFINED
  256. typedef u8 RGFW_bool;
  257. #endif
  258. #define RGFW_BOOL(x) (RGFW_bool)((x) ? RGFW_TRUE : RGFW_FALSE) /* force an value to be 0 or 1 */
  259. #define RGFW_TRUE (RGFW_bool)1
  260. #define RGFW_FALSE (RGFW_bool)0
  261. /* these OS macros look better & are standardized */
  262. /* plus it helps with cross-compiling */
  263. #ifdef __EMSCRIPTEN__
  264. #define RGFW_WASM
  265. #if !defined(RGFW_NO_API) && !defined(RGFW_WEBGPU)
  266. #define RGFW_OPENGL
  267. #endif
  268. #ifdef RGFW_EGL
  269. #undef RGFW_EGL
  270. #endif
  271. #include <emscripten/html5.h>
  272. #include <emscripten/key_codes.h>
  273. #ifdef RGFW_WEBGPU
  274. #include <emscripten/html5_webgpu.h>
  275. #endif
  276. #endif
  277. #if defined(RGFW_X11) && defined(__APPLE__) && !defined(RGFW_CUSTOM_BACKEND)
  278. #define RGFW_MACOS_X11
  279. #define RGFW_UNIX
  280. #undef __APPLE__
  281. #endif
  282. #if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_UNIX) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND) /* (if you're using X11 on windows some how) */
  283. #define RGFW_WINDOWS
  284. /* make sure the correct architecture is defined */
  285. #if defined(_WIN64)
  286. #define _AMD64_
  287. #undef _X86_
  288. #else
  289. #undef _AMD64_
  290. #ifndef _X86_
  291. #define _X86_
  292. #endif
  293. #endif
  294. #ifndef RGFW_NO_XINPUT
  295. #ifdef __MINGW32__ /* try to find the right header */
  296. #include <xinput.h>
  297. #else
  298. #include <XInput.h>
  299. #endif
  300. #endif
  301. #endif
  302. #if defined(RGFW_WAYLAND)
  303. #define RGFW_DEBUG /* wayland will be in debug mode by default for now */
  304. #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA)
  305. #define RGFW_EGL
  306. #define RGFW_OPENGL
  307. #define RGFW_UNIX
  308. #include <wayland-egl.h>
  309. #endif
  310. #include <wayland-client.h>
  311. #endif
  312. #if !defined(RGFW_NO_X11) && !defined(RGFW_NO_X11) && (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND)
  313. #define RGFW_MACOS_X11
  314. #define RGFW_X11
  315. #define RGFW_UNIX
  316. #include <X11/Xlib.h>
  317. #include <X11/Xutil.h>
  318. #elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WASM) && !defined(RGFW_CUSTOM_BACKEND)
  319. #define RGFW_MACOS
  320. #if !defined(RGFW_BUFFER_BGR)
  321. #define RGFW_BUFFER_BGR
  322. #else
  323. #undef RGFW_BUFFER_BGR
  324. #endif
  325. #endif
  326. #if (defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)) && !defined(RGFW_EGL)
  327. #define RGFW_EGL
  328. #endif
  329. #if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API)
  330. #define RGFW_OPENGL
  331. #endif
  332. #ifdef RGFW_EGL
  333. #include <EGL/egl.h>
  334. #elif defined(RGFW_OSMESA)
  335. #ifdef RGFW_WINDOWS
  336. #define OEMRESOURCE
  337. #include <GL/gl.h>
  338. #ifndef GLAPIENTRY
  339. #define GLAPIENTRY APIENTRY
  340. #endif
  341. #ifndef GLAPI
  342. #define GLAPI WINGDIAPI
  343. #endif
  344. #endif
  345. #ifndef __APPLE__
  346. #include <GL/osmesa.h>
  347. #else
  348. #include <OpenGL/osmesa.h>
  349. #endif
  350. #endif
  351. #if (defined(RGFW_OPENGL) || defined(RGFW_WEGL)) && defined(_MSC_VER)
  352. #pragma comment(lib, "opengl32")
  353. #endif
  354. #if defined(RGFW_OPENGL) && defined(RGFW_X11)
  355. #ifndef GLX_MESA_swap_control
  356. #define GLX_MESA_swap_control
  357. #endif
  358. #include <GL/glx.h> /* GLX defs, xlib.h, gl.h */
  359. #endif
  360. #define RGFW_COCOA_FRAME_NAME NULL
  361. /*! (unix) Toggle use of wayland. This will be on by default if you use `RGFW_WAYLAND` (if you don't use RGFW_WAYLAND, you don't expose WAYLAND functions)
  362. this is mostly used to allow you to force the use of XWayland
  363. */
  364. RGFWDEF void RGFW_useWayland(RGFW_bool wayland);
  365. RGFWDEF RGFW_bool RGFW_usingWayland(void);
  366. /*
  367. regular RGFW stuff
  368. */
  369. #define RGFW_key u8
  370. typedef RGFW_ENUM(u8, RGFW_eventType) {
  371. /*! event codes */
  372. RGFW_eventNone = 0, /*!< no event has been sent */
  373. RGFW_keyPressed, /* a key has been pressed */
  374. RGFW_keyReleased, /*!< a key has been released */
  375. /*! key event note
  376. the code of the key pressed is stored in
  377. RGFW_event.key
  378. !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!!
  379. while a string version is stored in
  380. RGFW_event.KeyString
  381. RGFW_event.keyMod holds the current keyMod
  382. this means if CapsLock, NumLock are active or not
  383. */
  384. RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right) */
  385. RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right) */
  386. RGFW_mousePosChanged, /*!< the position of the mouse has been changed */
  387. /*! mouse event note
  388. the x and y of the mouse can be found in the vector, RGFW_event.point
  389. RGFW_event.button holds which mouse button was pressed
  390. */
  391. RGFW_gamepadConnected, /*!< a gamepad was connected */
  392. RGFW_gamepadDisconnected, /*!< a gamepad was disconnected */
  393. RGFW_gamepadButtonPressed, /*!< a gamepad button was pressed */
  394. RGFW_gamepadButtonReleased, /*!< a gamepad button was released */
  395. RGFW_gamepadAxisMove, /*!< an axis of a gamepad was moved */
  396. /*! gamepad event note
  397. RGFW_event.gamepad holds which gamepad was altered, if any
  398. RGFW_event.button holds which gamepad button was pressed
  399. RGFW_event.axis holds the data of all the axises
  400. RGFW_event.axisesCount says how many axises there are
  401. */
  402. RGFW_windowMoved, /*!< the window was moved (by the user) */
  403. RGFW_windowResized, /*!< the window was resized (by the user), [on WASM this means the browser was resized] */
  404. RGFW_focusIn, /*!< window is in focus now */
  405. RGFW_focusOut, /*!< window is out of focus now */
  406. RGFW_mouseEnter, /* mouse entered the window */
  407. RGFW_mouseLeave, /* mouse left the window */
  408. RGFW_windowRefresh, /* The window content needs to be refreshed */
  409. /* attribs change event note
  410. The event data is sent straight to the window structure
  411. with win->r.x, win->r.y, win->r.w and win->r.h
  412. */
  413. RGFW_quit, /*!< the user clicked the quit button */
  414. RGFW_DND, /*!< a file has been dropped into the window */
  415. RGFW_DNDInit, /*!< the start of a dnd event, when the place where the file drop is known */
  416. /* dnd data note
  417. The x and y coords of the drop are stored in the vector RGFW_event.point
  418. RGFW_event.droppedFilesCount holds how many files were dropped
  419. This is also the size of the array which stores all the dropped file string,
  420. RGFW_event.droppedFiles
  421. */
  422. RGFW_windowMaximized, /*!< the window was maximized */
  423. RGFW_windowMinimized, /*!< the window was minimized */
  424. RGFW_windowRestored, /*!< the window was restored */
  425. RGFW_scaleUpdated /*!< content scale factor changed */
  426. };
  427. /*! mouse button codes (RGFW_event.button) */
  428. typedef RGFW_ENUM(u8, RGFW_mouseButton) {
  429. RGFW_mouseLeft = 0, /*!< left mouse button is pressed */
  430. RGFW_mouseMiddle, /*!< mouse-wheel-button is pressed */
  431. RGFW_mouseRight, /*!< right mouse button is pressed */
  432. RGFW_mouseScrollUp, /*!< mouse wheel is scrolling up */
  433. RGFW_mouseScrollDown, /*!< mouse wheel is scrolling down */
  434. RGFW_mouseMisc1, RGFW_mouseMisc2, RGFW_mouseMisc3, RGFW_mouseMisc4, RGFW_mouseMisc5,
  435. RGFW_mouseFinal
  436. };
  437. #ifndef RGFW_MAX_PATH
  438. #define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */
  439. #endif
  440. #ifndef RGFW_MAX_DROPS
  441. #define RGFW_MAX_DROPS 260 /* max items you can drop at once */
  442. #endif
  443. #define RGFW_BIT(x) (1 << x)
  444. /* for RGFW_event.lockstate */
  445. typedef RGFW_ENUM(u8, RGFW_keymod) {
  446. RGFW_modCapsLock = RGFW_BIT(0),
  447. RGFW_modNumLock = RGFW_BIT(1),
  448. RGFW_modControl = RGFW_BIT(2),
  449. RGFW_modAlt = RGFW_BIT(3),
  450. RGFW_modShift = RGFW_BIT(4),
  451. RGFW_modSuper = RGFW_BIT(5),
  452. RGFW_modScrollLock = RGFW_BIT(6)
  453. };
  454. /*! gamepad button codes (based on xbox/playstation), you may need to change these values per controller */
  455. typedef RGFW_ENUM(u8, RGFW_gamepadCodes) {
  456. RGFW_gamepadNone = 0, /*!< or PS X button */
  457. RGFW_gamepadA, /*!< or PS X button */
  458. RGFW_gamepadB, /*!< or PS circle button */
  459. RGFW_gamepadY, /*!< or PS triangle button */
  460. RGFW_gamepadX, /*!< or PS square button */
  461. RGFW_gamepadStart, /*!< start button */
  462. RGFW_gamepadSelect, /*!< select button */
  463. RGFW_gamepadHome, /*!< home button */
  464. RGFW_gamepadUp, /*!< dpad up */
  465. RGFW_gamepadDown, /*!< dpad down */
  466. RGFW_gamepadLeft, /*!< dpad left */
  467. RGFW_gamepadRight, /*!< dpad right */
  468. RGFW_gamepadL1, /*!< left bump */
  469. RGFW_gamepadL2, /*!< left trigger */
  470. RGFW_gamepadR1, /*!< right bumper */
  471. RGFW_gamepadR2, /*!< right trigger */
  472. RGFW_gamepadL3, /* left thumb stick */
  473. RGFW_gamepadR3, /*!< right thumb stick */
  474. RGFW_gamepadFinal
  475. };
  476. /*! basic vector type, if there's not already a point/vector type of choice */
  477. #ifndef RGFW_point
  478. typedef struct { i32 x, y; } RGFW_point;
  479. #endif
  480. /*! basic rect type, if there's not already a rect type of choice */
  481. #ifndef RGFW_rect
  482. typedef struct { i32 x, y, w, h; } RGFW_rect;
  483. #endif
  484. /*! basic area type, if there's not already a area type of choice */
  485. #ifndef RGFW_area
  486. typedef struct { u32 w, h; } RGFW_area;
  487. #endif
  488. #if defined(__cplusplus) && !defined(__APPLE__)
  489. #define RGFW_POINT(x, y) {(i32)x, (i32)y}
  490. #define RGFW_RECT(x, y, w, h) {(i32)x, (i32)y, (i32)w, (i32)h}
  491. #define RGFW_AREA(w, h) {(u32)w, (u32)h}
  492. #else
  493. #define RGFW_POINT(x, y) (RGFW_point){(i32)(x), (i32)(y)}
  494. #define RGFW_RECT(x, y, w, h) (RGFW_rect){(i32)(x), (i32)(y), (i32)(w), (i32)(h)}
  495. #define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)}
  496. #endif
  497. #ifndef RGFW_NO_MONITOR
  498. /* monitor mode data | can be changed by the user (with functions)*/
  499. typedef struct RGFW_monitorMode {
  500. RGFW_area area; /*!< monitor workarea size */
  501. u32 refreshRate; /*!< monitor refresh rate */
  502. u8 red, blue, green;
  503. } RGFW_monitorMode;
  504. /*! structure for monitor data */
  505. typedef struct RGFW_monitor {
  506. i32 x, y; /*!< x - y of the monitor workarea */
  507. char name[128]; /*!< monitor name */
  508. float scaleX, scaleY; /*!< monitor content scale */
  509. float pixelRatio; /*!< pixel ratio for monitor (1.0 for regular, 2.0 for hiDPI) */
  510. float physW, physH; /*!< monitor physical size in inches */
  511. RGFW_monitorMode mode;
  512. } RGFW_monitor;
  513. /*! get an array of all the monitors (max 6) */
  514. RGFWDEF RGFW_monitor* RGFW_getMonitors(size_t* len);
  515. /*! get the primary monitor */
  516. RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void);
  517. typedef RGFW_ENUM(u8, RGFW_modeRequest) {
  518. RGFW_monitorScale = RGFW_BIT(0), /*!< scale the monitor size */
  519. RGFW_monitorRefresh = RGFW_BIT(1), /*!< change the refresh rate */
  520. RGFW_monitorRGB = RGFW_BIT(2), /*!< change the monitor RGB bits size */
  521. RGFW_monitorAll = RGFW_monitorScale | RGFW_monitorRefresh | RGFW_monitorRGB
  522. };
  523. /*! request a specific mode */
  524. RGFWDEF RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request);
  525. /*! check if 2 monitor modes are the same */
  526. RGFWDEF RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request);
  527. #endif
  528. /* RGFW mouse loading */
  529. typedef void RGFW_mouse;
  530. /*!< loads mouse icon from bitmap (similar to RGFW_window_setIcon). Icon NOT resized by default */
  531. RGFWDEF RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels);
  532. /*!< frees RGFW_mouse data */
  533. RGFWDEF void RGFW_freeMouse(RGFW_mouse* mouse);
  534. /* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_event struct) */
  535. /*! Event structure for checking/getting events */
  536. typedef struct RGFW_event {
  537. RGFW_eventType type; /*!< which event has been sent?*/
  538. RGFW_point point; /*!< mouse x, y of event (or drop point) */
  539. RGFW_point vector; /*!< raw mouse movement */
  540. float scaleX, scaleY; /*!< DPI scaling */
  541. RGFW_key key; /*!< the physical key of the event, refers to where key is physically !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */
  542. u8 keyChar; /*!< mapped key char of the event */
  543. RGFW_bool repeat; /*!< key press event repeated (the key is being held) */
  544. RGFW_keymod keyMod;
  545. u8 button; /* !< which mouse (or gamepad) button was pressed */
  546. double scroll; /*!< the raw mouse scroll value */
  547. u16 gamepad; /*! which gamepad this event applies to (if applicable to any) */
  548. u8 axisesCount; /*!< number of axises */
  549. u8 whichAxis; /* which axis was effected */
  550. RGFW_point axis[4]; /*!< x, y of axises (-100 to 100) */
  551. /*! drag and drop data */
  552. /* 260 max paths with a max length of 260 */
  553. char** droppedFiles; /*!< dropped files */
  554. size_t droppedFilesCount; /*!< house many files were dropped */
  555. void* _win; /*!< the window this event applies too (for event queue events) */
  556. } RGFW_event;
  557. /*! source data for the window (used by the APIs) */
  558. #ifdef RGFW_WINDOWS
  559. typedef struct RGFW_window_src {
  560. HWND window; /*!< source window */
  561. HDC hdc; /*!< source HDC */
  562. u32 hOffset; /*!< height offset for window */
  563. HICON hIconSmall, hIconBig; /*!< source window icons */
  564. #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
  565. HGLRC ctx; /*!< source graphics context */
  566. #elif defined(RGFW_OSMESA)
  567. OSMesaContext ctx;
  568. #elif defined(RGFW_EGL)
  569. EGLSurface EGL_surface;
  570. EGLDisplay EGL_display;
  571. EGLContext EGL_context;
  572. #endif
  573. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  574. HDC hdcMem;
  575. HBITMAP bitmap;
  576. u8* bitmapBits;
  577. #endif
  578. RGFW_area maxSize, minSize, aspectRatio; /*!< for setting max/min resize (RGFW_WINDOWS) */
  579. } RGFW_window_src;
  580. #elif defined(RGFW_UNIX)
  581. typedef struct RGFW_window_src {
  582. #if defined(RGFW_X11)
  583. Display* display; /*!< source display */
  584. Window window; /*!< source window */
  585. #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
  586. GLXContext ctx; /*!< source graphics context */
  587. GLXFBConfig bestFbc;
  588. #elif defined(RGFW_OSMESA)
  589. OSMesaContext ctx;
  590. #elif defined(RGFW_EGL)
  591. EGLSurface EGL_surface;
  592. EGLDisplay EGL_display;
  593. EGLContext EGL_context;
  594. #endif
  595. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  596. XImage* bitmap;
  597. #endif
  598. GC gc;
  599. XVisualInfo visual;
  600. #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
  601. i64 counter_value;
  602. XID counter;
  603. #endif
  604. #endif /* RGFW_X11 */
  605. #if defined(RGFW_WAYLAND)
  606. struct wl_display* wl_display;
  607. struct wl_surface* surface;
  608. struct wl_buffer* wl_buffer;
  609. struct wl_keyboard* keyboard;
  610. struct wl_compositor* compositor;
  611. struct xdg_surface* xdg_surface;
  612. struct xdg_toplevel* xdg_toplevel;
  613. struct zxdg_toplevel_decoration_v1* decoration;
  614. struct xdg_wm_base* xdg_wm_base;
  615. struct wl_shm* shm;
  616. struct wl_seat *seat;
  617. u8* buffer;
  618. #if defined(RGFW_EGL)
  619. struct wl_egl_window* eglWindow;
  620. #endif
  621. #if defined(RGFW_EGL) && !defined(RGFW_X11)
  622. EGLSurface EGL_surface;
  623. EGLDisplay EGL_display;
  624. EGLContext EGL_context;
  625. #elif defined(RGFW_OSMESA) && !defined(RGFW_X11)
  626. OSMesaContext ctx;
  627. #endif
  628. #endif /* RGFW_WAYLAND */
  629. } RGFW_window_src;
  630. #endif /* RGFW_UNIX */
  631. #if defined(RGFW_MACOS)
  632. typedef struct RGFW_window_src {
  633. void* window;
  634. #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
  635. void* ctx; /*!< source graphics context */
  636. #elif defined(RGFW_OSMESA)
  637. OSMesaContext ctx;
  638. #elif defined(RGFW_EGL)
  639. EGLSurface EGL_surface;
  640. EGLDisplay EGL_display;
  641. EGLContext EGL_context;
  642. #endif
  643. void* view; /* apple viewpoint thingy */
  644. void* mouse;
  645. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  646. #endif
  647. } RGFW_window_src;
  648. #elif defined(RGFW_WASM)
  649. typedef struct RGFW_window_src {
  650. #if defined(RGFW_WEBGPU)
  651. WGPUInstance ctx;
  652. WGPUDevice device;
  653. WGPUQueue queue;
  654. #elif defined(RGFW_OSMESA)
  655. OSMesaContext ctx;
  656. #else
  657. EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
  658. #endif
  659. } RGFW_window_src;
  660. #endif
  661. /*! Optional arguments for making a windows */
  662. typedef RGFW_ENUM(u32, RGFW_windowFlags) {
  663. RGFW_windowNoInitAPI = RGFW_BIT(0), /* do NOT init an API (including the software rendering buffer) (mostly for bindings. you can also use `#define RGFW_NO_API`) */
  664. RGFW_windowNoBorder = RGFW_BIT(1), /*!< the window doesn't have a border */
  665. RGFW_windowNoResize = RGFW_BIT(2), /*!< the window cannot be resized by the user */
  666. RGFW_windowAllowDND = RGFW_BIT(3), /*!< the window supports drag and drop */
  667. RGFW_windowHideMouse = RGFW_BIT(4), /*! the window should hide the mouse (can be toggled later on using `RGFW_window_mouseShow`) */
  668. RGFW_windowFullscreen = RGFW_BIT(5), /*!< the window is fullscreen by default */
  669. RGFW_windowTransparent = RGFW_BIT(6), /*!< the window is transparent (only properly works on X11 and MacOS, although it's meant for for windows) */
  670. RGFW_windowCenter = RGFW_BIT(7), /*! center the window on the screen */
  671. RGFW_windowOpenglSoftware = RGFW_BIT(8), /*! use OpenGL software rendering */
  672. RGFW_windowCocoaCHDirToRes = RGFW_BIT(9), /*! (cocoa only), change directory to resource folder */
  673. RGFW_windowScaleToMonitor = RGFW_BIT(10), /*! scale the window to the screen */
  674. RGFW_windowHide = RGFW_BIT(11), /*! the window is hidden */
  675. RGFW_windowMaximize = RGFW_BIT(12),
  676. RGFW_windowCenterCursor = RGFW_BIT(13),
  677. RGFW_windowFloating = RGFW_BIT(14), /*!< create a floating window */
  678. RGFW_windowFreeOnClose = RGFW_BIT(15), /*!< free (RGFW_window_close) the RGFW_window struct when the window is closed (by the end user) */
  679. RGFW_windowFocusOnShow = RGFW_BIT(16), /*!< focus the window when it's shown */
  680. RGFW_windowMinimize = RGFW_BIT(17), /*!< focus the window when it's shown */
  681. RGFW_windowFocus = RGFW_BIT(18), /*!< if the window is in focus */
  682. RGFW_windowedFullscreen = RGFW_windowNoBorder | RGFW_windowMaximize
  683. };
  684. typedef struct RGFW_window {
  685. RGFW_window_src src; /*!< src window data */
  686. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  687. u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */
  688. /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */
  689. RGFW_area bufferSize;
  690. #endif
  691. void* userPtr; /* ptr for usr data */
  692. RGFW_event event; /*!< current event */
  693. RGFW_rect r; /*!< the x, y, w and h of the struct */
  694. RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */
  695. u32 _flags; /*!< windows flags (for RGFW to check) */
  696. RGFW_rect _oldRect; /*!< rect before fullscreen */
  697. } RGFW_window; /*!< window structure for managing the window */
  698. #if defined(RGFW_X11) || defined(RGFW_MACOS)
  699. typedef u64 RGFW_thread; /*!< thread type unix */
  700. #else
  701. typedef void* RGFW_thread; /*!< thread type for windows */
  702. #endif
  703. /*! scale monitor to window size */
  704. RGFWDEF RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win);
  705. /** * @defgroup Window_management
  706. * @{ */
  707. /*!
  708. * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM
  709. * by default the class name will == the root window's name
  710. */
  711. RGFWDEF void RGFW_setClassName(const char* name);
  712. RGFWDEF void RGFW_setXInstName(const char* name); /*!< X11 instance name (window name will by used by default) */
  713. /*! (cocoa only) change directory to resource folder */
  714. RGFWDEF void RGFW_moveToMacOSResourceDir(void);
  715. /* NOTE: (windows) if the executable has an icon resource named RGFW_ICON, it will be set as the initial icon for the window */
  716. RGFWDEF RGFW_window* RGFW_createWindow(
  717. const char* name, /* name of the window */
  718. RGFW_rect rect, /* rect of window */
  719. RGFW_windowFlags flags /* extra arguments ((u32)0 means no flags used)*/
  720. ); /*!< function to create a window and struct */
  721. RGFWDEF RGFW_window* RGFW_createWindowPtr(
  722. const char* name, /* name of the window */
  723. RGFW_rect rect, /* rect of window */
  724. RGFW_windowFlags flags, /* extra arguments (NULL / (u32)0 means no flags used) */
  725. RGFW_window* win /* ptr to the window struct you want to use */
  726. ); /*!< function to create a window (without allocating a window struct) */
  727. RGFWDEF void RGFW_window_initBuffer(RGFW_window* win);
  728. RGFWDEF void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area);
  729. RGFWDEF void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area);
  730. /*! set the window flags (will undo flags if they don't match the old ones) */
  731. RGFWDEF void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags);
  732. /*! get the size of the screen to an area struct */
  733. RGFWDEF RGFW_area RGFW_getScreenSize(void);
  734. /*!
  735. this function checks an *individual* event (and updates window structure attributes)
  736. this means, using this function without a while loop may cause event lag
  737. ex.
  738. while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one]
  739. this function is optional if you choose to use event callbacks,
  740. although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents`
  741. */
  742. RGFWDEF RGFW_event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/
  743. /*!
  744. for RGFW_window_eventWait and RGFW_window_checkEvents
  745. waitMS -> Allows the function to keep checking for events even after `RGFW_window_checkEvent == NULL`
  746. if waitMS == 0, the loop will not wait for events
  747. if waitMS > 0, the loop will wait that many miliseconds after there are no more events until it returns
  748. if waitMS == -1 or waitMS == the max size of an unsigned 32-bit int, the loop will not return until it gets another event
  749. */
  750. typedef RGFW_ENUM(i32, RGFW_eventWait) {
  751. RGFW_eventNoWait = 0,
  752. RGFW_eventWaitNext = -1
  753. };
  754. /*! sleep until RGFW gets an event or the timer ends (defined by OS) */
  755. RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS);
  756. /*!
  757. check all the events until there are none left.
  758. This should only be used if you're using callbacks only
  759. */
  760. RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS);
  761. /*!
  762. tell RGFW_window_eventWait to stop waiting (to be ran from another thread)
  763. */
  764. RGFWDEF void RGFW_stopCheckEvents(void);
  765. /*! window managment functions */
  766. RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */
  767. /*! move a window to a given point */
  768. RGFWDEF void RGFW_window_move(RGFW_window* win,
  769. RGFW_point v /*!< new pos */
  770. );
  771. #ifndef RGFW_NO_MONITOR
  772. /*! move window to a specific monitor */
  773. RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */);
  774. #endif
  775. /*! resize window to a current size/area */
  776. RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */
  777. RGFW_area a /*!< new size */
  778. );
  779. /*! set window aspect ratio */
  780. RGFWDEF void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a);
  781. /*! set the minimum dimensions of a window */
  782. RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a);
  783. /*! set the maximum dimensions of a window */
  784. RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a);
  785. RGFWDEF void RGFW_window_focus(RGFW_window* win); /*!< sets the focus to this window */
  786. RGFWDEF RGFW_bool RGFW_window_isInFocus(RGFW_window* win); /*!< checks the focus to this window */
  787. RGFWDEF void RGFW_window_raise(RGFW_window* win); /*!< raise the window (to the top) */
  788. RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window */
  789. RGFWDEF void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen); /*!< turn fullscreen on / off for a window */
  790. RGFWDEF void RGFW_window_center(RGFW_window* win); /*!< center the window */
  791. RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/
  792. RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/
  793. RGFWDEF void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating); /*!< make the window a floating window */
  794. RGFWDEF void RGFW_window_setOpacity(RGFW_window* win, u8 opacity); /*!< sets the opacity of a window */
  795. /*! if the window should have a border or not (borderless) based on bool value of `border` */
  796. RGFWDEF void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border);
  797. RGFWDEF RGFW_bool RGFW_window_borderless(RGFW_window* win);
  798. /*! turn on / off dnd (RGFW_windowAllowDND stil must be passed to the window)*/
  799. RGFWDEF void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow);
  800. /*! check if DND is allowed */
  801. RGFWDEF RGFW_bool RGFW_window_allowsDND(RGFW_window* win);
  802. #ifndef RGFW_NO_PASSTHROUGH
  803. /*! turn on / off mouse passthrough */
  804. RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough);
  805. #endif
  806. /*! rename window to a given string */
  807. RGFWDEF void RGFW_window_setName(RGFW_window* win,
  808. const char* name
  809. );
  810. RGFWDEF RGFW_bool RGFW_window_setIcon(RGFW_window* win, /*!< source window */
  811. u8* icon /*!< icon bitmap */,
  812. RGFW_area a /*!< width and height of the bitmap */,
  813. i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */
  814. ); /*!< image MAY be resized by default, set both the taskbar and window icon */
  815. typedef RGFW_ENUM(u8, RGFW_icon) {
  816. RGFW_iconTaskbar = RGFW_BIT(0),
  817. RGFW_iconWindow = RGFW_BIT(1),
  818. RGFW_iconBoth = RGFW_iconTaskbar | RGFW_iconWindow
  819. };
  820. RGFWDEF RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type);
  821. /*!< sets mouse to RGFW_mouse icon (loaded from a bitmap struct) */
  822. RGFWDEF void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse);
  823. /*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the RGFW_HEADER part of this file) */
  824. RGFWDEF RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse);
  825. RGFWDEF RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */
  826. /*
  827. Locks cursor at the center of the window
  828. win->event.point becomes raw mouse movement data
  829. this is useful for a 3D camera
  830. */
  831. RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area);
  832. /*! stop holding the mouse and let it move freely */
  833. RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win);
  834. /*! hide the window */
  835. RGFWDEF void RGFW_window_hide(RGFW_window* win);
  836. /*! show the window */
  837. RGFWDEF void RGFW_window_show(RGFW_window* win);
  838. /*
  839. makes it so `RGFW_window_shouldClose` returns true or overrides a window close
  840. by modifying window flags
  841. */
  842. RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose);
  843. /*! where the mouse is on the screen */
  844. RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void);
  845. /*! where the mouse is on the window */
  846. RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win);
  847. /*! show the mouse or hide the mouse */
  848. RGFWDEF void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show);
  849. /*! if the mouse is hidden */
  850. RGFWDEF RGFW_bool RGFW_window_mouseHidden(RGFW_window* win);
  851. /*! move the mouse to a given point */
  852. RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v);
  853. /*! if the window should close (RGFW_close was sent or escape was pressed) */
  854. RGFWDEF RGFW_bool RGFW_window_shouldClose(RGFW_window* win);
  855. /*! if the window is fullscreen */
  856. RGFWDEF RGFW_bool RGFW_window_isFullscreen(RGFW_window* win);
  857. /*! if the window is hidden */
  858. RGFWDEF RGFW_bool RGFW_window_isHidden(RGFW_window* win);
  859. /*! if the window is minimized */
  860. RGFWDEF RGFW_bool RGFW_window_isMinimized(RGFW_window* win);
  861. /*! if the window is maximized */
  862. RGFWDEF RGFW_bool RGFW_window_isMaximized(RGFW_window* win);
  863. /*! if the window is floating */
  864. RGFWDEF RGFW_bool RGFW_window_isFloating(RGFW_window* win);
  865. /** @} */
  866. /** * @defgroup Monitor
  867. * @{ */
  868. #ifndef RGFW_NO_MONITOR
  869. /*
  870. scale the window to the monitor.
  871. This is run by default if the user uses the arg `RGFW_scaleToMonitor` during window creation
  872. */
  873. RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win);
  874. /*! get the struct of the window's monitor */
  875. RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win);
  876. #endif
  877. /** @} */
  878. /** * @defgroup Input
  879. * @{ */
  880. /*! if window == NULL, it checks if the key is pressed globally. Otherwise, it checks only if the key is pressed while the window in focus. */
  881. RGFWDEF RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key); /*!< if key is pressed (key code)*/
  882. RGFWDEF RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key); /*!< if key was pressed (checks previous state only) (key code) */
  883. RGFWDEF RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key); /*!< if key is held (key code) */
  884. RGFWDEF RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key); /*!< if key is released (key code) */
  885. /* if a key is pressed and then released, pretty much the same as RGFW_isReleased */
  886. RGFWDEF RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key /*!< key code */);
  887. /*! if a mouse button is pressed */
  888. RGFWDEF RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
  889. /*! if a mouse button is held */
  890. RGFWDEF RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
  891. /*! if a mouse button was released */
  892. RGFWDEF RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
  893. /*! if a mouse button was pressed (checks previous state only) */
  894. RGFWDEF RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button /*!< mouse button code */ );
  895. /** @} */
  896. /** * @defgroup Clipboard
  897. * @{ */
  898. typedef ptrdiff_t RGFW_ssize_t;
  899. RGFWDEF const char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */
  900. /*! read clipboard data or send a NULL str to just get the length of the clipboard data */
  901. RGFWDEF RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity);
  902. RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */
  903. /** @} */
  904. /** * @defgroup error handling
  905. * @{ */
  906. typedef RGFW_ENUM(u8, RGFW_debugType) {
  907. RGFW_typeError = 0, RGFW_typeWarning, RGFW_typeInfo
  908. };
  909. typedef RGFW_ENUM(u8, RGFW_errorCode) {
  910. RGFW_noError = 0, /*!< no error */
  911. RGFW_errOpenglContext, RGFW_errEGLContext, /*!< error with the OpenGL context */
  912. RGFW_errWayland,
  913. RGFW_errDirectXContext,
  914. RGFW_errIOKit,
  915. RGFW_errClipboard,
  916. RGFW_errFailedFuncLoad,
  917. RGFW_errBuffer,
  918. RGFW_infoMonitor, RGFW_infoWindow, RGFW_infoBuffer, RGFW_infoGlobal, RGFW_infoOpenGL,
  919. RGFW_warningWayland, RGFW_warningOpenGL
  920. };
  921. typedef struct RGFW_debugContext { RGFW_window* win; RGFW_monitor monitor; u32 srcError; } RGFW_debugContext;
  922. #if defined(__cplusplus) && !defined(__APPLE__)
  923. #define RGFW_DEBUG_CTX(win, err) {win, { 0 }, err}
  924. #define RGFW_DEBUG_CTX_MON(monitor) {_RGFW.root, monitor, 0}
  925. #else
  926. #define RGFW_DEBUG_CTX(win, err) (RGFW_debugContext){win, (RGFW_monitor){ 0 }, err}
  927. #define RGFW_DEBUG_CTX_MON(monitor) (RGFW_debugContext){_RGFW.root, monitor, 0}
  928. #endif
  929. typedef void (* RGFW_debugfunc)(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg);
  930. RGFWDEF RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func);
  931. RGFWDEF void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg);
  932. /** @} */
  933. /**
  934. event callbacks.
  935. These are completely optional, so you can use the normal
  936. RGFW_checkEvent() method if you prefer that
  937. * @defgroup Callbacks
  938. * @{
  939. */
  940. /*! RGFW_windowMoved, the window and its new rect value */
  941. typedef void (* RGFW_windowMovedfunc)(RGFW_window* win, RGFW_rect r);
  942. /*! RGFW_windowResized, the window and its new rect value */
  943. typedef void (* RGFW_windowResizedfunc)(RGFW_window* win, RGFW_rect r);
  944. /*! RGFW_windowRestored, the window and its new rect value */
  945. typedef void (* RGFW_windowRestoredfunc)(RGFW_window* win, RGFW_rect r);
  946. /*! RGFW_windowMaximized, the window and its new rect value */
  947. typedef void (* RGFW_windowMaximizedfunc)(RGFW_window* win, RGFW_rect r);
  948. /*! RGFW_windowMinimized, the window and its new rect value */
  949. typedef void (* RGFW_windowMinimizedfunc)(RGFW_window* win, RGFW_rect r);
  950. /*! RGFW_quit, the window that was closed */
  951. typedef void (* RGFW_windowQuitfunc)(RGFW_window* win);
  952. /*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its in focus */
  953. typedef void (* RGFW_focusfunc)(RGFW_window* win, RGFW_bool inFocus);
  954. /*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */
  955. typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, RGFW_bool status);
  956. /*! RGFW_mousePosChanged, the window that the move happened on, and the new point of the mouse */
  957. typedef void (* RGFW_mousePosfunc)(RGFW_window* win, RGFW_point point, RGFW_point vector);
  958. /*! RGFW_DNDInit, the window, the point of the drop on the windows */
  959. typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_point point);
  960. /*! RGFW_windowRefresh, the window that needs to be refreshed */
  961. typedef void (* RGFW_windowRefreshfunc)(RGFW_window* win);
  962. /*! RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the mapped key, the physical key, the string version, the state of the mod keys, if it was a press (else it's a release) */
  963. typedef void (* RGFW_keyfunc)(RGFW_window* win, u8 key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed);
  964. /*! RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */
  965. typedef void (* RGFW_mouseButtonfunc)(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed);
  966. /*! RGFW_gamepadButtonPressed, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */
  967. typedef void (* RGFW_gamepadButtonfunc)(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed);
  968. /*! RGFW_gamepadAxisMove, the window that got the event, the gamepad in question, the axis values and the axis count */
  969. typedef void (* RGFW_gamepadAxisfunc)(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis);
  970. /*! RGFW_gamepadConnected / RGFW_gamepadDisconnected, the window that got the event, the gamepad in question, if the controller was connected (else it was disconnected) */
  971. typedef void (* RGFW_gamepadfunc)(RGFW_window* win, u16 gamepad, RGFW_bool connected);
  972. /*! RGFW_dnd, the window that had the drop, the drop data and the number of files dropped */
  973. typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount);
  974. /*! RGFW_scaleUpdated, the window the event was sent to, content scaleX, content scaleY */
  975. typedef void (* RGFW_scaleUpdatedfunc)(RGFW_window* win, float scaleX, float scaleY);
  976. /*! set callback for a window move event. Returns previous callback function (if it was set) */
  977. RGFWDEF RGFW_windowMovedfunc RGFW_setWindowMovedCallback(RGFW_windowMovedfunc func);
  978. /*! set callback for a window resize event. Returns previous callback function (if it was set) */
  979. RGFWDEF RGFW_windowResizedfunc RGFW_setWindowResizedCallback(RGFW_windowResizedfunc func);
  980. /*! set callback for a window quit event. Returns previous callback function (if it was set) */
  981. RGFWDEF RGFW_windowQuitfunc RGFW_setWindowQuitCallback(RGFW_windowQuitfunc func);
  982. /*! set callback for a mouse move event. Returns previous callback function (if it was set) */
  983. RGFWDEF RGFW_mousePosfunc RGFW_setMousePosCallback(RGFW_mousePosfunc func);
  984. /*! set callback for a window refresh event. Returns previous callback function (if it was set) */
  985. RGFWDEF RGFW_windowRefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowRefreshfunc func);
  986. /*! set callback for a window focus change event. Returns previous callback function (if it was set) */
  987. RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func);
  988. /*! set callback for a mouse notify event. Returns previous callback function (if it was set) */
  989. RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallback(RGFW_mouseNotifyfunc func);
  990. /*! set callback for a drop event event. Returns previous callback function (if it was set) */
  991. RGFWDEF RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func);
  992. /*! set callback for a start of a drop event. Returns previous callback function (if it was set) */
  993. RGFWDEF RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func);
  994. /*! set callback for a key (press / release) event. Returns previous callback function (if it was set) */
  995. RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func);
  996. /*! set callback for a mouse button (press / release) event. Returns previous callback function (if it was set) */
  997. RGFWDEF RGFW_mouseButtonfunc RGFW_setMouseButtonCallback(RGFW_mouseButtonfunc func);
  998. /*! set callback for a controller button (press / release) event. Returns previous callback function (if it was set) */
  999. RGFWDEF RGFW_gamepadButtonfunc RGFW_setGamepadButtonCallback(RGFW_gamepadButtonfunc func);
  1000. /*! set callback for a gamepad axis move event. Returns previous callback function (if it was set) */
  1001. RGFWDEF RGFW_gamepadAxisfunc RGFW_setGamepadAxisCallback(RGFW_gamepadAxisfunc func);
  1002. /*! set callback for when a controller is connected or disconnected. Returns the previous callback function (if it was set) */
  1003. RGFWDEF RGFW_gamepadfunc RGFW_setGamepadCallback(RGFW_gamepadfunc func);
  1004. /*! set call back for when window is maximized. Returns the previous callback function (if it was set) */
  1005. RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMaximizedCallback(RGFW_windowResizedfunc func);
  1006. /*! set call back for when window is minimized. Returns the previous callback function (if it was set) */
  1007. RGFWDEF RGFW_windowResizedfunc RGFW_setWindowMinimizedCallback(RGFW_windowResizedfunc func);
  1008. /*! set call back for when window is restored. Returns the previous callback function (if it was set) */
  1009. RGFWDEF RGFW_windowResizedfunc RGFW_setWindowRestoredCallback(RGFW_windowResizedfunc func);
  1010. /*! set callback for when the DPI changes. Returns previous callback function (if it was set) */
  1011. RGFWDEF RGFW_scaleUpdatedfunc RGFW_setScaleUpdatedCallback(RGFW_scaleUpdatedfunc func);
  1012. /** @} */
  1013. /** * @defgroup Threads
  1014. * @{ */
  1015. #ifndef RGFW_NO_THREADS
  1016. /*! threading functions */
  1017. /*! NOTE! (for X11/linux) : if you define a window in a thread, it must be run after the original thread's window is created or else there will be a memory error */
  1018. /*
  1019. I'd suggest you use sili's threading functions instead
  1020. if you're going to use sili
  1021. which is a good idea generally
  1022. */
  1023. #if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WASM) || defined(RGFW_CUSTOM_BACKEND)
  1024. typedef void* (* RGFW_threadFunc_ptr)(void*);
  1025. #else
  1026. typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter);
  1027. #endif
  1028. RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread */
  1029. RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread */
  1030. RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */
  1031. RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority */
  1032. #endif
  1033. /** @} */
  1034. /** * @defgroup gamepad
  1035. * @{ */
  1036. typedef RGFW_ENUM(u8, RGFW_gamepadType) {
  1037. RGFW_gamepadMicrosoft = 0, RGFW_gamepadSony, RGFW_gamepadNintendo, RGFW_gamepadLogitech, RGFW_gamepadUnknown
  1038. };
  1039. /*! gamepad count starts at 0*/
  1040. RGFWDEF u32 RGFW_isPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
  1041. RGFWDEF u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
  1042. RGFWDEF u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
  1043. RGFWDEF u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button);
  1044. RGFWDEF RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis);
  1045. RGFWDEF const char* RGFW_getGamepadName(RGFW_window* win, u16 controller);
  1046. RGFWDEF size_t RGFW_getGamepadCount(RGFW_window* win);
  1047. RGFWDEF RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller);
  1048. /** @} */
  1049. /** * @defgroup graphics_API
  1050. * @{ */
  1051. /*!< make the window the current opengl drawing context
  1052. NOTE:
  1053. if you want to switch the graphics context's thread,
  1054. you have to run RGFW_window_makeCurrent(NULL); on the old thread
  1055. then RGFW_window_makeCurrent(valid_window) on the new thread
  1056. */
  1057. RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win);
  1058. /*! get current RGFW window graphics context */
  1059. RGFWDEF RGFW_window* RGFW_getCurrent(void);
  1060. /* supports openGL, directX, OSMesa, EGL and software rendering */
  1061. RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */
  1062. RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval);
  1063. /*!< render the software rendering buffer (this is called by RGFW_window_swapInterval) */
  1064. RGFWDEF void RGFW_window_swapBuffers_software(RGFW_window* win);
  1065. typedef void (*RGFW_proc)(void); /* function pointer equivalent of void* */
  1066. /*! native API functions */
  1067. #if defined(RGFW_OPENGL) || defined(RGFW_EGL)
  1068. /*!< create an opengl context for the RGFW window, run by createWindow by default (unless the RGFW_windowNoInitAPI is included) */
  1069. RGFWDEF void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software);
  1070. /*!< called by `RGFW_window_close` by default (unless the RGFW_windowNoInitAPI is set) */
  1071. RGFWDEF void RGFW_window_freeOpenGL(RGFW_window* win);
  1072. /*! OpenGL init hints */
  1073. typedef RGFW_ENUM(u8, RGFW_glHints) {
  1074. RGFW_glStencil = 0, /*!< set stencil buffer bit size (8 by default) */
  1075. RGFW_glSamples, /*!< set number of sampiling buffers (4 by default) */
  1076. RGFW_glStereo, /*!< use GL_STEREO (GL_FALSE by default) */
  1077. RGFW_glAuxBuffers, /*!< number of aux buffers (0 by default) */
  1078. RGFW_glDoubleBuffer, /*!< request double buffering */
  1079. RGFW_glRed, RGFW_glGreen, RGFW_glBlue, RGFW_glAlpha, /*!< set RGBA bit sizes */
  1080. RGFW_glDepth,
  1081. RGFW_glAccumRed, RGFW_glAccumGreen, RGFW_glAccumBlue,RGFW_glAccumAlpha, /*!< set accumulated RGBA bit sizes */
  1082. RGFW_glSRGB, /*!< request sRGA */
  1083. RGFW_glRobustness, /*!< request a robust context */
  1084. RGFW_glDebug, /*!< request opengl debugging */
  1085. RGFW_glNoError, /*!< request no opengl errors */
  1086. RGFW_glReleaseBehavior,
  1087. RGFW_glProfile,
  1088. RGFW_glMajor, RGFW_glMinor,
  1089. RGFW_glFinalHint = 32, /*!< the final hint (not for setting) */
  1090. RGFW_releaseFlush = 0, RGFW_glReleaseNone, /* RGFW_glReleaseBehavior options */
  1091. RGFW_glCore = 0, RGFW_glCompatibility /*!< RGFW_glProfile options */
  1092. };
  1093. RGFWDEF void RGFW_setGLHint(RGFW_glHints hint, i32 value);
  1094. RGFWDEF RGFW_proc RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */
  1095. RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */
  1096. RGFWDEF void RGFW_window_swapBuffers_OpenGL(RGFW_window* win); /*!< swap opengl buffer (only) called by RGFW_window_swapInterval */
  1097. void* RGFW_getCurrent_OpenGL(void); /*!< get the current context (OpenGL backend (GLX) (WGL) (EGL) (cocoa) (webgl))*/
  1098. #endif
  1099. #ifdef RGFW_VULKAN
  1100. #if defined(RGFW_WAYLAND) && defined(RGFW_X11)
  1101. #define VK_USE_PLATFORM_WAYLAND_KHR
  1102. #define VK_USE_PLATFORM_XLIB_KHR
  1103. #define RGFW_VK_SURFACE ((RGFW_usingWayland()) ? ("VK_KHR_wayland_surface") : ("VK_KHR_xlib_surface"))
  1104. #elif defined(RGFW_WAYLAND)
  1105. #define VK_USE_PLATFORM_WAYLAND_KHR
  1106. #define VK_USE_PLATFORM_XLIB_KHR
  1107. #define RGFW_VK_SURFACE "VK_KHR_wayland_surface"
  1108. #elif defined(RGFW_X11)
  1109. #define VK_USE_PLATFORM_XLIB_KHR
  1110. #define RGFW_VK_SURFACE "VK_KHR_xlib_surface"
  1111. #elif defined(RGFW_WINDOWS)
  1112. #define VK_USE_PLATFORM_WIN32_KHR
  1113. #define OEMRESOURCE
  1114. #define RGFW_VK_SURFACE "VK_KHR_win32_surface"
  1115. #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
  1116. #define VK_USE_PLATFORM_MACOS_MVK
  1117. #define RGFW_VK_SURFACE "VK_MVK_macos_surface"
  1118. #else
  1119. #define RGFW_VK_SURFACE NULL
  1120. #endif
  1121. /* if you don't want to use the above macros */
  1122. RGFWDEF const char** RGFW_getVKRequiredInstanceExtensions(size_t* count); /*!< gets (static) extension array (and size (which will be 2)) */
  1123. #include <vulkan/vulkan.h>
  1124. RGFWDEF VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface);
  1125. RGFWDEF RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex);
  1126. #endif
  1127. #ifdef RGFW_DIRECTX
  1128. #ifndef RGFW_WINDOWS
  1129. #undef RGFW_DIRECTX
  1130. #else
  1131. #define OEMRESOURCE
  1132. #include <dxgi.h>
  1133. #ifndef __cplusplus
  1134. #define __uuidof(T) IID_##T
  1135. #endif
  1136. RGFWDEF int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain);
  1137. #endif
  1138. #endif
  1139. /** @} */
  1140. /** * @defgroup Supporting
  1141. * @{ */
  1142. /*! optional init/deinit function */
  1143. RGFWDEF i32 RGFW_init(void); /*!< is called by default when the first window is created by default */
  1144. RGFWDEF void RGFW_deinit(void); /*!< is called by default when the last open window is closed */
  1145. RGFWDEF double RGFW_getTime(void); /*!< get time in seconds since RGFW_setTime, which ran when the first window is open */
  1146. RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds RGFW_setTime, which ran when the first window is open */
  1147. RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */
  1148. RGFWDEF void RGFW_setTime(double time); /*!< set timer in seconds */
  1149. RGFWDEF u64 RGFW_getTimerValue(void); /*!< get API timer value */
  1150. RGFWDEF u64 RGFW_getTimerFreq(void); /*!< get API time freq */
  1151. /*< updates fps / sets fps to cap (must by ran manually by the user at the end of a frame), returns current fps */
  1152. RGFWDEF u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap);
  1153. /*!< change which window is the root window */
  1154. RGFWDEF void RGFW_setRootWindow(RGFW_window* win);
  1155. RGFWDEF RGFW_window* RGFW_getRootWindow(void);
  1156. /*! standard event queue, used for injecting events and returning source API callback events like any other queue check */
  1157. /* these are all used internally by RGFW */
  1158. void RGFW_eventQueuePush(RGFW_event event);
  1159. RGFW_event* RGFW_eventQueuePop(RGFW_window* win);
  1160. /*!
  1161. key codes and mouse icon enums
  1162. */
  1163. #undef RGFW_key
  1164. typedef RGFW_ENUM(u8, RGFW_key) {
  1165. RGFW_keyNULL = 0,
  1166. RGFW_escape = '\033',
  1167. RGFW_backtick = '`',
  1168. RGFW_0 = '0',
  1169. RGFW_1 = '1',
  1170. RGFW_2 = '2',
  1171. RGFW_3 = '3',
  1172. RGFW_4 = '4',
  1173. RGFW_5 = '5',
  1174. RGFW_6 = '6',
  1175. RGFW_7 = '7',
  1176. RGFW_8 = '8',
  1177. RGFW_9 = '9',
  1178. RGFW_minus = '-',
  1179. RGFW_equals = '=',
  1180. RGFW_backSpace = '\b',
  1181. RGFW_tab = '\t',
  1182. RGFW_space = ' ',
  1183. RGFW_a = 'a',
  1184. RGFW_b = 'b',
  1185. RGFW_c = 'c',
  1186. RGFW_d = 'd',
  1187. RGFW_e = 'e',
  1188. RGFW_f = 'f',
  1189. RGFW_g = 'g',
  1190. RGFW_h = 'h',
  1191. RGFW_i = 'i',
  1192. RGFW_j = 'j',
  1193. RGFW_k = 'k',
  1194. RGFW_l = 'l',
  1195. RGFW_m = 'm',
  1196. RGFW_n = 'n',
  1197. RGFW_o = 'o',
  1198. RGFW_p = 'p',
  1199. RGFW_q = 'q',
  1200. RGFW_r = 'r',
  1201. RGFW_s = 's',
  1202. RGFW_t = 't',
  1203. RGFW_u = 'u',
  1204. RGFW_v = 'v',
  1205. RGFW_w = 'w',
  1206. RGFW_x = 'x',
  1207. RGFW_y = 'y',
  1208. RGFW_z = 'z',
  1209. RGFW_period = '.',
  1210. RGFW_comma = ',',
  1211. RGFW_slash = '/',
  1212. RGFW_bracket = '{',
  1213. RGFW_closeBracket = '}',
  1214. RGFW_semicolon = ';',
  1215. RGFW_apostrophe = '\'',
  1216. RGFW_backSlash = '\\',
  1217. RGFW_return = '\n',
  1218. RGFW_delete = '\177', /* 127 */
  1219. RGFW_F1,
  1220. RGFW_F2,
  1221. RGFW_F3,
  1222. RGFW_F4,
  1223. RGFW_F5,
  1224. RGFW_F6,
  1225. RGFW_F7,
  1226. RGFW_F8,
  1227. RGFW_F9,
  1228. RGFW_F10,
  1229. RGFW_F11,
  1230. RGFW_F12,
  1231. RGFW_capsLock,
  1232. RGFW_shiftL,
  1233. RGFW_controlL,
  1234. RGFW_altL,
  1235. RGFW_superL,
  1236. RGFW_shiftR,
  1237. RGFW_controlR,
  1238. RGFW_altR,
  1239. RGFW_superR,
  1240. RGFW_up,
  1241. RGFW_down,
  1242. RGFW_left,
  1243. RGFW_right,
  1244. RGFW_insert,
  1245. RGFW_end,
  1246. RGFW_home,
  1247. RGFW_pageUp,
  1248. RGFW_pageDown,
  1249. RGFW_numLock,
  1250. RGFW_KP_Slash,
  1251. RGFW_multiply,
  1252. RGFW_KP_Minus,
  1253. RGFW_KP_1,
  1254. RGFW_KP_2,
  1255. RGFW_KP_3,
  1256. RGFW_KP_4,
  1257. RGFW_KP_5,
  1258. RGFW_KP_6,
  1259. RGFW_KP_7,
  1260. RGFW_KP_8,
  1261. RGFW_KP_9,
  1262. RGFW_KP_0,
  1263. RGFW_KP_Period,
  1264. RGFW_KP_Return,
  1265. RGFW_scrollLock,
  1266. RGFW_keyLast = 256 /* padding for alignment ~(175 by default) */
  1267. };
  1268. RGFWDEF u32 RGFW_apiKeyToRGFW(u32 keycode);
  1269. typedef RGFW_ENUM(u8, RGFW_mouseIcons) {
  1270. RGFW_mouseNormal = 0,
  1271. RGFW_mouseArrow,
  1272. RGFW_mouseIbeam,
  1273. RGFW_mouseCrosshair,
  1274. RGFW_mousePointingHand,
  1275. RGFW_mouseResizeEW,
  1276. RGFW_mouseResizeNS,
  1277. RGFW_mouseResizeNWSE,
  1278. RGFW_mouseResizeNESW,
  1279. RGFW_mouseResizeAll,
  1280. RGFW_mouseNotAllowed,
  1281. RGFW_mouseIconFinal = 16 /* padding for alignment */
  1282. };
  1283. /** @} */
  1284. #endif /* RGFW_HEADER */
  1285. #if defined(RGFW_X11) || defined(RGFW_WAYLAND)
  1286. #define RGFW_OS_BASED_VALUE(l, w, m, h) l
  1287. #elif defined(RGFW_WINDOWS)
  1288. #define RGFW_OS_BASED_VALUE(l, w, m, h) w
  1289. #elif defined(RGFW_MACOS)
  1290. #define RGFW_OS_BASED_VALUE(l, w, m, h) m
  1291. #elif defined(RGFW_WASM)
  1292. #define RGFW_OS_BASED_VALUE(l, w, m, h) h
  1293. #endif
  1294. #ifdef RGFW_IMPLEMENTATION
  1295. RGFW_bool RGFW_useWaylandBool = 1;
  1296. void RGFW_useWayland(RGFW_bool wayland) { RGFW_useWaylandBool = wayland; }
  1297. RGFW_bool RGFW_usingWayland(void) { return RGFW_useWaylandBool; }
  1298. #if !defined(RGFW_NO_X11) && defined(RGFW_WAYLAND)
  1299. #define RGFW_GOTO_WAYLAND(fallback) if (RGFW_useWaylandBool && fallback == 0) goto wayland
  1300. #else
  1301. #define RGFW_GOTO_WAYLAND(fallback)
  1302. #endif
  1303. char* RGFW_clipboard_data;
  1304. void RGFW_clipboard_switch(char* newstr);
  1305. void RGFW_clipboard_switch(char* newstr) {
  1306. if (RGFW_clipboard_data != NULL)
  1307. RGFW_FREE(RGFW_clipboard_data);
  1308. RGFW_clipboard_data = newstr;
  1309. }
  1310. #define RGFW_CHECK_CLIPBOARD() \
  1311. if (size <= 0 && RGFW_clipboard_data != NULL) \
  1312. return (const char*)RGFW_clipboard_data; \
  1313. else if (size <= 0) \
  1314. return "\0";
  1315. const char* RGFW_readClipboard(size_t* len) {
  1316. RGFW_ssize_t size = RGFW_readClipboardPtr(NULL, 0);
  1317. RGFW_CHECK_CLIPBOARD();
  1318. char* str = (char*)RGFW_ALLOC((size_t)size);
  1319. RGFW_ASSERT(str != NULL);
  1320. str[0] = '\0';
  1321. size = RGFW_readClipboardPtr(str, (size_t)size);
  1322. RGFW_CHECK_CLIPBOARD();
  1323. if (len != NULL) *len = (size_t)size;
  1324. RGFW_clipboard_switch(str);
  1325. return (const char*)str;
  1326. }
  1327. RGFW_debugfunc RGFW_debugCallback = NULL;
  1328. RGFW_debugfunc RGFW_setDebugCallback(RGFW_debugfunc func) {
  1329. RGFW_debugfunc RGFW_debugCallbackPrev = RGFW_debugCallback;
  1330. RGFW_debugCallback = func;
  1331. return RGFW_debugCallbackPrev;
  1332. }
  1333. #ifdef RGFW_DEBUG
  1334. #include <stdio.h>
  1335. #endif
  1336. void RGFW_sendDebugInfo(RGFW_debugType type, RGFW_errorCode err, RGFW_debugContext ctx, const char* msg) {
  1337. if (RGFW_debugCallback) RGFW_debugCallback(type, err, ctx, msg);
  1338. #ifdef RGFW_DEBUG
  1339. switch (type) {
  1340. case RGFW_typeInfo: printf("RGFW INFO (%i %i): %s", type, err, msg); break;
  1341. case RGFW_typeError: printf("RGFW DEBUG (%i %i): %s", type, err, msg); break;
  1342. case RGFW_typeWarning: printf("RGFW WARNING (%i %i): %s", type, err, msg); break;
  1343. default: break;
  1344. }
  1345. switch (err) {
  1346. #ifdef RGFW_BUFFER
  1347. case RGFW_errBuffer: case RGFW_infoBuffer: printf(" buffer size: %i %i\n", ctx.win->bufferSize.w, ctx.win->bufferSize.h); break;
  1348. #endif
  1349. case RGFW_infoMonitor: printf(": scale (%s):\n rect: {%i, %i, %i, %i}\n physical size:%f %f\n scale: %f %f\n pixelRatio: %f\n refreshRate: %i\n depth: %i\n", ctx.monitor.name, ctx.monitor.x, ctx.monitor.y, ctx.monitor.mode.area.w, ctx.monitor.mode.area.h, ctx.monitor.physW, ctx.monitor.physH, ctx.monitor.scaleX, ctx.monitor.scaleY, ctx.monitor.pixelRatio, ctx.monitor.mode.refreshRate, ctx.monitor.mode.red + ctx.monitor.mode.green + ctx.monitor.mode.blue); break;
  1350. case RGFW_infoWindow: printf(" with rect of {%i, %i, %i, %i} \n", ctx.win->r.x, ctx.win->r.y,ctx. win->r.w, ctx.win->r.h); break;
  1351. case RGFW_errDirectXContext: printf(" srcError %i\n", ctx.srcError); break;
  1352. default: printf("\n");
  1353. }
  1354. #endif
  1355. }
  1356. u64 RGFW_timerOffset = 0;
  1357. void RGFW_setTime(double time) {
  1358. RGFW_timerOffset = RGFW_getTimerValue() - (u64)(time * (double)RGFW_getTimerFreq());
  1359. }
  1360. double RGFW_getTime(void) {
  1361. return (double) ((double)(RGFW_getTimerValue() - RGFW_timerOffset) / (double)RGFW_getTimerFreq());
  1362. }
  1363. u64 RGFW_getTimeNS(void) {
  1364. return (u64)(((double)((RGFW_getTimerValue() - RGFW_timerOffset)) * 1e9) / (double)RGFW_getTimerFreq());
  1365. }
  1366. /*
  1367. RGFW_IMPLEMENTATION starts with generic RGFW defines
  1368. This is the start of keycode data
  1369. Why not use macros instead of the numbers itself?
  1370. Windows -> Not all scancodes keys are macros
  1371. Linux -> Only symcodes are values, (XK_0 - XK_1, XK_a - XK_z) are larger than 0xFF00, I can't find any way to work with them without making the array an unreasonable size
  1372. MacOS -> windows and linux already don't have keycodes as macros, so there's no point
  1373. */
  1374. /*
  1375. the c++ compiler doesn't support setting up an array like,
  1376. we'll have to do it during runtime using a function & this messy setup
  1377. */
  1378. #ifndef RGFW_CUSTOM_BACKEND
  1379. #if !defined(__cplusplus) && !defined(RGFW_C89)
  1380. #define RGFW_NEXT ,
  1381. #define RGFW_MAP
  1382. #else
  1383. #define RGFW_NEXT ;
  1384. #define RGFW_MAP RGFW_keycodes
  1385. #endif
  1386. u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(256, 512, 128, 256)] = {
  1387. #if defined(__cplusplus) || defined(RGFW_C89)
  1388. 0
  1389. };
  1390. void RGFW_init_keys(void);
  1391. void RGFW_init_keys(void) {
  1392. #endif
  1393. RGFW_MAP [RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] = RGFW_backtick RGFW_NEXT
  1394. RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x00B, 29, DOM_VK_0)] = RGFW_0 RGFW_NEXT
  1395. RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x002, 18, DOM_VK_1)] = RGFW_1 RGFW_NEXT
  1396. RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x003, 19, DOM_VK_2)] = RGFW_2 RGFW_NEXT
  1397. RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x004, 20, DOM_VK_3)] = RGFW_3 RGFW_NEXT
  1398. RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x005, 21, DOM_VK_4)] = RGFW_4 RGFW_NEXT
  1399. RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x006, 23, DOM_VK_5)] = RGFW_5 RGFW_NEXT
  1400. RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x007, 22, DOM_VK_6)] = RGFW_6 RGFW_NEXT
  1401. RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x008, 26, DOM_VK_7)] = RGFW_7 RGFW_NEXT
  1402. RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x009, 28, DOM_VK_8)] = RGFW_8 RGFW_NEXT
  1403. RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x00A, 25, DOM_VK_9)] = RGFW_9,
  1404. RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x039, 49, DOM_VK_SPACE)] = RGFW_space,
  1405. RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x01E, 0, DOM_VK_A)] = RGFW_a RGFW_NEXT
  1406. RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x030, 11, DOM_VK_B)] = RGFW_b RGFW_NEXT
  1407. RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x02E, 8, DOM_VK_C)] = RGFW_c RGFW_NEXT
  1408. RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x020, 2, DOM_VK_D)] = RGFW_d RGFW_NEXT
  1409. RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x012, 14, DOM_VK_E)] = RGFW_e RGFW_NEXT
  1410. RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x021, 3, DOM_VK_F)] = RGFW_f RGFW_NEXT
  1411. RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x022, 5, DOM_VK_G)] = RGFW_g RGFW_NEXT
  1412. RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x023, 4, DOM_VK_H)] = RGFW_h RGFW_NEXT
  1413. RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x017, 34, DOM_VK_I)] = RGFW_i RGFW_NEXT
  1414. RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x024, 38, DOM_VK_J)] = RGFW_j RGFW_NEXT
  1415. RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x025, 40, DOM_VK_K)] = RGFW_k RGFW_NEXT
  1416. RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x026, 37, DOM_VK_L)] = RGFW_l RGFW_NEXT
  1417. RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x032, 46, DOM_VK_M)] = RGFW_m RGFW_NEXT
  1418. RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x031, 45, DOM_VK_N)] = RGFW_n RGFW_NEXT
  1419. RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x018, 31, DOM_VK_O)] = RGFW_o RGFW_NEXT
  1420. RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x019, 35, DOM_VK_P)] = RGFW_p RGFW_NEXT
  1421. RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x010, 12, DOM_VK_Q)] = RGFW_q RGFW_NEXT
  1422. RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x013, 15, DOM_VK_R)] = RGFW_r RGFW_NEXT
  1423. RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x01F, 1, DOM_VK_S)] = RGFW_s RGFW_NEXT
  1424. RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x014, 17, DOM_VK_T)] = RGFW_t RGFW_NEXT
  1425. RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x016, 32, DOM_VK_U)] = RGFW_u RGFW_NEXT
  1426. RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x02F, 9, DOM_VK_V)] = RGFW_v RGFW_NEXT
  1427. RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x011, 13, DOM_VK_W)] = RGFW_w RGFW_NEXT
  1428. RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x02D, 7, DOM_VK_X)] = RGFW_x RGFW_NEXT
  1429. RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x015, 16, DOM_VK_Y)] = RGFW_y RGFW_NEXT
  1430. RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x02C, 6, DOM_VK_Z)] = RGFW_z,
  1431. RGFW_MAP [RGFW_OS_BASED_VALUE(60, 0x034, 47, DOM_VK_PERIOD)] = RGFW_period RGFW_NEXT
  1432. RGFW_MAP [RGFW_OS_BASED_VALUE(59, 0x033, 43, DOM_VK_COMMA)] = RGFW_comma RGFW_NEXT
  1433. RGFW_MAP [RGFW_OS_BASED_VALUE(61, 0x035, 44, DOM_VK_SLASH)] = RGFW_slash RGFW_NEXT
  1434. RGFW_MAP [RGFW_OS_BASED_VALUE(34, 0x01A, 33, DOM_VK_OPEN_BRACKET)] = RGFW_bracket RGFW_NEXT
  1435. RGFW_MAP [RGFW_OS_BASED_VALUE(35, 0x01B, 30, DOM_VK_CLOSE_BRACKET)] = RGFW_closeBracket RGFW_NEXT
  1436. RGFW_MAP [RGFW_OS_BASED_VALUE(47, 0x027, 41, DOM_VK_SEMICOLON)] = RGFW_semicolon RGFW_NEXT
  1437. RGFW_MAP [RGFW_OS_BASED_VALUE(48, 0x028, 39, DOM_VK_QUOTE)] = RGFW_apostrophe RGFW_NEXT
  1438. RGFW_MAP [RGFW_OS_BASED_VALUE(51, 0x02B, 42, DOM_VK_BACK_SLASH)] = RGFW_backSlash,
  1439. RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x01C, 36, DOM_VK_RETURN)] = RGFW_return RGFW_NEXT
  1440. RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x153, 118, DOM_VK_DELETE)] = RGFW_delete RGFW_NEXT
  1441. RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x145, 72, DOM_VK_NUM_LOCK)] = RGFW_numLock RGFW_NEXT
  1442. RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x135, 82, DOM_VK_DIVIDE)] = RGFW_KP_Slash RGFW_NEXT
  1443. RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x037, 76, DOM_VK_MULTIPLY)] = RGFW_multiply RGFW_NEXT
  1444. RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x04A, 67, DOM_VK_SUBTRACT)] = RGFW_KP_Minus RGFW_NEXT
  1445. RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x04F, 84, DOM_VK_NUMPAD1)] = RGFW_KP_1 RGFW_NEXT
  1446. RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x050, 85, DOM_VK_NUMPAD2)] = RGFW_KP_2 RGFW_NEXT
  1447. RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x051, 86, DOM_VK_NUMPAD3)] = RGFW_KP_3 RGFW_NEXT
  1448. RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x04B, 87, DOM_VK_NUMPAD4)] = RGFW_KP_4 RGFW_NEXT
  1449. RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x04C, 88, DOM_VK_NUMPAD5)] = RGFW_KP_5 RGFW_NEXT
  1450. RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x04D, 89, DOM_VK_NUMPAD6)] = RGFW_KP_6 RGFW_NEXT
  1451. RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x047, 90, DOM_VK_NUMPAD7)] = RGFW_KP_7 RGFW_NEXT
  1452. RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x048, 92, DOM_VK_NUMPAD8)] = RGFW_KP_8 RGFW_NEXT
  1453. RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x049, 93, DOM_VK_NUMPAD9)] = RGFW_KP_9 RGFW_NEXT
  1454. RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x052, 83, DOM_VK_NUMPAD0)] = RGFW_KP_0 RGFW_NEXT
  1455. RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x053, 65, DOM_VK_DECIMAL)] = RGFW_KP_Period RGFW_NEXT
  1456. RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x11C, 77, 0)] = RGFW_KP_Return,
  1457. RGFW_MAP [RGFW_OS_BASED_VALUE(20, 0x00C, 27, DOM_VK_HYPHEN_MINUS)] = RGFW_minus RGFW_NEXT
  1458. RGFW_MAP [RGFW_OS_BASED_VALUE(21, 0x00D, 24, DOM_VK_EQUALS)] = RGFW_equals RGFW_NEXT
  1459. RGFW_MAP [RGFW_OS_BASED_VALUE(22, 0x00E, 51, DOM_VK_BACK_SPACE)] = RGFW_backSpace RGFW_NEXT
  1460. RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x00F, 48, DOM_VK_TAB)] = RGFW_tab RGFW_NEXT
  1461. RGFW_MAP [RGFW_OS_BASED_VALUE(66, 0x03A, 57, DOM_VK_CAPS_LOCK)] = RGFW_capsLock RGFW_NEXT
  1462. RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x02A, 56, DOM_VK_SHIFT)] = RGFW_shiftL RGFW_NEXT
  1463. RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x01D, 59, DOM_VK_CONTROL)] = RGFW_controlL RGFW_NEXT
  1464. RGFW_MAP [RGFW_OS_BASED_VALUE(64, 0x038, 58, DOM_VK_ALT)] = RGFW_altL RGFW_NEXT
  1465. RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x15B, 55, DOM_VK_WIN)] = RGFW_superL,
  1466. #if !defined(RGFW_MACOS) && !defined(RGFW_WASM)
  1467. RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11D, 59, 0)] = RGFW_controlR RGFW_NEXT
  1468. RGFW_MAP [RGFW_OS_BASED_VALUE(135, 0x15C, 55, 0)] = RGFW_superR,
  1469. RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x036, 56, 0)] = RGFW_shiftR RGFW_NEXT
  1470. RGFW_MAP [RGFW_OS_BASED_VALUE(108, 0x138, 58, 0)] = RGFW_altR,
  1471. #endif
  1472. RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x03B, 127, DOM_VK_F1)] = RGFW_F1 RGFW_NEXT
  1473. RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x03C, 121, DOM_VK_F2)] = RGFW_F2 RGFW_NEXT
  1474. RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x03D, 100, DOM_VK_F3)] = RGFW_F3 RGFW_NEXT
  1475. RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x03E, 119, DOM_VK_F4)] = RGFW_F4 RGFW_NEXT
  1476. RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x03F, 97, DOM_VK_F5)] = RGFW_F5 RGFW_NEXT
  1477. RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x040, 98, DOM_VK_F6)] = RGFW_F6 RGFW_NEXT
  1478. RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x041, 99, DOM_VK_F7)] = RGFW_F7 RGFW_NEXT
  1479. RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x042, 101, DOM_VK_F8)] = RGFW_F8 RGFW_NEXT
  1480. RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x043, 102, DOM_VK_F9)] = RGFW_F9 RGFW_NEXT
  1481. RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x044, 110, DOM_VK_F10)] = RGFW_F10 RGFW_NEXT
  1482. RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x057, 104, DOM_VK_F11)] = RGFW_F11 RGFW_NEXT
  1483. RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x058, 112, DOM_VK_F12)] = RGFW_F12 RGFW_NEXT
  1484. RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x148, 126, DOM_VK_UP)] = RGFW_up RGFW_NEXT
  1485. RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x150, 125, DOM_VK_DOWN)] = RGFW_down RGFW_NEXT
  1486. RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x14B, 123, DOM_VK_LEFT)] = RGFW_left RGFW_NEXT
  1487. RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x14D, 124, DOM_VK_RIGHT)] = RGFW_right RGFW_NEXT
  1488. RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x152, 115, DOM_VK_INSERT)] = RGFW_insert RGFW_NEXT
  1489. RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x14F, 120, DOM_VK_END)] = RGFW_end RGFW_NEXT
  1490. RGFW_MAP [RGFW_OS_BASED_VALUE(112, 0x149, 117, DOM_VK_PAGE_UP)] = RGFW_pageUp RGFW_NEXT
  1491. RGFW_MAP [RGFW_OS_BASED_VALUE(117, 0x151, 122, DOM_VK_PAGE_DOWN)] = RGFW_pageDown RGFW_NEXT
  1492. RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x001, 53, DOM_VK_ESCAPE)] = RGFW_escape RGFW_NEXT
  1493. RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x147, 116, DOM_VK_HOME)] = RGFW_home RGFW_NEXT
  1494. RGFW_MAP [RGFW_OS_BASED_VALUE(78, 0x046, 107, DOM_VK_SCROLL_LOCK)] = RGFW_scrollLock RGFW_NEXT
  1495. #if defined(__cplusplus) || defined(RGFW_C89)
  1496. }
  1497. #else
  1498. };
  1499. #endif
  1500. #undef RGFW_NEXT
  1501. #undef RGFW_MAP
  1502. u32 RGFW_apiKeyToRGFW(u32 keycode) {
  1503. #if defined(__cplusplus) || defined(RGFW_C89)
  1504. if (RGFW_keycodes[RGFW_OS_BASED_VALUE(49, 0x029, 50, DOM_VK_BACK_QUOTE)] != RGFW_backtick) {
  1505. RGFW_init_keys();
  1506. }
  1507. #endif
  1508. /* make sure the key isn't out of bounds */
  1509. if (keycode > sizeof(RGFW_keycodes) / sizeof(u8))
  1510. return 0;
  1511. return RGFW_keycodes[keycode];
  1512. }
  1513. #endif /* RGFW_CUSTOM_BACKEND */
  1514. typedef struct {
  1515. RGFW_bool current : 1;
  1516. RGFW_bool prev : 1;
  1517. } RGFW_keyState;
  1518. RGFW_keyState RGFW_keyboard[RGFW_keyLast] = { {0, 0} };
  1519. RGFWDEF void RGFW_resetKey(void);
  1520. void RGFW_resetKey(void) {
  1521. size_t len = RGFW_keyLast; /*!< last_key == length */
  1522. size_t i; /*!< reset each previous state */
  1523. for (i = 0; i < len; i++)
  1524. RGFW_keyboard[i].prev = 0;
  1525. }
  1526. /*
  1527. this is the end of keycode data
  1528. */
  1529. /* gamepad data */
  1530. RGFW_keyState RGFW_gamepadPressed[4][32]; /*!< if a key is currently pressed or not (per gamepad) */
  1531. RGFW_point RGFW_gamepadAxes[4][4]; /*!< if a key is currently pressed or not (per gamepad) */
  1532. RGFW_gamepadType RGFW_gamepads_type[4]; /*!< if a key is currently pressed or not (per gamepad) */
  1533. i32 RGFW_gamepads[4] = {0, 0, 0, 0}; /*!< limit of 4 gamepads at a time */
  1534. char RGFW_gamepads_name[4][128]; /*!< gamepad names */
  1535. u16 RGFW_gamepadCount = 0; /*!< the actual amount of gamepads */
  1536. /*
  1537. event callback defines start here
  1538. */
  1539. /*
  1540. These exist to avoid the
  1541. if (func == NULL) check
  1542. for (allegedly) better performance
  1543. RGFW_EMPTY_DEF exists to prevent the missing-prototypes warning
  1544. */
  1545. static void RGFW_windowMovedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
  1546. static void RGFW_windowResizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
  1547. static void RGFW_windowRestoredfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
  1548. static void RGFW_windowMinimizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
  1549. static void RGFW_windowMaximizedfuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
  1550. static void RGFW_windowQuitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); }
  1551. static void RGFW_focusfuncEMPTY(RGFW_window* win, RGFW_bool inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);}
  1552. static void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_bool status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);}
  1553. static void RGFW_mousePosfuncEMPTY(RGFW_window* win, RGFW_point point, RGFW_point vector) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(vector);}
  1554. static void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);}
  1555. static void RGFW_windowRefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); }
  1556. static void RGFW_keyfuncEMPTY(RGFW_window* win, RGFW_key key, u8 keyChar, RGFW_keymod keyMod, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(key); RGFW_UNUSED(keyChar); RGFW_UNUSED(keyMod); RGFW_UNUSED(pressed);}
  1557. static void RGFW_mouseButtonfuncEMPTY(RGFW_window* win, RGFW_mouseButton button, double scroll, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);}
  1558. static void RGFW_gamepadButtonfuncEMPTY(RGFW_window* win, u16 gamepad, u8 button, RGFW_bool pressed) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(button); RGFW_UNUSED(pressed); }
  1559. static void RGFW_gamepadAxisfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_point axis[2], u8 axisesCount, u8 whichAxis) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); RGFW_UNUSED(whichAxis); }
  1560. static void RGFW_gamepadfuncEMPTY(RGFW_window* win, u16 gamepad, RGFW_bool connected) {RGFW_UNUSED(win); RGFW_UNUSED(gamepad); RGFW_UNUSED(connected);}
  1561. static void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, size_t droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);}
  1562. static void RGFW_scaleUpdatedfuncEMPTY(RGFW_window* win, float scaleX, float scaleY) {RGFW_UNUSED(win); RGFW_UNUSED(scaleX); RGFW_UNUSED(scaleY); }
  1563. #define RGFW_CALLBACK_DEFINE(x, x2) \
  1564. RGFW_##x##func RGFW_##x##Callback = RGFW_##x##funcEMPTY; \
  1565. RGFW_##x##func RGFW_set##x2##Callback(RGFW_##x##func func) { \
  1566. RGFW_##x##func prev = RGFW_##x##Callback; \
  1567. RGFW_##x##Callback = func; \
  1568. return prev; \
  1569. }
  1570. RGFW_CALLBACK_DEFINE(windowMaximized, WindowMaximized)
  1571. RGFW_CALLBACK_DEFINE(windowMinimized, WindowMinimized)
  1572. RGFW_CALLBACK_DEFINE(windowRestored, WindowRestored)
  1573. RGFW_CALLBACK_DEFINE(windowMoved, WindowMoved)
  1574. RGFW_CALLBACK_DEFINE(windowResized, WindowResized)
  1575. RGFW_CALLBACK_DEFINE(windowQuit, WindowQuit)
  1576. RGFW_CALLBACK_DEFINE(mousePos, MousePos)
  1577. RGFW_CALLBACK_DEFINE(windowRefresh, WindowRefresh)
  1578. RGFW_CALLBACK_DEFINE(focus, Focus)
  1579. RGFW_CALLBACK_DEFINE(mouseNotify, MouseNotify)
  1580. RGFW_CALLBACK_DEFINE(dnd, Dnd)
  1581. RGFW_CALLBACK_DEFINE(dndInit, DndInit)
  1582. RGFW_CALLBACK_DEFINE(key, Key)
  1583. RGFW_CALLBACK_DEFINE(mouseButton, MouseButton)
  1584. RGFW_CALLBACK_DEFINE(gamepadButton, GamepadButton)
  1585. RGFW_CALLBACK_DEFINE(gamepadAxis, GamepadAxis)
  1586. RGFW_CALLBACK_DEFINE(gamepad, Gamepad)
  1587. RGFW_CALLBACK_DEFINE(scaleUpdated, ScaleUpdated)
  1588. #undef RGFW_CALLBACK_DEFINE
  1589. void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) {
  1590. RGFW_window_eventWait(win, waitMS);
  1591. while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) {
  1592. if (win->event.type == RGFW_quit) return;
  1593. }
  1594. #ifdef RGFW_WASM /* WASM needs to run the sleep function for asyncify */
  1595. RGFW_sleep(0);
  1596. #endif
  1597. }
  1598. void RGFW_window_checkMode(RGFW_window* win);
  1599. void RGFW_window_checkMode(RGFW_window* win) {
  1600. if (RGFW_window_isMinimized(win)) {
  1601. win->_flags |= RGFW_windowMinimize;
  1602. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowMinimized, ._win = win});
  1603. RGFW_windowMinimizedCallback(win, win->r);
  1604. } else if (RGFW_window_isMaximized(win)) {
  1605. win->_flags |= RGFW_windowMaximize;
  1606. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowMaximized, ._win = win});
  1607. RGFW_windowMaximizedCallback(win, win->r);
  1608. } else if (((win->_flags & RGFW_windowMinimize) && !RGFW_window_isMaximized(win)) ||
  1609. (win->_flags & RGFW_windowMaximize && !RGFW_window_isMaximized(win))) {
  1610. win->_flags &= ~(u32)RGFW_windowMinimize;
  1611. if (RGFW_window_isMaximized(win) == RGFW_FALSE) win->_flags &= ~(u32)RGFW_windowMaximize;
  1612. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowRestored, ._win = win});
  1613. RGFW_windowRestoredCallback(win, win->r);
  1614. }
  1615. }
  1616. /*
  1617. no more event call back defines
  1618. */
  1619. #define SET_ATTRIB(a, v) { \
  1620. RGFW_ASSERT(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
  1621. attribs[index++] = a; \
  1622. attribs[index++] = v; \
  1623. }
  1624. #define RGFW_EVENT_PASSED RGFW_BIT(24) /* if a queued event was passed */
  1625. #define RGFW_EVENT_QUIT RGFW_BIT(25) /* the window close button was pressed */
  1626. #define RGFW_HOLD_MOUSE RGFW_BIT(26) /*!< hold the moues still */
  1627. #define RGFW_MOUSE_LEFT RGFW_BIT(27) /* if mouse left the window */
  1628. #define RGFW_WINDOW_ALLOC RGFW_BIT(28) /* if window was allocated by RGFW */
  1629. #define RGFW_BUFFER_ALLOC RGFW_BIT(29) /* if window.buffer was allocated by RGFW */
  1630. #define RGFW_WINDOW_INIT RGFW_BIT(30) /* if window.buffer was allocated by RGFW */
  1631. #define RGFW_INTERNAL_FLAGS (RGFW_EVENT_QUIT | RGFW_EVENT_PASSED | RGFW_HOLD_MOUSE | RGFW_MOUSE_LEFT | RGFW_WINDOW_ALLOC | RGFW_BUFFER_ALLOC | RGFW_windowFocus)
  1632. RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, RGFW_windowFlags flags) {
  1633. RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window));
  1634. RGFW_ASSERT(win != NULL);
  1635. win->_flags = RGFW_WINDOW_ALLOC;
  1636. return RGFW_createWindowPtr(name, rect, flags, win);
  1637. }
  1638. #if defined(RGFW_USE_XDL) && defined(RGFW_X11)
  1639. #define XDL_IMPLEMENTATION
  1640. #include "XDL.h"
  1641. #endif
  1642. #define RGFW_MAX_EVENTS 32
  1643. typedef struct RGFW_globalStruct {
  1644. RGFW_window* root;
  1645. RGFW_window* current;
  1646. i32 windowCount;
  1647. i32 eventLen;
  1648. i32 eventIndex;
  1649. #ifdef RGFW_X11
  1650. Display* display;
  1651. Window helperWindow;
  1652. char* clipboard; /* for writing to the clipboard selection */
  1653. size_t clipboard_len;
  1654. #endif
  1655. #ifdef RGFW_WAYLAND
  1656. struct wl_display* wl_display;
  1657. #endif
  1658. #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
  1659. RGFW_mouse* hiddenMouse;
  1660. #endif
  1661. RGFW_event events[RGFW_MAX_EVENTS];
  1662. } RGFW_globalStruct;
  1663. #ifndef RGFW_C89
  1664. RGFW_globalStruct _RGFW = {.root = NULL, .current = NULL, .windowCount = -1, .eventLen = 0, .eventIndex = 0};
  1665. #else
  1666. RGFW_globalStruct _RGFW = {NULL, NULL, -1, 0, 0};
  1667. #endif
  1668. void RGFW_eventQueuePush(RGFW_event event) {
  1669. if (_RGFW.eventLen >= RGFW_MAX_EVENTS) return;
  1670. _RGFW.events[_RGFW.eventLen] = event;
  1671. _RGFW.eventLen++;
  1672. }
  1673. RGFW_event* RGFW_eventQueuePop(RGFW_window* win) {
  1674. if (_RGFW.eventLen == 0) return NULL;
  1675. RGFW_event* ev = (RGFW_event*)&_RGFW.events[_RGFW.eventIndex];
  1676. _RGFW.eventLen--;
  1677. if (_RGFW.eventLen && _RGFW.eventIndex < (_RGFW.eventLen - 1))
  1678. _RGFW.eventIndex++;
  1679. else if (_RGFW.eventLen == 0)
  1680. _RGFW.eventIndex = 0;
  1681. if (ev->_win != win && ev->_win != NULL) {
  1682. RGFW_eventQueuePush(*ev);
  1683. return NULL;
  1684. }
  1685. ev->droppedFiles = win->event.droppedFiles;
  1686. return ev;
  1687. }
  1688. RGFW_event* RGFW_window_checkEventCore(RGFW_window* win);
  1689. RGFW_event* RGFW_window_checkEventCore(RGFW_window* win) {
  1690. RGFW_ASSERT(win != NULL);
  1691. if (win->event.type == 0 && _RGFW.eventLen == 0)
  1692. RGFW_resetKey();
  1693. if (win->event.type == RGFW_quit && win->_flags & RGFW_windowFreeOnClose) {
  1694. static RGFW_event ev;
  1695. ev = win->event;
  1696. RGFW_window_close(win);
  1697. return &ev;
  1698. }
  1699. if (win->event.type != RGFW_DNDInit) win->event.type = 0;
  1700. /* check queued events */
  1701. RGFW_event* ev = RGFW_eventQueuePop(win);
  1702. if (ev != NULL) {
  1703. if (ev->type == RGFW_quit) RGFW_window_setShouldClose(win, RGFW_TRUE);
  1704. win->event = *ev;
  1705. }
  1706. else return NULL;
  1707. return &win->event;
  1708. }
  1709. RGFWDEF void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags);
  1710. void RGFW_setRootWindow(RGFW_window* win) { _RGFW.root = win; }
  1711. RGFW_window* RGFW_getRootWindow(void) { return _RGFW.root; }
  1712. /* do a basic initialization for RGFW_window, this is to standard it for each OS */
  1713. void RGFW_window_basic_init(RGFW_window* win, RGFW_rect rect, RGFW_windowFlags flags) {
  1714. RGFW_UNUSED(flags);
  1715. if (_RGFW.windowCount == -1) RGFW_init();
  1716. _RGFW.windowCount++;
  1717. /* rect based the requested flags */
  1718. if (_RGFW.root == NULL) {
  1719. RGFW_setRootWindow(win);
  1720. RGFW_setTime(0);
  1721. }
  1722. if (!(win->_flags & RGFW_WINDOW_ALLOC)) win->_flags = 0;
  1723. /* set and init the new window's data */
  1724. win->r = rect;
  1725. win->event.droppedFilesCount = 0;
  1726. win->_flags = 0 | (win->_flags & RGFW_WINDOW_ALLOC);
  1727. win->_flags |= flags;
  1728. win->event.keyMod = 0;
  1729. win->_lastMousePoint = RGFW_POINT(0, 0);
  1730. win->event.droppedFiles = (char**)RGFW_ALLOC(RGFW_MAX_PATH * RGFW_MAX_DROPS);
  1731. RGFW_ASSERT(win->event.droppedFiles != NULL);
  1732. u32 i;
  1733. for (i = 0; i < RGFW_MAX_DROPS; i++)
  1734. win->event.droppedFiles[i] = (char*)(win->event.droppedFiles + RGFW_MAX_DROPS + (i * RGFW_MAX_PATH));
  1735. }
  1736. void RGFW_window_setFlags(RGFW_window* win, RGFW_windowFlags flags) {
  1737. RGFW_windowFlags cmpFlags = win->_flags;
  1738. if (win->_flags & RGFW_WINDOW_INIT) cmpFlags = 0;
  1739. #ifndef RGFW_NO_MONITOR
  1740. if (flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win);
  1741. #endif
  1742. if (flags & RGFW_windowCenter) RGFW_window_center(win);
  1743. if (flags & RGFW_windowCenterCursor)
  1744. RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
  1745. if (flags & RGFW_windowNoBorder) RGFW_window_setBorder(win, 0);
  1746. else RGFW_window_setBorder(win, 1);
  1747. if (flags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, RGFW_TRUE);
  1748. else if (cmpFlags & RGFW_windowFullscreen) RGFW_window_setFullscreen(win, 0);
  1749. if (flags & RGFW_windowMaximize) RGFW_window_maximize(win);
  1750. else if (cmpFlags & RGFW_windowMaximize) RGFW_window_restore(win);
  1751. if (flags & RGFW_windowMinimize) RGFW_window_minimize(win);
  1752. else if (cmpFlags & RGFW_windowMinimize) RGFW_window_restore(win);
  1753. if (flags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 0);
  1754. else if (cmpFlags & RGFW_windowHideMouse) RGFW_window_showMouse(win, 1);
  1755. if (flags & RGFW_windowHide) RGFW_window_hide(win);
  1756. else if (cmpFlags & RGFW_windowHide) RGFW_window_show(win);
  1757. if (flags & RGFW_windowCocoaCHDirToRes) RGFW_moveToMacOSResourceDir();
  1758. if (flags & RGFW_windowFloating) RGFW_window_setFloating(win, 1);
  1759. else if (cmpFlags & RGFW_windowFloating) RGFW_window_setFloating(win, 0);
  1760. if (flags & RGFW_windowFocus) RGFW_window_focus(win);
  1761. if (flags & RGFW_windowNoResize) {
  1762. RGFW_window_setMaxSize(win, RGFW_AREA(win->r.w, win->r.h));
  1763. RGFW_window_setMinSize(win, RGFW_AREA(win->r.w, win->r.h));
  1764. } else if (cmpFlags & RGFW_windowNoResize) {
  1765. RGFW_window_setMaxSize(win, RGFW_AREA(0, 0));
  1766. RGFW_window_setMinSize(win, RGFW_AREA(0, 0));
  1767. }
  1768. win->_flags = flags | (win->_flags & RGFW_INTERNAL_FLAGS);
  1769. }
  1770. RGFW_bool RGFW_window_isInFocus(RGFW_window* win) {
  1771. #ifdef RGFW_WASM
  1772. return RGFW_TRUE;
  1773. #else
  1774. return RGFW_BOOL(win->_flags & RGFW_windowFocus);
  1775. #endif
  1776. }
  1777. void RGFW_window_initBuffer(RGFW_window* win) {
  1778. RGFW_area area = RGFW_getScreenSize();
  1779. if ((win->_flags & RGFW_windowNoResize))
  1780. area = RGFW_AREA(win->r.w, win->r.h);
  1781. RGFW_window_initBufferSize(win, area);
  1782. }
  1783. void RGFW_window_initBufferSize(RGFW_window* win, RGFW_area area) {
  1784. #if defined(RGFW_BUFFER) || defined(RGFW_OSMESA)
  1785. win->_flags |= RGFW_BUFFER_ALLOC;
  1786. #ifndef RGFW_WINDOWS
  1787. u8* buffer = (u8*)RGFW_ALLOC(area.w * area.h * 4);
  1788. RGFW_ASSERT(buffer != NULL);
  1789. RGFW_window_initBufferPtr(win, buffer, area);
  1790. #else /* windows's bitmap allocs memory for us */
  1791. RGFW_window_initBufferPtr(win, (u8*)NULL, area);
  1792. #endif
  1793. #else
  1794. RGFW_UNUSED(win); RGFW_UNUSED(area);
  1795. #endif
  1796. }
  1797. #ifdef RGFW_MACOS
  1798. RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer);
  1799. RGFWDEF void* RGFW_cocoaGetLayer(void);
  1800. #endif
  1801. const char* RGFW_className = NULL;
  1802. void RGFW_setClassName(const char* name) { RGFW_className = name; }
  1803. #ifndef RGFW_X11
  1804. void RGFW_setXInstName(const char* name) { RGFW_UNUSED(name); }
  1805. #endif
  1806. RGFW_keyState RGFW_mouseButtons[RGFW_mouseFinal] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} };
  1807. RGFW_bool RGFW_isMousePressed(RGFW_window* win, RGFW_mouseButton button) {
  1808. return RGFW_mouseButtons[button].current && (win == NULL || RGFW_window_isInFocus(win));
  1809. }
  1810. RGFW_bool RGFW_wasMousePressed(RGFW_window* win, RGFW_mouseButton button) {
  1811. return RGFW_mouseButtons[button].prev && (win != NULL || RGFW_window_isInFocus(win));
  1812. }
  1813. RGFW_bool RGFW_isMouseHeld(RGFW_window* win, RGFW_mouseButton button) {
  1814. return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
  1815. }
  1816. RGFW_bool RGFW_isMouseReleased(RGFW_window* win, RGFW_mouseButton button) {
  1817. return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
  1818. }
  1819. RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
  1820. RGFW_ASSERT(win != NULL);
  1821. return win->_lastMousePoint;
  1822. }
  1823. RGFW_bool RGFW_isPressed(RGFW_window* win, RGFW_key key) {
  1824. return RGFW_keyboard[key].current && (win == NULL || RGFW_window_isInFocus(win));
  1825. }
  1826. RGFW_bool RGFW_wasPressed(RGFW_window* win, RGFW_key key) {
  1827. return RGFW_keyboard[key].prev && (win == NULL || RGFW_window_isInFocus(win));
  1828. }
  1829. RGFW_bool RGFW_isHeld(RGFW_window* win, RGFW_key key) {
  1830. return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
  1831. }
  1832. RGFW_bool RGFW_isClicked(RGFW_window* win, RGFW_key key) {
  1833. return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key));
  1834. }
  1835. RGFW_bool RGFW_isReleased(RGFW_window* win, RGFW_key key) {
  1836. return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
  1837. }
  1838. void RGFW_window_makeCurrent(RGFW_window* win) {
  1839. _RGFW.current = win;
  1840. #if defined(RGFW_OPENGL) || defined(RGFW_EGL)
  1841. RGFW_window_makeCurrent_OpenGL(win);
  1842. #endif
  1843. }
  1844. RGFW_window* RGFW_getCurrent(void) {
  1845. return _RGFW.current;
  1846. }
  1847. void RGFW_window_swapBuffers(RGFW_window* win) {
  1848. RGFW_ASSERT(win != NULL);
  1849. RGFW_window_swapBuffers_software(win);
  1850. #if defined(RGFW_OPENGL) || defined(RGFW_EGL)
  1851. RGFW_window_swapBuffers_OpenGL(win);
  1852. #endif
  1853. }
  1854. RGFWDEF void RGFW_setBit(u32* data, u32 bit, RGFW_bool value);
  1855. void RGFW_setBit(u32* data, u32 bit, RGFW_bool value) {
  1856. if (value)
  1857. *data |= bit;
  1858. else if (!value && (*(data) & bit))
  1859. *data ^= bit;
  1860. }
  1861. void RGFW_window_center(RGFW_window* win) {
  1862. RGFW_ASSERT(win != NULL);
  1863. RGFW_area screenR = RGFW_getScreenSize();
  1864. RGFW_window_move(win, RGFW_POINT((i32)(screenR.w - (u32)win->r.w) / 2, (screenR.h - (u32)win->r.h) / 2));
  1865. }
  1866. RGFW_bool RGFW_monitor_scaleToWindow(RGFW_monitor mon, RGFW_window* win) {
  1867. RGFW_ASSERT(win != NULL);
  1868. RGFW_monitorMode mode;
  1869. mode.area = RGFW_AREA(win->r.w, win->r.h);
  1870. return RGFW_monitor_requestMode(mon, mode, RGFW_monitorScale);
  1871. }
  1872. void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode);
  1873. void RGFW_splitBPP(u32 bpp, RGFW_monitorMode* mode) {
  1874. if (bpp == 32) bpp = 24;
  1875. mode->red = mode->green = mode->blue = (u8)(bpp / 3);
  1876. u32 delta = bpp - (mode->red * 3); /* handle leftovers */
  1877. if (delta >= 1) mode->green = mode->green + 1;
  1878. if (delta == 2) mode->red = mode->red + 1;
  1879. }
  1880. RGFW_bool RGFW_monitorModeCompare(RGFW_monitorMode mon, RGFW_monitorMode mon2, RGFW_modeRequest request) {
  1881. return (((mon.area.w == mon2.area.w && mon.area.h == mon2.area.h) || !(request & RGFW_monitorScale)) &&
  1882. ((mon.refreshRate == mon2.refreshRate) || !(request & RGFW_monitorRefresh)) &&
  1883. ((mon.red == mon2.red && mon.green == mon2.green && mon.blue == mon2.blue) || !(request & RGFW_monitorRGB)));
  1884. }
  1885. RGFW_bool RGFW_window_shouldClose(RGFW_window* win) {
  1886. return (win == NULL || (win->_flags & RGFW_EVENT_QUIT)|| RGFW_isPressed(win, RGFW_escape));
  1887. }
  1888. void RGFW_window_setShouldClose(RGFW_window* win, RGFW_bool shouldClose) {
  1889. if (shouldClose) {
  1890. win->_flags |= RGFW_EVENT_QUIT;
  1891. RGFW_windowQuitCallback(win);
  1892. } else {
  1893. win->_flags &= ~(u32)RGFW_EVENT_QUIT;
  1894. }
  1895. }
  1896. #ifndef RGFW_NO_MONITOR
  1897. void RGFW_window_scaleToMonitor(RGFW_window* win) {
  1898. RGFW_monitor monitor = RGFW_window_getMonitor(win);
  1899. if (monitor.scaleX == 0 && monitor.scaleY == 0)
  1900. return;
  1901. RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleY * (float)win->r.h)));
  1902. }
  1903. void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) {
  1904. RGFW_window_move(win, RGFW_POINT(m.x + win->r.x, m.y + win->r.y));
  1905. }
  1906. #endif
  1907. RGFW_bool RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) {
  1908. return RGFW_window_setIconEx(win, icon, a, channels, RGFW_iconBoth);
  1909. }
  1910. RGFWDEF void RGFW_captureCursor(RGFW_window* win, RGFW_rect);
  1911. RGFWDEF void RGFW_releaseCursor(RGFW_window* win);
  1912. void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) {
  1913. if ((win->_flags & RGFW_HOLD_MOUSE))
  1914. return;
  1915. if (!area.w && !area.h)
  1916. area = RGFW_AREA(win->r.w / 2, win->r.h / 2);
  1917. win->_flags |= RGFW_HOLD_MOUSE;
  1918. RGFW_captureCursor(win, win->r);
  1919. RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
  1920. }
  1921. void RGFW_window_mouseUnhold(RGFW_window* win) {
  1922. win->_flags &= ~(u32)RGFW_HOLD_MOUSE;
  1923. RGFW_releaseCursor(win);
  1924. }
  1925. u32 RGFW_checkFPS(double startTime, u32 frameCount, u32 fpsCap) {
  1926. double deltaTime = RGFW_getTime() - startTime;
  1927. if (deltaTime == 0) return 0;
  1928. double fps = (frameCount / deltaTime); /* the numer of frames over the time it took for them to render */
  1929. if (fpsCap && fps > fpsCap) {
  1930. double frameTime = (double)frameCount / (double)fpsCap; /* how long it should take to finish the frames */
  1931. double sleepTime = frameTime - deltaTime; /* subtract how long it should have taken with how long it did take */
  1932. if (sleepTime > 0) RGFW_sleep((u32)(sleepTime * 1000));
  1933. }
  1934. return (u32) fps;
  1935. }
  1936. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  1937. void RGFW_RGB_to_BGR(RGFW_window* win, u8* data) {
  1938. #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA)
  1939. u32 x, y;
  1940. for (y = 0; y < (u32)win->r.h; y++) {
  1941. for (x = 0; x < (u32)win->r.w; x++) {
  1942. u32 index = (y * 4 * win->bufferSize.w) + x * 4;
  1943. u8 red = data[index];
  1944. data[index] = win->buffer[index + 2];
  1945. data[index + 2] = red;
  1946. }
  1947. }
  1948. #elif defined(RGFW_OSMESA)
  1949. u32 y;
  1950. for(y = 0; y < (u32)win->r.h; y++){
  1951. u32 index_from = (y + (win->bufferSize.h - win->r.h)) * 4 * win->bufferSize.w;
  1952. u32 index_to = y * 4 * win->bufferSize.w;
  1953. memcpy(&data[index_to], &data[index_from], 4 * win->bufferSize.w);
  1954. }
  1955. #else
  1956. RGFW_UNUSED(win); RGFW_UNUSED(data);
  1957. #endif
  1958. }
  1959. #endif
  1960. u32 RGFW_isPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) {
  1961. RGFW_UNUSED(win);
  1962. return RGFW_gamepadPressed[c][button].current;
  1963. }
  1964. u32 RGFW_wasPressedGamepad(RGFW_window* win, u8 c, RGFW_gamepadCodes button) {
  1965. RGFW_UNUSED(win);
  1966. return RGFW_gamepadPressed[c][button].prev;
  1967. }
  1968. u32 RGFW_isReleasedGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) {
  1969. RGFW_UNUSED(win);
  1970. return !RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button);
  1971. }
  1972. u32 RGFW_isHeldGamepad(RGFW_window* win, u8 controller, RGFW_gamepadCodes button) {
  1973. RGFW_UNUSED(win);
  1974. return RGFW_isPressedGamepad(win, controller, button) && RGFW_wasPressedGamepad(win, controller, button);
  1975. }
  1976. RGFW_point RGFW_getGamepadAxis(RGFW_window* win, u16 controller, u16 whichAxis) {
  1977. RGFW_UNUSED(win);
  1978. return RGFW_gamepadAxes[controller][whichAxis];
  1979. }
  1980. const char* RGFW_getGamepadName(RGFW_window* win, u16 controller) {
  1981. RGFW_UNUSED(win);
  1982. return (const char*)RGFW_gamepads_name[controller];
  1983. }
  1984. size_t RGFW_getGamepadCount(RGFW_window* win) {
  1985. RGFW_UNUSED(win);
  1986. return RGFW_gamepadCount;
  1987. }
  1988. RGFW_gamepadType RGFW_getGamepadType(RGFW_window* win, u16 controller) {
  1989. RGFW_UNUSED(win);
  1990. return RGFW_gamepads_type[controller];
  1991. }
  1992. RGFWDEF void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value);
  1993. void RGFW_updateKeyMod(RGFW_window* win, RGFW_keymod mod, RGFW_bool value) {
  1994. if (value) win->event.keyMod |= mod;
  1995. else win->event.keyMod &= ~mod;
  1996. }
  1997. RGFWDEF void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll);
  1998. void RGFW_updateKeyModsPro(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
  1999. RGFW_updateKeyMod(win, RGFW_modCapsLock, capital);
  2000. RGFW_updateKeyMod(win, RGFW_modNumLock, numlock);
  2001. RGFW_updateKeyMod(win, RGFW_modControl, control);
  2002. RGFW_updateKeyMod(win, RGFW_modAlt, alt);
  2003. RGFW_updateKeyMod(win, RGFW_modShift, shift);
  2004. RGFW_updateKeyMod(win, RGFW_modSuper, super);
  2005. RGFW_updateKeyMod(win, RGFW_modScrollLock, scroll);
  2006. }
  2007. RGFWDEF void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll);
  2008. void RGFW_updateKeyMods(RGFW_window* win, RGFW_bool capital, RGFW_bool numlock, RGFW_bool scroll) {
  2009. RGFW_updateKeyModsPro(win, capital, numlock,
  2010. RGFW_isPressed(win, RGFW_controlL) || RGFW_isPressed(win, RGFW_controlR),
  2011. RGFW_isPressed(win, RGFW_altL) || RGFW_isPressed(win, RGFW_altR),
  2012. RGFW_isPressed(win, RGFW_shiftL) || RGFW_isPressed(win, RGFW_shiftR),
  2013. RGFW_isPressed(win, RGFW_superL) || RGFW_isPressed(win, RGFW_superR),
  2014. scroll);
  2015. }
  2016. RGFWDEF void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show);
  2017. void RGFW_window_showMouseFlags(RGFW_window* win, RGFW_bool show) {
  2018. if (show && (win->_flags & RGFW_windowHideMouse))
  2019. win->_flags ^= RGFW_windowHideMouse;
  2020. else if (!show && !(win->_flags & RGFW_windowHideMouse))
  2021. win->_flags |= RGFW_windowHideMouse;
  2022. }
  2023. RGFW_bool RGFW_window_mouseHidden(RGFW_window* win) {
  2024. return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowHideMouse);
  2025. }
  2026. RGFW_bool RGFW_window_borderless(RGFW_window* win) {
  2027. return (RGFW_bool)RGFW_BOOL(win->_flags & RGFW_windowNoBorder);
  2028. }
  2029. RGFW_bool RGFW_window_isFullscreen(RGFW_window* win){ return RGFW_BOOL(win->_flags & RGFW_windowFullscreen); }
  2030. RGFW_bool RGFW_window_allowsDND(RGFW_window* win) { return RGFW_BOOL(win->_flags & RGFW_windowAllowDND); }
  2031. #ifndef RGFW_WINDOWS
  2032. void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
  2033. RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow);
  2034. }
  2035. #endif
  2036. #if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND)
  2037. #ifndef __USE_POSIX199309
  2038. #define __USE_POSIX199309
  2039. #endif
  2040. #include <time.h>
  2041. struct timespec;
  2042. #endif
  2043. #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
  2044. void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
  2045. RGFW_window_showMouseFlags(win, show);
  2046. if (show == 0)
  2047. RGFW_window_setMouse(win, _RGFW.hiddenMouse);
  2048. else
  2049. RGFW_window_setMouseDefault(win);
  2050. }
  2051. #endif
  2052. #ifndef RGFW_MACOS
  2053. void RGFW_moveToMacOSResourceDir(void) { }
  2054. #endif
  2055. /*
  2056. graphics API specific code (end of generic code)
  2057. starts here
  2058. */
  2059. /*
  2060. OpenGL defines start here (Normal, EGL, OSMesa)
  2061. */
  2062. #if defined(RGFW_OPENGL) || defined(RGFW_EGL)
  2063. #ifdef RGFW_WINDOWS
  2064. #define WIN32_LEAN_AND_MEAN
  2065. #define OEMRESOURCE
  2066. #include <windows.h>
  2067. #endif
  2068. #if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER)
  2069. #include <GL/gl.h>
  2070. #elif defined(__APPLE__)
  2071. #ifndef GL_SILENCE_DEPRECATION
  2072. #define GL_SILENCE_DEPRECATION
  2073. #endif
  2074. #include <OpenGL/gl.h>
  2075. #include <OpenGL/OpenGL.h>
  2076. #endif
  2077. /* EGL, normal OpenGL only */
  2078. #ifndef RGFW_EGL
  2079. i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {8,
  2080. #else
  2081. i32 RGFW_GL_HINTS[RGFW_glFinalHint] = {0,
  2082. #endif
  2083. 0, 0, 0, 1, 8, 8, 8, 8, 24, 0, 0, 0, 0, 0, 0, 0, 0, RGFW_glReleaseNone, RGFW_glCore, 0, 0};
  2084. void RGFW_setGLHint(RGFW_glHints hint, i32 value) {
  2085. if (hint < RGFW_glFinalHint && hint) RGFW_GL_HINTS[hint] = value;
  2086. }
  2087. /* OPENGL normal only (no EGL / OSMesa) */
  2088. #if defined(RGFW_OPENGL) && !defined(RGFW_EGL) && !defined(RGFW_CUSTOM_BACKEND) && !defined(RGFW_WASM)
  2089. #define RGFW_GL_RENDER_TYPE RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE, 0x2003, 73, 0)
  2090. #define RGFW_GL_ALPHA_SIZE RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE, 0x201b, 11, 0)
  2091. #define RGFW_GL_DEPTH_SIZE RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE, 0x2022, 12, 0)
  2092. #define RGFW_GL_DOUBLEBUFFER RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER, 0x2011, 5, 0)
  2093. #define RGFW_GL_STENCIL_SIZE RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE, 0x2023, 13, 0)
  2094. #define RGFW_GL_SAMPLES RGFW_OS_BASED_VALUE(GLX_SAMPLES, 0x2042, 55, 0)
  2095. #define RGFW_GL_STEREO RGFW_OS_BASED_VALUE(GLX_STEREO, 0x2012, 6, 0)
  2096. #define RGFW_GL_AUX_BUFFERS RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS, 0x2024, 7, 0)
  2097. #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
  2098. #define RGFW_GL_DRAW RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE, 0x2001, 0, 0)
  2099. #define RGFW_GL_DRAW_TYPE RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE, 0x2013, 0, 0)
  2100. #define RGFW_GL_FULL_FORMAT RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR, 0x2027, 0, 0)
  2101. #define RGFW_GL_RED_SIZE RGFW_OS_BASED_VALUE(GLX_RED_SIZE, 0x2015, 0, 0)
  2102. #define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0, 0)
  2103. #define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0, 0)
  2104. #define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0, 0)
  2105. #define RGFW_GL_ACCUM_RED_SIZE RGFW_OS_BASED_VALUE(14, 0x201E, 0, 0)
  2106. #define RGFW_GL_ACCUM_GREEN_SIZE RGFW_OS_BASED_VALUE(15, 0x201F, 0, 0)
  2107. #define RGFW_GL_ACCUM_BLUE_SIZE RGFW_OS_BASED_VALUE(16, 0x2020, 0, 0)
  2108. #define RGFW_GL_ACCUM_ALPHA_SIZE RGFW_OS_BASED_VALUE(17, 0x2021, 0, 0)
  2109. #define RGFW_GL_SRGB RGFW_OS_BASED_VALUE(0x20b2, 0x3089, 0, 0)
  2110. #define RGFW_GL_NOERROR RGFW_OS_BASED_VALUE(0x31b3, 0x31b3, 0, 0)
  2111. #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0)
  2112. #define RGFW_GL_RELEASE_BEHAVIOR RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB, 0x2097 , 0, 0)
  2113. #define RGFW_GL_CONTEXT_RELEASE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB, 0x2098, 0, 0)
  2114. #define RGFW_GL_CONTEXT_NONE RGFW_OS_BASED_VALUE(GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB, 0x0000, 0, 0)
  2115. #define RGFW_GL_FLAGS RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0)
  2116. #define RGFW_GL_DEBUG_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_FLAGS_ARB, 0x2094, 0, 0)
  2117. #define RGFW_GL_ROBUST_BIT RGFW_OS_BASED_VALUE(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB, 0x00000004, 0, 0)
  2118. #endif
  2119. #ifdef RGFW_WINDOWS
  2120. #define WGL_SUPPORT_OPENGL_ARB 0x2010
  2121. #define WGL_COLOR_BITS_ARB 0x2014
  2122. #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
  2123. #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
  2124. #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
  2125. #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
  2126. #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
  2127. #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
  2128. #define WGL_SAMPLE_BUFFERS_ARB 0x2041
  2129. #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
  2130. #define WGL_PIXEL_TYPE_ARB 0x2013
  2131. #define WGL_TYPE_RGBA_ARB 0x202B
  2132. #define WGL_TRANSPARENT_ARB 0x200A
  2133. #endif
  2134. /* The window'ing api needs to know how to render the data we (or opengl) give it
  2135. MacOS and Windows do this using a structure called a "pixel format"
  2136. X11 calls it a "Visual"
  2137. This function returns the attributes for the format we want */
  2138. i32* RGFW_initFormatAttribs(u32 useSoftware);
  2139. i32* RGFW_initFormatAttribs(u32 useSoftware) {
  2140. RGFW_UNUSED(useSoftware);
  2141. static i32 attribs[] = {
  2142. #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
  2143. RGFW_GL_RENDER_TYPE,
  2144. RGFW_GL_FULL_FORMAT,
  2145. RGFW_GL_DRAW, 1,
  2146. RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA,
  2147. #endif
  2148. #ifdef RGFW_X11
  2149. GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
  2150. #endif
  2151. #ifdef RGFW_MACOS
  2152. 72,
  2153. 8, 24,
  2154. #endif
  2155. #ifdef RGFW_WINDOWS
  2156. WGL_SUPPORT_OPENGL_ARB, 1,
  2157. WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
  2158. WGL_COLOR_BITS_ARB, 32,
  2159. #endif
  2160. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  2161. };
  2162. size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 27;
  2163. #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
  2164. if (attVal) { \
  2165. attribs[index] = attrib;\
  2166. attribs[index + 1] = attVal;\
  2167. index += 2;\
  2168. }
  2169. #if defined(RGFW_MACOS) && defined(RGFW_COCOA_GRAPHICS_SWITCHING)
  2170. RGFW_GL_ADD_ATTRIB(96, kCGLPFASupportsAutomaticGraphicsSwitching);
  2171. #endif
  2172. RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1);
  2173. RGFW_GL_ADD_ATTRIB(RGFW_GL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]);
  2174. RGFW_GL_ADD_ATTRIB(RGFW_GL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]);
  2175. RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]);
  2176. RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_GL_HINTS[RGFW_glStereo]);
  2177. RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_GL_HINTS[RGFW_glAuxBuffers]);
  2178. #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
  2179. RGFW_GL_ADD_ATTRIB(RGFW_GL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]);
  2180. RGFW_GL_ADD_ATTRIB(RGFW_GL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]);
  2181. RGFW_GL_ADD_ATTRIB(RGFW_GL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]);
  2182. #endif
  2183. #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
  2184. RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_RED_SIZE, RGFW_GL_HINTS[RGFW_glAccumRed]);
  2185. RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glAccumBlue]);
  2186. RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glAccumGreen]);
  2187. RGFW_GL_ADD_ATTRIB(RGFW_GL_ACCUM_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAccumAlpha]);
  2188. RGFW_GL_ADD_ATTRIB(RGFW_GL_SRGB, RGFW_GL_HINTS[RGFW_glSRGB]);
  2189. RGFW_GL_ADD_ATTRIB(RGFW_GL_NOERROR, RGFW_GL_HINTS[RGFW_glNoError]);
  2190. if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) {
  2191. RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_RELEASE);
  2192. } else if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_glReleaseNone) {
  2193. RGFW_GL_ADD_ATTRIB(RGFW_GL_RELEASE_BEHAVIOR, RGFW_GL_CONTEXT_NONE);
  2194. }
  2195. i32 flags = 0;
  2196. if (RGFW_GL_HINTS[RGFW_glDebug]) flags |= RGFW_GL_DEBUG_BIT;
  2197. if (RGFW_GL_HINTS[RGFW_glRobustness]) flags |= RGFW_GL_ROBUST_BIT;
  2198. RGFW_GL_ADD_ATTRIB(RGFW_GL_FLAGS, flags);
  2199. #else
  2200. i32 accumSize = (i32)(RGFW_GL_HINTS[RGFW_glAccumRed] + RGFW_GL_HINTS[RGFW_glAccumGreen] + RGFW_GL_HINTS[RGFW_glAccumBlue] + RGFW_GL_HINTS[RGFW_glAccumAlpha]) / 4;
  2201. RGFW_GL_ADD_ATTRIB(14, accumSize);
  2202. #endif
  2203. #ifndef RGFW_X11
  2204. RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]);
  2205. #endif
  2206. #ifdef RGFW_MACOS
  2207. if (useSoftware) {
  2208. RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID);
  2209. } else {
  2210. attribs[index] = RGFW_GL_RENDER_TYPE;
  2211. index += 1;
  2212. }
  2213. #endif
  2214. #ifdef RGFW_MACOS
  2215. /* macOS has the surface attribs and the opengl attribs connected for some reason
  2216. maybe this is to give macOS more control to limit openGL/the opengl version? */
  2217. attribs[index] = 99;
  2218. attribs[index + 1] = 0x1000;
  2219. if (RGFW_GL_HINTS[RGFW_glMajor] >= 4 || RGFW_GL_HINTS[RGFW_glMajor] >= 3) {
  2220. attribs[index + 1] = (i32) ((RGFW_GL_HINTS[RGFW_glMajor] >= 4) ? 0x4100 : 0x3200);
  2221. }
  2222. #endif
  2223. RGFW_GL_ADD_ATTRIB(0, 0);
  2224. return attribs;
  2225. }
  2226. /* EGL only (no OSMesa nor normal OPENGL) */
  2227. #elif defined(RGFW_EGL)
  2228. #include <EGL/egl.h>
  2229. #if defined(RGFW_LINK_EGL)
  2230. typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*);
  2231. PFNEGLINITIALIZEPROC eglInitializeSource;
  2232. PFNEGLGETCONFIGSPROC eglGetConfigsSource;
  2233. PFNEGLCHOOSECONFIgamepadROC eglChooseConfigSource;
  2234. PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource;
  2235. PFNEGLCREATECONTEXTPROC eglCreateContextSource;
  2236. PFNEGLMAKECURRENTPROC eglMakeCurrentSource;
  2237. PFNEGLGETDISPLAYPROC eglGetDisplaySource;
  2238. PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource;
  2239. PFNEGLSWAPINTERVALPROC eglSwapIntervalSource;
  2240. PFNEGLBINDAPIPROC eglBindAPISource;
  2241. PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource;
  2242. PFNEGLTERMINATEPROC eglTerminateSource;
  2243. PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource;
  2244. #define eglInitialize eglInitializeSource
  2245. #define eglGetConfigs eglGetConfigsSource
  2246. #define eglChooseConfig eglChooseConfigSource
  2247. #define eglCreateWindowSurface eglCreateWindowSurfaceSource
  2248. #define eglCreateContext eglCreateContextSource
  2249. #define eglMakeCurrent eglMakeCurrentSource
  2250. #define eglGetDisplay eglGetDisplaySource
  2251. #define eglSwapBuffers eglSwapBuffersSource
  2252. #define eglSwapInterval eglSwapIntervalSource
  2253. #define eglBindAPI eglBindAPISource
  2254. #define eglDestroyContext eglDestroyContextSource
  2255. #define eglTerminate eglTerminateSource
  2256. #define eglDestroySurface eglDestroySurfaceSource;
  2257. #endif
  2258. #define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098
  2259. #define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb
  2260. #ifndef RGFW_GL_ADD_ATTRIB
  2261. #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
  2262. if (attVal) { \
  2263. attribs[index] = attrib;\
  2264. attribs[index + 1] = attVal;\
  2265. index += 2;\
  2266. }
  2267. #endif
  2268. void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software) {
  2269. RGFW_UNUSED(software);
  2270. #if defined(RGFW_LINK_EGL)
  2271. eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize");
  2272. eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs");
  2273. eglChooseConfigSource = (PFNEGLCHOOSECONFIgamepadROC) eglGetProcAddress("eglChooseConfig");
  2274. eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface");
  2275. eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext");
  2276. eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent");
  2277. eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay");
  2278. eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers");
  2279. eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval");
  2280. eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI");
  2281. eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext");
  2282. eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate");
  2283. eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface");
  2284. RGFW_ASSERT(eglInitializeSource != NULL &&
  2285. eglGetConfigsSource != NULL &&
  2286. eglChooseConfigSource != NULL &&
  2287. eglCreateWindowSurfaceSource != NULL &&
  2288. eglCreateContextSource != NULL &&
  2289. eglMakeCurrentSource != NULL &&
  2290. eglGetDisplaySource != NULL &&
  2291. eglSwapBuffersSource != NULL &&
  2292. eglSwapIntervalsSource != NULL &&
  2293. eglBindAPISource != NULL &&
  2294. eglDestroyContextSource != NULL &&
  2295. eglTerminateSource != NULL &&
  2296. eglDestroySurfaceSource != NULL);
  2297. #endif /* RGFW_LINK_EGL */
  2298. #ifdef RGFW_WAYLAND
  2299. if (RGFW_useWaylandBool)
  2300. win->src.eglWindow = wl_egl_window_create(win->src.surface, win->r.w, win->r.h);
  2301. #endif
  2302. #ifdef RGFW_WINDOWS
  2303. win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc);
  2304. #elif defined(RGFW_MACOS)
  2305. win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0);
  2306. #elif defined(RGFW_WAYLAND)
  2307. if (RGFW_useWaylandBool)
  2308. win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.wl_display);
  2309. else
  2310. win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
  2311. #else
  2312. win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
  2313. #endif
  2314. EGLint major, minor;
  2315. eglInitialize(win->src.EGL_display, &major, &minor);
  2316. #ifndef EGL_OPENGL_ES1_BIT
  2317. #define EGL_OPENGL_ES1_BIT 0x1
  2318. #endif
  2319. EGLint egl_config[24] = {
  2320. EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  2321. EGL_RENDERABLE_TYPE,
  2322. #ifdef RGFW_OPENGL_ES1
  2323. EGL_OPENGL_ES1_BIT,
  2324. #elif defined(RGFW_OPENGL_ES3)
  2325. EGL_OPENGL_ES3_BIT,
  2326. #elif defined(RGFW_OPENGL_ES2)
  2327. EGL_OPENGL_ES2_BIT,
  2328. #else
  2329. EGL_OPENGL_BIT,
  2330. #endif
  2331. EGL_NONE, EGL_NONE
  2332. };
  2333. {
  2334. size_t index = 7;
  2335. EGLint* attribs = egl_config;
  2336. RGFW_GL_ADD_ATTRIB(EGL_RED_SIZE, RGFW_GL_HINTS[RGFW_glRed]);
  2337. RGFW_GL_ADD_ATTRIB(EGL_GREEN_SIZE, RGFW_GL_HINTS[RGFW_glBlue]);
  2338. RGFW_GL_ADD_ATTRIB(EGL_BLUE_SIZE, RGFW_GL_HINTS[RGFW_glGreen]);
  2339. RGFW_GL_ADD_ATTRIB(EGL_ALPHA_SIZE, RGFW_GL_HINTS[RGFW_glAlpha]);
  2340. RGFW_GL_ADD_ATTRIB(EGL_DEPTH_SIZE, RGFW_GL_HINTS[RGFW_glDepth]);
  2341. if (RGFW_GL_HINTS[RGFW_glSRGB])
  2342. RGFW_GL_ADD_ATTRIB(0x3089, RGFW_GL_HINTS[RGFW_glSRGB]);
  2343. RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE);
  2344. }
  2345. EGLConfig config;
  2346. EGLint numConfigs;
  2347. eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs);
  2348. #if defined(RGFW_MACOS)
  2349. void* layer = RGFW_cocoaGetLayer();
  2350. RGFW_window_cocoaSetLayer(win, layer);
  2351. win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL);
  2352. #elif defined(RGFW_WINDOWS)
  2353. win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
  2354. #elif defined(RGFW_WAYLAND)
  2355. if (RGFW_useWaylandBool)
  2356. win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.eglWindow, NULL);
  2357. else
  2358. win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
  2359. #else
  2360. win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
  2361. #endif
  2362. EGLint attribs[12];
  2363. size_t index = 0;
  2364. #ifdef RGFW_OPENGL_ES1
  2365. RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 1);
  2366. #elif defined(RGFW_OPENGL_ES2)
  2367. RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 2);
  2368. #elif defined(RGFW_OPENGL_ES3)
  2369. RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, 3);
  2370. #endif
  2371. RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_GL_HINTS[RGFW_glStencil]);
  2372. RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_GL_HINTS[RGFW_glSamples]);
  2373. if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0)
  2374. RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
  2375. if (RGFW_GL_HINTS[RGFW_glMajor]) {
  2376. RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_GL_HINTS[RGFW_glMajor]);
  2377. RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_GL_HINTS[RGFW_glMinor]);
  2378. if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore) {
  2379. RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
  2380. }
  2381. else {
  2382. RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
  2383. }
  2384. }
  2385. RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_ROBUST_ACCESS, RGFW_GL_HINTS[RGFW_glRobustness]);
  2386. RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_DEBUG, RGFW_GL_HINTS[RGFW_glDebug]);
  2387. if (RGFW_GL_HINTS[RGFW_glReleaseBehavior] == RGFW_releaseFlush) {
  2388. RGFW_GL_ADD_ATTRIB(0x2097, 0x2098);
  2389. } else {
  2390. RGFW_GL_ADD_ATTRIB(0x2097, 0x0000);
  2391. }
  2392. RGFW_GL_ADD_ATTRIB(EGL_NONE, EGL_NONE);
  2393. #if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)
  2394. eglBindAPI(EGL_OPENGL_ES_API);
  2395. #else
  2396. eglBindAPI(EGL_OPENGL_API);
  2397. #endif
  2398. win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs);
  2399. if (win->src.EGL_context == NULL) {
  2400. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errEGLContext, RGFW_DEBUG_CTX(win, 0), "failed to create an EGL opengl context");
  2401. return;
  2402. }
  2403. eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
  2404. eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
  2405. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context initalized");
  2406. }
  2407. void RGFW_window_freeOpenGL(RGFW_window* win) {
  2408. if (win->src.EGL_display == NULL) return;
  2409. eglDestroySurface(win->src.EGL_display, win->src.EGL_surface);
  2410. eglDestroyContext(win->src.EGL_display, win->src.EGL_context);
  2411. eglTerminate(win->src.EGL_display);
  2412. win->src.EGL_display = NULL;
  2413. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "EGL opengl context freed");
  2414. }
  2415. void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
  2416. if (win == NULL)
  2417. eglMakeCurrent(_RGFW.root->src.EGL_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  2418. else {
  2419. eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
  2420. }
  2421. }
  2422. void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); }
  2423. void* RGFW_getCurrent_OpenGL(void) { return eglGetCurrentContext(); }
  2424. #ifdef RGFW_APPLE
  2425. void* RGFWnsglFramework = NULL;
  2426. #elif defined(RGFW_WINDOWS)
  2427. HMODULE RGFW_wgl_dll = NULL;
  2428. #endif
  2429. RGFW_proc RGFW_getProcAddress(const char* procname) {
  2430. #if defined(RGFW_WINDOWS)
  2431. RGFW_proc proc = (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
  2432. if (proc)
  2433. return proc;
  2434. #endif
  2435. return (RGFW_proc) eglGetProcAddress(procname);
  2436. }
  2437. void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
  2438. RGFW_ASSERT(win != NULL);
  2439. eglSwapInterval(win->src.EGL_display, swapInterval);
  2440. }
  2441. #endif /* RGFW_EGL */
  2442. /*
  2443. end of RGFW_EGL defines
  2444. */
  2445. #endif /* end of RGFW_GL (OpenGL, EGL, OSMesa )*/
  2446. /*
  2447. RGFW_VULKAN defines
  2448. */
  2449. #ifdef RGFW_VULKAN
  2450. #ifdef RGFW_MACOS
  2451. #include <objc/message.h>
  2452. #endif
  2453. const char** RGFW_getVKRequiredInstanceExtensions(size_t* count) {
  2454. static const char* arr[2] = {VK_KHR_SURFACE_EXTENSION_NAME};
  2455. arr[1] = RGFW_VK_SURFACE;
  2456. if (count != NULL) *count = 2;
  2457. return (const char**)arr;
  2458. }
  2459. VkResult RGFW_window_createVKSurface(RGFW_window* win, VkInstance instance, VkSurfaceKHR* surface) {
  2460. RGFW_ASSERT(win != NULL); RGFW_ASSERT(instance);
  2461. RGFW_ASSERT(surface != NULL);
  2462. *surface = VK_NULL_HANDLE;
  2463. #ifdef RGFW_X11
  2464. RGFW_GOTO_WAYLAND(0);
  2465. VkXlibSurfaceCreateInfoKHR x11 = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, 0, 0, (Display*) win->src.display, (Window) win->src.window };
  2466. return vkCreateXlibSurfaceKHR(instance, &x11, NULL, surface);
  2467. #endif
  2468. #if defined(RGFW_WAYLAND)
  2469. wayland:
  2470. VkWaylandSurfaceCreateInfoKHR wayland = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, 0, 0, (struct wl_display*) win->src.wl_display, (struct wl_surface*) win->src.surface };
  2471. return vkCreateWaylandSurfaceKHR(instance, &wayland, NULL, surface);
  2472. #elif defined(RGFW_WINDOWS)
  2473. VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, 0, 0, GetModuleHandle(NULL), (HWND)win->src.window };
  2474. return vkCreateWin32SurfaceKHR(instance, &win32, NULL, surface);
  2475. #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
  2476. void* contentView = ((void* (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView"));
  2477. VkMacOSSurfaceCreateFlagsMVK macos = { VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, 0, 0, win->src.display, (void*)contentView };
  2478. return vkCreateMacOSSurfaceMVK(instance, &macos, NULL, surface);
  2479. #endif
  2480. }
  2481. RGFW_bool RGFW_getVKPresentationSupport(VkInstance instance, VkPhysicalDevice physicalDevice, u32 queueFamilyIndex) {
  2482. RGFW_ASSERT(instance);
  2483. if (_RGFW.windowCount == -1) RGFW_init();
  2484. #ifdef RGFW_X11
  2485. RGFW_GOTO_WAYLAND(0);
  2486. Visual* visual = DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display));
  2487. if (_RGFW.root)
  2488. visual = _RGFW.root->src.visual.visual;
  2489. RGFW_bool out = vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.display, XVisualIDFromVisual(visual));
  2490. return out;
  2491. #endif
  2492. #if defined(RGFW_WAYLAND)
  2493. wayland:
  2494. RGFW_bool wlout = vkGetPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, _RGFW.wl_display);
  2495. return wlout;
  2496. #elif defined(RGFW_WINDOWS)
  2497. #elif defined(RGFW_MACOS) && !defined(RGFW_MACOS_X11)
  2498. return RGFW_FALSE; /* TODO */
  2499. #endif
  2500. }
  2501. #endif /* end of RGFW_vulkan */
  2502. /*
  2503. This is where OS specific stuff starts
  2504. */
  2505. #if (defined(RGFW_WAYLAND) || defined(RGFW_X11)) && !defined(RGFW_NO_LINUX)
  2506. int RGFW_eventWait_forceStop[] = {0, 0, 0}; /* for wait events */
  2507. #if defined(__linux__)
  2508. #include <linux/joystick.h>
  2509. #include <fcntl.h>
  2510. #include <unistd.h>
  2511. #include <errno.h>
  2512. u32 RGFW_linux_updateGamepad(RGFW_window* win);
  2513. u32 RGFW_linux_updateGamepad(RGFW_window* win) {
  2514. /* check for new gamepads */
  2515. static const char* str[] = {"/dev/input/js0", "/dev/input/js1", "/dev/input/js2", "/dev/input/js3", "/dev/input/js4", "/dev/input/js5"};
  2516. static u8 RGFW_rawGamepads[6];
  2517. {
  2518. u16 i;
  2519. for (i = 0; i < 6; i++) {
  2520. u16 index = RGFW_gamepadCount;
  2521. if (RGFW_rawGamepads[i]) {
  2522. struct input_id device_info;
  2523. if (ioctl(RGFW_rawGamepads[i], EVIOCGID, &device_info) == -2) {
  2524. if (errno == ENODEV) {
  2525. RGFW_rawGamepads[i] = 0;
  2526. }
  2527. }
  2528. continue;
  2529. }
  2530. i32 js = open(str[i], O_RDONLY);
  2531. if (js <= 0)
  2532. break;
  2533. if (RGFW_gamepadCount >= 4) {
  2534. close(js);
  2535. break;
  2536. }
  2537. RGFW_rawGamepads[i] = 1;
  2538. int axes, buttons;
  2539. if (ioctl(js, JSIOCGAXES, &axes) < 0 || ioctl(js, JSIOCGBUTTONS, &buttons) < 0) {
  2540. close(js);
  2541. continue;
  2542. }
  2543. if (buttons <= 5 || buttons >= 30) {
  2544. close(js);
  2545. continue;
  2546. }
  2547. RGFW_gamepadCount++;
  2548. RGFW_gamepads[index] = js;
  2549. ioctl(js, JSIOCGNAME(sizeof(RGFW_gamepads_name[index])), RGFW_gamepads_name[index]);
  2550. RGFW_gamepads_name[index][sizeof(RGFW_gamepads_name[index]) - 1] = 0;
  2551. u8 j;
  2552. for (j = 0; j < 16; j++)
  2553. RGFW_gamepadPressed[index][j] = (RGFW_keyState){0, 0};
  2554. win->event.type = RGFW_gamepadConnected;
  2555. RGFW_gamepads_type[index] = RGFW_gamepadUnknown;
  2556. if (RGFW_STRSTR(RGFW_gamepads_name[index], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[index], "X-Box"))
  2557. RGFW_gamepads_type[index] = RGFW_gamepadMicrosoft;
  2558. else if (RGFW_STRSTR(RGFW_gamepads_name[index], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[index], "PS5"))
  2559. RGFW_gamepads_type[index] = RGFW_gamepadSony;
  2560. else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Nintendo"))
  2561. RGFW_gamepads_type[index] = RGFW_gamepadNintendo;
  2562. else if (RGFW_STRSTR(RGFW_gamepads_name[index], "Logitech"))
  2563. RGFW_gamepads_type[index] = RGFW_gamepadLogitech;
  2564. win->event.gamepad = index;
  2565. RGFW_gamepadCallback(win, index, 1);
  2566. return 1;
  2567. }
  2568. }
  2569. /* check gamepad events */
  2570. u8 i;
  2571. for (i = 0; i < RGFW_gamepadCount; i++) {
  2572. struct js_event e;
  2573. if (RGFW_gamepads[i] == 0)
  2574. continue;
  2575. i32 flags = fcntl(RGFW_gamepads[i], F_GETFL, 0);
  2576. fcntl(RGFW_gamepads[i], F_SETFL, flags | O_NONBLOCK);
  2577. ssize_t bytes;
  2578. while ((bytes = read(RGFW_gamepads[i], &e, sizeof(e))) > 0) {
  2579. switch (e.type) {
  2580. case JS_EVENT_BUTTON: {
  2581. size_t typeIndex = 0;
  2582. if (RGFW_gamepads_type[i] == RGFW_gamepadMicrosoft) typeIndex = 1;
  2583. else if (RGFW_gamepads_type[i] == RGFW_gamepadLogitech) typeIndex = 2;
  2584. win->event.type = e.value ? RGFW_gamepadButtonPressed : RGFW_gamepadButtonReleased;
  2585. u8 RGFW_linux2RGFW[3][RGFW_gamepadR3 + 8] = {{ /* ps */
  2586. RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadY, RGFW_gamepadX, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
  2587. RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight,
  2588. },{ /* xbox */
  2589. RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadSelect, RGFW_gamepadStart,
  2590. RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, 255, 255, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight
  2591. },{ /* Logitech */
  2592. RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY, RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
  2593. RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight
  2594. }
  2595. };
  2596. win->event.button = RGFW_linux2RGFW[typeIndex][e.number];
  2597. win->event.gamepad = i;
  2598. if (win->event.button == 255) break;
  2599. RGFW_gamepadPressed[i][win->event.button].prev = RGFW_gamepadPressed[i][win->event.button].current;
  2600. RGFW_gamepadPressed[i][win->event.button].current = RGFW_BOOL(e.value);
  2601. RGFW_gamepadButtonCallback(win, i, win->event.button, RGFW_BOOL(e.value));
  2602. return 1;
  2603. }
  2604. case JS_EVENT_AXIS: {
  2605. size_t axis = e.number / 2;
  2606. if (axis == 2) axis = 1;
  2607. ioctl(RGFW_gamepads[i], JSIOCGAXES, &win->event.axisesCount);
  2608. win->event.axisesCount = 2;
  2609. if (axis < 3) {
  2610. if (e.number == 0 || e.number == 3)
  2611. RGFW_gamepadAxes[i][axis].x = (i32)((e.value / 32767.0f) * 100);
  2612. else if (e.number == 1 || e.number == 4) {
  2613. RGFW_gamepadAxes[i][axis].y = (i32)((e.value / 32767.0f) * 100);
  2614. }
  2615. }
  2616. win->event.axis[axis] = RGFW_gamepadAxes[i][axis];
  2617. win->event.type = RGFW_gamepadAxisMove;
  2618. win->event.gamepad = i;
  2619. win->event.whichAxis = (u8)axis;
  2620. RGFW_gamepadAxisCallback(win, i, win->event.axis, win->event.axisesCount, win->event.whichAxis);
  2621. return 1;
  2622. }
  2623. default: break;
  2624. }
  2625. }
  2626. if (bytes == -1 && errno == ENODEV) {
  2627. RGFW_gamepadCount--;
  2628. close(RGFW_gamepads[i]);
  2629. RGFW_gamepads[i] = 0;
  2630. win->event.type = RGFW_gamepadDisconnected;
  2631. win->event.gamepad = i;
  2632. RGFW_gamepadCallback(win, i, 0);
  2633. return 1;
  2634. }
  2635. }
  2636. return 0;
  2637. }
  2638. #endif
  2639. #endif
  2640. /*
  2641. Start of Wayland defines
  2642. */
  2643. #ifdef RGFW_WAYLAND
  2644. /*
  2645. Wayland TODO: (out of date)
  2646. - fix RGFW_keyPressed lock state
  2647. RGFW_windowMoved, the window was moved (by the user)
  2648. RGFW_windowResized the window was resized (by the user), [on WASM this means the browser was resized]
  2649. RGFW_windowRefresh The window content needs to be refreshed
  2650. RGFW_DND a file has been dropped into the window
  2651. RGFW_DNDInit
  2652. - window args:
  2653. #define RGFW_windowNoResize the window cannot be resized by the user
  2654. #define RGFW_windowAllowDND the window supports drag and drop
  2655. #define RGFW_scaleToMonitor scale the window to the screen
  2656. - other missing functions functions ("TODO wayland") (~30 functions)
  2657. - fix buffer rendering weird behavior
  2658. */
  2659. #include <errno.h>
  2660. #include <unistd.h>
  2661. #include <sys/mman.h>
  2662. #include <xkbcommon/xkbcommon.h>
  2663. #include <xkbcommon/xkbcommon-keysyms.h>
  2664. #include <dirent.h>
  2665. #include <linux/kd.h>
  2666. #include <wayland-cursor.h>
  2667. RGFW_window* RGFW_key_win = NULL;
  2668. /* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */
  2669. #include "xdg-shell.h"
  2670. #include "xdg-decoration-unstable-v1.h"
  2671. struct xkb_context *xkb_context;
  2672. struct xkb_keymap *keymap = NULL;
  2673. struct xkb_state *xkb_state = NULL;
  2674. enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, RGFW_current_mode;
  2675. struct zxdg_decoration_manager_v1 *decoration_manager = NULL;
  2676. struct wl_cursor_theme* RGFW_wl_cursor_theme = NULL;
  2677. struct wl_surface* RGFW_cursor_surface = NULL;
  2678. struct wl_cursor_image* RGFW_cursor_image = NULL;
  2679. void xdg_wm_base_ping_handler(void *data,
  2680. struct xdg_wm_base *wm_base, uint32_t serial)
  2681. {
  2682. RGFW_UNUSED(data);
  2683. xdg_wm_base_pong(wm_base, serial);
  2684. }
  2685. const struct xdg_wm_base_listener xdg_wm_base_listener = {
  2686. .ping = xdg_wm_base_ping_handler,
  2687. };
  2688. RGFW_bool RGFW_wl_configured = 0;
  2689. void xdg_surface_configure_handler(void *data,
  2690. struct xdg_surface *xdg_surface, uint32_t serial)
  2691. {
  2692. RGFW_UNUSED(data);
  2693. xdg_surface_ack_configure(xdg_surface, serial);
  2694. RGFW_wl_configured = 1;
  2695. }
  2696. const struct xdg_surface_listener xdg_surface_listener = {
  2697. .configure = xdg_surface_configure_handler,
  2698. };
  2699. void xdg_toplevel_configure_handler(void *data,
  2700. struct xdg_toplevel *toplevel, int32_t width, int32_t height,
  2701. struct wl_array *states)
  2702. {
  2703. RGFW_UNUSED(data); RGFW_UNUSED(toplevel); RGFW_UNUSED(states);
  2704. RGFW_UNUSED(width); RGFW_UNUSED(height);
  2705. }
  2706. void xdg_toplevel_close_handler(void *data,
  2707. struct xdg_toplevel *toplevel)
  2708. {
  2709. RGFW_UNUSED(data);
  2710. RGFW_window* win = (RGFW_window*)xdg_toplevel_get_user_data(toplevel);
  2711. if (win == NULL)
  2712. win = RGFW_key_win;
  2713. RGFW_eventQueuePush((RGFW_event){.type = RGFW_quit, ._win = win});
  2714. RGFW_windowQuitCallback(win);
  2715. }
  2716. void shm_format_handler(void *data,
  2717. struct wl_shm *shm, uint32_t format)
  2718. {
  2719. RGFW_UNUSED(data); RGFW_UNUSED(shm); RGFW_UNUSED(format);
  2720. }
  2721. const struct wl_shm_listener shm_listener = {
  2722. .format = shm_format_handler,
  2723. };
  2724. const struct xdg_toplevel_listener xdg_toplevel_listener = {
  2725. .configure = xdg_toplevel_configure_handler,
  2726. .close = xdg_toplevel_close_handler,
  2727. };
  2728. RGFW_window* RGFW_mouse_win = NULL;
  2729. void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
  2730. RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface_x); RGFW_UNUSED(surface_y);
  2731. RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
  2732. RGFW_mouse_win = win;
  2733. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mouseEnter,
  2734. .point = RGFW_POINT(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)),
  2735. ._win = win});
  2736. RGFW_mouseNotifyCallback(win, win->event.point, RGFW_TRUE);
  2737. }
  2738. void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) {
  2739. RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface);
  2740. RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
  2741. if (RGFW_mouse_win == win)
  2742. RGFW_mouse_win = NULL;
  2743. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mouseLeave,
  2744. .point = win->event.point,
  2745. ._win = win});
  2746. RGFW_mouseNotifyCallback(win, win->event.point, RGFW_FALSE);
  2747. }
  2748. void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) {
  2749. RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(x); RGFW_UNUSED(y);
  2750. RGFW_ASSERT(RGFW_mouse_win != NULL);
  2751. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mousePosChanged,
  2752. .point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)),
  2753. ._win = RGFW_mouse_win});
  2754. RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)), RGFW_mouse_win->event.vector);
  2755. }
  2756. void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
  2757. RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial);
  2758. RGFW_ASSERT(RGFW_mouse_win != NULL);
  2759. u32 b = (button - 0x110) + 1;
  2760. /* flip right and middle button codes */
  2761. if (b == 2) b = 3;
  2762. else if (b == 3) b = 2;
  2763. RGFW_mouseButtons[b].prev = RGFW_mouseButtons[b].current;
  2764. RGFW_mouseButtons[b].current = RGFW_BOOL(state);
  2765. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mouseButtonPressed + RGFW_BOOL(state),
  2766. .button = (u8)b,
  2767. ._win = RGFW_mouse_win});
  2768. RGFW_mouseButtonCallback(RGFW_mouse_win, (u8)b, 0, RGFW_BOOL(state));
  2769. }
  2770. void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {
  2771. RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis);
  2772. RGFW_ASSERT(RGFW_mouse_win != NULL);
  2773. double scroll = wl_fixed_to_double(value);
  2774. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mouseButtonPressed,
  2775. .button = RGFW_mouseScrollUp + (scroll < 0),
  2776. .scroll = scroll,
  2777. ._win = RGFW_mouse_win});
  2778. RGFW_mouseButtonCallback(RGFW_mouse_win, RGFW_mouseScrollUp + (scroll < 0), scroll, 1);
  2779. }
  2780. void RGFW_doNothing(void) { }
  2781. void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) {
  2782. RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(format);
  2783. char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
  2784. xkb_keymap_unref (keymap);
  2785. keymap = xkb_keymap_new_from_string (xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
  2786. munmap (keymap_string, size);
  2787. close (fd);
  2788. xkb_state_unref (xkb_state);
  2789. xkb_state = xkb_state_new (keymap);
  2790. }
  2791. void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
  2792. RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys);
  2793. RGFW_key_win = (RGFW_window*)wl_surface_get_user_data(surface);
  2794. RGFW_key_win->_flags |= RGFW_windowFocus;
  2795. RGFW_eventQueuePush((RGFW_event){.type = RGFW_focusIn, ._win = RGFW_key_win});
  2796. RGFW_focusCallback(RGFW_key_win, RGFW_TRUE);
  2797. }
  2798. void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) {
  2799. RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial);
  2800. RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
  2801. if (RGFW_key_win == win)
  2802. RGFW_key_win = NULL;
  2803. RGFW_eventQueuePush((RGFW_event){.type = RGFW_focusOut, ._win = win});
  2804. win->_flags &= ~(u32)RGFW_windowFocus;
  2805. RGFW_focusCallback(win, RGFW_FALSE);
  2806. }
  2807. void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
  2808. RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
  2809. if (RGFW_key_win == NULL) return;
  2810. xkb_keysym_t keysym = xkb_state_key_get_one_sym(xkb_state, key + 8);
  2811. u32 RGFWkey = RGFW_apiKeyToRGFW(key + 8);
  2812. RGFW_keyboard[RGFWkey].prev = RGFW_keyboard[RGFWkey].current;
  2813. RGFW_keyboard[RGFWkey].current = RGFW_BOOL(state);
  2814. RGFW_eventQueuePush((RGFW_event){.type = (u8)(RGFW_keyPressed + state),
  2815. .key = (u8)RGFWkey,
  2816. .keyChar = (u8)keysym,
  2817. .repeat = RGFW_isHeld(RGFW_key_win, (u8)RGFWkey),
  2818. ._win = RGFW_key_win});
  2819. RGFW_updateKeyMods(RGFW_key_win, RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Lock")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "Mod2")), RGFW_BOOL(xkb_keymap_mod_get_index(keymap, "ScrollLock")));
  2820. RGFW_keyCallback(RGFW_key_win, (u8)RGFWkey, (u8)keysym, RGFW_key_win->event.keyMod, RGFW_BOOL(state));
  2821. }
  2822. void keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
  2823. RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
  2824. xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
  2825. }
  2826. struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers, (void (*)(void *, struct wl_keyboard *,
  2827. int, int))&RGFW_doNothing};
  2828. void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) {
  2829. RGFW_UNUSED(data);
  2830. struct wl_pointer_listener pointer_listener = (struct wl_pointer_listener){&pointer_enter, &pointer_leave, &pointer_motion, &pointer_button, &pointer_axis, (void (*)(void *, struct wl_pointer *))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, uint32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing, (void (*)(void *, struct wl_pointer *, uint32_t, int32_t))&RGFW_doNothing};
  2831. if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
  2832. struct wl_pointer *pointer = wl_seat_get_pointer (seat);
  2833. wl_pointer_add_listener (pointer, &pointer_listener, NULL);
  2834. }
  2835. if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
  2836. struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat);
  2837. wl_keyboard_add_listener (keyboard, &keyboard_listener, NULL);
  2838. }
  2839. }
  2840. struct wl_seat_listener seat_listener = {&seat_capabilities, (void (*)(void *, struct wl_seat *, const char *))&RGFW_doNothing};
  2841. void wl_global_registry_handler(void *data,
  2842. struct wl_registry *registry, uint32_t id, const char *interface,
  2843. uint32_t version)
  2844. {
  2845. RGFW_window* win = (RGFW_window*)data;
  2846. RGFW_UNUSED(version);
  2847. if (RGFW_STRNCMP(interface, "wl_compositor", 16) == 0) {
  2848. win->src.compositor = wl_registry_bind(registry,
  2849. id, &wl_compositor_interface, 4);
  2850. } else if (RGFW_STRNCMP(interface, "xdg_wm_base", 12) == 0) {
  2851. win->src.xdg_wm_base = wl_registry_bind(registry,
  2852. id, &xdg_wm_base_interface, 1);
  2853. } else if (RGFW_STRNCMP(interface, zxdg_decoration_manager_v1_interface.name, 255) == 0) {
  2854. decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
  2855. } else if (RGFW_STRNCMP(interface, "wl_shm", 7) == 0) {
  2856. win->src.shm = wl_registry_bind(registry,
  2857. id, &wl_shm_interface, 1);
  2858. wl_shm_add_listener(win->src.shm, &shm_listener, NULL);
  2859. } else if (RGFW_STRNCMP(interface,"wl_seat", 8) == 0) {
  2860. win->src.seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
  2861. wl_seat_add_listener(win->src.seat, &seat_listener, NULL);
  2862. }
  2863. }
  2864. void wl_global_registry_remove(void *data, struct wl_registry *registry, uint32_t name) { RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_UNUSED(name); }
  2865. const struct wl_registry_listener registry_listener = {
  2866. .global = wl_global_registry_handler,
  2867. .global_remove = wl_global_registry_remove,
  2868. };
  2869. void decoration_handle_configure(void *data,
  2870. struct zxdg_toplevel_decoration_v1 *decoration,
  2871. enum zxdg_toplevel_decoration_v1_mode mode) {
  2872. RGFW_UNUSED(data); RGFW_UNUSED(decoration);
  2873. RGFW_current_mode = mode;
  2874. }
  2875. const struct zxdg_toplevel_decoration_v1_listener decoration_listener = {
  2876. .configure = decoration_handle_configure,
  2877. };
  2878. void randname(char *buf) {
  2879. struct timespec ts;
  2880. clock_gettime(CLOCK_REALTIME, &ts);
  2881. long r = ts.tv_nsec;
  2882. int i;
  2883. for (i = 0; i < 6; ++i) {
  2884. buf[i] = (char)('A'+(r&15)+(r&16)*2);
  2885. r >>= 5;
  2886. }
  2887. }
  2888. size_t wl_stringlen(char* name) {
  2889. size_t i = 0;
  2890. while (name[i]) { i++; }
  2891. return i;
  2892. }
  2893. int anonymous_shm_open(void) {
  2894. char name[] = "/RGFW-wayland-XXXXXX";
  2895. int retries = 100;
  2896. do {
  2897. randname(name + wl_stringlen(name) - 6);
  2898. --retries;
  2899. /* shm_open guarantees that O_CLOEXEC is set */
  2900. int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
  2901. if (fd >= 0) {
  2902. shm_unlink(name);
  2903. return fd;
  2904. }
  2905. } while (retries > 0 && errno == EEXIST);
  2906. return -1;
  2907. }
  2908. int create_shm_file(off_t size) {
  2909. int fd = anonymous_shm_open();
  2910. if (fd < 0) {
  2911. return fd;
  2912. }
  2913. if (ftruncate(fd, size) < 0) {
  2914. close(fd);
  2915. return -1;
  2916. }
  2917. return fd;
  2918. }
  2919. void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) {
  2920. RGFW_UNUSED(data); RGFW_UNUSED(cb); RGFW_UNUSED(time);
  2921. #ifdef RGFW_BUFFER
  2922. RGFW_window* win = (RGFW_window*)data;
  2923. wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
  2924. wl_surface_damage_buffer(win->src.surface, 0, 0, win->r.w, win->r.h);
  2925. wl_surface_commit(win->src.surface);
  2926. #endif
  2927. }
  2928. const struct wl_callback_listener wl_surface_frame_listener = {
  2929. .done = wl_surface_frame_done,
  2930. };
  2931. #endif /* RGFW_WAYLAND */
  2932. /*
  2933. End of Wayland defines
  2934. */
  2935. /*
  2936. Start of Linux / Unix defines
  2937. */
  2938. #ifdef RGFW_UNIX
  2939. #if !defined(RGFW_NO_X11_CURSOR) && defined(RGFW_X11)
  2940. #include <X11/Xcursor/Xcursor.h>
  2941. #endif
  2942. #include <dlfcn.h>
  2943. #ifndef RGFW_NO_DPI
  2944. #include <X11/extensions/Xrandr.h>
  2945. #include <X11/Xresource.h>
  2946. #endif
  2947. #include <X11/Xatom.h>
  2948. #include <X11/keysymdef.h>
  2949. #include <X11/extensions/sync.h>
  2950. #include <unistd.h>
  2951. #include <X11/XKBlib.h> /* for converting keycode to string */
  2952. #include <X11/cursorfont.h> /* for hiding */
  2953. #include <X11/extensions/shapeconst.h>
  2954. #include <X11/extensions/shape.h>
  2955. #include <X11/extensions/XInput2.h>
  2956. #include <limits.h> /* for data limits (mainly used in drag and drop functions) */
  2957. #include <poll.h>
  2958. /* atoms needed for drag and drop */
  2959. Atom XdndAware, XtextPlain, XtextUriList;
  2960. Atom RGFW_XUTF8_STRING = 0;
  2961. Atom wm_delete_window = 0, RGFW_XCLIPBOARD = 0;
  2962. #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
  2963. typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int);
  2964. typedef void (*PFN_XcursorImageDestroy)(XcursorImage*);
  2965. typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*);
  2966. #endif
  2967. #ifdef RGFW_OPENGL
  2968. typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
  2969. #endif
  2970. #if !defined(RGFW_NO_X11_XI_PRELOAD)
  2971. typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
  2972. PFN_XISelectEvents XISelectEventsSRC = NULL;
  2973. #define XISelectEvents XISelectEventsSRC
  2974. void* X11Xihandle = NULL;
  2975. #endif
  2976. #if !defined(RGFW_NO_X11_EXT_PRELOAD)
  2977. typedef void (* PFN_XSyncIntToValue)(XSyncValue*, int);
  2978. PFN_XSyncIntToValue XSyncIntToValueSRC = NULL;
  2979. #define XSyncIntToValue XSyncIntToValueSRC
  2980. typedef Status (* PFN_XSyncSetCounter)(Display*, XSyncCounter, XSyncValue);
  2981. PFN_XSyncSetCounter XSyncSetCounterSRC = NULL;
  2982. #define XSyncSetCounter XSyncSetCounterSRC
  2983. typedef XSyncCounter (* PFN_XSyncCreateCounter)(Display*, XSyncValue);
  2984. PFN_XSyncCreateCounter XSyncCreateCounterSRC = NULL;
  2985. #define XSyncCreateCounter XSyncCreateCounterSRC
  2986. typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
  2987. PFN_XShapeCombineMask XShapeCombineMaskSRC;
  2988. #define XShapeCombineMask XShapeCombineMaskSRC
  2989. typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int);
  2990. PFN_XShapeCombineRegion XShapeCombineRegionSRC;
  2991. #define XShapeCombineRegion XShapeCombineRegionSRC
  2992. void* X11XEXThandle = NULL;
  2993. #endif
  2994. #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
  2995. PFN_XcursorImageLoadCursor XcursorImageLoadCursorSRC = NULL;
  2996. PFN_XcursorImageCreate XcursorImageCreateSRC = NULL;
  2997. PFN_XcursorImageDestroy XcursorImageDestroySRC = NULL;
  2998. #define XcursorImageLoadCursor XcursorImageLoadCursorSRC
  2999. #define XcursorImageCreate XcursorImageCreateSRC
  3000. #define XcursorImageDestroy XcursorImageDestroySRC
  3001. void* X11Cursorhandle = NULL;
  3002. #endif
  3003. const char* RGFW_instName = NULL;
  3004. void RGFW_setXInstName(const char* name) {
  3005. RGFW_instName = name;
  3006. }
  3007. #if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
  3008. RGFW_proc RGFW_getProcAddress(const char* procname) { return (RGFW_proc) glXGetProcAddress((GLubyte*) procname); }
  3009. #endif
  3010. void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) {
  3011. RGFW_GOTO_WAYLAND(0);
  3012. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  3013. win->buffer = (u8*)buffer;
  3014. win->bufferSize = area;
  3015. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoBuffer, RGFW_DEBUG_CTX(win, 0), "createing a 4 channel buffer");
  3016. #ifdef RGFW_X11
  3017. #ifdef RGFW_OSMESA
  3018. win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
  3019. OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
  3020. OSMesaPixelStore(OSMESA_Y_UP, 0);
  3021. #endif
  3022. win->src.bitmap = XCreateImage(
  3023. win->src.display, win->src.visual.visual, (u32)win->src.visual.depth,
  3024. ZPixmap, 0, NULL, area.w, area.h, 32, 0
  3025. );
  3026. #endif
  3027. #ifdef RGFW_WAYLAND
  3028. wayland: {}
  3029. u32 size = (u32)(win->r.w * win->r.h * 4);
  3030. int fd = create_shm_file(size);
  3031. if (fd < 0) {
  3032. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, (u32)fd),"Failed to create a buffer.");
  3033. exit(1);
  3034. }
  3035. win->src.buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  3036. if (win->src.buffer == MAP_FAILED) {
  3037. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errBuffer, RGFW_DEBUG_CTX(win, 0), "mmap failed!");
  3038. close(fd);
  3039. exit(1);
  3040. }
  3041. win->_flags |= RGFW_BUFFER_ALLOC;
  3042. struct wl_shm_pool* pool = wl_shm_create_pool(win->src.shm, fd, (i32)size);
  3043. win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4,
  3044. WL_SHM_FORMAT_ARGB8888);
  3045. wl_shm_pool_destroy(pool);
  3046. close(fd);
  3047. wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
  3048. wl_surface_commit(win->src.surface);
  3049. u8 color[] = {0x00, 0x00, 0x00, 0xFF};
  3050. size_t i;
  3051. for (i = 0; i < area.w * area.h * 4; i += 4) {
  3052. RGFW_MEMCPY(&win->buffer[i], color, 4);
  3053. }
  3054. RGFW_MEMCPY(win->src.buffer, win->buffer, (size_t)(win->r.w * win->r.h * 4));
  3055. #if defined(RGFW_OSMESA)
  3056. win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
  3057. OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
  3058. OSMesaPixelStore(OSMESA_Y_UP, 0);
  3059. #endif
  3060. #endif
  3061. #else
  3062. #ifdef RGFW_WAYLAND
  3063. wayland:{}
  3064. #endif
  3065. RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area);
  3066. #endif
  3067. }
  3068. #define RGFW_LOAD_ATOM(name) \
  3069. static Atom name = 0; \
  3070. if (name == 0) name = XInternAtom(_RGFW.display, #name, False);
  3071. void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
  3072. RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
  3073. RGFW_GOTO_WAYLAND(0);
  3074. #ifdef RGFW_X11
  3075. RGFW_LOAD_ATOM(_MOTIF_WM_HINTS);
  3076. struct __x11WindowHints {
  3077. unsigned long flags, functions, decorations, status;
  3078. long input_mode;
  3079. } hints;
  3080. hints.flags = 2;
  3081. hints.decorations = border;
  3082. XChangeProperty(win->src.display, win->src.window, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32,
  3083. PropModeReplace, (u8*)&hints, 5
  3084. );
  3085. if (RGFW_window_isHidden(win) == 0) {
  3086. RGFW_window_hide(win);
  3087. RGFW_window_show(win);
  3088. }
  3089. #endif
  3090. #ifdef RGFW_WAYLAND
  3091. wayland:
  3092. RGFW_UNUSED(win); RGFW_UNUSED(border);
  3093. #endif
  3094. }
  3095. void RGFW_releaseCursor(RGFW_window* win) {
  3096. RGFW_GOTO_WAYLAND(0);
  3097. #ifdef RGFW_X11
  3098. XUngrabPointer(win->src.display, CurrentTime);
  3099. /* disable raw input */
  3100. unsigned char mask[] = { 0 };
  3101. XIEventMask em;
  3102. em.deviceid = XIAllMasterDevices;
  3103. em.mask_len = sizeof(mask);
  3104. em.mask = mask;
  3105. XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
  3106. #endif
  3107. #ifdef RGFW_WAYLAND
  3108. wayland:
  3109. RGFW_UNUSED(win);
  3110. #endif
  3111. }
  3112. void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
  3113. RGFW_GOTO_WAYLAND(0);
  3114. #ifdef RGFW_X11
  3115. /* enable raw input */
  3116. unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
  3117. XISetMask(mask, XI_RawMotion);
  3118. XIEventMask em;
  3119. em.deviceid = XIAllMasterDevices;
  3120. em.mask_len = sizeof(mask);
  3121. em.mask = mask;
  3122. XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
  3123. XGrabPointer(win->src.display, win->src.window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
  3124. RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (i32)(r.w / 2), win->r.y + (i32)(r.h / 2)));
  3125. #endif
  3126. #ifdef RGFW_WAYLAND
  3127. wayland:
  3128. RGFW_UNUSED(win); RGFW_UNUSED(r);
  3129. #endif
  3130. }
  3131. #define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = dlopen(lib, RTLD_LAZY | RTLD_LOCAL)
  3132. #define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) { \
  3133. void* ptr = dlsym(proc, #name); \
  3134. if (ptr != NULL) memcpy(&name##SRC, &ptr, sizeof(PFN_##name)); \
  3135. }
  3136. void RGFW_window_getVisual(RGFW_window* win, RGFW_bool software) {
  3137. #if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
  3138. i32* visual_attribs = RGFW_initFormatAttribs(software);
  3139. i32 fbcount;
  3140. GLXFBConfig* fbc = glXChooseFBConfig(win->src.display, DefaultScreen(win->src.display), visual_attribs, &fbcount);
  3141. i32 best_fbc = -1;
  3142. i32 best_depth = 0;
  3143. i32 best_samples = 0;
  3144. if (fbcount == 0) {
  3145. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to find any valid GLX visual configs");
  3146. return;
  3147. }
  3148. i32 i;
  3149. for (i = 0; i < fbcount; i++) {
  3150. XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, fbc[i]);
  3151. if (vi == NULL)
  3152. continue;
  3153. i32 samp_buf, samples;
  3154. glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
  3155. glXGetFBConfigAttrib(win->src.display, fbc[i], GLX_SAMPLES, &samples);
  3156. if (best_fbc == -1) best_fbc = i;
  3157. if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && best_depth == 0) {
  3158. best_fbc = i;
  3159. best_depth = vi->depth;
  3160. }
  3161. if ((!(win->_flags & RGFW_windowTransparent) || vi->depth == 32) && samples <= RGFW_GL_HINTS[RGFW_glSamples] && samples > best_samples) {
  3162. best_fbc = i;
  3163. best_depth = vi->depth;
  3164. best_samples = samples;
  3165. }
  3166. XFree(vi);
  3167. }
  3168. if (best_fbc == -1) {
  3169. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to get a valid GLX visual");
  3170. return;
  3171. }
  3172. win->src.bestFbc = fbc[best_fbc];
  3173. XVisualInfo* vi = glXGetVisualFromFBConfig(win->src.display, win->src.bestFbc);
  3174. if (vi->depth != 32 && (win->_flags & RGFW_windowTransparent))
  3175. RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to to find a matching visual with a 32-bit depth");
  3176. if (best_samples < RGFW_GL_HINTS[RGFW_glSamples])
  3177. RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load matching sampiling");
  3178. XFree(fbc);
  3179. win->src.visual = *vi;
  3180. #else
  3181. RGFW_UNUSED(software);
  3182. win->src.visual.visual = DefaultVisual(win->src.display, DefaultScreen(win->src.display));
  3183. win->src.visual.depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display));
  3184. if (win->_flags & RGFW_windowTransparent) {
  3185. XMatchVisualInfo(win->src.display, DefaultScreen(win->src.display), 32, TrueColor, &win->src.visual); /*!< for RGBA backgrounds */
  3186. if (win->src.visual.depth != 32)
  3187. RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Failed to load a 32-bit depth");
  3188. }
  3189. #endif
  3190. }
  3191. #ifndef RGFW_EGL
  3192. void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software) {
  3193. RGFW_UNUSED(software);
  3194. #ifdef RGFW_OPENGL
  3195. i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 };
  3196. context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB;
  3197. if (RGFW_GL_HINTS[RGFW_glProfile] == RGFW_glCore)
  3198. context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
  3199. else
  3200. context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
  3201. if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) {
  3202. context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB;
  3203. context_attribs[3] = RGFW_GL_HINTS[RGFW_glMajor];
  3204. context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB;
  3205. context_attribs[5] = RGFW_GL_HINTS[RGFW_glMinor];
  3206. }
  3207. glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
  3208. glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
  3209. glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB");
  3210. GLXContext ctx = NULL;
  3211. if (_RGFW.root != NULL && _RGFW.root != win) {
  3212. ctx = _RGFW.root->src.ctx;
  3213. RGFW_window_makeCurrent_OpenGL(_RGFW.root);
  3214. }
  3215. if (glXCreateContextAttribsARB == NULL) {
  3216. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to load proc address 'glXCreateContextAttribsARB', loading a generic opengl context");
  3217. win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True);
  3218. }
  3219. else {
  3220. win->src.ctx = glXCreateContextAttribsARB(win->src.display, win->src.bestFbc, ctx, True, context_attribs);
  3221. XSync(win->src.display, False);
  3222. if (win->src.ctx == NULL) {
  3223. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "failed to create an opengl context with AttribsARB, loading a generic opengl context");
  3224. win->src.ctx = glXCreateContext(win->src.display, &win->src.visual, ctx, True);
  3225. }
  3226. }
  3227. glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);
  3228. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
  3229. #else
  3230. RGFW_UNUSED(win); RGFW_UNUSED(software);
  3231. #endif
  3232. }
  3233. void RGFW_window_freeOpenGL(RGFW_window* win) {
  3234. #ifdef RGFW_OPENGL
  3235. if (win->src.ctx == NULL) return;
  3236. glXDestroyContext(win->src.display, win->src.ctx);
  3237. win->src.ctx = NULL;
  3238. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
  3239. #else
  3240. RGFW_UNUSED(win);
  3241. #endif
  3242. }
  3243. #endif
  3244. i32 RGFW_init(void) {
  3245. RGFW_GOTO_WAYLAND(1);
  3246. #ifdef RGFW_X11
  3247. if (_RGFW.windowCount != -1) return 0;
  3248. #ifdef RGFW_USE_XDL
  3249. XDL_init();
  3250. #endif
  3251. #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
  3252. #if defined(__CYGWIN__)
  3253. RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor-1.so");
  3254. #elif defined(__OpenBSD__) || defined(__NetBSD__)
  3255. RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so");
  3256. #else
  3257. RGFW_LOAD_LIBRARY(X11Cursorhandle, "libXcursor.so.1");
  3258. #endif
  3259. RGFW_PROC_DEF(X11Cursorhandle, XcursorImageCreate);
  3260. RGFW_PROC_DEF(X11Cursorhandle, XcursorImageDestroy);
  3261. RGFW_PROC_DEF(X11Cursorhandle, XcursorImageLoadCursor);
  3262. #endif
  3263. #if !defined(RGFW_NO_X11_XI_PRELOAD)
  3264. #if defined(__CYGWIN__)
  3265. RGFW_LOAD_LIBRARY(X11Xihandle, "libXi-6.so");
  3266. #elif defined(__OpenBSD__) || defined(__NetBSD__)
  3267. RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so");
  3268. #else
  3269. RGFW_LOAD_LIBRARY(X11Xihandle, "libXi.so.6");
  3270. #endif
  3271. RGFW_PROC_DEF(X11Xihandle, XISelectEvents);
  3272. #endif
  3273. #if !defined(RGFW_NO_X11_EXT_PRELOAD)
  3274. #if defined(__CYGWIN__)
  3275. RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext-6.so");
  3276. #elif defined(__OpenBSD__) || defined(__NetBSD__)
  3277. RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so");
  3278. #else
  3279. RGFW_LOAD_LIBRARY(X11XEXThandle, "libXext.so.6");
  3280. #endif
  3281. RGFW_PROC_DEF(X11XEXThandle, XSyncCreateCounter);
  3282. RGFW_PROC_DEF(X11XEXThandle, XSyncIntToValue);
  3283. RGFW_PROC_DEF(X11XEXThandle, XSyncSetCounter);
  3284. RGFW_PROC_DEF(X11XEXThandle, XShapeCombineRegion);
  3285. RGFW_PROC_DEF(X11XEXThandle, XShapeCombineMask);
  3286. #endif
  3287. XInitThreads(); /*!< init X11 threading */
  3288. _RGFW.display = XOpenDisplay(0);
  3289. XSetWindowAttributes wa;
  3290. wa.event_mask = PropertyChangeMask;
  3291. _RGFW.helperWindow = XCreateWindow(_RGFW.display, XDefaultRootWindow(_RGFW.display), 0, 0, 1, 1, 0, 0,
  3292. InputOnly, DefaultVisual(_RGFW.display, DefaultScreen(_RGFW.display)), CWEventMask, &wa);
  3293. _RGFW.windowCount = 0;
  3294. u8 RGFW_blk[] = { 0, 0, 0, 0 };
  3295. _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4);
  3296. _RGFW.clipboard = NULL;
  3297. XkbComponentNamesRec rec;
  3298. XkbDescPtr desc = XkbGetMap(_RGFW.display, 0, XkbUseCoreKbd);
  3299. XkbDescPtr evdesc;
  3300. u8 old[sizeof(RGFW_keycodes) / sizeof(RGFW_keycodes[0])];
  3301. XkbGetNames(_RGFW.display, XkbKeyNamesMask, desc);
  3302. memset(&rec, 0, sizeof(rec));
  3303. rec.keycodes = (char*)"evdev";
  3304. evdesc = XkbGetKeyboardByName(_RGFW.display, XkbUseCoreKbd, &rec, XkbGBN_KeyNamesMask, XkbGBN_KeyNamesMask, False);
  3305. /* memo: RGFW_keycodes[x11 keycode] = rgfw keycode */
  3306. if(evdesc != NULL && desc != NULL){
  3307. for(int i = 0; i < (int)sizeof(RGFW_keycodes) / (int)sizeof(RGFW_keycodes[0]); i++){
  3308. old[i] = RGFW_keycodes[i];
  3309. RGFW_keycodes[i] = 0;
  3310. }
  3311. for(int i = evdesc->min_key_code; i <= evdesc->max_key_code; i++){
  3312. for(int j = desc->min_key_code; j <= desc->max_key_code; j++){
  3313. if(strncmp(evdesc->names->keys[i].name, desc->names->keys[j].name, XkbKeyNameLength) == 0){
  3314. RGFW_keycodes[j] = old[i];
  3315. break;
  3316. }
  3317. }
  3318. }
  3319. XkbFreeKeyboard(desc, 0, True);
  3320. XkbFreeKeyboard(evdesc, 0, True);
  3321. }
  3322. #endif
  3323. #ifdef RGFW_WAYLAND
  3324. wayland:
  3325. _RGFW.wl_display = wl_display_connect(NULL);
  3326. #endif
  3327. _RGFW.windowCount = 0;
  3328. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, (RGFW_debugContext){0}, "global context initialized");
  3329. return 0;
  3330. }
  3331. RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
  3332. RGFW_window_basic_init(win, rect, flags);
  3333. #ifdef RGFW_WAYLAND
  3334. win->src.compositor = NULL;
  3335. #endif
  3336. RGFW_GOTO_WAYLAND(0);
  3337. #ifdef RGFW_X11
  3338. i64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted */
  3339. win->src.display = XOpenDisplay(NULL);
  3340. RGFW_window_getVisual(win, RGFW_BOOL(flags & RGFW_windowOpenglSoftware));
  3341. /* make X window attrubutes */
  3342. XSetWindowAttributes swa;
  3343. Colormap cmap;
  3344. swa.colormap = cmap = XCreateColormap(win->src.display,
  3345. DefaultRootWindow(win->src.display),
  3346. win->src.visual.visual, AllocNone);
  3347. swa.background_pixmap = None;
  3348. swa.border_pixel = 0;
  3349. swa.event_mask = event_mask;
  3350. swa.background_pixel = 0;
  3351. /* create the window */
  3352. win->src.window = XCreateWindow(win->src.display, DefaultRootWindow(win->src.display), win->r.x, win->r.y, (u32)win->r.w, (u32)win->r.h,
  3353. 0, win->src.visual.depth, InputOutput, win->src.visual.visual,
  3354. CWColormap | CWBorderPixel | CWBackPixel | CWEventMask, &swa);
  3355. XFreeColors(win->src.display, cmap, NULL, 0, 0);
  3356. win->src.gc = XCreateGC(win->src.display, win->src.window, 0, NULL);
  3357. /* In your .desktop app, if you set the property
  3358. StartupWMClass=RGFW that will assoicate the launcher icon
  3359. with your application - robrohan */
  3360. if (RGFW_className == NULL)
  3361. RGFW_className = (char*)name;
  3362. XClassHint hint;
  3363. hint.res_class = (char*)RGFW_className;
  3364. if (RGFW_instName == NULL) hint.res_name = (char*)name;
  3365. else hint.res_name = (char*)RGFW_instName;
  3366. XSetClassHint(win->src.display, win->src.window, &hint);
  3367. #ifndef RGFW_NO_MONITOR
  3368. if (flags & RGFW_windowScaleToMonitor)
  3369. RGFW_window_scaleToMonitor(win);
  3370. #endif
  3371. XSelectInput(win->src.display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want */
  3372. /* make it so the user can't close the window until the program does */
  3373. if (wm_delete_window == 0) {
  3374. wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False);
  3375. RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False);
  3376. RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False);
  3377. }
  3378. XSetWMProtocols(win->src.display, (Drawable) win->src.window, &wm_delete_window, 1);
  3379. /* set the background */
  3380. RGFW_window_setName(win, name);
  3381. XMoveWindow(win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /*!< move the window to it's proper cords */
  3382. if (flags & RGFW_windowAllowDND) { /* init drag and drop atoms and turn on drag and drop for this window */
  3383. win->_flags |= RGFW_windowAllowDND;
  3384. /* actions */
  3385. XtextUriList = XInternAtom(win->src.display, "text/uri-list", False);
  3386. XtextPlain = XInternAtom(win->src.display, "text/plain", False);
  3387. XdndAware = XInternAtom(win->src.display, "XdndAware", False);
  3388. const u8 version = 5;
  3389. XChangeProperty(win->src.display, win->src.window,
  3390. XdndAware, 4, 32,
  3391. PropModeReplace, &version, 1); /*!< turns on drag and drop */
  3392. }
  3393. #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
  3394. RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST_COUNTER)
  3395. RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST)
  3396. Atom protcols[2] = {_NET_WM_SYNC_REQUEST, wm_delete_window};
  3397. XSetWMProtocols(win->src.display, win->src.window, protcols, 2);
  3398. XSyncValue initial_value;
  3399. XSyncIntToValue(&initial_value, 0);
  3400. win->src.counter = XSyncCreateCounter(win->src.display, initial_value);
  3401. XChangeProperty(win->src.display, win->src.window, _NET_WM_SYNC_REQUEST_COUNTER, XA_CARDINAL, 32, PropModeReplace, (uint8_t*)&win->src.counter, 1);
  3402. #endif
  3403. if ((flags & RGFW_windowNoInitAPI) == 0) {
  3404. RGFW_window_initOpenGL(win, RGFW_BOOL(flags & RGFW_windowOpenglSoftware));
  3405. RGFW_window_initBuffer(win);
  3406. }
  3407. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
  3408. RGFW_window_setMouseDefault(win);
  3409. RGFW_window_setFlags(win, flags);
  3410. RGFW_window_show(win);
  3411. return win; /*return newly created window */
  3412. #endif
  3413. #ifdef RGFW_WAYLAND
  3414. wayland:
  3415. RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "RGFW Wayland support is experimental");
  3416. win->src.wl_display = _RGFW.wl_display;
  3417. if (win->src.wl_display == NULL) {
  3418. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Failed to load Wayland display");
  3419. #ifdef RGFW_X11
  3420. RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningWayland, RGFW_DEBUG_CTX(win, 0), "Falling back to X11");
  3421. RGFW_useWayland(0);
  3422. return RGFW_createWindowPtr(name, rect, flags, win);
  3423. #endif
  3424. return NULL;
  3425. }
  3426. #ifdef RGFW_X11
  3427. win->src.window = _RGFW.helperWindow;
  3428. XMapWindow(win->src.display, win->src.window);
  3429. XFlush(win->src.display);
  3430. if (wm_delete_window == 0) {
  3431. wm_delete_window = XInternAtom(win->src.display, "WM_DELETE_WINDOW", False);
  3432. RGFW_XUTF8_STRING = XInternAtom(win->src.display, "UTF8_STRING", False);
  3433. RGFW_XCLIPBOARD = XInternAtom(win->src.display, "CLIPBOARD", False);
  3434. }
  3435. #endif
  3436. struct wl_registry *registry = wl_display_get_registry(win->src.wl_display);
  3437. wl_registry_add_listener(registry, &registry_listener, win);
  3438. wl_display_roundtrip(win->src.wl_display);
  3439. wl_display_dispatch(win->src.wl_display);
  3440. if (win->src.compositor == NULL) {
  3441. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errWayland, RGFW_DEBUG_CTX(win, 0), "Can't find compositor.");
  3442. return NULL;
  3443. }
  3444. if (RGFW_wl_cursor_theme == NULL) {
  3445. RGFW_wl_cursor_theme = wl_cursor_theme_load(NULL, 24, win->src.shm);
  3446. RGFW_cursor_surface = wl_compositor_create_surface(win->src.compositor);
  3447. struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, "left_ptr");
  3448. RGFW_cursor_image = cursor->images[0];
  3449. struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
  3450. wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
  3451. wl_surface_commit(RGFW_cursor_surface);
  3452. }
  3453. xdg_wm_base_add_listener(win->src.xdg_wm_base, &xdg_wm_base_listener, NULL);
  3454. xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  3455. win->src.surface = wl_compositor_create_surface(win->src.compositor);
  3456. wl_surface_set_user_data(win->src.surface, win);
  3457. win->src.xdg_surface = xdg_wm_base_get_xdg_surface(win->src.xdg_wm_base, win->src.surface);
  3458. xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, NULL);
  3459. xdg_wm_base_set_user_data(win->src.xdg_wm_base, win);
  3460. win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface);
  3461. xdg_toplevel_set_user_data(win->src.xdg_toplevel, win);
  3462. xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, NULL);
  3463. xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h);
  3464. if (!(flags & RGFW_windowNoBorder)) {
  3465. win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
  3466. decoration_manager, win->src.xdg_toplevel);
  3467. }
  3468. wl_display_roundtrip(win->src.wl_display);
  3469. wl_surface_commit(win->src.surface);
  3470. RGFW_window_show(win);
  3471. /* wait for the surface to be configured */
  3472. while (wl_display_dispatch(win->src.wl_display) != -1 && !RGFW_wl_configured) { }
  3473. if ((flags & RGFW_windowNoInitAPI) == 0) {
  3474. RGFW_window_initOpenGL(win, RGFW_BOOL(flags & RGFW_windowOpenglSoftware));
  3475. RGFW_window_initBuffer(win);
  3476. }
  3477. struct wl_callback* callback = wl_surface_frame(win->src.surface);
  3478. wl_callback_add_listener(callback, &wl_surface_frame_listener, win);
  3479. wl_surface_commit(win->src.surface);
  3480. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
  3481. #ifndef RGFW_NO_MONITOR
  3482. if (flags & RGFW_windowScaleToMonitor)
  3483. RGFW_window_scaleToMonitor(win);
  3484. #endif
  3485. RGFW_window_setMouseDefault(win);
  3486. RGFW_window_setFlags(win, flags);
  3487. return win; /* return newly created window */
  3488. #endif
  3489. }
  3490. RGFW_area RGFW_getScreenSize(void) {
  3491. RGFW_GOTO_WAYLAND(1);
  3492. RGFW_init();
  3493. #ifdef RGFW_X11
  3494. Screen* scrn = DefaultScreenOfDisplay(_RGFW.display);
  3495. return RGFW_AREA(scrn->width, scrn->height);
  3496. #endif
  3497. #ifdef RGFW_WAYLAND
  3498. wayland: return RGFW_AREA(_RGFW.root->r.w, _RGFW.root->r.h); /* TODO */
  3499. #endif
  3500. }
  3501. RGFW_point RGFW_getGlobalMousePoint(void) {
  3502. RGFW_init();
  3503. RGFW_point RGFWMouse;
  3504. i32 x, y;
  3505. u32 z;
  3506. Window window1, window2;
  3507. XQueryPointer(_RGFW.display, XDefaultRootWindow(_RGFW.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z);
  3508. return RGFWMouse;
  3509. }
  3510. RGFWDEF void RGFW_XHandleClipboardSelection(XEvent* event);
  3511. void RGFW_XHandleClipboardSelection(XEvent* event) {
  3512. RGFW_LOAD_ATOM(ATOM_PAIR);
  3513. RGFW_LOAD_ATOM(MULTIPLE);
  3514. RGFW_LOAD_ATOM(TARGETS);
  3515. RGFW_LOAD_ATOM(SAVE_TARGETS);
  3516. const XSelectionRequestEvent* request = &event->xselectionrequest;
  3517. const Atom formats[] = { RGFW_XUTF8_STRING, XA_STRING };
  3518. const int formatCount = sizeof(formats) / sizeof(formats[0]);
  3519. if (request->target == TARGETS) {
  3520. const Atom targets[] = { TARGETS, MULTIPLE, RGFW_XUTF8_STRING, XA_STRING };
  3521. XChangeProperty(_RGFW.display, request->requestor, request->property,
  3522. XA_ATOM, 32, PropModeReplace, (u8*) targets, sizeof(targets) / sizeof(Atom));
  3523. } else if (request->target == MULTIPLE) {
  3524. Atom* targets = NULL;
  3525. Atom actualType = 0;
  3526. int actualFormat = 0;
  3527. unsigned long count = 0, bytesAfter = 0;
  3528. XGetWindowProperty(_RGFW.display, request->requestor, request->property, 0, LONG_MAX,
  3529. False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets);
  3530. unsigned long i;
  3531. for (i = 0; i < (u32)count; i += 2) {
  3532. if (targets[i] == RGFW_XUTF8_STRING || targets[i] == XA_STRING)
  3533. XChangeProperty(_RGFW.display, request->requestor, targets[i + 1], targets[i],
  3534. 8, PropModeReplace, (const unsigned char *)_RGFW.clipboard, (i32)_RGFW.clipboard_len);
  3535. else
  3536. targets[i + 1] = None;
  3537. }
  3538. XChangeProperty(_RGFW.display,
  3539. request->requestor, request->property, ATOM_PAIR, 32,
  3540. PropModeReplace, (u8*) targets, (i32)count);
  3541. XFlush(_RGFW.display);
  3542. XFree(targets);
  3543. } else if (request->target == SAVE_TARGETS)
  3544. XChangeProperty(_RGFW.display, request->requestor, request->property, 0, 32, PropModeReplace, NULL, 0);
  3545. else {
  3546. int i;
  3547. for (i = 0; i < formatCount; i++) {
  3548. if (request->target != formats[i])
  3549. continue;
  3550. XChangeProperty(_RGFW.display, request->requestor, request->property, request->target,
  3551. 8, PropModeReplace, (u8*) _RGFW.clipboard, (i32)_RGFW.clipboard_len);
  3552. }
  3553. }
  3554. XEvent reply = { SelectionNotify };
  3555. reply.xselection.property = request->property;
  3556. reply.xselection.display = request->display;
  3557. reply.xselection.requestor = request->requestor;
  3558. reply.xselection.selection = request->selection;
  3559. reply.xselection.target = request->target;
  3560. reply.xselection.time = request->time;
  3561. XSendEvent(_RGFW.display, request->requestor, False, 0, &reply);
  3562. }
  3563. char* RGFW_strtok(char* str, const char* delimStr);
  3564. char* RGFW_strtok(char* str, const char* delimStr) {
  3565. static char* static_str = NULL;
  3566. if (str != NULL)
  3567. static_str = str;
  3568. if (static_str == NULL) {
  3569. return NULL;
  3570. }
  3571. while (*static_str != '\0') {
  3572. RGFW_bool delim = 0;
  3573. const char* d;
  3574. for (d = delimStr; *d != '\0'; d++) {
  3575. if (*static_str == *d) {
  3576. delim = 1;
  3577. break;
  3578. }
  3579. }
  3580. if (!delim)
  3581. break;
  3582. static_str++;
  3583. }
  3584. if (*static_str == '\0')
  3585. return NULL;
  3586. char* token_start = static_str;
  3587. while (*static_str != '\0') {
  3588. int delim = 0;
  3589. const char* d;
  3590. for (d = delimStr; *d != '\0'; d++) {
  3591. if (*static_str == *d) {
  3592. delim = 1;
  3593. break;
  3594. }
  3595. }
  3596. if (delim) {
  3597. *static_str = '\0';
  3598. static_str++;
  3599. break;
  3600. }
  3601. static_str++;
  3602. }
  3603. return token_start;
  3604. }
  3605. i32 RGFW_XHandleClipboardSelectionHelper(void);
  3606. RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
  3607. RGFW_XHandleClipboardSelectionHelper();
  3608. if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
  3609. RGFW_event* ev = RGFW_window_checkEventCore(win);
  3610. if (ev) return ev;
  3611. #if defined(__linux__) && !defined(RGFW_NO_LINUX)
  3612. if (RGFW_linux_updateGamepad(win)) return &win->event;
  3613. #endif
  3614. RGFW_GOTO_WAYLAND(0);
  3615. #ifdef RGFW_X11
  3616. RGFW_LOAD_ATOM(XdndTypeList);
  3617. RGFW_LOAD_ATOM(XdndSelection);
  3618. RGFW_LOAD_ATOM(XdndEnter);
  3619. RGFW_LOAD_ATOM(XdndPosition);
  3620. RGFW_LOAD_ATOM(XdndStatus);
  3621. RGFW_LOAD_ATOM(XdndLeave);
  3622. RGFW_LOAD_ATOM(XdndDrop);
  3623. RGFW_LOAD_ATOM(XdndFinished);
  3624. RGFW_LOAD_ATOM(XdndActionCopy);
  3625. RGFW_LOAD_ATOM(_NET_WM_SYNC_REQUEST);
  3626. RGFW_LOAD_ATOM(WM_PROTOCOLS);
  3627. XPending(win->src.display);
  3628. XEvent E; /*!< raw X11 event */
  3629. /* if there is no unread qued events, get a new one */
  3630. if ((QLength(win->src.display) || XEventsQueued(win->src.display, QueuedAlready) + XEventsQueued(win->src.display, QueuedAfterReading))
  3631. && win->event.type != RGFW_quit
  3632. )
  3633. XNextEvent(win->src.display, &E);
  3634. else {
  3635. return NULL;
  3636. }
  3637. win->event.type = 0;
  3638. /* xdnd data */
  3639. static Window source = 0;
  3640. static long version = 0;
  3641. static i32 format = 0;
  3642. XEvent reply = { ClientMessage };
  3643. switch (E.type) {
  3644. case KeyPress:
  3645. case KeyRelease: {
  3646. win->event.repeat = RGFW_FALSE;
  3647. /* check if it's a real key release */
  3648. if (E.type == KeyRelease && XEventsQueued(win->src.display, QueuedAfterReading)) { /* get next event if there is one */
  3649. XEvent NE;
  3650. XPeekEvent(win->src.display, &NE);
  3651. if (E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) /* check if the current and next are both the same */
  3652. win->event.repeat = RGFW_TRUE;
  3653. }
  3654. /* set event key data */
  3655. win->event.key = (u8)RGFW_apiKeyToRGFW(E.xkey.keycode);
  3656. KeySym sym = (KeySym)XkbKeycodeToKeysym(win->src.display, (KeyCode)E.xkey.keycode, 0, (KeyCode)E.xkey.state & ShiftMask ? 1 : 0);
  3657. if ((E.xkey.state & LockMask) && sym >= XK_a && sym <= XK_z)
  3658. sym = (E.xkey.state & ShiftMask) ? sym + 32 : sym - 32;
  3659. if ((u8)sym != (u32)sym)
  3660. sym = 0;
  3661. win->event.keyChar = (u8)sym;
  3662. RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
  3663. /* get keystate data */
  3664. win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased;
  3665. XKeyboardState keystate;
  3666. XGetKeyboardControl(win->src.display, &keystate);
  3667. RGFW_keyboard[win->event.key].current = (E.type == KeyPress);
  3668. XkbStateRec state;
  3669. XkbGetState(win->src.display, XkbUseCoreKbd, &state);
  3670. RGFW_updateKeyMods(win, (state.locked_mods & LockMask), (state.locked_mods & Mod2Mask), (state.locked_mods & Mod3Mask));
  3671. RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, (E.type == KeyPress));
  3672. break;
  3673. }
  3674. case ButtonPress:
  3675. case ButtonRelease:
  3676. if (E.xbutton.button > RGFW_mouseFinal) { /* skip this event */
  3677. XFlush(win->src.display);
  3678. return RGFW_window_checkEvent(win);
  3679. }
  3680. win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); /* the events match */
  3681. win->event.button = (u8)(E.xbutton.button - 1);
  3682. switch(win->event.button) {
  3683. case RGFW_mouseScrollUp:
  3684. win->event.scroll = 1;
  3685. break;
  3686. case RGFW_mouseScrollDown:
  3687. win->event.scroll = -1;
  3688. break;
  3689. default: break;
  3690. }
  3691. RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
  3692. if (win->event.repeat == RGFW_FALSE)
  3693. win->event.repeat = RGFW_isPressed(win, win->event.key);
  3694. RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress);
  3695. RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress));
  3696. break;
  3697. case MotionNotify:
  3698. win->event.point.x = E.xmotion.x;
  3699. win->event.point.y = E.xmotion.y;
  3700. win->event.vector.x = win->event.point.x - win->_lastMousePoint.x;
  3701. win->event.vector.y = win->event.point.y - win->_lastMousePoint.y;
  3702. win->_lastMousePoint = win->event.point;
  3703. win->event.type = RGFW_mousePosChanged;
  3704. RGFW_mousePosCallback(win, win->event.point, win->event.vector);
  3705. break;
  3706. case GenericEvent: {
  3707. /* MotionNotify is used for mouse events if the mouse isn't held */
  3708. if (!(win->_flags & RGFW_HOLD_MOUSE)) {
  3709. XFreeEventData(win->src.display, &E.xcookie);
  3710. break;
  3711. }
  3712. XGetEventData(win->src.display, &E.xcookie);
  3713. if (E.xcookie.evtype == XI_RawMotion) {
  3714. XIRawEvent *raw = (XIRawEvent *)E.xcookie.data;
  3715. if (raw->valuators.mask_len == 0) {
  3716. XFreeEventData(win->src.display, &E.xcookie);
  3717. break;
  3718. }
  3719. double deltaX = 0.0f;
  3720. double deltaY = 0.0f;
  3721. /* check if relative motion data exists where we think it does */
  3722. if (XIMaskIsSet(raw->valuators.mask, 0) != 0)
  3723. deltaX += raw->raw_values[0];
  3724. if (XIMaskIsSet(raw->valuators.mask, 1) != 0)
  3725. deltaY += raw->raw_values[1];
  3726. win->event.vector = RGFW_POINT((i32)deltaX, (i32)deltaY);
  3727. win->event.point.x = win->_lastMousePoint.x + win->event.vector.x;
  3728. win->event.point.y = win->_lastMousePoint.y + win->event.vector.y;
  3729. win->_lastMousePoint = win->event.point;
  3730. RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
  3731. win->event.type = RGFW_mousePosChanged;
  3732. RGFW_mousePosCallback(win, win->event.point, win->event.vector);
  3733. }
  3734. XFreeEventData(win->src.display, &E.xcookie);
  3735. break;
  3736. }
  3737. case Expose: {
  3738. win->event.type = RGFW_windowRefresh;
  3739. RGFW_windowRefreshCallback(win);
  3740. #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
  3741. XSyncValue value;
  3742. XSyncIntToValue(&value, (i32)win->src.counter_value);
  3743. XSyncSetCounter(win->src.display, win->src.counter, value);
  3744. #endif
  3745. break;
  3746. }
  3747. case MapNotify: case UnmapNotify: RGFW_window_checkMode(win); break;
  3748. case ClientMessage: {
  3749. /* if the client closed the window */
  3750. if (E.xclient.data.l[0] == (long)wm_delete_window) {
  3751. win->event.type = RGFW_quit;
  3752. RGFW_window_setShouldClose(win, RGFW_TRUE);
  3753. RGFW_windowQuitCallback(win);
  3754. break;
  3755. }
  3756. #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
  3757. if (E.xclient.message_type == WM_PROTOCOLS && (Atom)E.xclient.data.l[0] == _NET_WM_SYNC_REQUEST) {
  3758. RGFW_windowRefreshCallback(win);
  3759. win->src.counter_value = 0;
  3760. win->src.counter_value |= E.xclient.data.l[2];
  3761. win->src.counter_value |= (E.xclient.data.l[3] << 32);
  3762. XSyncValue value;
  3763. XSyncIntToValue(&value, (i32)win->src.counter_value);
  3764. XSyncSetCounter(win->src.display, win->src.counter, value);
  3765. break;
  3766. }
  3767. #endif
  3768. if ((win->_flags & RGFW_windowAllowDND) == 0)
  3769. break;
  3770. reply.xclient.window = source;
  3771. reply.xclient.format = 32;
  3772. reply.xclient.data.l[0] = (long)win->src.window;
  3773. reply.xclient.data.l[1] = 0;
  3774. reply.xclient.data.l[2] = None;
  3775. if (E.xclient.message_type == XdndEnter) {
  3776. if (version > 5)
  3777. break;
  3778. unsigned long count;
  3779. Atom* formats;
  3780. Atom real_formats[6];
  3781. Bool list = E.xclient.data.l[1] & 1;
  3782. source = (unsigned long int)E.xclient.data.l[0];
  3783. version = E.xclient.data.l[1] >> 24;
  3784. format = None;
  3785. if (list) {
  3786. Atom actualType;
  3787. i32 actualFormat;
  3788. unsigned long bytesAfter;
  3789. XGetWindowProperty(
  3790. win->src.display, source, XdndTypeList,
  3791. 0, LONG_MAX, False, 4,
  3792. &actualType, &actualFormat, &count, &bytesAfter, (u8**)&formats
  3793. );
  3794. } else {
  3795. count = 0;
  3796. size_t i;
  3797. for (i = 2; i < 5; i++) {
  3798. if (E.xclient.data.l[i] != None) {
  3799. real_formats[count] = (unsigned long int)E.xclient.data.l[i];
  3800. count += 1;
  3801. }
  3802. }
  3803. formats = real_formats;
  3804. }
  3805. size_t i;
  3806. for (i = 0; i < count; i++) {
  3807. if (formats[i] == XtextUriList || formats[i] == XtextPlain) {
  3808. format = (int)formats[i];
  3809. break;
  3810. }
  3811. }
  3812. if (list) {
  3813. XFree(formats);
  3814. }
  3815. break;
  3816. }
  3817. if (E.xclient.message_type == XdndPosition) {
  3818. const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff;
  3819. const i32 yabs = (E.xclient.data.l[2]) & 0xffff;
  3820. Window dummy;
  3821. i32 xpos, ypos;
  3822. if (version > 5)
  3823. break;
  3824. XTranslateCoordinates(
  3825. win->src.display, XDefaultRootWindow(win->src.display), win->src.window,
  3826. xabs, yabs, &xpos, &ypos, &dummy
  3827. );
  3828. win->event.point.x = xpos;
  3829. win->event.point.y = ypos;
  3830. reply.xclient.window = source;
  3831. reply.xclient.message_type = XdndStatus;
  3832. if (format) {
  3833. reply.xclient.data.l[1] = 1;
  3834. if (version >= 2)
  3835. reply.xclient.data.l[4] = (long)XdndActionCopy;
  3836. }
  3837. XSendEvent(win->src.display, source, False, NoEventMask, &reply);
  3838. XFlush(win->src.display);
  3839. break;
  3840. }
  3841. if (E.xclient.message_type != XdndDrop)
  3842. break;
  3843. if (version > 5)
  3844. break;
  3845. size_t i;
  3846. for (i = 0; i < win->event.droppedFilesCount; i++)
  3847. win->event.droppedFiles[i][0] = '\0';
  3848. win->event.droppedFilesCount = 0;
  3849. win->event.type = RGFW_DNDInit;
  3850. if (format) {
  3851. Time time = (version >= 1)
  3852. ? (Time)E.xclient.data.l[2]
  3853. : CurrentTime;
  3854. XConvertSelection(
  3855. win->src.display, XdndSelection, (Atom)format,
  3856. XdndSelection, win->src.window, time
  3857. );
  3858. } else if (version >= 2) {
  3859. XEvent new_reply = { ClientMessage };
  3860. XSendEvent(win->src.display, source, False, NoEventMask, &new_reply);
  3861. XFlush(win->src.display);
  3862. }
  3863. RGFW_dndInitCallback(win, win->event.point);
  3864. } break;
  3865. case SelectionRequest:
  3866. RGFW_XHandleClipboardSelection(&E);
  3867. XFlush(win->src.display);
  3868. return RGFW_window_checkEvent(win);
  3869. case SelectionNotify: {
  3870. /* this is only for checking for xdnd drops */
  3871. if (E.xselection.property != XdndSelection || !(win->_flags & RGFW_windowAllowDND))
  3872. break;
  3873. char* data;
  3874. unsigned long result;
  3875. Atom actualType;
  3876. i32 actualFormat;
  3877. unsigned long bytesAfter;
  3878. XGetWindowProperty(win->src.display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data);
  3879. if (result == 0)
  3880. break;
  3881. const char* prefix = (const char*)"file://";
  3882. char* line;
  3883. win->event.droppedFilesCount = 0;
  3884. win->event.type = RGFW_DND;
  3885. while ((line = (char*)RGFW_strtok(data, "\r\n"))) {
  3886. char path[RGFW_MAX_PATH];
  3887. data = NULL;
  3888. if (line[0] == '#')
  3889. continue;
  3890. char* l;
  3891. for (l = line; 1; l++) {
  3892. if ((l - line) > 7)
  3893. break;
  3894. else if (*l != prefix[(l - line)])
  3895. break;
  3896. else if (*l == '\0' && prefix[(l - line)] == '\0') {
  3897. line += 7;
  3898. while (*line != '/')
  3899. line++;
  3900. break;
  3901. } else if (*l == '\0')
  3902. break;
  3903. }
  3904. win->event.droppedFilesCount++;
  3905. size_t index = 0;
  3906. while (*line) {
  3907. if (line[0] == '%' && line[1] && line[2]) {
  3908. const char digits[3] = { line[1], line[2], '\0' };
  3909. path[index] = (char) RGFW_STRTOL(digits, NULL, 16);
  3910. line += 2;
  3911. } else
  3912. path[index] = *line;
  3913. index++;
  3914. line++;
  3915. }
  3916. path[index] = '\0';
  3917. RGFW_MEMCPY(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1);
  3918. }
  3919. RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
  3920. if (data)
  3921. XFree(data);
  3922. if (version >= 2) {
  3923. XEvent new_reply = { ClientMessage };
  3924. new_reply.xclient.format = 32;
  3925. new_reply.xclient.message_type = XdndFinished;
  3926. new_reply.xclient.data.l[1] = (long int)result;
  3927. new_reply.xclient.data.l[2] = (long int)XdndActionCopy;
  3928. XSendEvent(win->src.display, source, False, NoEventMask, &new_reply);
  3929. XFlush(win->src.display);
  3930. }
  3931. break;
  3932. }
  3933. case FocusIn:
  3934. if ((win->_flags & RGFW_windowFullscreen))
  3935. XMapRaised(win->src.display, win->src.window);
  3936. win->_flags |= RGFW_windowFocus;
  3937. win->event.type = RGFW_focusIn;
  3938. RGFW_focusCallback(win, 1);
  3939. break;
  3940. case FocusOut:
  3941. if ((win->_flags & RGFW_windowFullscreen))
  3942. RGFW_window_minimize(win);
  3943. win->_flags &= ~(u32)RGFW_windowFocus;
  3944. win->event.type = RGFW_focusOut;
  3945. RGFW_focusCallback(win, 0);
  3946. break;
  3947. case PropertyNotify: RGFW_window_checkMode(win); break;
  3948. case EnterNotify: {
  3949. win->event.type = RGFW_mouseEnter;
  3950. win->event.point.x = E.xcrossing.x;
  3951. win->event.point.y = E.xcrossing.y;
  3952. RGFW_mouseNotifyCallback(win, win->event.point, 1);
  3953. break;
  3954. }
  3955. case LeaveNotify: {
  3956. win->event.type = RGFW_mouseLeave;
  3957. RGFW_mouseNotifyCallback(win, win->event.point, 0);
  3958. break;
  3959. }
  3960. case ConfigureNotify: {
  3961. /* detect resize */
  3962. RGFW_window_checkMode(win);
  3963. if (E.xconfigure.width != win->r.w || E.xconfigure.height != win->r.h) {
  3964. win->event.type = RGFW_windowResized;
  3965. win->r = RGFW_RECT(win->r.x, win->r.y, E.xconfigure.width, E.xconfigure.height);
  3966. RGFW_windowResizedCallback(win, win->r);
  3967. break;
  3968. }
  3969. /* detect move */
  3970. if (E.xconfigure.x != win->r.x || E.xconfigure.y != win->r.y) {
  3971. win->event.type = RGFW_windowMoved;
  3972. win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, win->r.w, win->r.h);
  3973. RGFW_windowMovedCallback(win, win->r);
  3974. break;
  3975. }
  3976. break;
  3977. }
  3978. default:
  3979. XFlush(win->src.display);
  3980. return RGFW_window_checkEvent(win);
  3981. }
  3982. XFlush(win->src.display);
  3983. if (win->event.type) return &win->event;
  3984. else return NULL;
  3985. #endif
  3986. #ifdef RGFW_WAYLAND
  3987. wayland:
  3988. if ((win->_flags & RGFW_windowHide) == 0)
  3989. wl_display_roundtrip(win->src.wl_display);
  3990. return NULL;
  3991. #endif
  3992. }
  3993. void RGFW_window_move(RGFW_window* win, RGFW_point v) {
  3994. RGFW_ASSERT(win != NULL);
  3995. win->r.x = v.x;
  3996. win->r.y = v.y;
  3997. RGFW_GOTO_WAYLAND(0);
  3998. #ifdef RGFW_X11
  3999. XMoveWindow(win->src.display, win->src.window, v.x, v.y);
  4000. #endif
  4001. #ifdef RGFW_WAYLAND
  4002. wayland:
  4003. RGFW_ASSERT(win != NULL);
  4004. if (win->src.compositor) {
  4005. struct wl_pointer *pointer = wl_seat_get_pointer(win->src.seat);
  4006. if (!pointer) {
  4007. return;
  4008. }
  4009. wl_display_flush(win->src.wl_display);
  4010. }
  4011. #endif
  4012. }
  4013. void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
  4014. RGFW_ASSERT(win != NULL);
  4015. win->r.w = (i32)a.w;
  4016. win->r.h = (i32)a.h;
  4017. RGFW_GOTO_WAYLAND(0);
  4018. #ifdef RGFW_X11
  4019. XResizeWindow(win->src.display, win->src.window, a.w, a.h);
  4020. if ((win->_flags & RGFW_windowNoResize)) {
  4021. XSizeHints sh;
  4022. sh.flags = (1L << 4) | (1L << 5);
  4023. sh.min_width = sh.max_width = (i32)a.w;
  4024. sh.min_height = sh.max_height = (i32)a.h;
  4025. XSetWMSizeHints(win->src.display, (Drawable) win->src.window, &sh, XA_WM_NORMAL_HINTS);
  4026. }
  4027. #endif
  4028. #ifdef RGFW_WAYLAND
  4029. wayland:
  4030. if (win->src.compositor) {
  4031. xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h);
  4032. #ifdef RGFW_OPENGL
  4033. wl_egl_window_resize(win->src.eglWindow, (i32)a.w, (i32)a.h, 0, 0);
  4034. #endif
  4035. }
  4036. #endif
  4037. }
  4038. void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
  4039. RGFW_ASSERT(win != NULL);
  4040. if (a.w == 0 && a.h == 0)
  4041. return;
  4042. XSizeHints hints;
  4043. long flags;
  4044. XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
  4045. hints.flags |= PAspect;
  4046. hints.min_aspect.x = hints.max_aspect.x = (i32)a.w;
  4047. hints.min_aspect.y = hints.max_aspect.y = (i32)a.h;
  4048. XSetWMNormalHints(win->src.display, win->src.window, &hints);
  4049. }
  4050. void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
  4051. RGFW_ASSERT(win != NULL);
  4052. if (a.w == 0 && a.h == 0)
  4053. return;
  4054. XSizeHints hints;
  4055. long flags;
  4056. XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
  4057. hints.flags |= PMinSize;
  4058. hints.min_width = (i32)a.w;
  4059. hints.min_height = (i32)a.h;
  4060. XSetWMNormalHints(win->src.display, win->src.window, &hints);
  4061. }
  4062. void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
  4063. RGFW_ASSERT(win != NULL);
  4064. if (a.w == 0 && a.h == 0)
  4065. a = RGFW_getScreenSize();
  4066. XSizeHints hints;
  4067. long flags;
  4068. XGetWMNormalHints(win->src.display, win->src.window, &hints, &flags);
  4069. hints.flags |= PMaxSize;
  4070. hints.max_width = (i32)a.w;
  4071. hints.max_height = (i32)a.h;
  4072. XSetWMNormalHints(win->src.display, win->src.window, &hints);
  4073. }
  4074. void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized);
  4075. void RGFW_toggleXMaximized(RGFW_window* win, RGFW_bool maximized) {
  4076. RGFW_ASSERT(win != NULL);
  4077. RGFW_LOAD_ATOM(_NET_WM_STATE);
  4078. RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
  4079. RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
  4080. XEvent xev = {0};
  4081. xev.type = ClientMessage;
  4082. xev.xclient.window = win->src.window;
  4083. xev.xclient.message_type = _NET_WM_STATE;
  4084. xev.xclient.format = 32;
  4085. xev.xclient.data.l[0] = maximized;
  4086. xev.xclient.data.l[1] = (long int)_NET_WM_STATE_MAXIMIZED_HORZ;
  4087. xev.xclient.data.l[2] = (long int)_NET_WM_STATE_MAXIMIZED_VERT;
  4088. xev.xclient.data.l[3] = 0;
  4089. xev.xclient.data.l[4] = 0;
  4090. XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
  4091. }
  4092. void RGFW_window_maximize(RGFW_window* win) {
  4093. win->_oldRect = win->r;
  4094. RGFW_toggleXMaximized(win, 1);
  4095. }
  4096. void RGFW_window_focus(RGFW_window* win) {
  4097. RGFW_ASSERT(win);
  4098. XWindowAttributes attr;
  4099. XGetWindowAttributes(win->src.display, win->src.window, &attr);
  4100. if (attr.map_state != IsViewable) return;
  4101. XSetInputFocus(win->src.display, win->src.window, RevertToPointerRoot, CurrentTime);
  4102. XFlush(win->src.display);
  4103. }
  4104. void RGFW_window_raise(RGFW_window* win) {
  4105. RGFW_ASSERT(win);
  4106. XRaiseWindow(win->src.display, win->src.window);
  4107. XMapRaised(win->src.display, win->src.window);
  4108. }
  4109. void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen);
  4110. void RGFW_window_setXAtom(RGFW_window* win, Atom netAtom, RGFW_bool fullscreen) {
  4111. RGFW_ASSERT(win != NULL);
  4112. RGFW_LOAD_ATOM(_NET_WM_STATE);
  4113. XEvent xev = {0};
  4114. xev.xclient.type = ClientMessage;
  4115. xev.xclient.serial = 0;
  4116. xev.xclient.send_event = True;
  4117. xev.xclient.message_type = _NET_WM_STATE;
  4118. xev.xclient.window = win->src.window;
  4119. xev.xclient.format = 32;
  4120. xev.xclient.data.l[0] = fullscreen;
  4121. xev.xclient.data.l[1] = (long int)netAtom;
  4122. xev.xclient.data.l[2] = 0;
  4123. XSendEvent(win->src.display, DefaultRootWindow(win->src.display), False, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
  4124. }
  4125. void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
  4126. RGFW_ASSERT(win != NULL);
  4127. if (fullscreen) {
  4128. win->_flags |= RGFW_windowFullscreen;
  4129. win->_oldRect = win->r;
  4130. }
  4131. else win->_flags &= ~(u32)RGFW_windowFullscreen;
  4132. RGFW_LOAD_ATOM(_NET_WM_STATE_FULLSCREEN);
  4133. RGFW_window_setXAtom(win, _NET_WM_STATE_FULLSCREEN, fullscreen);
  4134. XRaiseWindow(win->src.display, win->src.window);
  4135. XMapRaised(win->src.display, win->src.window);
  4136. }
  4137. void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
  4138. RGFW_ASSERT(win != NULL);
  4139. RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
  4140. RGFW_window_setXAtom(win, _NET_WM_STATE_ABOVE, floating);
  4141. }
  4142. void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
  4143. RGFW_ASSERT(win != NULL);
  4144. const u32 value = (u32) (0xffffffffu * (double) opacity);
  4145. RGFW_LOAD_ATOM(NET_WM_WINDOW_OPACITY);
  4146. XChangeProperty(win->src.display, win->src.window,
  4147. NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) &value, 1);
  4148. }
  4149. void RGFW_window_minimize(RGFW_window* win) {
  4150. RGFW_ASSERT(win != NULL);
  4151. if (RGFW_window_isMaximized(win)) return;
  4152. win->_oldRect = win->r;
  4153. XIconifyWindow(win->src.display, win->src.window, DefaultScreen(win->src.display));
  4154. XFlush(win->src.display);
  4155. }
  4156. void RGFW_window_restore(RGFW_window* win) {
  4157. RGFW_ASSERT(win != NULL);
  4158. RGFW_toggleXMaximized(win, 0);
  4159. win->r = win->_oldRect;
  4160. RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y));
  4161. RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h));
  4162. RGFW_window_show(win);
  4163. XFlush(win->src.display);
  4164. }
  4165. RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
  4166. RGFW_LOAD_ATOM(_NET_WM_STATE);
  4167. RGFW_LOAD_ATOM(_NET_WM_STATE_ABOVE);
  4168. Atom actual_type;
  4169. int actual_format;
  4170. unsigned long nitems, bytes_after;
  4171. Atom* prop_return = NULL;
  4172. int status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, (~0L), False, XA_ATOM,
  4173. &actual_type, &actual_format, &nitems, &bytes_after,
  4174. (unsigned char **)&prop_return);
  4175. if (status != Success || actual_type != XA_ATOM)
  4176. return RGFW_FALSE;
  4177. unsigned long i;
  4178. for (i = 0; i < nitems; i++)
  4179. if (prop_return[i] == _NET_WM_STATE_ABOVE) return RGFW_TRUE;
  4180. if (prop_return)
  4181. XFree(prop_return);
  4182. return RGFW_FALSE;
  4183. }
  4184. void RGFW_window_setName(RGFW_window* win, const char* name) {
  4185. RGFW_ASSERT(win != NULL);
  4186. RGFW_GOTO_WAYLAND(0);
  4187. #ifdef RGFW_X11
  4188. XStoreName(win->src.display, win->src.window, name);
  4189. RGFW_LOAD_ATOM(_NET_WM_NAME);
  4190. XChangeProperty(
  4191. win->src.display, win->src.window, _NET_WM_NAME, RGFW_XUTF8_STRING,
  4192. 8, PropModeReplace, (u8*)name, 256
  4193. );
  4194. #endif
  4195. #ifdef RGFW_WAYLAND
  4196. wayland:
  4197. if (win->src.compositor)
  4198. xdg_toplevel_set_title(win->src.xdg_toplevel, name);
  4199. #endif
  4200. }
  4201. #ifndef RGFW_NO_PASSTHROUGH
  4202. void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
  4203. RGFW_ASSERT(win != NULL);
  4204. if (passthrough) {
  4205. Region region = XCreateRegion();
  4206. XShapeCombineRegion(win->src.display, win->src.window, ShapeInput, 0, 0, region, ShapeSet);
  4207. XDestroyRegion(region);
  4208. return;
  4209. }
  4210. XShapeCombineMask(win->src.display, win->src.window, ShapeInput, 0, 0, None, ShapeSet);
  4211. }
  4212. #endif /* RGFW_NO_PASSTHROUGH */
  4213. RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) {
  4214. RGFW_ASSERT(win != NULL);
  4215. RGFW_GOTO_WAYLAND(0);
  4216. #ifdef RGFW_X11
  4217. RGFW_LOAD_ATOM(_NET_WM_ICON);
  4218. if (icon == NULL || (channels != 3 && channels != 4)) {
  4219. RGFW_bool res = (RGFW_bool)XChangeProperty(
  4220. win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
  4221. PropModeReplace, (u8*)NULL, 0
  4222. );
  4223. return res;
  4224. }
  4225. i32 count = (i32)(2 + (a.w * a.h));
  4226. unsigned long* data = (unsigned long*) RGFW_ALLOC((u32)count * sizeof(unsigned long));
  4227. RGFW_ASSERT(data != NULL);
  4228. data[0] = (unsigned long)a.w;
  4229. data[1] = (unsigned long)a.h;
  4230. unsigned long* target = &data[2];
  4231. u32 x, y;
  4232. for (x = 0; x < a.w; x++) {
  4233. for (y = 0; y < a.h; y++) {
  4234. size_t i = y * a.w + x;
  4235. u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF;
  4236. target[i] = (unsigned long)((icon[i * 4 + 0]) << 16) |
  4237. (unsigned long)((icon[i * 4 + 1]) << 8) |
  4238. (unsigned long)((icon[i * 4 + 2]) << 0) |
  4239. (unsigned long)(alpha << 24);
  4240. }
  4241. }
  4242. RGFW_bool res = RGFW_TRUE;
  4243. if (type & RGFW_iconTaskbar) {
  4244. res = (RGFW_bool)XChangeProperty(
  4245. win->src.display, win->src.window, _NET_WM_ICON, XA_CARDINAL, 32,
  4246. PropModeReplace, (u8*)data, count
  4247. );
  4248. }
  4249. if (type & RGFW_iconWindow) {
  4250. XWMHints wm_hints;
  4251. wm_hints.flags = IconPixmapHint;
  4252. i32 depth = DefaultDepth(win->src.display, DefaultScreen(win->src.display));
  4253. XImage *image = XCreateImage(win->src.display, DefaultVisual(win->src.display, DefaultScreen(win->src.display)),
  4254. (u32)depth, ZPixmap, 0, (char *)target, a.w, a.h, 32, 0);
  4255. wm_hints.icon_pixmap = XCreatePixmap(win->src.display, win->src.window, a.w, a.h, (u32)depth);
  4256. XPutImage(win->src.display, wm_hints.icon_pixmap, DefaultGC(win->src.display, DefaultScreen(win->src.display)), image, 0, 0, 0, 0, a.w, a.h);
  4257. image->data = NULL;
  4258. XDestroyImage(image);
  4259. XSetWMHints(win->src.display, win->src.window, &wm_hints);
  4260. }
  4261. RGFW_FREE(data);
  4262. XFlush(win->src.display);
  4263. return RGFW_BOOL(res);
  4264. #endif
  4265. #ifdef RGFW_WAYLAND
  4266. wayland:
  4267. return RGFW_FALSE;
  4268. #endif
  4269. }
  4270. RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
  4271. RGFW_ASSERT(icon);
  4272. RGFW_ASSERT(channels == 3 || channels == 4);
  4273. RGFW_GOTO_WAYLAND(0);
  4274. #ifdef RGFW_X11
  4275. #ifndef RGFW_NO_X11_CURSOR
  4276. RGFW_init();
  4277. XcursorImage* native = XcursorImageCreate((i32)a.w, (i32)a.h);
  4278. native->xhot = 0;
  4279. native->yhot = 0;
  4280. XcursorPixel* target = native->pixels;
  4281. size_t x, y;
  4282. for (x = 0; x < a.w; x++) {
  4283. for (y = 0; y < a.h; y++) {
  4284. size_t i = y * a.w + x;
  4285. u32 alpha = (channels == 4) ? icon[i * 4 + 3] : 0xFF;
  4286. target[i] = (u32)((icon[i * 4 + 0]) << 16)
  4287. | (u32)((icon[i * 4 + 1]) << 8)
  4288. | (u32)((icon[i * 4 + 2]) << 0)
  4289. | (u32)(alpha << 24);
  4290. }
  4291. }
  4292. Cursor cursor = XcursorImageLoadCursor(_RGFW.display, native);
  4293. XcursorImageDestroy(native);
  4294. return (void*)cursor;
  4295. #else
  4296. RGFW_UNUSED(image); RGFW_UNUSED(a.w); RGFW_UNUSED(channels);
  4297. return NULL;
  4298. #endif
  4299. #endif
  4300. #ifdef RGFW_WAYLAND
  4301. wayland:
  4302. RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels);
  4303. return NULL; /* TODO */
  4304. #endif
  4305. }
  4306. void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
  4307. RGFW_GOTO_WAYLAND(0);
  4308. #ifdef RGFW_X11
  4309. RGFW_ASSERT(win && mouse);
  4310. XDefineCursor(win->src.display, win->src.window, (Cursor)mouse);
  4311. #endif
  4312. #ifdef RGFW_WAYLAND
  4313. wayland:
  4314. RGFW_UNUSED(win); RGFW_UNUSED(mouse);
  4315. #endif
  4316. }
  4317. void RGFW_freeMouse(RGFW_mouse* mouse) {
  4318. RGFW_GOTO_WAYLAND(0);
  4319. #ifdef RGFW_X11
  4320. RGFW_ASSERT(mouse);
  4321. XFreeCursor(_RGFW.display, (Cursor)mouse);
  4322. #endif
  4323. #ifdef RGFW_WAYLAND
  4324. wayland:
  4325. RGFW_UNUSED(mouse);
  4326. #endif
  4327. }
  4328. void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) {
  4329. RGFW_GOTO_WAYLAND(1);
  4330. #ifdef RGFW_X11
  4331. RGFW_ASSERT(win != NULL);
  4332. XEvent event;
  4333. XQueryPointer(win->src.display, DefaultRootWindow(win->src.display),
  4334. &event.xbutton.root, &event.xbutton.window,
  4335. &event.xbutton.x_root, &event.xbutton.y_root,
  4336. &event.xbutton.x, &event.xbutton.y,
  4337. &event.xbutton.state);
  4338. win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y);
  4339. if (event.xbutton.x == p.x && event.xbutton.y == p.y)
  4340. return;
  4341. XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) p.x - win->r.x, (int) p.y - win->r.y);
  4342. #endif
  4343. #ifdef RGFW_WAYLAND
  4344. wayland:
  4345. RGFW_UNUSED(win); RGFW_UNUSED(p);
  4346. #endif
  4347. }
  4348. RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
  4349. return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
  4350. }
  4351. RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
  4352. RGFW_ASSERT(win != NULL);
  4353. RGFW_GOTO_WAYLAND(0);
  4354. #ifdef RGFW_X11
  4355. static const u8 mouseIconSrc[16] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor};
  4356. if (mouse > (sizeof(mouseIconSrc) / sizeof(u8)))
  4357. return RGFW_FALSE;
  4358. mouse = mouseIconSrc[mouse];
  4359. Cursor cursor = XCreateFontCursor(win->src.display, mouse);
  4360. XDefineCursor(win->src.display, win->src.window, (Cursor) cursor);
  4361. XFreeCursor(win->src.display, (Cursor) cursor);
  4362. return RGFW_TRUE;
  4363. #endif
  4364. #ifdef RGFW_WAYLAND
  4365. wayland: { }
  4366. static const char* iconStrings[16] = { "left_ptr", "left_ptr", "text", "cross", "pointer", "e-resize", "n-resize", "nw-resize", "ne-resize", "all-resize", "not-allowed" };
  4367. struct wl_cursor* wlcursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]);
  4368. RGFW_cursor_image = wlcursor->images[0];
  4369. struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
  4370. wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
  4371. wl_surface_commit(RGFW_cursor_surface);
  4372. return RGFW_TRUE;
  4373. #endif
  4374. }
  4375. void RGFW_window_hide(RGFW_window* win) {
  4376. RGFW_GOTO_WAYLAND(0);
  4377. #ifdef RGFW_X11
  4378. XUnmapWindow(win->src.display, win->src.window);
  4379. #endif
  4380. #ifdef RGFW_WAYLAND
  4381. wayland:
  4382. wl_surface_attach(win->src.surface, NULL, 0, 0);
  4383. wl_surface_commit(win->src.surface);
  4384. win->_flags |= RGFW_windowHide;
  4385. #endif
  4386. }
  4387. void RGFW_window_show(RGFW_window* win) {
  4388. win->_flags &= ~(u32)RGFW_windowHide;
  4389. if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
  4390. RGFW_GOTO_WAYLAND(0);
  4391. #ifdef RGFW_X11
  4392. XMapWindow(win->src.display, win->src.window);
  4393. #endif
  4394. #ifdef RGFW_WAYLAND
  4395. wayland:
  4396. /* wl_surface_attach(win->src.surface, win->rc., 0, 0); */
  4397. wl_surface_commit(win->src.surface);
  4398. #endif
  4399. }
  4400. RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
  4401. RGFW_GOTO_WAYLAND(1);
  4402. #ifdef RGFW_X11
  4403. RGFW_init();
  4404. if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) {
  4405. if (str != NULL)
  4406. RGFW_STRNCPY(str, _RGFW.clipboard, _RGFW.clipboard_len);
  4407. return (RGFW_ssize_t)_RGFW.clipboard_len;
  4408. }
  4409. XEvent event;
  4410. int format;
  4411. unsigned long N, sizeN;
  4412. char* data;
  4413. Atom target;
  4414. RGFW_LOAD_ATOM(XSEL_DATA);
  4415. XConvertSelection(_RGFW.display, RGFW_XCLIPBOARD, RGFW_XUTF8_STRING, XSEL_DATA, _RGFW.helperWindow, CurrentTime);
  4416. XSync(_RGFW.display, 0);
  4417. while (1) {
  4418. XNextEvent(_RGFW.display, &event);
  4419. if (event.type != SelectionNotify) continue;
  4420. if (event.xselection.selection != RGFW_XCLIPBOARD || event.xselection.property == 0)
  4421. return -1;
  4422. break;
  4423. }
  4424. XGetWindowProperty(event.xselection.display, event.xselection.requestor,
  4425. event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,
  4426. &format, &sizeN, &N, (u8**) &data);
  4427. RGFW_ssize_t size;
  4428. if (sizeN > strCapacity && str != NULL)
  4429. size = -1;
  4430. if ((target == RGFW_XUTF8_STRING || target == XA_STRING) && str != NULL) {
  4431. RGFW_MEMCPY(str, data, sizeN);
  4432. str[sizeN] = '\0';
  4433. XFree(data);
  4434. } else if (str != NULL) size = -1;
  4435. XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
  4436. size = (RGFW_ssize_t)sizeN;
  4437. return size;
  4438. #endif
  4439. #if defined(RGFW_WAYLAND)
  4440. wayland: return 0;
  4441. #endif
  4442. }
  4443. i32 RGFW_XHandleClipboardSelectionHelper(void) {
  4444. #ifdef RGFW_X11
  4445. RGFW_LOAD_ATOM(SAVE_TARGETS);
  4446. XEvent event;
  4447. XPending(_RGFW.display);
  4448. if (QLength(_RGFW.display) || XEventsQueued(_RGFW.display, QueuedAlready) + XEventsQueued(_RGFW.display, QueuedAfterReading))
  4449. XNextEvent(_RGFW.display, &event);
  4450. else
  4451. return 0;
  4452. switch (event.type) {
  4453. case SelectionRequest:
  4454. RGFW_XHandleClipboardSelection(&event);
  4455. return 0;
  4456. case SelectionNotify:
  4457. if (event.xselection.target == SAVE_TARGETS)
  4458. return 0;
  4459. break;
  4460. default: break;
  4461. }
  4462. return 0;
  4463. #else
  4464. return 1;
  4465. #endif
  4466. }
  4467. void RGFW_writeClipboard(const char* text, u32 textLen) {
  4468. RGFW_GOTO_WAYLAND(1);
  4469. #ifdef RGFW_X11
  4470. RGFW_LOAD_ATOM(SAVE_TARGETS);
  4471. RGFW_init();
  4472. /* request ownership of the clipboard section and request to convert it, this means its our job to convert it */
  4473. XSetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD, _RGFW.helperWindow, CurrentTime);
  4474. if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) != _RGFW.helperWindow) {
  4475. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(_RGFW.root, 0), "X11 failed to become owner of clipboard selection");
  4476. return;
  4477. }
  4478. if (_RGFW.clipboard)
  4479. RGFW_FREE(_RGFW.clipboard);
  4480. _RGFW.clipboard = (char*)RGFW_ALLOC(textLen);
  4481. RGFW_ASSERT(_RGFW.clipboard != NULL);
  4482. RGFW_STRNCPY(_RGFW.clipboard, text, textLen);
  4483. _RGFW.clipboard_len = textLen;
  4484. #endif
  4485. #ifdef RGFW_WAYLAND
  4486. wayland:
  4487. RGFW_UNUSED(text); RGFW_UNUSED(textLen);
  4488. #endif
  4489. }
  4490. RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
  4491. RGFW_ASSERT(win != NULL);
  4492. XWindowAttributes windowAttributes;
  4493. XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes);
  4494. return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win));
  4495. }
  4496. RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
  4497. RGFW_ASSERT(win != NULL);
  4498. RGFW_LOAD_ATOM(WM_STATE);
  4499. Atom actual_type;
  4500. i32 actual_format;
  4501. unsigned long nitems, bytes_after;
  4502. unsigned char* prop_data;
  4503. i32 status = XGetWindowProperty(win->src.display, win->src.window, WM_STATE, 0, 2, False,
  4504. AnyPropertyType, &actual_type, &actual_format,
  4505. &nitems, &bytes_after, &prop_data);
  4506. if (status == Success && nitems >= 1 && prop_data == (unsigned char*)IconicState) {
  4507. XFree(prop_data);
  4508. return RGFW_TRUE;
  4509. }
  4510. if (prop_data != NULL)
  4511. XFree(prop_data);
  4512. XWindowAttributes windowAttributes;
  4513. XGetWindowAttributes(win->src.display, win->src.window, &windowAttributes);
  4514. return windowAttributes.map_state != IsViewable;
  4515. }
  4516. RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
  4517. RGFW_ASSERT(win != NULL);
  4518. RGFW_LOAD_ATOM(_NET_WM_STATE);
  4519. RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
  4520. RGFW_LOAD_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
  4521. Atom actual_type;
  4522. i32 actual_format;
  4523. unsigned long nitems, bytes_after;
  4524. unsigned char* prop_data;
  4525. i32 status = XGetWindowProperty(win->src.display, win->src.window, _NET_WM_STATE, 0, 1024, False,
  4526. XA_ATOM, &actual_type, &actual_format,
  4527. &nitems, &bytes_after, &prop_data);
  4528. if (status != Success) {
  4529. if (prop_data != NULL)
  4530. XFree(prop_data);
  4531. return RGFW_FALSE;
  4532. }
  4533. u64 i;
  4534. for (i = 0; i < nitems; ++i) {
  4535. if (prop_data[i] == _NET_WM_STATE_MAXIMIZED_VERT ||
  4536. prop_data[i] == _NET_WM_STATE_MAXIMIZED_HORZ) {
  4537. XFree(prop_data);
  4538. return RGFW_TRUE;
  4539. }
  4540. }
  4541. if (prop_data != NULL)
  4542. XFree(prop_data);
  4543. return RGFW_FALSE;
  4544. }
  4545. #ifndef RGFW_NO_DPI
  4546. u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi);
  4547. u32 RGFW_XCalculateRefreshRate(XRRModeInfo mi) {
  4548. if (mi.hTotal == 0 || mi.vTotal == 0) return 0;
  4549. return (u32) RGFW_ROUND((double) mi.dotClock / ((double) mi.hTotal * (double) mi.vTotal));
  4550. }
  4551. #endif
  4552. static float XGetSystemContentDPI(Display* display, i32 screen) {
  4553. float dpi = 96.0f;
  4554. #ifndef RGFW_NO_DPI
  4555. RGFW_UNUSED(screen);
  4556. char* rms = XResourceManagerString(display);
  4557. XrmDatabase db = NULL;
  4558. if (rms) db = XrmGetStringDatabase(rms);
  4559. if (rms && db) {
  4560. XrmValue value;
  4561. char* type = NULL;
  4562. if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && RGFW_STRNCMP(type, "String", 7) == 0)
  4563. dpi = (float)RGFW_ATOF(value.addr);
  4564. XrmDestroyDatabase(db);
  4565. }
  4566. #else
  4567. dpi = RGFW_ROUND(DisplayWidth(display, screen) / (DisplayWidthMM(display, screen) / 25.4));
  4568. #endif
  4569. return dpi;
  4570. }
  4571. RGFW_monitor RGFW_XCreateMonitor(i32 screen);
  4572. RGFW_monitor RGFW_XCreateMonitor(i32 screen) {
  4573. RGFW_monitor monitor;
  4574. RGFW_init();
  4575. Display* display = _RGFW.display;
  4576. if (screen == -1) screen = DefaultScreen(display);
  4577. Screen* scrn = DefaultScreenOfDisplay(display);
  4578. RGFW_area size = RGFW_AREA(scrn->width, scrn->height);
  4579. monitor.x = 0;
  4580. monitor.y = 0;
  4581. monitor.mode.area = RGFW_AREA(size.w, size.h);
  4582. monitor.physW = (float)DisplayWidthMM(display, screen) / 25.4f;
  4583. monitor.physH = (float)DisplayHeightMM(display, screen) / 25.4f;
  4584. RGFW_splitBPP((u32)DefaultDepth(display, DefaultScreen(display)), &monitor.mode);
  4585. char* name = XDisplayName((const char*)display);
  4586. RGFW_MEMCPY(monitor.name, name, 128);
  4587. float dpi = XGetSystemContentDPI(display, screen);
  4588. monitor.pixelRatio = dpi >= 192.0f ? 2 : 1;
  4589. monitor.scaleX = (float) (dpi) / 96.0f;
  4590. monitor.scaleY = (float) (dpi) / 96.0f;
  4591. #ifndef RGFW_NO_DPI
  4592. XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen));
  4593. monitor.mode.refreshRate = RGFW_XCalculateRefreshRate(sr->modes[screen]);
  4594. XRRCrtcInfo* ci = NULL;
  4595. int crtc = screen;
  4596. if (sr->ncrtc > crtc) {
  4597. ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]);
  4598. }
  4599. #endif
  4600. #ifndef RGFW_NO_DPI
  4601. XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]);
  4602. if (info == NULL || ci == NULL) {
  4603. XRRFreeScreenResources(sr);
  4604. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
  4605. return monitor;
  4606. }
  4607. float physW = (float)info->mm_width / 25.4f;
  4608. float physH = (float)info->mm_height / 25.4f;
  4609. RGFW_MEMCPY(monitor.name, info->name, 128);
  4610. if ((u8)physW && (u8)physH) {
  4611. monitor.physW = physW;
  4612. monitor.physH = physH;
  4613. }
  4614. monitor.x = ci->x;
  4615. monitor.y = ci->y;
  4616. if (ci->width && ci->height) {
  4617. monitor.mode.area.w = (u32)ci->width;
  4618. monitor.mode.area.h = (u32)ci->height;
  4619. }
  4620. #endif
  4621. #ifndef RGFW_NO_DPI
  4622. XRRFreeCrtcInfo(ci);
  4623. XRRFreeScreenResources(sr);
  4624. #endif
  4625. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
  4626. return monitor;
  4627. }
  4628. RGFW_monitor* RGFW_getMonitors(size_t* len) {
  4629. static RGFW_monitor monitors[7];
  4630. RGFW_GOTO_WAYLAND(1);
  4631. #ifdef RGFW_X11
  4632. RGFW_init();
  4633. Display* display = _RGFW.display;
  4634. i32 max = ScreenCount(display);
  4635. i32 i;
  4636. for (i = 0; i < max && i < 6; i++)
  4637. monitors[i] = RGFW_XCreateMonitor(i);
  4638. if (len != NULL) *len = (size_t)((max <= 6) ? (max) : (6));
  4639. return monitors;
  4640. #endif
  4641. #ifdef RGFW_WAYLAND
  4642. wayland: return monitors; /* TODO WAYLAND */
  4643. #endif
  4644. }
  4645. RGFW_monitor RGFW_getPrimaryMonitor(void) {
  4646. RGFW_GOTO_WAYLAND(1);
  4647. #ifdef RGFW_X11
  4648. return RGFW_XCreateMonitor(-1);
  4649. #endif
  4650. #ifdef RGFW_WAYLAND
  4651. wayland: return (RGFW_monitor){ 0 }; /* TODO WAYLAND */
  4652. #endif
  4653. }
  4654. RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
  4655. RGFW_GOTO_WAYLAND(1);
  4656. #ifdef RGFW_X11
  4657. #ifndef RGFW_NO_DPI
  4658. RGFW_init();
  4659. XRRScreenResources* screenRes = XRRGetScreenResources(_RGFW.display, DefaultRootWindow(_RGFW.display));
  4660. if (screenRes == NULL) return RGFW_FALSE;
  4661. int i;
  4662. for (i = 0; i < screenRes->ncrtc; i++) {
  4663. XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(_RGFW.display, screenRes, screenRes->crtcs[i]);
  4664. if (!crtcInfo) continue;
  4665. if (mon.x == crtcInfo->x && mon.y == crtcInfo->y && (u32)mon.mode.area.w == crtcInfo->width && (u32)mon.mode.area.h == crtcInfo->height) {
  4666. RRMode rmode = None;
  4667. int index;
  4668. for (index = 0; index < screenRes->nmode; index++) {
  4669. RGFW_monitorMode foundMode;
  4670. foundMode.area = RGFW_AREA(screenRes->modes[index].width, screenRes->modes[index].height);
  4671. foundMode.refreshRate = RGFW_XCalculateRefreshRate(screenRes->modes[index]);
  4672. RGFW_splitBPP((u32)DefaultDepth(_RGFW.display, DefaultScreen(_RGFW.display)), &foundMode);
  4673. if (RGFW_monitorModeCompare(mode, foundMode, request)) {
  4674. rmode = screenRes->modes[index].id;
  4675. RROutput output = screenRes->outputs[i];
  4676. XRROutputInfo* info = XRRGetOutputInfo(_RGFW.display, screenRes, output);
  4677. if (info) {
  4678. XRRSetCrtcConfig(_RGFW.display, screenRes, screenRes->crtcs[i],
  4679. CurrentTime, 0, 0, rmode, RR_Rotate_0, &output, 1);
  4680. XRRFreeOutputInfo(info);
  4681. XRRFreeCrtcInfo(crtcInfo);
  4682. XRRFreeScreenResources(screenRes);
  4683. return RGFW_TRUE;
  4684. }
  4685. }
  4686. }
  4687. XRRFreeCrtcInfo(crtcInfo);
  4688. XRRFreeScreenResources(screenRes);
  4689. return RGFW_FALSE;
  4690. }
  4691. XRRFreeCrtcInfo(crtcInfo);
  4692. }
  4693. XRRFreeScreenResources(screenRes);
  4694. return RGFW_FALSE;
  4695. #endif
  4696. #endif
  4697. #ifdef RGFW_WAYLAND
  4698. wayland:
  4699. #endif
  4700. return RGFW_FALSE;
  4701. }
  4702. RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
  4703. RGFW_ASSERT(win != NULL);
  4704. RGFW_GOTO_WAYLAND(1);
  4705. #ifdef RGFW_X11
  4706. XWindowAttributes attrs;
  4707. if (!XGetWindowAttributes(win->src.display, win->src.window, &attrs)) {
  4708. return (RGFW_monitor){0};
  4709. }
  4710. i32 i;
  4711. for (i = 0; i < ScreenCount(win->src.display) && i < 6; i++) {
  4712. Screen* screen = ScreenOfDisplay(win->src.display, i);
  4713. if (attrs.x >= 0 && attrs.x < XWidthOfScreen(screen) &&
  4714. attrs.y >= 0 && attrs.y < XHeightOfScreen(screen))
  4715. return RGFW_XCreateMonitor(i);
  4716. }
  4717. #endif
  4718. #ifdef RGFW_WAYLAND
  4719. wayland:
  4720. #endif
  4721. return (RGFW_monitor){0};
  4722. }
  4723. #if defined(RGFW_OPENGL) && !defined(RGFW_EGL)
  4724. void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
  4725. if (win == NULL)
  4726. glXMakeCurrent(NULL, (Drawable)NULL, (GLXContext) NULL);
  4727. else
  4728. glXMakeCurrent(win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);
  4729. }
  4730. void* RGFW_getCurrent_OpenGL(void) { return glXGetCurrentContext(); }
  4731. void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) { glXSwapBuffers(win->src.display, win->src.window); }
  4732. #endif
  4733. void RGFW_window_swapBuffers_software(RGFW_window* win) {
  4734. RGFW_ASSERT(win != NULL);
  4735. RGFW_GOTO_WAYLAND(0);
  4736. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  4737. #ifdef RGFW_X11
  4738. win->src.bitmap->data = (char*) win->buffer;
  4739. RGFW_RGB_to_BGR(win, (u8*)win->src.bitmap->data);
  4740. XPutImage(win->src.display, win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, win->bufferSize.w, win->bufferSize.h);
  4741. win->src.bitmap->data = NULL;
  4742. return;
  4743. #endif
  4744. #ifdef RGFW_WAYLAND
  4745. wayland:
  4746. #if !defined(RGFW_BUFFER_BGR) && !defined(RGFW_OSMESA)
  4747. RGFW_RGB_to_BGR(win, win->src.buffer);
  4748. #else
  4749. size_t y;
  4750. for (y = 0; y < win->r.h; y++) {
  4751. u32 index = (y * 4 * win->r.w);
  4752. u32 index2 = (y * 4 * win->bufferSize.w);
  4753. RGFW_MEMCPY(&win->src.buffer[index], &win->buffer[index2], win->r.w * 4);
  4754. }
  4755. #endif
  4756. wl_surface_frame_done(win, NULL, 0);
  4757. wl_surface_commit(win->src.surface);
  4758. #endif
  4759. #else
  4760. #ifdef RGFW_WAYLAND
  4761. wayland:
  4762. #endif
  4763. RGFW_UNUSED(win);
  4764. #endif
  4765. }
  4766. #if !defined(RGFW_EGL)
  4767. void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
  4768. RGFW_ASSERT(win != NULL);
  4769. #if defined(RGFW_OPENGL)
  4770. // cached pfn to avoid calling glXGetProcAddress more than once
  4771. static PFNGLXSWAPINTERVALEXTPROC pfn = (PFNGLXSWAPINTERVALEXTPROC)123;
  4772. static int (*pfn2)(int) = NULL;
  4773. if (pfn == (PFNGLXSWAPINTERVALEXTPROC)123) {
  4774. pfn = ((PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT"));
  4775. if (pfn == NULL) {
  4776. const char* array[] = {"GLX_MESA_swap_control", "GLX_SGI_swap_control"};
  4777. u32 i;
  4778. for (i = 0; i < sizeof(array) / sizeof(char*) && pfn2 == NULL; i++)
  4779. pfn2 = ((int(*)(int))glXGetProcAddress((GLubyte*) array[i]));
  4780. if (pfn2 != NULL) {
  4781. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function, fallingback to the native swapinterval function");
  4782. } else {
  4783. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function");
  4784. }
  4785. }
  4786. }
  4787. if (pfn != NULL)
  4788. pfn(win->src.display, win->src.window, swapInterval);
  4789. else if (pfn2 != NULL) {
  4790. pfn2(swapInterval);
  4791. }
  4792. #else
  4793. RGFW_UNUSED(swapInterval);
  4794. #endif
  4795. }
  4796. #endif
  4797. void RGFW_deinit(void) {
  4798. if (_RGFW.windowCount == -1) return;
  4799. #define RGFW_FREE_LIBRARY(x) if (x != NULL) dlclose(x); x = NULL;
  4800. #ifdef RGFW_X11
  4801. /* to save the clipboard on the x server after the window is closed */
  4802. RGFW_LOAD_ATOM(CLIPBOARD_MANAGER);
  4803. RGFW_LOAD_ATOM(SAVE_TARGETS);
  4804. if (XGetSelectionOwner(_RGFW.display, RGFW_XCLIPBOARD) == _RGFW.helperWindow) {
  4805. XConvertSelection(_RGFW.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, _RGFW.helperWindow, CurrentTime);
  4806. while (RGFW_XHandleClipboardSelectionHelper());
  4807. }
  4808. if (_RGFW.clipboard) {
  4809. RGFW_FREE(_RGFW.clipboard);
  4810. _RGFW.clipboard = NULL;
  4811. }
  4812. RGFW_freeMouse(_RGFW.hiddenMouse);
  4813. XCloseDisplay(_RGFW.display); /*!< kill connection to the x server */
  4814. #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR)
  4815. RGFW_FREE_LIBRARY(X11Cursorhandle);
  4816. #endif
  4817. #if !defined(RGFW_NO_X11_XI_PRELOAD)
  4818. RGFW_FREE_LIBRARY(X11Xihandle);
  4819. #endif
  4820. #ifdef RGFW_USE_XDL
  4821. XDL_close();
  4822. #endif
  4823. #if !defined(RGFW_NO_X11_EXT_PRELOAD)
  4824. RGFW_FREE_LIBRARY(X11XEXThandle);
  4825. #endif
  4826. #endif
  4827. #ifdef RGFW_WAYLAND
  4828. wl_display_disconnect(_RGFW.wl_display);
  4829. #endif
  4830. #ifndef RGFW_NO_LINUX
  4831. if (RGFW_eventWait_forceStop[0] || RGFW_eventWait_forceStop[1]){
  4832. close(RGFW_eventWait_forceStop[0]);
  4833. close(RGFW_eventWait_forceStop[1]);
  4834. }
  4835. u8 i;
  4836. for (i = 0; i < RGFW_gamepadCount; i++) {
  4837. if(RGFW_gamepads[i])
  4838. close(RGFW_gamepads[i]);
  4839. }
  4840. #endif
  4841. _RGFW.root = NULL;
  4842. _RGFW.windowCount = -1;
  4843. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, (RGFW_debugContext){0}, "global context deinitialized");
  4844. }
  4845. void RGFW_window_close(RGFW_window* win) {
  4846. RGFW_ASSERT(win != NULL);
  4847. if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
  4848. #ifdef RGFW_X11
  4849. RGFW_GOTO_WAYLAND(0);
  4850. /* ungrab pointer if it was grabbed */
  4851. if (win->_flags & RGFW_HOLD_MOUSE)
  4852. XUngrabPointer(win->src.display, CurrentTime);
  4853. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  4854. if (win->buffer != NULL) {
  4855. if ((win->_flags & RGFW_BUFFER_ALLOC))
  4856. RGFW_FREE(win->buffer);
  4857. XDestroyImage((XImage*) win->src.bitmap);
  4858. }
  4859. #endif
  4860. XFreeGC(win->src.display, win->src.gc);
  4861. XDestroyWindow(win->src.display, (Drawable) win->src.window); /*!< close the window */
  4862. win->src.window = 0;
  4863. XCloseDisplay(win->src.display);
  4864. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
  4865. _RGFW.windowCount--;
  4866. if (_RGFW.windowCount == 0) RGFW_deinit();
  4867. RGFW_clipboard_switch(NULL);
  4868. RGFW_FREE(win->event.droppedFiles);
  4869. if ((win->_flags & RGFW_WINDOW_ALLOC)) {
  4870. RGFW_FREE(win);
  4871. win = NULL;
  4872. }
  4873. return;
  4874. #endif
  4875. #ifdef RGFW_WAYLAND
  4876. wayland:
  4877. #ifdef RGFW_X11
  4878. XDestroyWindow(win->src.display, (Drawable) win->src.window);
  4879. #endif
  4880. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
  4881. _RGFW.windowCount--;
  4882. if (_RGFW.windowCount == 0) RGFW_deinit();
  4883. xdg_toplevel_destroy(win->src.xdg_toplevel);
  4884. xdg_surface_destroy(win->src.xdg_surface);
  4885. wl_surface_destroy(win->src.surface);
  4886. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  4887. wl_buffer_destroy(win->src.wl_buffer);
  4888. if ((win->_flags & RGFW_BUFFER_ALLOC))
  4889. RGFW_FREE(win->buffer);
  4890. munmap(win->src.buffer, (size_t)(win->r.w * win->r.h * 4));
  4891. #endif
  4892. RGFW_clipboard_switch(NULL);
  4893. RGFW_FREE(win->event.droppedFiles);
  4894. if ((win->_flags & RGFW_WINDOW_ALLOC)) {
  4895. RGFW_FREE(win);
  4896. win = NULL;
  4897. }
  4898. #endif
  4899. }
  4900. /*
  4901. End of X11 linux / wayland / unix defines
  4902. */
  4903. #include <fcntl.h>
  4904. #include <poll.h>
  4905. #include <unistd.h>
  4906. void RGFW_stopCheckEvents(void) {
  4907. RGFW_eventWait_forceStop[2] = 1;
  4908. while (1) {
  4909. const char byte = 0;
  4910. const ssize_t result = write(RGFW_eventWait_forceStop[1], &byte, 1);
  4911. if (result == 1 || result == -1)
  4912. break;
  4913. }
  4914. }
  4915. void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
  4916. if (waitMS == 0) return;
  4917. u8 i;
  4918. if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) {
  4919. if (pipe(RGFW_eventWait_forceStop) != -1) {
  4920. fcntl(RGFW_eventWait_forceStop[0], F_GETFL, 0);
  4921. fcntl(RGFW_eventWait_forceStop[0], F_GETFD, 0);
  4922. fcntl(RGFW_eventWait_forceStop[1], F_GETFL, 0);
  4923. fcntl(RGFW_eventWait_forceStop[1], F_GETFD, 0);
  4924. }
  4925. }
  4926. struct pollfd fds[] = {
  4927. #ifdef RGFW_WAYLAND
  4928. { wl_display_get_fd(win->src.wl_display), POLLIN, 0 },
  4929. #else
  4930. { ConnectionNumber(win->src.display), POLLIN, 0 },
  4931. #endif
  4932. #ifdef RGFW_X11
  4933. { ConnectionNumber(_RGFW.display), POLLIN, 0 },
  4934. #endif
  4935. { RGFW_eventWait_forceStop[0], POLLIN, 0 },
  4936. #if defined(__linux__)
  4937. { -1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0}
  4938. #endif
  4939. };
  4940. u8 index = 2;
  4941. #ifdef RGFW_X11
  4942. index++;
  4943. #endif
  4944. #if defined(__linux__) || defined(__NetBSD__)
  4945. for (i = 0; i < RGFW_gamepadCount; i++) {
  4946. if (RGFW_gamepads[i] == 0)
  4947. continue;
  4948. fds[index].fd = RGFW_gamepads[i];
  4949. index++;
  4950. }
  4951. #endif
  4952. u64 start = RGFW_getTimeNS();
  4953. #ifdef RGFW_WAYLAND
  4954. while (wl_display_dispatch(win->src.wl_display) <= 0
  4955. #else
  4956. while (XPending(win->src.display) == 0
  4957. #endif
  4958. #ifdef RGFW_X11
  4959. && XPending(_RGFW.display) == 0
  4960. #endif
  4961. ) {
  4962. if (poll(fds, index, waitMS) <= 0)
  4963. break;
  4964. if (waitMS != RGFW_eventWaitNext)
  4965. waitMS -= (i32)(RGFW_getTimeNS() - start) / (i32)1e+6;
  4966. }
  4967. /* drain any data in the stop request */
  4968. if (RGFW_eventWait_forceStop[2]) {
  4969. char data[64];
  4970. (void)!read(RGFW_eventWait_forceStop[0], data, sizeof(data));
  4971. RGFW_eventWait_forceStop[2] = 0;
  4972. }
  4973. }
  4974. i32 RGFW_getClock(void);
  4975. i32 RGFW_getClock(void) {
  4976. static i32 clock = -1;
  4977. if (clock != -1) return clock;
  4978. #if defined(_POSIX_MONOTONIC_CLOCK)
  4979. struct timespec ts;
  4980. if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
  4981. clock = CLOCK_MONOTONIC;
  4982. #else
  4983. clock = CLOCK_REALTIME;
  4984. #endif
  4985. return clock;
  4986. }
  4987. u64 RGFW_getTimerFreq(void) { return 1000000000LLU; }
  4988. u64 RGFW_getTimerValue(void) {
  4989. struct timespec ts;
  4990. clock_gettime(CLOCK_REALTIME, &ts);
  4991. return (u64)ts.tv_sec * RGFW_getTimerFreq() + (u64)ts.tv_nsec;
  4992. }
  4993. #endif /* end of wayland or X11 defines */
  4994. /*
  4995. Start of Windows defines
  4996. */
  4997. #ifdef RGFW_WINDOWS
  4998. #define WIN32_LEAN_AND_MEAN
  4999. #define OEMRESOURCE
  5000. #include <windows.h>
  5001. #include <processthreadsapi.h>
  5002. #include <windowsx.h>
  5003. #include <shellapi.h>
  5004. #include <shellscalingapi.h>
  5005. #include <wchar.h>
  5006. #include <locale.h>
  5007. #include <winuser.h>
  5008. #ifndef WM_DPICHANGED
  5009. #define WM_DPICHANGED 0x02E0
  5010. #endif
  5011. #ifndef RGFW_NO_XINPUT
  5012. typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
  5013. PFN_XInputGetState XInputGetStateSRC = NULL;
  5014. #define XInputGetState XInputGetStateSRC
  5015. typedef DWORD (WINAPI * PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE);
  5016. PFN_XInputGetKeystroke XInputGetKeystrokeSRC = NULL;
  5017. #define XInputGetKeystroke XInputGetKeystrokeSRC
  5018. HMODULE RGFW_XInput_dll = NULL;
  5019. #endif
  5020. char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source);
  5021. #define GL_FRONT 0x0404
  5022. #define GL_BACK 0x0405
  5023. #define GL_LEFT 0x0406
  5024. #define GL_RIGHT 0x0407
  5025. typedef int (*PFN_wglGetSwapIntervalEXT)(void);
  5026. PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;
  5027. #define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc
  5028. void* RGFWgamepadApi = NULL;
  5029. /* these two wgl functions need to be preloaded */
  5030. typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList);
  5031. PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
  5032. #ifndef RGFW_EGL
  5033. HMODULE RGFW_wgl_dll = NULL;
  5034. #endif
  5035. #ifndef RGFW_NO_LOAD_WGL
  5036. typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC);
  5037. typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC);
  5038. typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR);
  5039. typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC);
  5040. typedef HDC(WINAPI* PFN_wglGetCurrentDC)(void);
  5041. typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)(void);
  5042. typedef BOOL(WINAPI* PFN_wglShareLists)(HGLRC, HGLRC);
  5043. PFN_wglCreateContext wglCreateContextSRC;
  5044. PFN_wglDeleteContext wglDeleteContextSRC;
  5045. PFN_wglGetProcAddress wglGetProcAddressSRC;
  5046. PFN_wglMakeCurrent wglMakeCurrentSRC;
  5047. PFN_wglGetCurrentDC wglGetCurrentDCSRC;
  5048. PFN_wglGetCurrentContext wglGetCurrentContextSRC;
  5049. PFN_wglShareLists wglShareListsSRC;
  5050. #define wglCreateContext wglCreateContextSRC
  5051. #define wglDeleteContext wglDeleteContextSRC
  5052. #define wglGetProcAddress wglGetProcAddressSRC
  5053. #define wglMakeCurrent wglMakeCurrentSRC
  5054. #define wglGetCurrentDC wglGetCurrentDCSRC
  5055. #define wglGetCurrentContext wglGetCurrentContextSRC
  5056. #define wglShareLists wglShareListsSRC
  5057. #endif
  5058. #ifdef RGFW_OPENGL
  5059. RGFW_proc RGFW_getProcAddress(const char* procname) {
  5060. RGFW_proc proc = (RGFW_proc)wglGetProcAddress(procname);
  5061. if (proc)
  5062. return proc;
  5063. return (RGFW_proc) GetProcAddress(RGFW_wgl_dll, procname);
  5064. }
  5065. typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
  5066. PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
  5067. typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval);
  5068. PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
  5069. #endif
  5070. #ifndef RGFW_NO_DWM
  5071. HMODULE RGFW_dwm_dll = NULL;
  5072. typedef struct { DWORD dwFlags; int fEnable; HRGN hRgnBlur; int fTransitionOnMaximized;} DWM_BLURBEHIND;
  5073. typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*);
  5074. PFN_DwmEnableBlurBehindWindow DwmEnableBlurBehindWindowSRC = NULL;
  5075. #endif
  5076. void RGFW_win32_makeWindowTransparent(RGFW_window* win);
  5077. void RGFW_win32_makeWindowTransparent(RGFW_window* win) {
  5078. if (!(win->_flags & RGFW_windowTransparent)) return;
  5079. #ifndef RGFW_NO_DWM
  5080. if (DwmEnableBlurBehindWindowSRC != NULL) {
  5081. DWM_BLURBEHIND bb = {0, 0, 0, 0};
  5082. bb.dwFlags = 0x1;
  5083. bb.fEnable = TRUE;
  5084. bb.hRgnBlur = NULL;
  5085. DwmEnableBlurBehindWindowSRC(win->src.window, &bb);
  5086. } else
  5087. #endif
  5088. {
  5089. SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
  5090. SetLayeredWindowAttributes(win->src.window, 0, 128, LWA_ALPHA);
  5091. }
  5092. }
  5093. LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  5094. LRESULT CALLBACK WndProcW(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  5095. RGFW_window* win = (RGFW_window*)GetPropW(hWnd, L"RGFW");
  5096. if (win == NULL) return DefWindowProcW(hWnd, message, wParam, lParam);
  5097. RECT windowRect;
  5098. GetWindowRect(hWnd, &windowRect);
  5099. switch (message) {
  5100. case WM_CLOSE:
  5101. case WM_QUIT:
  5102. RGFW_eventQueuePush((RGFW_event){.type = RGFW_quit, ._win = win});
  5103. RGFW_windowQuitCallback(win);
  5104. return 0;
  5105. case WM_ACTIVATE: {
  5106. RGFW_bool inFocus = RGFW_BOOL(LOWORD(wParam) != WA_INACTIVE);
  5107. if (inFocus) win->_flags |= RGFW_windowFocus;
  5108. else win->_flags &= ~ (u32)RGFW_windowFocus;
  5109. RGFW_eventQueuePush((RGFW_event){.type = (RGFW_eventType)((u8)RGFW_focusOut - inFocus), ._win = win});
  5110. RGFW_focusCallback(win, inFocus);
  5111. if ((win->_flags & RGFW_windowFullscreen) == 0)
  5112. return DefWindowProcW(hWnd, message, wParam, lParam);
  5113. win->_flags &= ~(u32)RGFW_EVENT_PASSED;
  5114. if (inFocus == RGFW_FALSE) RGFW_window_minimize(win);
  5115. else RGFW_window_setFullscreen(win, 1);
  5116. return DefWindowProcW(hWnd, message, wParam, lParam);
  5117. }
  5118. case WM_MOVE:
  5119. win->r.x = windowRect.left;
  5120. win->r.y = windowRect.top;
  5121. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowMoved, ._win = win});
  5122. RGFW_windowMovedCallback(win, win->r);
  5123. return DefWindowProcW(hWnd, message, wParam, lParam);
  5124. case WM_SIZE: {
  5125. if (win->src.aspectRatio.w != 0 && win->src.aspectRatio.h != 0) {
  5126. double aspectRatio = (double)win->src.aspectRatio.w / win->src.aspectRatio.h;
  5127. int width = windowRect.right - windowRect.left;
  5128. int height = windowRect.bottom - windowRect.top;
  5129. int newHeight = (int)(width / aspectRatio);
  5130. int newWidth = (int)(height * aspectRatio);
  5131. if (win->r.w > windowRect.right - windowRect.left ||
  5132. win->r.h > (i32)((u32)(windowRect.bottom - windowRect.top) - win->src.hOffset))
  5133. {
  5134. if (newHeight > height) windowRect.right = windowRect.left + newWidth;
  5135. else windowRect.bottom = windowRect.top + newHeight;
  5136. } else {
  5137. if (newHeight < height) windowRect.right = windowRect.left + newWidth;
  5138. else windowRect.bottom = windowRect.top + newHeight;
  5139. }
  5140. RGFW_window_resize(win, RGFW_AREA((windowRect.right - windowRect.left),
  5141. (u32)(windowRect.bottom - windowRect.top) - (u32)win->src.hOffset));
  5142. }
  5143. win->r.w = windowRect.right - windowRect.left;
  5144. win->r.h = (windowRect.bottom - windowRect.top) - (i32)win->src.hOffset;
  5145. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowResized, ._win = win});
  5146. RGFW_windowResizedCallback(win, win->r);
  5147. RGFW_window_checkMode(win);
  5148. return DefWindowProcW(hWnd, message, wParam, lParam);
  5149. }
  5150. #ifndef RGFW_NO_MONITOR
  5151. case WM_DPICHANGED: {
  5152. if (win->_flags & RGFW_windowScaleToMonitor) RGFW_window_scaleToMonitor(win);
  5153. const float scaleX = HIWORD(wParam) / (float) 96;
  5154. const float scaleY = LOWORD(wParam) / (float) 96;
  5155. RGFW_scaleUpdatedCallback(win, scaleX, scaleY);
  5156. RGFW_eventQueuePush((RGFW_event){.type = RGFW_scaleUpdated, .scaleX = scaleX, .scaleY = scaleY , ._win = win});
  5157. return DefWindowProcW(hWnd, message, wParam, lParam);
  5158. }
  5159. #endif
  5160. case WM_GETMINMAXINFO: {
  5161. MINMAXINFO* mmi = (MINMAXINFO*) lParam;
  5162. mmi->ptMinTrackSize.x = (LONG)win->src.minSize.w;
  5163. mmi->ptMinTrackSize.y = (LONG)(win->src.minSize.h + win->src.hOffset);
  5164. if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0)
  5165. return DefWindowProcW(hWnd, message, wParam, lParam);
  5166. mmi->ptMaxTrackSize.x = (LONG)win->src.maxSize.w;
  5167. mmi->ptMaxTrackSize.y = (LONG)(win->src.maxSize.h + win->src.hOffset);
  5168. return DefWindowProcW(hWnd, message, wParam, lParam);
  5169. }
  5170. case WM_PAINT: {
  5171. PAINTSTRUCT ps;
  5172. BeginPaint(hWnd, &ps);
  5173. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowRefresh, ._win = win});
  5174. RGFW_windowRefreshCallback(win);
  5175. EndPaint(hWnd, &ps);
  5176. return DefWindowProcW(hWnd, message, wParam, lParam);
  5177. }
  5178. #if(_WIN32_WINNT >= 0x0600)
  5179. case WM_DWMCOMPOSITIONCHANGED:
  5180. case WM_DWMCOLORIZATIONCOLORCHANGED:
  5181. RGFW_win32_makeWindowTransparent(win);
  5182. break;
  5183. #endif
  5184. /* based on sokol_app.h */
  5185. #ifdef RGFW_ADVANCED_SMOOTH_RESIZE
  5186. case WM_ENTERSIZEMOVE: SetTimer(win->src.window, 1, USER_TIMER_MINIMUM, NULL); break;
  5187. case WM_EXITSIZEMOVE: KillTimer(win->src.window, 1); break;
  5188. case WM_TIMER: RGFW_windowRefreshCallback(win); break;
  5189. #endif
  5190. case WM_NCLBUTTONDOWN: {
  5191. /* workaround for half-second pause when starting to move window
  5192. see: https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/
  5193. */
  5194. POINT point = { 0, 0 };
  5195. if (SendMessage(win->src.window, WM_NCHITTEST, wParam, lParam) != HTCAPTION || GetCursorPos(&point) == FALSE)
  5196. break;
  5197. ScreenToClient(win->src.window, &point);
  5198. PostMessage(win->src.window, WM_MOUSEMOVE, 0, ((uint32_t)point.x)|(((uint32_t)point.y) << 16));
  5199. break;
  5200. }
  5201. default: break;
  5202. }
  5203. return DefWindowProcW(hWnd, message, wParam, lParam);
  5204. }
  5205. #ifndef RGFW_NO_DPI
  5206. HMODULE RGFW_Shcore_dll = NULL;
  5207. typedef HRESULT (WINAPI *PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*);
  5208. PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL;
  5209. #define GetDpiForMonitor GetDpiForMonitorSRC
  5210. #endif
  5211. #if !defined(RGFW_NO_LOAD_WINMM) && !defined(RGFW_NO_WINMM)
  5212. HMODULE RGFW_winmm_dll = NULL;
  5213. typedef u32 (WINAPI * PFN_timeBeginPeriod)(u32);
  5214. typedef PFN_timeBeginPeriod PFN_timeEndPeriod;
  5215. PFN_timeBeginPeriod timeBeginPeriodSRC, timeEndPeriodSRC;
  5216. #define timeBeginPeriod timeBeginPeriodSRC
  5217. #define timeEndPeriod timeEndPeriodSRC
  5218. #elif !defined(RGFW_NO_WINMM)
  5219. __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod);
  5220. __declspec(dllimport) u32 __stdcall timeEndPeriod(u32 uPeriod);
  5221. #endif
  5222. #define RGFW_PROC_DEF(proc, name) if (name##SRC == NULL && proc != NULL) name##SRC = (PFN_##name)(RGFW_proc)GetProcAddress((proc), (#name));
  5223. #ifndef RGFW_NO_XINPUT
  5224. void RGFW_loadXInput(void);
  5225. void RGFW_loadXInput(void) {
  5226. u32 i;
  5227. static const char* names[] = {"xinput1_4.dll", "xinput9_1_0.dll", "xinput1_2.dll", "xinput1_1.dll"};
  5228. for (i = 0; i < sizeof(names) / sizeof(const char*) && (XInputGetStateSRC == NULL || XInputGetKeystrokeSRC != NULL); i++) {
  5229. RGFW_XInput_dll = LoadLibraryA(names[i]);
  5230. RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetState);
  5231. RGFW_PROC_DEF(RGFW_XInput_dll, XInputGetKeystroke);
  5232. }
  5233. if (XInputGetStateSRC == NULL)
  5234. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(.win = _RGFW.root, .srcError = 0), "Failed to load XInputGetState");
  5235. if (XInputGetKeystrokeSRC == NULL)
  5236. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errFailedFuncLoad, RGFW_DEBUG_CTX(.win = _RGFW.root, .srcError = 0), "Failed to load XInputGetKeystroke");
  5237. }
  5238. #endif
  5239. void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){
  5240. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  5241. win->buffer = buffer;
  5242. win->bufferSize = area;
  5243. BITMAPV5HEADER bi = { 0 };
  5244. ZeroMemory(&bi, sizeof(bi));
  5245. bi.bV5Size = sizeof(bi);
  5246. bi.bV5Width = (i32)area.w;
  5247. bi.bV5Height = -((LONG) area.h);
  5248. bi.bV5Planes = 1;
  5249. bi.bV5BitCount = 32;
  5250. bi.bV5Compression = BI_RGB;
  5251. win->src.bitmap = CreateDIBSection(win->src.hdc,
  5252. (BITMAPINFO*) &bi, DIB_RGB_COLORS,
  5253. (void**) &win->src.bitmapBits,
  5254. NULL, (DWORD) 0);
  5255. if (win->buffer == NULL)
  5256. win->buffer = win->src.bitmapBits;
  5257. win->src.hdcMem = CreateCompatibleDC(win->src.hdc);
  5258. SelectObject(win->src.hdcMem, win->src.bitmap);
  5259. #if defined(RGFW_OSMESA)
  5260. win->src.ctx = OSMesaCreateContext(OSMESA_BGRA, NULL);
  5261. OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
  5262. OSMesaPixelStore(OSMESA_Y_UP, 0);
  5263. #endif
  5264. #else
  5265. RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
  5266. #endif
  5267. }
  5268. void RGFW_releaseCursor(RGFW_window* win) {
  5269. RGFW_UNUSED(win);
  5270. ClipCursor(NULL);
  5271. const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL };
  5272. RegisterRawInputDevices(&id, 1, sizeof(id));
  5273. }
  5274. void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) {
  5275. RGFW_UNUSED(win); RGFW_UNUSED(rect);
  5276. RECT clipRect;
  5277. GetClientRect(win->src.window, &clipRect);
  5278. ClientToScreen(win->src.window, (POINT*) &clipRect.left);
  5279. ClientToScreen(win->src.window, (POINT*) &clipRect.right);
  5280. ClipCursor(&clipRect);
  5281. const RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window };
  5282. RegisterRawInputDevices(&id, 1, sizeof(id));
  5283. }
  5284. #define RGFW_LOAD_LIBRARY(x, lib) if (x == NULL) x = LoadLibraryA(lib)
  5285. #ifdef RGFW_DIRECTX
  5286. int RGFW_window_createDXSwapChain(RGFW_window* win, IDXGIFactory* pFactory, IUnknown* pDevice, IDXGISwapChain** swapchain) {
  5287. RGFW_ASSERT(win && pFactory && pDevice && swapchain);
  5288. static DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
  5289. swapChainDesc.BufferCount = 2;
  5290. swapChainDesc.BufferDesc.Width = win->r.w;
  5291. swapChainDesc.BufferDesc.Height = win->r.h;
  5292. swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  5293. swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  5294. swapChainDesc.OutputWindow = (HWND)win->src.window;
  5295. swapChainDesc.SampleDesc.Count = 1;
  5296. swapChainDesc.SampleDesc.Quality = 0;
  5297. swapChainDesc.Windowed = TRUE;
  5298. swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
  5299. HRESULT hr = pFactory->lpVtbl->CreateSwapChain(pFactory, (IUnknown*)pDevice, &swapChainDesc, swapchain);
  5300. if (FAILED(hr)) {
  5301. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errDirectXContext, RGFW_DEBUG_CTX(.win = win, .srcError = hr), "Failed to create DirectX swap chain!");
  5302. return -2;
  5303. }
  5304. return 0;
  5305. }
  5306. #endif
  5307. void RGFW_win32_loadOpenGLFuncs(HWND dummyWin);
  5308. void RGFW_win32_loadOpenGLFuncs(HWND dummyWin) {
  5309. #ifdef RGFW_OPENGL
  5310. if (wglSwapIntervalEXT != NULL && wglChoosePixelFormatARB != NULL && wglChoosePixelFormatARB != NULL)
  5311. return;
  5312. HDC dummy_dc = GetDC(dummyWin);
  5313. u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  5314. PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 32, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 32, 8, 0, PFD_MAIN_PLANE, 0, 0, 0, 0};
  5315. int dummy_pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
  5316. SetPixelFormat(dummy_dc, dummy_pixel_format, &pfd);
  5317. HGLRC dummy_context = wglCreateContext(dummy_dc);
  5318. wglMakeCurrent(dummy_dc, dummy_context);
  5319. wglCreateContextAttribsARB = ((PFNWGLCREATECONTEXTATTRIBSARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglCreateContextAttribsARB");
  5320. wglChoosePixelFormatARB = ((PFNWGLCHOOSEPIXELFORMATARBPROC(WINAPI *)(const char*)) wglGetProcAddress)("wglChoosePixelFormatARB");
  5321. wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)(RGFW_proc)wglGetProcAddress("wglSwapIntervalEXT");
  5322. if (wglSwapIntervalEXT == NULL) {
  5323. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to load swap interval function");
  5324. }
  5325. wglMakeCurrent(dummy_dc, 0);
  5326. wglDeleteContext(dummy_context);
  5327. ReleaseDC(dummyWin, dummy_dc);
  5328. #else
  5329. RGFW_UNUSED(dummyWin);
  5330. #endif
  5331. }
  5332. #ifndef RGFW_EGL
  5333. void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software) {
  5334. #ifdef RGFW_OPENGL
  5335. PIXELFORMATDESCRIPTOR pfd;
  5336. pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
  5337. pfd.nVersion = 1;
  5338. pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  5339. pfd.iPixelType = PFD_TYPE_RGBA;
  5340. pfd.iLayerType = PFD_MAIN_PLANE;
  5341. pfd.cColorBits = 32;
  5342. pfd.cAlphaBits = 8;
  5343. pfd.cDepthBits = 24;
  5344. pfd.cStencilBits = (BYTE)RGFW_GL_HINTS[RGFW_glStencil];
  5345. pfd.cAuxBuffers = (BYTE)RGFW_GL_HINTS[RGFW_glAuxBuffers];
  5346. if (RGFW_GL_HINTS[RGFW_glStereo]) pfd.dwFlags |= PFD_STEREO;
  5347. /* try to create the pixel format we want for opengl and then try to create an opengl context for the specified version */
  5348. if (software)
  5349. pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED;
  5350. /* get pixel format, default to a basic pixel format */
  5351. int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd);
  5352. if (wglChoosePixelFormatARB != NULL) {
  5353. i32* pixel_format_attribs = (i32*)RGFW_initFormatAttribs(software);
  5354. int new_pixel_format;
  5355. UINT num_formats;
  5356. wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &new_pixel_format, &num_formats);
  5357. if (!num_formats)
  5358. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create a pixel format for WGL");
  5359. else pixel_format = new_pixel_format;
  5360. }
  5361. PIXELFORMATDESCRIPTOR suggested;
  5362. if (!DescribePixelFormat(win->src.hdc, pixel_format, sizeof(suggested), &suggested) ||
  5363. !SetPixelFormat(win->src.hdc, pixel_format, &pfd))
  5364. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set the WGL pixel format");
  5365. if (wglCreateContextAttribsARB != NULL) {
  5366. /* create opengl/WGL context for the specified version */
  5367. u32 index = 0;
  5368. i32 attribs[40];
  5369. if (RGFW_GL_HINTS[RGFW_glProfile]== RGFW_glCore) {
  5370. SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
  5371. }
  5372. else {
  5373. SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
  5374. }
  5375. if (RGFW_GL_HINTS[RGFW_glMinor] || RGFW_GL_HINTS[RGFW_glMajor]) {
  5376. SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMajor]);
  5377. SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_GL_HINTS[RGFW_glMinor]);
  5378. }
  5379. SET_ATTRIB(0, 0);
  5380. win->src.ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs);
  5381. } else { /* fall back to a default context (probably opengl 2 or something) */
  5382. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to create an accelerated OpenGL Context");
  5383. win->src.ctx = wglCreateContext(win->src.hdc);
  5384. }
  5385. ReleaseDC(win->src.window, win->src.hdc);
  5386. win->src.hdc = GetDC(win->src.window);
  5387. wglMakeCurrent(win->src.hdc, win->src.ctx);
  5388. if (_RGFW.root != win)
  5389. wglShareLists(_RGFW.root->src.ctx, win->src.ctx);
  5390. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
  5391. #else
  5392. RGFW_UNUSED(win); RGFW_UNUSED(software);
  5393. #endif
  5394. }
  5395. void RGFW_window_freeOpenGL(RGFW_window* win) {
  5396. #ifdef RGFW_OPENGL
  5397. if (win->src.ctx == NULL) return;
  5398. wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */
  5399. win->src.ctx = NULL;
  5400. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
  5401. #else
  5402. RGFW_UNUSED(win);
  5403. #endif
  5404. }
  5405. #endif
  5406. i32 RGFW_init(void) {
  5407. #ifndef RGFW_NO_XINPUT
  5408. if (RGFW_XInput_dll == NULL)
  5409. RGFW_loadXInput();
  5410. #endif
  5411. #ifndef RGFW_NO_DPI
  5412. #if (_WIN32_WINNT >= 0x0600)
  5413. SetProcessDPIAware();
  5414. #endif
  5415. #endif
  5416. #ifndef RGFW_NO_WINMM
  5417. #ifndef RGFW_NO_LOAD_WINMM
  5418. RGFW_LOAD_LIBRARY(RGFW_winmm_dll, "winmm.dll");
  5419. RGFW_PROC_DEF(RGFW_winmm_dll, timeBeginPeriod);
  5420. RGFW_PROC_DEF(RGFW_winmm_dll, timeEndPeriod);
  5421. #endif
  5422. timeBeginPeriod(1);
  5423. #endif
  5424. #ifndef RGFW_NO_DWM
  5425. RGFW_LOAD_LIBRARY(RGFW_dwm_dll, "dwmapi.dll");
  5426. RGFW_PROC_DEF(RGFW_dwm_dll, DwmEnableBlurBehindWindow);
  5427. #endif
  5428. RGFW_LOAD_LIBRARY(RGFW_wgl_dll, "opengl32.dll");
  5429. #ifndef RGFW_NO_LOAD_WGL
  5430. RGFW_PROC_DEF(RGFW_wgl_dll, wglCreateContext);
  5431. RGFW_PROC_DEF(RGFW_wgl_dll, wglDeleteContext);
  5432. RGFW_PROC_DEF(RGFW_wgl_dll, wglDeleteContext);
  5433. RGFW_PROC_DEF(RGFW_wgl_dll, wglGetProcAddress);
  5434. RGFW_PROC_DEF(RGFW_wgl_dll, wglMakeCurrent);
  5435. RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentDC);
  5436. RGFW_PROC_DEF(RGFW_wgl_dll, wglGetCurrentContext);
  5437. RGFW_PROC_DEF(RGFW_wgl_dll, wglShareLists);
  5438. #endif
  5439. u8 RGFW_blk[] = { 0, 0, 0, 0 };
  5440. _RGFW.hiddenMouse = RGFW_loadMouse(RGFW_blk, RGFW_AREA(1, 1), 4);
  5441. _RGFW.windowCount = 0;
  5442. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, (RGFW_debugContext){0}, "global context initialized");
  5443. return 1;
  5444. }
  5445. RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
  5446. if (name[0] == 0) name = (char*) " ";
  5447. RGFW_window_basic_init(win, rect, flags);
  5448. win->src.hIconSmall = win->src.hIconBig = NULL;
  5449. win->src.maxSize = RGFW_AREA(0, 0);
  5450. win->src.minSize = RGFW_AREA(0, 0);
  5451. win->src.aspectRatio = RGFW_AREA(0, 0);
  5452. HINSTANCE inh = GetModuleHandleA(NULL);
  5453. #ifndef __cplusplus
  5454. WNDCLASSW Class = { 0 }; /*!< Setup the Window class. */
  5455. #else
  5456. WNDCLASSW Class = { };
  5457. #endif
  5458. if (RGFW_className == NULL)
  5459. RGFW_className = (char*)name;
  5460. wchar_t wide_class[256];
  5461. MultiByteToWideChar(CP_UTF8, 0, RGFW_className, -1, wide_class, 255);
  5462. Class.lpszClassName = wide_class;
  5463. Class.hInstance = inh;
  5464. Class.hCursor = LoadCursor(NULL, IDC_ARROW);
  5465. Class.lpfnWndProc = WndProcW;
  5466. Class.cbClsExtra = sizeof(RGFW_window*);
  5467. Class.hIcon = (HICON)LoadImageA(GetModuleHandleW(NULL), "RGFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
  5468. if (Class.hIcon == NULL)
  5469. Class.hIcon = (HICON)LoadImageA(NULL, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
  5470. RegisterClassW(&Class);
  5471. DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
  5472. RECT windowRect, clientRect;
  5473. if (!(flags & RGFW_windowNoBorder)) {
  5474. window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX | WS_THICKFRAME;
  5475. if (!(flags & RGFW_windowNoResize))
  5476. window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
  5477. } else
  5478. window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU;
  5479. wchar_t wide_name[256];
  5480. MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 255);
  5481. HWND dummyWin = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0);
  5482. GetWindowRect(dummyWin, &windowRect);
  5483. GetClientRect(dummyWin, &clientRect);
  5484. RGFW_win32_loadOpenGLFuncs(dummyWin);
  5485. DestroyWindow(dummyWin);
  5486. win->src.hOffset = (u32)(windowRect.bottom - windowRect.top) - (u32)(clientRect.bottom - clientRect.top);
  5487. win->src.window = CreateWindowW(Class.lpszClassName, (wchar_t*)wide_name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + (i32)win->src.hOffset, 0, 0, inh, 0);
  5488. SetPropW(win->src.window, L"RGFW", win);
  5489. RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h)); /* so WM_GETMINMAXINFO gets called again */
  5490. if (flags & RGFW_windowAllowDND) {
  5491. win->_flags |= RGFW_windowAllowDND;
  5492. RGFW_window_setDND(win, 1);
  5493. }
  5494. win->src.hdc = GetDC(win->src.window);
  5495. if ((flags & RGFW_windowNoInitAPI) == 0) {
  5496. RGFW_window_initOpenGL(win, RGFW_BOOL(flags & RGFW_windowOpenglSoftware));
  5497. RGFW_window_initBuffer(win);
  5498. }
  5499. RGFW_window_setFlags(win, flags);
  5500. RGFW_win32_makeWindowTransparent(win);
  5501. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
  5502. RGFW_window_show(win);
  5503. return win;
  5504. }
  5505. void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
  5506. RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
  5507. LONG style = GetWindowLong(win->src.window, GWL_STYLE);
  5508. if (border == 0) {
  5509. SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW);
  5510. SetWindowPos(
  5511. win->src.window, HWND_TOP, 0, 0, 0, 0,
  5512. SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
  5513. );
  5514. }
  5515. else {
  5516. style |= WS_OVERLAPPEDWINDOW;
  5517. if (win->_flags & RGFW_windowNoResize) style &= ~WS_MAXIMIZEBOX;
  5518. SetWindowPos(
  5519. win->src.window, HWND_TOP, 0, 0, 0, 0,
  5520. SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
  5521. );
  5522. }
  5523. }
  5524. void RGFW_window_setDND(RGFW_window* win, RGFW_bool allow) {
  5525. RGFW_setBit(&win->_flags, RGFW_windowAllowDND, allow);
  5526. DragAcceptFiles(win->src.window, allow);
  5527. }
  5528. RGFW_area RGFW_getScreenSize(void) {
  5529. HDC dc = GetDC(NULL);
  5530. RGFW_area area = RGFW_AREA(GetDeviceCaps(dc, HORZRES), GetDeviceCaps(dc, VERTRES));
  5531. ReleaseDC(NULL, dc);
  5532. return area;
  5533. }
  5534. RGFW_point RGFW_getGlobalMousePoint(void) {
  5535. POINT p;
  5536. GetCursorPos(&p);
  5537. return RGFW_POINT(p.x, p.y);
  5538. }
  5539. void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
  5540. RGFW_ASSERT(win != NULL);
  5541. win->src.aspectRatio = a;
  5542. }
  5543. void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
  5544. RGFW_ASSERT(win != NULL);
  5545. win->src.minSize = a;
  5546. }
  5547. void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
  5548. RGFW_ASSERT(win != NULL);
  5549. win->src.maxSize = a;
  5550. }
  5551. void RGFW_window_focus(RGFW_window* win) {
  5552. RGFW_ASSERT(win);
  5553. SetForegroundWindow(win->src.window);
  5554. SetFocus(win->src.window);
  5555. }
  5556. void RGFW_window_raise(RGFW_window* win) {
  5557. RGFW_ASSERT(win);
  5558. BringWindowToTop(win->src.window);
  5559. SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, win->r.w, win->r.h, SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
  5560. }
  5561. void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
  5562. RGFW_ASSERT(win != NULL);
  5563. if (fullscreen == RGFW_FALSE) {
  5564. RGFW_window_setBorder(win, 1);
  5565. SetWindowPos(win->src.window, HWND_NOTOPMOST, win->_oldRect.x, win->_oldRect.y, win->_oldRect.w, win->_oldRect.h + (i32)win->src.hOffset,
  5566. SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
  5567. win->_flags &= ~(u32)RGFW_windowFullscreen;
  5568. win->r = win->_oldRect;
  5569. return;
  5570. }
  5571. win->_oldRect = win->r;
  5572. win->_flags |= RGFW_windowFullscreen;
  5573. RGFW_monitor mon = RGFW_window_getMonitor(win);
  5574. RGFW_window_setBorder(win, 0);
  5575. SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, (i32)mon.mode.area.w, (i32)mon.mode.area.h, SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
  5576. RGFW_monitor_scaleToWindow(mon, win);
  5577. win->r = RGFW_RECT(0, 0, mon.mode.area.w, mon.mode.area.h);
  5578. }
  5579. void RGFW_window_maximize(RGFW_window* win) {
  5580. RGFW_ASSERT(win != NULL);
  5581. RGFW_window_hide(win);
  5582. ShowWindow(win->src.window, SW_MAXIMIZE);
  5583. }
  5584. void RGFW_window_minimize(RGFW_window* win) {
  5585. RGFW_ASSERT(win != NULL);
  5586. ShowWindow(win->src.window, SW_MINIMIZE);
  5587. }
  5588. void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
  5589. RGFW_ASSERT(win != NULL);
  5590. if (floating) SetWindowPos(win->src.window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  5591. else SetWindowPos(win->src.window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  5592. }
  5593. void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
  5594. SetWindowLong(win->src.window, GWL_EXSTYLE, WS_EX_LAYERED);
  5595. SetLayeredWindowAttributes(win->src.window, 0, opacity, LWA_ALPHA);
  5596. }
  5597. void RGFW_window_restore(RGFW_window* win) { RGFW_window_show(win); }
  5598. RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
  5599. return (GetWindowLongPtr(win->src.window, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
  5600. }
  5601. u8 RGFW_xinput2RGFW[] = {
  5602. RGFW_gamepadA, /* or PS X button */
  5603. RGFW_gamepadB, /* or PS circle button */
  5604. RGFW_gamepadX, /* or PS square button */
  5605. RGFW_gamepadY, /* or PS triangle button */
  5606. RGFW_gamepadR1, /* right bumper */
  5607. RGFW_gamepadL1, /* left bump */
  5608. RGFW_gamepadL2, /* left trigger */
  5609. RGFW_gamepadR2, /* right trigger */
  5610. 0, 0, 0, 0, 0, 0, 0, 0,
  5611. RGFW_gamepadUp, /* dpad up */
  5612. RGFW_gamepadDown, /* dpad down */
  5613. RGFW_gamepadLeft, /* dpad left */
  5614. RGFW_gamepadRight, /* dpad right */
  5615. RGFW_gamepadStart, /* start button */
  5616. RGFW_gamepadSelect,/* select button */
  5617. RGFW_gamepadL3,
  5618. RGFW_gamepadR3,
  5619. };
  5620. i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e);
  5621. i32 RGFW_checkXInput(RGFW_window* win, RGFW_event* e) {
  5622. #ifndef RGFW_NO_XINPUT
  5623. RGFW_UNUSED(win);
  5624. u16 i;
  5625. for (i = 0; i < 4; i++) {
  5626. XINPUT_KEYSTROKE keystroke;
  5627. if (XInputGetKeystroke == NULL)
  5628. return 0;
  5629. DWORD result = XInputGetKeystroke((DWORD)i, 0, &keystroke);
  5630. if ((keystroke.Flags & XINPUT_KEYSTROKE_REPEAT) == 0 && result != ERROR_EMPTY) {
  5631. if (result != ERROR_SUCCESS)
  5632. return 0;
  5633. if (keystroke.VirtualKey > VK_PAD_RTHUMB_PRESS)
  5634. continue;
  5635. /* gamepad + 1 = RGFW_gamepadButtonReleased */
  5636. e->type = RGFW_gamepadButtonPressed + !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
  5637. e->button = RGFW_xinput2RGFW[keystroke.VirtualKey - 0x5800];
  5638. RGFW_gamepadPressed[i][e->button].prev = RGFW_gamepadPressed[i][e->button].current;
  5639. RGFW_gamepadPressed[i][e->button].current = RGFW_BOOL(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
  5640. RGFW_gamepadButtonCallback(win, i, e->button, e->type == RGFW_gamepadButtonPressed);
  5641. return 1;
  5642. }
  5643. XINPUT_STATE state;
  5644. if (XInputGetState == NULL ||
  5645. XInputGetState((DWORD) i, &state) == ERROR_DEVICE_NOT_CONNECTED
  5646. ) {
  5647. if (RGFW_gamepads[i] == 0)
  5648. continue;
  5649. RGFW_gamepads[i] = 0;
  5650. RGFW_gamepadCount--;
  5651. win->event.type = RGFW_gamepadDisconnected;
  5652. win->event.gamepad = (u16)i;
  5653. RGFW_gamepadCallback(win, i, 0);
  5654. return 1;
  5655. }
  5656. if (RGFW_gamepads[i] == 0) {
  5657. RGFW_gamepads[i] = 1;
  5658. RGFW_gamepadCount++;
  5659. char str[] = "Microsoft X-Box (XInput device)";
  5660. RGFW_MEMCPY(RGFW_gamepads_name[i], str, sizeof(str));
  5661. RGFW_gamepads_name[i][sizeof(RGFW_gamepads_name[i]) - 1] = '\0';
  5662. win->event.type = RGFW_gamepadConnected;
  5663. win->event.gamepad = i;
  5664. RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
  5665. RGFW_gamepadCallback(win, i, 1);
  5666. return 1;
  5667. }
  5668. #define INPUT_DEADZONE ( 0.24f * (float)(0x7FFF) ) /* Default to 24% of the +/- 32767 range. This is a reasonable default value but can be altered if needed. */
  5669. if ((state.Gamepad.sThumbLX < INPUT_DEADZONE &&
  5670. state.Gamepad.sThumbLX > -INPUT_DEADZONE) &&
  5671. (state.Gamepad.sThumbLY < INPUT_DEADZONE &&
  5672. state.Gamepad.sThumbLY > -INPUT_DEADZONE))
  5673. {
  5674. state.Gamepad.sThumbLX = 0;
  5675. state.Gamepad.sThumbLY = 0;
  5676. }
  5677. if ((state.Gamepad.sThumbRX < INPUT_DEADZONE &&
  5678. state.Gamepad.sThumbRX > -INPUT_DEADZONE) &&
  5679. (state.Gamepad.sThumbRY < INPUT_DEADZONE &&
  5680. state.Gamepad.sThumbRY > -INPUT_DEADZONE))
  5681. {
  5682. state.Gamepad.sThumbRX = 0;
  5683. state.Gamepad.sThumbRY = 0;
  5684. }
  5685. e->axisesCount = 2;
  5686. RGFW_point axis1 = RGFW_POINT(((float)state.Gamepad.sThumbLX / 32768.0f) * 100, ((float)state.Gamepad.sThumbLY / -32768.0f) * 100);
  5687. RGFW_point axis2 = RGFW_POINT(((float)state.Gamepad.sThumbRX / 32768.0f) * 100, ((float)state.Gamepad.sThumbRY / -32768.0f) * 100);
  5688. if (axis1.x != e->axis[0].x || axis1.y != e->axis[0].y){
  5689. win->event.whichAxis = 0;
  5690. e->type = RGFW_gamepadAxisMove;
  5691. e->axis[0] = axis1;
  5692. RGFW_gamepadAxes[i][0] = e->axis[0];
  5693. RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis);
  5694. return 1;
  5695. }
  5696. if (axis2.x != e->axis[1].x || axis2.y != e->axis[1].y) {
  5697. win->event.whichAxis = 1;
  5698. e->type = RGFW_gamepadAxisMove;
  5699. e->axis[1] = axis2;
  5700. RGFW_gamepadAxes[i][1] = e->axis[1];
  5701. RGFW_gamepadAxisCallback(win, e->gamepad, e->axis, e->axisesCount, e->whichAxis);
  5702. return 1;
  5703. }
  5704. }
  5705. #endif
  5706. return 0;
  5707. }
  5708. void RGFW_stopCheckEvents(void) {
  5709. PostMessageW(_RGFW.root->src.window, WM_NULL, 0, 0);
  5710. }
  5711. void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
  5712. RGFW_UNUSED(win);
  5713. MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD)waitMS, QS_ALLINPUT);
  5714. }
  5715. RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
  5716. if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
  5717. RGFW_event* ev = RGFW_window_checkEventCore(win);
  5718. if (ev) return ev;
  5719. static HDROP drop;
  5720. if (win->event.type == RGFW_DNDInit) {
  5721. if (win->event.droppedFilesCount) {
  5722. u32 i;
  5723. for (i = 0; i < win->event.droppedFilesCount; i++)
  5724. win->event.droppedFiles[i][0] = '\0';
  5725. }
  5726. win->event.droppedFilesCount = 0;
  5727. win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0);
  5728. u32 i;
  5729. for (i = 0; i < win->event.droppedFilesCount; i++) {
  5730. UINT length = DragQueryFileW(drop, i, NULL, 0);
  5731. if (length == 0)
  5732. continue;
  5733. WCHAR buffer[RGFW_MAX_PATH * 2];
  5734. if (length > (RGFW_MAX_PATH * 2) - 1)
  5735. length = RGFW_MAX_PATH * 2;
  5736. DragQueryFileW(drop, i, buffer, length + 1);
  5737. char* str = RGFW_createUTF8FromWideStringWin32(buffer);
  5738. if (str != NULL)
  5739. RGFW_MEMCPY(win->event.droppedFiles[i], str, length + 1);
  5740. win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
  5741. }
  5742. DragFinish(drop);
  5743. RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
  5744. win->event.type = RGFW_DND;
  5745. return &win->event;
  5746. }
  5747. if (RGFW_checkXInput(win, &win->event))
  5748. return &win->event;
  5749. static BYTE keyboardState[256];
  5750. GetKeyboardState(keyboardState);
  5751. MSG msg;
  5752. if (PeekMessageA(&msg, NULL, 0u, 0u, PM_REMOVE)) {
  5753. if (msg.hwnd != win->src.window && msg.hwnd != NULL) {
  5754. TranslateMessage(&msg);
  5755. DispatchMessageA(&msg);
  5756. return RGFW_window_checkEvent(win);
  5757. }
  5758. } else {
  5759. return NULL;
  5760. }
  5761. switch (msg.message) {
  5762. case WM_MOUSELEAVE:
  5763. win->event.type = RGFW_mouseLeave;
  5764. win->_flags |= RGFW_MOUSE_LEFT;
  5765. RGFW_mouseNotifyCallback(win, win->event.point, 0);
  5766. break;
  5767. case WM_SYSKEYUP: case WM_KEYUP: {
  5768. i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff));
  5769. if (scancode == 0)
  5770. scancode = (i32)MapVirtualKeyW((UINT)msg.wParam, MAPVK_VK_TO_VSC);
  5771. switch (scancode) {
  5772. case 0x54: scancode = 0x137; break; /* Alt+PrtS */
  5773. case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
  5774. case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */
  5775. default: break;
  5776. }
  5777. win->event.key = (u8)RGFW_apiKeyToRGFW((u32) scancode);
  5778. if (msg.wParam == VK_CONTROL) {
  5779. if (HIWORD(msg.lParam) & KF_EXTENDED)
  5780. win->event.key = RGFW_controlR;
  5781. else win->event.key = RGFW_controlL;
  5782. }
  5783. wchar_t charBuffer;
  5784. ToUnicodeEx((UINT)msg.wParam, (UINT)scancode, keyboardState, (wchar_t*)&charBuffer, 1, 0, NULL);
  5785. win->event.keyChar = (u8)charBuffer;
  5786. RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
  5787. win->event.type = RGFW_keyReleased;
  5788. RGFW_keyboard[win->event.key].current = 0;
  5789. RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
  5790. RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0);
  5791. break;
  5792. }
  5793. case WM_SYSKEYDOWN: case WM_KEYDOWN: {
  5794. i32 scancode = (HIWORD(msg.lParam) & (KF_EXTENDED | 0xff));
  5795. if (scancode == 0)
  5796. scancode = (i32)MapVirtualKeyW((u32)msg.wParam, MAPVK_VK_TO_VSC);
  5797. switch (scancode) {
  5798. case 0x54: scancode = 0x137; break; /* Alt+PrtS */
  5799. case 0x146: scancode = 0x45; break; /* Ctrl+Pause */
  5800. case 0x136: scancode = 0x36; break; /* CJK IME sets the extended bit for right Shift */
  5801. default: break;
  5802. }
  5803. win->event.key = (u8)RGFW_apiKeyToRGFW((u32) scancode);
  5804. if (msg.wParam == VK_CONTROL) {
  5805. if (HIWORD(msg.lParam) & KF_EXTENDED)
  5806. win->event.key = RGFW_controlR;
  5807. else win->event.key = RGFW_controlL;
  5808. }
  5809. wchar_t charBuffer;
  5810. ToUnicodeEx((UINT)msg.wParam, (UINT)scancode, keyboardState, &charBuffer, 1, 0, NULL);
  5811. win->event.keyChar = (u8)charBuffer;
  5812. RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
  5813. win->event.type = RGFW_keyPressed;
  5814. win->event.repeat = RGFW_isPressed(win, win->event.key);
  5815. RGFW_keyboard[win->event.key].current = 1;
  5816. RGFW_updateKeyMods(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001), (GetKeyState(VK_SCROLL) & 0x0001));
  5817. RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1);
  5818. break;
  5819. }
  5820. case WM_MOUSEMOVE: {
  5821. if ((win->_flags & RGFW_HOLD_MOUSE))
  5822. break;
  5823. win->event.type = RGFW_mousePosChanged;
  5824. i32 x = GET_X_LPARAM(msg.lParam);
  5825. i32 y = GET_Y_LPARAM(msg.lParam);
  5826. RGFW_mousePosCallback(win, win->event.point, win->event.vector);
  5827. if (win->_flags & RGFW_MOUSE_LEFT) {
  5828. win->_flags &= ~(u32)RGFW_MOUSE_LEFT;
  5829. win->event.type = RGFW_mouseEnter;
  5830. RGFW_mouseNotifyCallback(win, win->event.point, 1);
  5831. }
  5832. win->event.point.x = x;
  5833. win->event.point.y = y;
  5834. win->_lastMousePoint = RGFW_POINT(x, y);
  5835. break;
  5836. }
  5837. case WM_INPUT: {
  5838. if (!(win->_flags & RGFW_HOLD_MOUSE))
  5839. break;
  5840. unsigned size = sizeof(RAWINPUT);
  5841. static RAWINPUT raw = {0};
  5842. GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER));
  5843. if (raw.header.dwType != RIM_TYPEMOUSE || (raw.data.mouse.lLastX == 0 && raw.data.mouse.lLastY == 0) )
  5844. break;
  5845. if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
  5846. POINT pos = {0, 0};
  5847. int width, height;
  5848. if (raw.data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) {
  5849. pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN);
  5850. pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN);
  5851. width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
  5852. height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
  5853. }
  5854. else {
  5855. width = GetSystemMetrics(SM_CXSCREEN);
  5856. height = GetSystemMetrics(SM_CYSCREEN);
  5857. }
  5858. pos.x += (int) (((float)raw.data.mouse.lLastX / 65535.f) * (float)width);
  5859. pos.y += (int) (((float)raw.data.mouse.lLastY / 65535.f) * (float)height);
  5860. ScreenToClient(win->src.window, &pos);
  5861. win->event.vector.x = pos.x - win->_lastMousePoint.x;
  5862. win->event.vector.y = pos.y - win->_lastMousePoint.y;
  5863. } else {
  5864. win->event.vector.x = raw.data.mouse.lLastX;
  5865. win->event.vector.y = raw.data.mouse.lLastY;
  5866. }
  5867. win->event.type = RGFW_mousePosChanged;
  5868. win->_lastMousePoint.x += win->event.vector.x;
  5869. win->_lastMousePoint.y += win->event.vector.y;
  5870. win->event.point = win->_lastMousePoint;
  5871. RGFW_mousePosCallback(win, win->event.point, win->event.vector);
  5872. break;
  5873. }
  5874. case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_XBUTTONDOWN:
  5875. if (msg.message == WM_XBUTTONDOWN)
  5876. win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2);
  5877. else win->event.button = (msg.message == WM_LBUTTONDOWN) ? RGFW_mouseLeft :
  5878. (msg.message == WM_RBUTTONDOWN) ? RGFW_mouseRight : RGFW_mouseMiddle;
  5879. win->event.type = RGFW_mouseButtonPressed;
  5880. RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
  5881. RGFW_mouseButtons[win->event.button].current = 1;
  5882. RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
  5883. break;
  5884. case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_XBUTTONUP:
  5885. if (msg.message == WM_XBUTTONUP)
  5886. win->event.button = RGFW_mouseMisc1 + (GET_XBUTTON_WPARAM(msg.wParam) == XBUTTON2);
  5887. else win->event.button = (msg.message == WM_LBUTTONUP) ? RGFW_mouseLeft :
  5888. (msg.message == WM_RBUTTONUP) ? RGFW_mouseRight : RGFW_mouseMiddle;
  5889. win->event.type = RGFW_mouseButtonReleased;
  5890. RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
  5891. RGFW_mouseButtons[win->event.button].current = 0;
  5892. RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
  5893. break;
  5894. case WM_MOUSEWHEEL:
  5895. if (msg.wParam > 0)
  5896. win->event.button = RGFW_mouseScrollUp;
  5897. else
  5898. win->event.button = RGFW_mouseScrollDown;
  5899. RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
  5900. RGFW_mouseButtons[win->event.button].current = 1;
  5901. win->event.scroll = (SHORT) HIWORD(msg.wParam) / (double) WHEEL_DELTA;
  5902. win->event.type = RGFW_mouseButtonPressed;
  5903. RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
  5904. break;
  5905. case WM_DROPFILES: {
  5906. win->event.type = RGFW_DNDInit;
  5907. drop = (HDROP) msg.wParam;
  5908. POINT pt;
  5909. /* Move the mouse to the position of the drop */
  5910. DragQueryPoint(drop, &pt);
  5911. win->event.point.x = pt.x;
  5912. win->event.point.y = pt.y;
  5913. RGFW_dndInitCallback(win, win->event.point);
  5914. }
  5915. break;
  5916. default:
  5917. TranslateMessage(&msg);
  5918. DispatchMessageA(&msg);
  5919. return RGFW_window_checkEvent(win);
  5920. }
  5921. TranslateMessage(&msg);
  5922. DispatchMessageA(&msg);
  5923. return &win->event;
  5924. }
  5925. RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
  5926. RGFW_ASSERT(win != NULL);
  5927. return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);
  5928. }
  5929. RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
  5930. RGFW_ASSERT(win != NULL);
  5931. #ifndef __cplusplus
  5932. WINDOWPLACEMENT placement = { 0 };
  5933. #else
  5934. WINDOWPLACEMENT placement = { };
  5935. #endif
  5936. GetWindowPlacement(win->src.window, &placement);
  5937. return placement.showCmd == SW_SHOWMINIMIZED;
  5938. }
  5939. RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
  5940. RGFW_ASSERT(win != NULL);
  5941. #ifndef __cplusplus
  5942. WINDOWPLACEMENT placement = { 0 };
  5943. #else
  5944. WINDOWPLACEMENT placement = { };
  5945. #endif
  5946. GetWindowPlacement(win->src.window, &placement);
  5947. return placement.showCmd == SW_SHOWMAXIMIZED || IsZoomed(win->src.window);
  5948. }
  5949. typedef struct { int iIndex; HMONITOR hMonitor; RGFW_monitor* monitors; } RGFW_mInfo;
  5950. #ifndef RGFW_NO_MONITOR
  5951. RGFW_monitor win32CreateMonitor(HMONITOR src);
  5952. RGFW_monitor win32CreateMonitor(HMONITOR src) {
  5953. RGFW_monitor monitor;
  5954. MONITORINFOEX monitorInfo;
  5955. monitorInfo.cbSize = sizeof(MONITORINFOEX);
  5956. GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
  5957. /* get the monitor's index */
  5958. DISPLAY_DEVICEA dd;
  5959. dd.cb = sizeof(dd);
  5960. DWORD deviceNum;
  5961. for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) {
  5962. if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
  5963. continue;
  5964. DEVMODE dm;
  5965. ZeroMemory(&dm, sizeof(dm));
  5966. dm.dmSize = sizeof(dm);
  5967. if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
  5968. monitor.mode.refreshRate = dm.dmDisplayFrequency;
  5969. RGFW_splitBPP(dm.dmBitsPerPel, &monitor.mode);
  5970. }
  5971. DISPLAY_DEVICEA mdd;
  5972. mdd.cb = sizeof(mdd);
  5973. if (EnumDisplayDevicesA(dd.DeviceName, (DWORD)deviceNum, &mdd, 0)) {
  5974. RGFW_MEMCPY(monitor.name, mdd.DeviceString, 128);
  5975. break;
  5976. }
  5977. }
  5978. monitor.x = monitorInfo.rcWork.left;
  5979. monitor.y = monitorInfo.rcWork.top;
  5980. monitor.mode.area.w = (u32)(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left);
  5981. monitor.mode.area.h = (u32)(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top);
  5982. HDC hdc = CreateDC(monitorInfo.szDevice, NULL, NULL, NULL);
  5983. /* get pixels per inch */
  5984. float dpiX = (float)GetDeviceCaps(hdc, LOGPIXELSX);
  5985. float dpiY = (float)GetDeviceCaps(hdc, LOGPIXELSX);
  5986. monitor.scaleX = dpiX / 96.0f;
  5987. monitor.scaleY = dpiY / 96.0f;
  5988. monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
  5989. monitor.physW = (float)GetDeviceCaps(hdc, HORZSIZE) / 25.4f;
  5990. monitor.physH = (float)GetDeviceCaps(hdc, VERTSIZE) / 25.4f;
  5991. DeleteDC(hdc);
  5992. #ifndef RGFW_NO_DPI
  5993. RGFW_LOAD_LIBRARY(RGFW_Shcore_dll, "shcore.dll");
  5994. RGFW_PROC_DEF(RGFW_Shcore_dll, GetDpiForMonitor);
  5995. if (GetDpiForMonitor != NULL) {
  5996. u32 x, y;
  5997. GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y);
  5998. monitor.scaleX = (float) (x) / (float) 96.0f;
  5999. monitor.scaleY = (float) (y) / (float) 96.0f;
  6000. monitor.pixelRatio = dpiX >= 192.0f ? 2.0f : 1.0f;
  6001. }
  6002. #endif
  6003. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
  6004. return monitor;
  6005. }
  6006. #endif /* RGFW_NO_MONITOR */
  6007. #ifndef RGFW_NO_MONITOR
  6008. BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
  6009. BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
  6010. RGFW_UNUSED(hdcMonitor);
  6011. RGFW_UNUSED(lprcMonitor);
  6012. RGFW_mInfo* info = (RGFW_mInfo*) dwData;
  6013. if (info->iIndex >= 6)
  6014. return FALSE;
  6015. info->monitors[info->iIndex] = win32CreateMonitor(hMonitor);
  6016. info->iIndex++;
  6017. return TRUE;
  6018. }
  6019. RGFW_monitor RGFW_getPrimaryMonitor(void) {
  6020. #ifdef __cplusplus
  6021. return win32CreateMonitor(MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
  6022. #else
  6023. return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
  6024. #endif
  6025. }
  6026. RGFW_monitor* RGFW_getMonitors(size_t* len) {
  6027. static RGFW_monitor monitors[6];
  6028. RGFW_mInfo info;
  6029. info.iIndex = 0;
  6030. info.monitors = monitors;
  6031. EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info);
  6032. if (len != NULL) *len = (size_t)info.iIndex;
  6033. return monitors;
  6034. }
  6035. RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
  6036. HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY);
  6037. return win32CreateMonitor(src);
  6038. }
  6039. RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
  6040. HMONITOR src = MonitorFromPoint((POINT) { mon.x, mon.y }, MONITOR_DEFAULTTOPRIMARY);
  6041. MONITORINFOEX monitorInfo;
  6042. monitorInfo.cbSize = sizeof(MONITORINFOEX);
  6043. GetMonitorInfoA(src, (LPMONITORINFO)&monitorInfo);
  6044. DISPLAY_DEVICE dd;
  6045. dd.cb = sizeof(dd);
  6046. /* Enumerate display devices */
  6047. DWORD deviceNum;
  6048. for (deviceNum = 0; EnumDisplayDevicesA(NULL, deviceNum, &dd, 0); deviceNum++) {
  6049. if (!(dd.StateFlags & DISPLAY_DEVICE_ACTIVE))
  6050. continue;
  6051. if (strcmp(dd.DeviceName, monitorInfo.szDevice) != 0)
  6052. continue;
  6053. DEVMODE dm;
  6054. ZeroMemory(&dm, sizeof(dm));
  6055. dm.dmSize = sizeof(dm);
  6056. if (EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
  6057. if (request & RGFW_monitorScale) {
  6058. dm.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
  6059. dm.dmPelsWidth = mode.area.w;
  6060. dm.dmPelsHeight = mode.area.h;
  6061. }
  6062. if (request & RGFW_monitorRefresh) {
  6063. dm.dmFields |= DM_DISPLAYFREQUENCY;
  6064. dm.dmDisplayFrequency = mode.refreshRate;
  6065. }
  6066. if (request & RGFW_monitorRGB) {
  6067. dm.dmFields |= DM_BITSPERPEL;
  6068. dm.dmBitsPerPel = (DWORD)(mode.red + mode.green + mode.blue);
  6069. }
  6070. if (ChangeDisplaySettingsEx(dd.DeviceName, &dm, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL) {
  6071. if (ChangeDisplaySettingsEx(dd.DeviceName, &dm, NULL, CDS_UPDATEREGISTRY, NULL) == DISP_CHANGE_SUCCESSFUL)
  6072. return RGFW_TRUE;
  6073. return RGFW_FALSE;
  6074. } else return RGFW_FALSE;
  6075. }
  6076. }
  6077. return RGFW_FALSE;
  6078. }
  6079. #endif
  6080. HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon);
  6081. HICON RGFW_loadHandleImage(u8* src, i32 c, RGFW_area a, BOOL icon) {
  6082. size_t channels = (size_t)c;
  6083. BITMAPV5HEADER bi;
  6084. ZeroMemory(&bi, sizeof(bi));
  6085. bi.bV5Size = sizeof(bi);
  6086. bi.bV5Width = (i32)a.w;
  6087. bi.bV5Height = -((LONG) a.h);
  6088. bi.bV5Planes = 1;
  6089. bi.bV5BitCount = (WORD)(channels * 8);
  6090. bi.bV5Compression = BI_RGB;
  6091. HDC dc = GetDC(NULL);
  6092. u8* target = NULL;
  6093. HBITMAP color = CreateDIBSection(dc,
  6094. (BITMAPINFO*) &bi, DIB_RGB_COLORS, (void**) &target,
  6095. NULL, (DWORD) 0);
  6096. size_t x, y;
  6097. for (y = 0; y < a.h; y++) {
  6098. for (x = 0; x < a.w; x++) {
  6099. size_t index = (y * 4 * (size_t)a.w) + x * channels;
  6100. target[index] = src[index + 2];
  6101. target[index + 1] = src[index + 1];
  6102. target[index + 2] = src[index];
  6103. target[index + 3] = src[index + 3];
  6104. }
  6105. }
  6106. ReleaseDC(NULL, dc);
  6107. HBITMAP mask = CreateBitmap((i32)a.w, (i32)a.h, 1, 1, NULL);
  6108. ICONINFO ii;
  6109. ZeroMemory(&ii, sizeof(ii));
  6110. ii.fIcon = icon;
  6111. ii.xHotspot = a.w / 2;
  6112. ii.yHotspot = a.h / 2;
  6113. ii.hbmMask = mask;
  6114. ii.hbmColor = color;
  6115. HICON handle = CreateIconIndirect(&ii);
  6116. DeleteObject(color);
  6117. DeleteObject(mask);
  6118. return handle;
  6119. }
  6120. void* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
  6121. HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(icon, channels, a, FALSE);
  6122. return cursor;
  6123. }
  6124. void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
  6125. RGFW_ASSERT(win && mouse);
  6126. SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) mouse);
  6127. SetCursor((HCURSOR)mouse);
  6128. }
  6129. void RGFW_freeMouse(RGFW_mouse* mouse) {
  6130. RGFW_ASSERT(mouse);
  6131. DestroyCursor((HCURSOR)mouse);
  6132. }
  6133. RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
  6134. return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
  6135. }
  6136. RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
  6137. RGFW_ASSERT(win != NULL);
  6138. static const u32 mouseIconSrc[16] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO};
  6139. if (mouse > (sizeof(mouseIconSrc) / sizeof(u32)))
  6140. return RGFW_FALSE;
  6141. char* icon = MAKEINTRESOURCEA(mouseIconSrc[mouse]);
  6142. SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon));
  6143. SetCursor(LoadCursorA(NULL, icon));
  6144. return RGFW_TRUE;
  6145. }
  6146. void RGFW_window_hide(RGFW_window* win) {
  6147. ShowWindow(win->src.window, SW_HIDE);
  6148. }
  6149. void RGFW_window_show(RGFW_window* win) {
  6150. if (win->_flags & RGFW_windowFocusOnShow) RGFW_window_focus(win);
  6151. ShowWindow(win->src.window, SW_RESTORE);
  6152. }
  6153. #define RGFW_FREE_LIBRARY(x) if (x != NULL) FreeLibrary(x); x = NULL;
  6154. void RGFW_deinit(void) {
  6155. #ifndef RGFW_NO_XINPUT
  6156. RGFW_FREE_LIBRARY(RGFW_XInput_dll);
  6157. #endif
  6158. #ifndef RGFW_NO_DPI
  6159. RGFW_FREE_LIBRARY(RGFW_Shcore_dll);
  6160. #endif
  6161. #ifndef RGFW_NO_WINMM
  6162. timeEndPeriod(1);
  6163. #ifndef RGFW_NO_LOAD_WINMM
  6164. RGFW_FREE_LIBRARY(RGFW_winmm_dll);
  6165. #endif
  6166. #endif
  6167. RGFW_FREE_LIBRARY(RGFW_wgl_dll);
  6168. _RGFW.root = NULL;
  6169. RGFW_freeMouse(_RGFW.hiddenMouse);
  6170. _RGFW.windowCount = -1;
  6171. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, (RGFW_debugContext){0}, "global context deinitialized");
  6172. }
  6173. void RGFW_window_close(RGFW_window* win) {
  6174. RGFW_ASSERT(win != NULL);
  6175. #ifdef RGFW_BUFFER
  6176. DeleteDC(win->src.hdcMem);
  6177. DeleteObject(win->src.bitmap);
  6178. #endif
  6179. if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
  6180. RemovePropW(win->src.window, L"RGFW");
  6181. ReleaseDC(win->src.window, win->src.hdc); /*!< delete device context */
  6182. DestroyWindow(win->src.window); /*!< delete window */
  6183. if (win->src.hIconSmall) DestroyIcon(win->src.hIconSmall);
  6184. if (win->src.hIconBig) DestroyIcon(win->src.hIconBig);
  6185. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
  6186. _RGFW.windowCount--;
  6187. if (_RGFW.windowCount == 0) RGFW_deinit();
  6188. RGFW_clipboard_switch(NULL);
  6189. RGFW_FREE(win->event.droppedFiles);
  6190. if ((win->_flags & RGFW_WINDOW_ALLOC)) {
  6191. RGFW_FREE(win);
  6192. win = NULL;
  6193. }
  6194. }
  6195. void RGFW_window_move(RGFW_window* win, RGFW_point v) {
  6196. RGFW_ASSERT(win != NULL);
  6197. win->r.x = v.x;
  6198. win->r.y = v.y;
  6199. SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE);
  6200. }
  6201. void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
  6202. RGFW_ASSERT(win != NULL);
  6203. win->r.w = (i32)a.w;
  6204. win->r.h = (i32)a.h;
  6205. SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w, win->r.h + (i32)win->src.hOffset, SWP_NOMOVE);
  6206. }
  6207. void RGFW_window_setName(RGFW_window* win, const char* name) {
  6208. RGFW_ASSERT(win != NULL);
  6209. wchar_t wide_name[256];
  6210. MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_name, 256);
  6211. SetWindowTextW(win->src.window, wide_name);
  6212. }
  6213. #ifndef RGFW_NO_PASSTHROUGH
  6214. void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
  6215. RGFW_ASSERT(win != NULL);
  6216. COLORREF key = 0;
  6217. BYTE alpha = 0;
  6218. DWORD flags = 0;
  6219. i32 exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE);
  6220. if (exStyle & WS_EX_LAYERED)
  6221. GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags);
  6222. if (passthrough)
  6223. exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
  6224. else {
  6225. exStyle &= ~WS_EX_TRANSPARENT;
  6226. if (exStyle & WS_EX_LAYERED && !(flags & LWA_ALPHA))
  6227. exStyle &= ~WS_EX_LAYERED;
  6228. }
  6229. SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle);
  6230. if (passthrough)
  6231. SetLayeredWindowAttributes(win->src.window, key, alpha, flags);
  6232. }
  6233. #endif
  6234. RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* src, RGFW_area a, i32 channels, u8 type) {
  6235. RGFW_ASSERT(win != NULL);
  6236. #ifndef RGFW_WIN95
  6237. RGFW_UNUSED(channels);
  6238. if (win->src.hIconSmall && (type & RGFW_iconWindow)) DestroyIcon(win->src.hIconSmall);
  6239. if (win->src.hIconBig && (type & RGFW_iconTaskbar)) DestroyIcon(win->src.hIconBig);
  6240. if (src == NULL) {
  6241. HICON defaultIcon = LoadIcon(NULL, IDI_APPLICATION);
  6242. if (type & RGFW_iconWindow)
  6243. SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)defaultIcon);
  6244. if (type & RGFW_iconTaskbar)
  6245. SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)defaultIcon);
  6246. return RGFW_TRUE;
  6247. }
  6248. if (type & RGFW_iconWindow) {
  6249. win->src.hIconSmall = RGFW_loadHandleImage(src, channels, a, TRUE);
  6250. SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)win->src.hIconSmall);
  6251. }
  6252. if (type & RGFW_iconTaskbar) {
  6253. win->src.hIconBig = RGFW_loadHandleImage(src, channels, a, TRUE);
  6254. SendMessage(win->src.window, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)win->src.hIconBig);
  6255. }
  6256. return RGFW_TRUE;
  6257. #else
  6258. RGFW_UNUSED(src);
  6259. RGFW_UNUSED(a);
  6260. RGFW_UNUSED(channels);
  6261. return RGFW_FALSE;
  6262. #endif
  6263. }
  6264. RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
  6265. /* Open the clipboard */
  6266. if (OpenClipboard(NULL) == 0)
  6267. return -1;
  6268. /* Get the clipboard data as a Unicode string */
  6269. HANDLE hData = GetClipboardData(CF_UNICODETEXT);
  6270. if (hData == NULL) {
  6271. CloseClipboard();
  6272. return -1;
  6273. }
  6274. wchar_t* wstr = (wchar_t*) GlobalLock(hData);
  6275. RGFW_ssize_t textLen = 0;
  6276. {
  6277. setlocale(LC_ALL, "en_US.UTF-8");
  6278. textLen = (RGFW_ssize_t)wcstombs(NULL, wstr, 0) + 1;
  6279. if (str != NULL && (RGFW_ssize_t)strCapacity <= textLen - 1)
  6280. textLen = 0;
  6281. if (str != NULL && textLen) {
  6282. if (textLen > 1)
  6283. wcstombs(str, wstr, (size_t)(textLen));
  6284. str[textLen] = '\0';
  6285. }
  6286. }
  6287. /* Release the clipboard data */
  6288. GlobalUnlock(hData);
  6289. CloseClipboard();
  6290. return textLen;
  6291. }
  6292. void RGFW_writeClipboard(const char* text, u32 textLen) {
  6293. HANDLE object;
  6294. WCHAR* buffer;
  6295. object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));
  6296. if (!object)
  6297. return;
  6298. buffer = (WCHAR*) GlobalLock(object);
  6299. if (!buffer) {
  6300. GlobalFree(object);
  6301. return;
  6302. }
  6303. MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, (i32)textLen);
  6304. GlobalUnlock(object);
  6305. if (!OpenClipboard(_RGFW.root->src.window)) {
  6306. GlobalFree(object);
  6307. return;
  6308. }
  6309. EmptyClipboard();
  6310. SetClipboardData(CF_UNICODETEXT, object);
  6311. CloseClipboard();
  6312. }
  6313. void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) {
  6314. RGFW_ASSERT(win != NULL);
  6315. win->_lastMousePoint = RGFW_POINT(p.x - win->r.x, p.y - win->r.y);
  6316. SetCursorPos(p.x, p.y);
  6317. }
  6318. #ifdef RGFW_OPENGL
  6319. void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
  6320. if (win == NULL)
  6321. wglMakeCurrent(NULL, NULL);
  6322. else
  6323. wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx);
  6324. }
  6325. void* RGFW_getCurrent_OpenGL(void) { return wglGetCurrentContext(); }
  6326. void RGFW_window_swapBuffers_OpenGL(RGFW_window* win){ SwapBuffers(win->src.hdc); }
  6327. #endif
  6328. #ifndef RGFW_EGL
  6329. void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
  6330. RGFW_ASSERT(win != NULL);
  6331. #if defined(RGFW_OPENGL)
  6332. if (wglSwapIntervalEXT == NULL || wglSwapIntervalEXT(swapInterval) == FALSE)
  6333. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to set swap interval");
  6334. #else
  6335. RGFW_UNUSED(swapInterval);
  6336. #endif
  6337. }
  6338. #endif
  6339. void RGFW_window_swapBuffers_software(RGFW_window* win) {
  6340. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  6341. if (win->buffer != win->src.bitmapBits)
  6342. memcpy(win->src.bitmapBits, win->buffer, win->bufferSize.w * win->bufferSize.h * 4);
  6343. RGFW_RGB_to_BGR(win, win->src.bitmapBits);
  6344. BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY);
  6345. #else
  6346. RGFW_UNUSED(win);
  6347. #endif
  6348. }
  6349. char* RGFW_createUTF8FromWideStringWin32(const WCHAR* source) {
  6350. if (source == NULL) {
  6351. return NULL;
  6352. }
  6353. i32 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
  6354. if (!size) {
  6355. return NULL;
  6356. }
  6357. static char target[RGFW_MAX_PATH * 2];
  6358. if (size > RGFW_MAX_PATH * 2)
  6359. size = RGFW_MAX_PATH * 2;
  6360. target[size] = 0;
  6361. if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) {
  6362. return NULL;
  6363. }
  6364. return target;
  6365. }
  6366. u64 RGFW_getTimerFreq(void) {
  6367. static u64 frequency = 0;
  6368. if (frequency == 0) QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
  6369. return frequency;
  6370. }
  6371. u64 RGFW_getTimerValue(void) {
  6372. u64 value;
  6373. QueryPerformanceCounter((LARGE_INTEGER*)&value);
  6374. return value;
  6375. }
  6376. void RGFW_sleep(u64 ms) {
  6377. Sleep((u32)ms);
  6378. }
  6379. #ifndef RGFW_NO_THREADS
  6380. RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { return CreateThread(NULL, 0, ptr, args, 0, NULL); }
  6381. void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); }
  6382. void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); }
  6383. void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); }
  6384. #endif
  6385. #endif /* RGFW_WINDOWS */
  6386. /*
  6387. End of Windows defines
  6388. */
  6389. /*
  6390. Start of MacOS defines
  6391. */
  6392. #if defined(RGFW_MACOS)
  6393. /*
  6394. based on silicon.h
  6395. start of cocoa wrapper
  6396. */
  6397. #include <CoreGraphics/CoreGraphics.h>
  6398. #include <ApplicationServices/ApplicationServices.h>
  6399. #include <objc/runtime.h>
  6400. #include <objc/message.h>
  6401. #include <mach/mach_time.h>
  6402. #include <CoreVideo/CoreVideo.h>
  6403. typedef CGRect NSRect;
  6404. typedef CGPoint NSPoint;
  6405. typedef CGSize NSSize;
  6406. typedef const char* NSPasteboardType;
  6407. typedef unsigned long NSUInteger;
  6408. typedef long NSInteger;
  6409. typedef NSInteger NSModalResponse;
  6410. #ifdef __arm64__
  6411. /* ARM just uses objc_msgSend */
  6412. #define abi_objc_msgSend_stret objc_msgSend
  6413. #define abi_objc_msgSend_fpret objc_msgSend
  6414. #else /* __i386__ */
  6415. /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */
  6416. #define abi_objc_msgSend_stret objc_msgSend_stret
  6417. #define abi_objc_msgSend_fpret objc_msgSend_fpret
  6418. #endif
  6419. #define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc"))
  6420. #define objc_msgSend_bool(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
  6421. #define objc_msgSend_void(x, y) ((void (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
  6422. #define objc_msgSend_void_id(x, y, z) ((void (*)(id, SEL, id))objc_msgSend) ((id)x, (SEL)y, (id)z)
  6423. #define objc_msgSend_uint(x, y) ((NSUInteger (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
  6424. #define objc_msgSend_void_bool(x, y, z) ((void (*)(id, SEL, BOOL))objc_msgSend) ((id)(x), (SEL)y, (BOOL)z)
  6425. #define objc_msgSend_bool_void(x, y) ((BOOL (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
  6426. #define objc_msgSend_void_SEL(x, y, z) ((void (*)(id, SEL, SEL))objc_msgSend) ((id)(x), (SEL)y, (SEL)z)
  6427. #define objc_msgSend_id(x, y) ((id (*)(id, SEL))objc_msgSend) ((id)(x), (SEL)y)
  6428. #define objc_msgSend_id_id(x, y, z) ((id (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z)
  6429. #define objc_msgSend_id_bool(x, y, z) ((BOOL (*)(id, SEL, id))objc_msgSend) ((id)(x), (SEL)y, (id)z)
  6430. #define objc_msgSend_int(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z)
  6431. #define objc_msgSend_arr(x, y, z) ((id (*)(id, SEL, int))objc_msgSend) ((id)(x), (SEL)y, (int)z)
  6432. #define objc_msgSend_ptr(x, y, z) ((id (*)(id, SEL, void*))objc_msgSend) ((id)(x), (SEL)y, (void*)z)
  6433. #define objc_msgSend_class(x, y) ((id (*)(Class, SEL))objc_msgSend) ((Class)(x), (SEL)y)
  6434. #define objc_msgSend_class_char(x, y, z) ((id (*)(Class, SEL, char*))objc_msgSend) ((Class)(x), (SEL)y, (char*)z)
  6435. id NSApp = NULL;
  6436. #define NSRelease(obj) objc_msgSend_void((id)obj, sel_registerName("release"))
  6437. id NSString_stringWithUTF8String(const char* str);
  6438. id NSString_stringWithUTF8String(const char* str) {
  6439. return ((id(*)(id, SEL, const char*))objc_msgSend)
  6440. ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str);
  6441. }
  6442. const char* NSString_to_char(id str);
  6443. const char* NSString_to_char(id str) {
  6444. return ((const char* (*)(id, SEL)) objc_msgSend) ((id)(id)str, sel_registerName("UTF8String"));
  6445. }
  6446. void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function);
  6447. void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) {
  6448. Class selected_class;
  6449. if (RGFW_STRNCMP(class_name, "NSView", 6) == 0) {
  6450. selected_class = objc_getClass("ViewClass");
  6451. } else if (RGFW_STRNCMP(class_name, "NSWindow", 8) == 0) {
  6452. selected_class = objc_getClass("WindowClass");
  6453. } else {
  6454. selected_class = objc_getClass(class_name);
  6455. }
  6456. class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0);
  6457. }
  6458. /* Header for the array. */
  6459. typedef struct siArrayHeader {
  6460. size_t count;
  6461. /* TODO(EimaMei): Add a `type_width` later on. */
  6462. } siArrayHeader;
  6463. /* Gets the header of the siArray. */
  6464. #define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1)
  6465. #define si_array_len(array) (SI_ARRAY_HEADER(array)->count)
  6466. #define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", (void*)function)
  6467. /* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/
  6468. #define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", (void*)function)
  6469. unsigned char* NSBitmapImageRep_bitmapData(id imageRep);
  6470. unsigned char* NSBitmapImageRep_bitmapData(id imageRep) {
  6471. return ((unsigned char* (*)(id, SEL))objc_msgSend) ((id)imageRep, sel_registerName("bitmapData"));
  6472. }
  6473. typedef RGFW_ENUM(NSUInteger, NSBitmapFormat) {
  6474. NSBitmapFormatAlphaFirst = 1 << 0, /* 0 means is alpha last (RGBA, CMYKA, etc.) */
  6475. NSBitmapFormatAlphaNonpremultiplied = 1 << 1, /* 0 means is premultiplied */
  6476. NSBitmapFormatFloatingpointSamples = 1 << 2, /* 0 is integer */
  6477. NSBitmapFormatSixteenBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 8),
  6478. NSBitmapFormatThirtyTwoBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 9),
  6479. NSBitmapFormatSixteenBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 10),
  6480. NSBitmapFormatThirtyTwoBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 11)
  6481. };
  6482. id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits);
  6483. id NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) {
  6484. SEL func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:");
  6485. return (id) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, id, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend)
  6486. (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits);
  6487. }
  6488. id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha);
  6489. id NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) {
  6490. void* nsclass = objc_getClass("NSColor");
  6491. SEL func = sel_registerName("colorWithSRGBRed:green:blue:alpha:");
  6492. return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)
  6493. ((id)nsclass, func, red, green, blue, alpha);
  6494. }
  6495. #define NS_OPENGL_ENUM_DEPRECATED(minVers, maxVers) API_AVAILABLE(macos(minVers))
  6496. typedef RGFW_ENUM(NSInteger, NSOpenGLContextParameter) {
  6497. NSOpenGLContextParameterSwapInterval NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */
  6498. NSOpenGLContextParametectxaceOrder NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */
  6499. NSOpenGLContextParametectxaceOpacity NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */
  6500. NSOpenGLContextParametectxaceBackingSize NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 304, /* 2 params. Width/height of surface backing size */
  6501. NSOpenGLContextParameterReclaimResources NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 308, /* 0 params. */
  6502. NSOpenGLContextParameterCurrentRendererID NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 309, /* 1 param. Retrieves the current renderer ID */
  6503. NSOpenGLContextParameterGPUVertexProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 310, /* 1 param. Currently processing vertices with GPU (get) */
  6504. NSOpenGLContextParameterGPUFragmentProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 311, /* 1 param. Currently processing fragments with GPU (get) */
  6505. NSOpenGLContextParameterHasDrawable NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 314, /* 1 param. Boolean returned if drawable is attached */
  6506. NSOpenGLContextParameterMPSwapsInFlight NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 315, /* 1 param. Max number of swaps queued by the MP GL engine */
  6507. NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */
  6508. NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */
  6509. NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */
  6510. NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */
  6511. NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */
  6512. };
  6513. typedef RGFW_ENUM(NSInteger, NSWindowButton) {
  6514. NSWindowCloseButton = 0,
  6515. NSWindowMiniaturizeButton = 1,
  6516. NSWindowZoomButton = 2,
  6517. NSWindowToolbarButton = 3,
  6518. NSWindowDocumentIconButton = 4,
  6519. NSWindowDocumentVersionsButton = 6,
  6520. NSWindowFullScreenButton = 7,
  6521. };
  6522. void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param);
  6523. void NSOpenGLContext_setValues(id context, const int* vals, NSOpenGLContextParameter param) {
  6524. ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend)
  6525. (context, sel_registerName("setValues:forParameter:"), vals, param);
  6526. }
  6527. void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs);
  6528. void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) {
  6529. return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend)
  6530. (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), sel_registerName("initWithAttributes:"), attribs);
  6531. }
  6532. id NSPasteboard_generalPasteboard(void);
  6533. id NSPasteboard_generalPasteboard(void) {
  6534. return (id) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard"));
  6535. }
  6536. id* cstrToNSStringArray(char** strs, size_t len);
  6537. id* cstrToNSStringArray(char** strs, size_t len) {
  6538. static id nstrs[6];
  6539. size_t i;
  6540. for (i = 0; i < len; i++)
  6541. nstrs[i] = NSString_stringWithUTF8String(strs[i]);
  6542. return nstrs;
  6543. }
  6544. const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len);
  6545. const char* NSPasteboard_stringForType(id pasteboard, NSPasteboardType dataType, size_t* len) {
  6546. SEL func = sel_registerName("stringForType:");
  6547. id nsstr = NSString_stringWithUTF8String(dataType);
  6548. id nsString = ((id(*)(id, SEL, id))objc_msgSend)(pasteboard, func, nsstr);
  6549. const char* str = NSString_to_char(nsString);
  6550. if (len != NULL)
  6551. *len = (size_t)((NSUInteger(*)(id, SEL, int))objc_msgSend)(nsString, sel_registerName("maximumLengthOfBytesUsingEncoding:"), 4);
  6552. return str;
  6553. }
  6554. id c_array_to_NSArray(void* array, size_t len);
  6555. id c_array_to_NSArray(void* array, size_t len) {
  6556. SEL func = sel_registerName("initWithObjects:count:");
  6557. void* nsclass = objc_getClass("NSArray");
  6558. return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend)
  6559. (NSAlloc(nsclass), func, array, len);
  6560. }
  6561. void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len);
  6562. void NSregisterForDraggedTypes(id view, NSPasteboardType* newTypes, size_t len) {
  6563. id* ntypes = cstrToNSStringArray((char**)newTypes, len);
  6564. id array = c_array_to_NSArray(ntypes, len);
  6565. objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array);
  6566. NSRelease(array);
  6567. }
  6568. NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner);
  6569. NSInteger NSPasteBoard_declareTypes(id pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) {
  6570. id* ntypes = cstrToNSStringArray((char**)newTypes, len);
  6571. SEL func = sel_registerName("declareTypes:owner:");
  6572. id array = c_array_to_NSArray(ntypes, len);
  6573. NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend)
  6574. (pasteboard, func, array, owner);
  6575. NSRelease(array);
  6576. return output;
  6577. }
  6578. #define NSRetain(obj) objc_msgSend_void((id)obj, sel_registerName("retain"))
  6579. typedef enum NSApplicationActivationPolicy {
  6580. NSApplicationActivationPolicyRegular,
  6581. NSApplicationActivationPolicyAccessory,
  6582. NSApplicationActivationPolicyProhibited
  6583. } NSApplicationActivationPolicy;
  6584. typedef RGFW_ENUM(u32, NSBackingStoreType) {
  6585. NSBackingStoreRetained = 0,
  6586. NSBackingStoreNonretained = 1,
  6587. NSBackingStoreBuffered = 2
  6588. };
  6589. typedef RGFW_ENUM(u32, NSWindowStyleMask) {
  6590. NSWindowStyleMaskBorderless = 0,
  6591. NSWindowStyleMaskTitled = 1 << 0,
  6592. NSWindowStyleMaskClosable = 1 << 1,
  6593. NSWindowStyleMaskMiniaturizable = 1 << 2,
  6594. NSWindowStyleMaskResizable = 1 << 3,
  6595. NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */
  6596. NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12,
  6597. NSWindowStyleMaskFullScreen = 1 << 14,
  6598. NSWindowStyleMaskFullSizeContentView = 1 << 15,
  6599. NSWindowStyleMaskUtilityWindow = 1 << 4,
  6600. NSWindowStyleMaskDocModalWindow = 1 << 6,
  6601. NSWindowStyleMaskNonactivatingpanel = 1 << 7,
  6602. NSWindowStyleMaskHUDWindow = 1 << 13
  6603. };
  6604. NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; /* Replaces NSStringPasteboardType */
  6605. typedef RGFW_ENUM(i32, NSDragOperation) {
  6606. NSDragOperationNone = 0,
  6607. NSDragOperationCopy = 1,
  6608. NSDragOperationLink = 2,
  6609. NSDragOperationGeneric = 4,
  6610. NSDragOperationPrivate = 8,
  6611. NSDragOperationMove = 16,
  6612. NSDragOperationDelete = 32,
  6613. NSDragOperationEvery = (int)ULONG_MAX
  6614. };
  6615. void* NSArray_objectAtIndex(id array, NSUInteger index) {
  6616. SEL func = sel_registerName("objectAtIndex:");
  6617. return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index);
  6618. }
  6619. id NSWindow_contentView(id window) {
  6620. SEL func = sel_registerName("contentView");
  6621. return objc_msgSend_id(window, func);
  6622. }
  6623. /*
  6624. End of cocoa wrapper
  6625. */
  6626. #ifdef RGFW_OPENGL
  6627. CFBundleRef RGFWnsglFramework = NULL;
  6628. RGFW_proc RGFW_getProcAddress(const char* procname) {
  6629. if (RGFWnsglFramework == NULL)
  6630. RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
  6631. CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);
  6632. RGFW_proc symbol = (RGFW_proc)CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);
  6633. CFRelease(symbolName);
  6634. return symbol;
  6635. }
  6636. #endif
  6637. id NSWindow_delegate(RGFW_window* win) {
  6638. return (id) objc_msgSend_id((id)win->src.window, sel_registerName("delegate"));
  6639. }
  6640. u32 RGFW_OnClose(id self) {
  6641. RGFW_window* win = NULL;
  6642. object_getInstanceVariable(self, (const char*)"RGFW_window", (void**)&win);
  6643. if (win == NULL)
  6644. return true;
  6645. RGFW_eventQueuePush((RGFW_event){.type = RGFW_quit, ._win = win});
  6646. RGFW_windowQuitCallback(win);
  6647. return false;
  6648. }
  6649. /* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */
  6650. bool acceptsFirstResponder(void) { return true; }
  6651. bool performKeyEquivalent(id event) { RGFW_UNUSED(event); return true; }
  6652. NSDragOperation draggingEntered(id self, SEL sel, id sender) {
  6653. RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
  6654. return NSDragOperationCopy;
  6655. }
  6656. NSDragOperation draggingUpdated(id self, SEL sel, id sender) {
  6657. RGFW_UNUSED(sel);
  6658. RGFW_window* win = NULL;
  6659. object_getInstanceVariable(self, "RGFW_window", (void**)&win);
  6660. if (win == NULL || (!(win->_flags & RGFW_windowAllowDND)))
  6661. return 0;
  6662. NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
  6663. RGFW_eventQueuePush((RGFW_event){.type = RGFW_DNDInit,
  6664. .point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)),
  6665. ._win = win});
  6666. RGFW_dndInitCallback(win, win->event.point);
  6667. return NSDragOperationCopy;
  6668. }
  6669. bool prepareForDragOperation(id self) {
  6670. RGFW_window* win = NULL;
  6671. object_getInstanceVariable(self, "RGFW_window", (void**)&win);
  6672. if (win == NULL)
  6673. return true;
  6674. if (!(win->_flags & RGFW_windowAllowDND)) {
  6675. return false;
  6676. }
  6677. return true;
  6678. }
  6679. void RGFW__osxDraggingEnded(id self, SEL sel, id sender);
  6680. void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; }
  6681. /* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */
  6682. bool performDragOperation(id self, SEL sel, id sender) {
  6683. RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
  6684. RGFW_window* win = NULL;
  6685. object_getInstanceVariable(self, "RGFW_window", (void**)&win);
  6686. if (win == NULL)
  6687. return false;
  6688. /* id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); */
  6689. id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
  6690. /* Get the types of data available on the pasteboard */
  6691. id types = objc_msgSend_id(pasteBoard, sel_registerName("types"));
  6692. /* Get the string type for file URLs */
  6693. id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType");
  6694. /* Check if the pasteboard contains file URLs */
  6695. if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) {
  6696. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errClipboard, RGFW_DEBUG_CTX(win, 0), "No files found on the pasteboard.");
  6697. return 0;
  6698. }
  6699. id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType);
  6700. int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count"));
  6701. if (count == 0)
  6702. return 0;
  6703. int i;
  6704. for (i = 0; i < count; i++) {
  6705. id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i);
  6706. const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String"));
  6707. RGFW_MEMCPY(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH);
  6708. win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
  6709. }
  6710. NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
  6711. RGFW_eventQueuePush((RGFW_event){.type = RGFW_DND,
  6712. .point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)),
  6713. .droppedFilesCount = (size_t)count,
  6714. ._win = win});
  6715. RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
  6716. return false;
  6717. }
  6718. #ifndef RGFW_NO_IOKIT
  6719. #include <IOKit/IOKitLib.h>
  6720. #include <IOKit/hid/IOHIDManager.h>
  6721. IOHIDDeviceRef RGFW_osxControllers[4] = {NULL};
  6722. size_t findControllerIndex(IOHIDDeviceRef device) {
  6723. size_t i;
  6724. for (i = 0; i < 4; i++)
  6725. if (RGFW_osxControllers[i] == device)
  6726. return i;
  6727. return (size_t)-1;
  6728. }
  6729. void RGFW__osxInputValueChangedCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) {
  6730. RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender);
  6731. IOHIDElementRef element = IOHIDValueGetElement(value);
  6732. IOHIDDeviceRef device = IOHIDElementGetDevice(element);
  6733. size_t index = findControllerIndex(device);
  6734. if (index == (size_t)-1) return;
  6735. uint32_t usagePage = IOHIDElementGetUsagePage(element);
  6736. uint32_t usage = IOHIDElementGetUsage(element);
  6737. CFIndex intValue = IOHIDValueGetIntegerValue(value);
  6738. u8 RGFW_osx2RGFWSrc[2][RGFW_gamepadFinal] = {{
  6739. 0, RGFW_gamepadSelect, RGFW_gamepadL3, RGFW_gamepadR3, RGFW_gamepadStart,
  6740. RGFW_gamepadUp, RGFW_gamepadRight, RGFW_gamepadDown, RGFW_gamepadLeft,
  6741. RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadL1, RGFW_gamepadR1,
  6742. RGFW_gamepadY, RGFW_gamepadB, RGFW_gamepadA, RGFW_gamepadX, RGFW_gamepadHome},
  6743. {0, RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadR3, RGFW_gamepadX,
  6744. RGFW_gamepadY, RGFW_gamepadRight, RGFW_gamepadL1, RGFW_gamepadR1,
  6745. RGFW_gamepadL2, RGFW_gamepadR2, RGFW_gamepadDown, RGFW_gamepadStart,
  6746. RGFW_gamepadUp, RGFW_gamepadL3, RGFW_gamepadSelect, RGFW_gamepadStart, RGFW_gamepadHome}
  6747. };
  6748. u8* RGFW_osx2RGFW = RGFW_osx2RGFWSrc[0];
  6749. if (RGFW_gamepads_type[index] == RGFW_gamepadMicrosoft)
  6750. RGFW_osx2RGFW = RGFW_osx2RGFWSrc[1];
  6751. switch (usagePage) {
  6752. case kHIDPage_Button: {
  6753. u8 button = 0;
  6754. if (usage < sizeof(RGFW_osx2RGFW))
  6755. button = RGFW_osx2RGFW[usage];
  6756. RGFW_gamepadButtonCallback(_RGFW.root, (u16)index, button, (u8)intValue);
  6757. RGFW_gamepadPressed[index][button].prev = RGFW_gamepadPressed[index][button].current;
  6758. RGFW_gamepadPressed[index][button].current = RGFW_BOOL(intValue);
  6759. RGFW_eventQueuePush((RGFW_event){.type = intValue ? RGFW_gamepadButtonPressed: RGFW_gamepadButtonReleased,
  6760. .button = button,
  6761. .gamepad = (u16)index,
  6762. ._win = _RGFW.root});
  6763. break;
  6764. }
  6765. case kHIDPage_GenericDesktop: {
  6766. CFIndex logicalMin = IOHIDElementGetLogicalMin(element);
  6767. CFIndex logicalMax = IOHIDElementGetLogicalMax(element);
  6768. if (logicalMax <= logicalMin) return;
  6769. if (intValue < logicalMin) intValue = logicalMin;
  6770. if (intValue > logicalMax) intValue = logicalMax;
  6771. i8 axisValue = (i8)(-100.0 + ((intValue - logicalMin) * 200.0) / (logicalMax - logicalMin));
  6772. u8 whichAxis = 0;
  6773. switch (usage) {
  6774. case kHIDUsage_GD_X: RGFW_gamepadAxes[index][0].x = axisValue; whichAxis = 0; break;
  6775. case kHIDUsage_GD_Y: RGFW_gamepadAxes[index][0].y = axisValue; whichAxis = 0; break;
  6776. case kHIDUsage_GD_Z: RGFW_gamepadAxes[index][1].x = axisValue; whichAxis = 1; break;
  6777. case kHIDUsage_GD_Rz: RGFW_gamepadAxes[index][1].y = axisValue; whichAxis = 1; break;
  6778. default: return;
  6779. }
  6780. RGFW_eventQueuePush((RGFW_event){.type = RGFW_gamepadAxisMove,
  6781. .gamepad = (u16)index,
  6782. .axis = {RGFW_gamepadAxes[index][0], RGFW_gamepadAxes[index][1],
  6783. RGFW_gamepadAxes[index][2], RGFW_gamepadAxes[index][3]},
  6784. .whichAxis = whichAxis,
  6785. ._win = _RGFW.root});
  6786. RGFW_gamepadAxisCallback(_RGFW.root, (u16)index, RGFW_gamepadAxes[index], 2, whichAxis);
  6787. }
  6788. }
  6789. }
  6790. void RGFW__osxDeviceAddedCallback(void* context, IOReturn result, void *sender, IOHIDDeviceRef device) {
  6791. RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender);
  6792. CFTypeRef usageRef = (CFTypeRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
  6793. int usage = 0;
  6794. if (usageRef)
  6795. CFNumberGetValue((CFNumberRef)usageRef, kCFNumberIntType, (void*)&usage);
  6796. if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) {
  6797. return;
  6798. }
  6799. size_t i;
  6800. for (i = 0; i < 4; i++) {
  6801. if (RGFW_osxControllers[i] != NULL)
  6802. continue;
  6803. RGFW_osxControllers[i] = device;
  6804. IOHIDDeviceRegisterInputValueCallback(device, RGFW__osxInputValueChangedCallback, NULL);
  6805. CFStringRef deviceName = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
  6806. if (deviceName)
  6807. CFStringGetCString(deviceName, RGFW_gamepads_name[i], sizeof(RGFW_gamepads_name[i]), kCFStringEncodingUTF8);
  6808. RGFW_gamepads_type[i] = RGFW_gamepadUnknown;
  6809. if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box") || RGFW_STRSTR(RGFW_gamepads_name[i], "Xbox"))
  6810. RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
  6811. else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5"))
  6812. RGFW_gamepads_type[i] = RGFW_gamepadSony;
  6813. else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo"))
  6814. RGFW_gamepads_type[i] = RGFW_gamepadNintendo;
  6815. else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech"))
  6816. RGFW_gamepads_type[i] = RGFW_gamepadLogitech;
  6817. RGFW_gamepads[i] = (u16)i;
  6818. RGFW_gamepadCount++;
  6819. RGFW_eventQueuePush((RGFW_event){.type = RGFW_gamepadConnected,
  6820. .gamepad = (u16)i,
  6821. ._win = _RGFW.root});
  6822. RGFW_gamepadCallback(_RGFW.root, (u16)i, 1);
  6823. break;
  6824. }
  6825. }
  6826. void RGFW__osxDeviceRemovedCallback(void *context, IOReturn result, void *sender, IOHIDDeviceRef device) {
  6827. RGFW_UNUSED(context); RGFW_UNUSED(result); RGFW_UNUSED(sender); RGFW_UNUSED(device);
  6828. CFNumberRef usageRef = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
  6829. int usage = 0;
  6830. if (usageRef)
  6831. CFNumberGetValue(usageRef, kCFNumberIntType, &usage);
  6832. if (usage != kHIDUsage_GD_Joystick && usage != kHIDUsage_GD_GamePad && usage != kHIDUsage_GD_MultiAxisController) {
  6833. return;
  6834. }
  6835. size_t index = findControllerIndex(device);
  6836. if (index != (size_t)-1)
  6837. RGFW_osxControllers[index] = NULL;
  6838. RGFW_eventQueuePush((RGFW_event){.type = RGFW_gamepadDisconnected,
  6839. .gamepad = (u16)index,
  6840. ._win = _RGFW.root});
  6841. RGFW_gamepadCallback(_RGFW.root, (u16)index, 0);
  6842. RGFW_gamepadCount--;
  6843. }
  6844. RGFWDEF void RGFW_osxInitIOKit(void);
  6845. void RGFW_osxInitIOKit(void) {
  6846. IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
  6847. if (!hidManager) {
  6848. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create IOHIDManager.");
  6849. return;
  6850. }
  6851. CFMutableDictionaryRef matchingDictionary = CFDictionaryCreateMutable(
  6852. kCFAllocatorDefault,
  6853. 0,
  6854. &kCFTypeDictionaryKeyCallBacks,
  6855. &kCFTypeDictionaryValueCallBacks
  6856. );
  6857. if (!matchingDictionary) {
  6858. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errIOKit, RGFW_DEBUG_CTX(_RGFW.root, 0), "Failed to create matching dictionary for IOKit.");
  6859. CFRelease(hidManager);
  6860. return;
  6861. }
  6862. CFDictionarySetValue(
  6863. matchingDictionary,
  6864. CFSTR(kIOHIDDeviceUsagePageKey),
  6865. CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, (int[]){kHIDPage_GenericDesktop})
  6866. );
  6867. IOHIDManagerSetDeviceMatching(hidManager, matchingDictionary);
  6868. IOHIDManagerRegisterDeviceMatchingCallback(hidManager, RGFW__osxDeviceAddedCallback, NULL);
  6869. IOHIDManagerRegisterDeviceRemovalCallback(hidManager, RGFW__osxDeviceRemovedCallback, NULL);
  6870. IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  6871. IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);
  6872. /* Execute the run loop once in order to register any initially-attached joysticks */
  6873. CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
  6874. }
  6875. #endif
  6876. void RGFW_moveToMacOSResourceDir(void) {
  6877. char resourcesPath[256];
  6878. CFBundleRef bundle = CFBundleGetMainBundle();
  6879. if (!bundle)
  6880. return;
  6881. CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
  6882. CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
  6883. if (
  6884. CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo ||
  6885. CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0
  6886. ) {
  6887. CFRelease(last);
  6888. CFRelease(resourcesURL);
  6889. return;
  6890. }
  6891. CFRelease(last);
  6892. CFRelease(resourcesURL);
  6893. chdir(resourcesPath);
  6894. }
  6895. void RGFW__osxWindowDeminiaturize(id self, SEL sel) {
  6896. RGFW_UNUSED(sel);
  6897. RGFW_window* win = NULL;
  6898. object_getInstanceVariable(self, "RGFW_window", (void**)&win);
  6899. if (win == NULL) return;
  6900. win->_flags |= RGFW_windowMinimize;
  6901. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowRestored, ._win = win});
  6902. RGFW_windowRestoredCallback(win, win->r);
  6903. }
  6904. void RGFW__osxWindowMiniaturize(id self, SEL sel) {
  6905. RGFW_UNUSED(sel);
  6906. RGFW_window* win = NULL;
  6907. object_getInstanceVariable(self, "RGFW_window", (void**)&win);
  6908. if (win == NULL) return;
  6909. win->_flags &= ~(u32)RGFW_windowMinimize;
  6910. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowMinimized, ._win = win});
  6911. RGFW_windowMinimizedCallback(win, win->r);
  6912. }
  6913. void RGFW__osxWindowBecameKey(id self, SEL sel) {
  6914. RGFW_UNUSED(sel);
  6915. RGFW_window* win = NULL;
  6916. object_getInstanceVariable(self, "RGFW_window", (void**)&win);
  6917. if (win == NULL) return;
  6918. win->_flags |= RGFW_windowFocus;
  6919. RGFW_eventQueuePush((RGFW_event){.type = RGFW_focusIn, ._win = win});
  6920. RGFW_focusCallback(win, RGFW_TRUE);
  6921. }
  6922. void RGFW__osxWindowResignKey(id self, SEL sel) {
  6923. RGFW_UNUSED(sel);
  6924. RGFW_window* win = NULL;
  6925. object_getInstanceVariable(self, "RGFW_window", (void**)&win);
  6926. if (win == NULL) return;
  6927. win->_flags &= ~(u32)RGFW_windowFocus;
  6928. RGFW_eventQueuePush((RGFW_event){.type = RGFW_focusOut, ._win = win});
  6929. RGFW_focusCallback(win, RGFW_FALSE);
  6930. }
  6931. NSSize RGFW__osxWindowResize(id self, SEL sel, NSSize frameSize) {
  6932. RGFW_UNUSED(sel);
  6933. RGFW_window* win = NULL;
  6934. object_getInstanceVariable(self, "RGFW_window", (void**)&win);
  6935. if (win == NULL) return frameSize;
  6936. win->r.w = (i32)frameSize.width;
  6937. win->r.h = (i32)frameSize.height;
  6938. RGFW_monitor mon = RGFW_window_getMonitor(win);
  6939. if ((i32)mon.mode.area.w == win->r.w && (i32)mon.mode.area.h - 102 <= win->r.h) {
  6940. win->_flags |= RGFW_windowMaximize;
  6941. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowMaximized, ._win = win});
  6942. RGFW_windowMaximizedCallback(win, win->r);
  6943. } else if (win->_flags & RGFW_windowMaximize) {
  6944. win->_flags &= ~(u32)RGFW_windowMaximize;
  6945. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowRestored, ._win = win});
  6946. RGFW_windowRestoredCallback(win, win->r);
  6947. }
  6948. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowResized, ._win = win});
  6949. RGFW_windowResizedCallback(win, win->r);
  6950. return frameSize;
  6951. }
  6952. void RGFW__osxWindowMove(id self, SEL sel) {
  6953. RGFW_UNUSED(sel);
  6954. RGFW_window* win = NULL;
  6955. object_getInstanceVariable(self, "RGFW_window", (void**)&win);
  6956. if (win == NULL) return;
  6957. NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
  6958. win->r.x = (i32) frame.origin.x;
  6959. win->r.y = (i32) frame.origin.y;
  6960. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowMoved, ._win = win});
  6961. RGFW_windowMovedCallback(win, win->r);
  6962. }
  6963. void RGFW__osxViewDidChangeBackingProperties(id self, SEL _cmd) {
  6964. RGFW_UNUSED(_cmd);
  6965. RGFW_window* win = NULL;
  6966. object_getInstanceVariable(self, "RGFW_window", (void**)&win);
  6967. if (win == NULL) return;
  6968. RGFW_monitor mon = RGFW_window_getMonitor(win);
  6969. RGFW_scaleUpdatedCallback(win, mon.scaleX, mon.scaleY);
  6970. RGFW_eventQueuePush((RGFW_event){.type = RGFW_scaleUpdated, .scaleX = mon.scaleX, .scaleY = mon.scaleY , ._win = win});
  6971. }
  6972. void RGFW__osxDrawRect(id self, SEL _cmd, CGRect rect) {
  6973. RGFW_UNUSED(rect); RGFW_UNUSED(_cmd);
  6974. RGFW_window* win = NULL;
  6975. object_getInstanceVariable(self, "RGFW_window", (void**)&win);
  6976. if (win == NULL) return;
  6977. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowRefresh, ._win = win});
  6978. RGFW_windowRefreshCallback(win);
  6979. }
  6980. void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area) {
  6981. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  6982. win->buffer = buffer;
  6983. win->bufferSize = area;
  6984. win->_flags |= RGFW_BUFFER_ALLOC;
  6985. #ifdef RGFW_OSMESA
  6986. win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
  6987. OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
  6988. OSMesaPixelStore(OSMESA_Y_UP, 0);
  6989. #endif
  6990. #else
  6991. RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
  6992. #endif
  6993. }
  6994. void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) {
  6995. objc_msgSend_void_id((id)win->src.view, sel_registerName("setLayer"), (id)layer);
  6996. }
  6997. void* RGFW_cocoaGetLayer(void) {
  6998. return objc_msgSend_class((id)objc_getClass("CAMetalLayer"), (SEL)sel_registerName("layer"));
  6999. }
  7000. NSPasteboardType const NSPasteboardTypeURL = "public.url";
  7001. NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url";
  7002. id RGFW__osx_generateViewClass(const char* subclass, RGFW_window* win) {
  7003. Class customViewClass;
  7004. customViewClass = objc_allocateClassPair(objc_getClass(subclass), "RGFWCustomView", 0);
  7005. class_addIvar( customViewClass, "RGFW_window", sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))), "L");
  7006. class_addMethod(customViewClass, sel_registerName("drawRect:"), (IMP)RGFW__osxDrawRect, "v@:{CGRect=ffff}");
  7007. class_addMethod(customViewClass, sel_registerName("viewDidChangeBackingProperties"), (IMP)RGFW__osxViewDidChangeBackingProperties, "");
  7008. id customView = objc_msgSend_id(NSAlloc(customViewClass), sel_registerName("init"));
  7009. object_setInstanceVariable(customView, "RGFW_window", win);
  7010. return customView;
  7011. }
  7012. #ifndef RGFW_EGL
  7013. void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software) {
  7014. #ifdef RGFW_OPENGL
  7015. void* attrs = RGFW_initFormatAttribs(software);
  7016. void* format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)attrs);
  7017. if (format == NULL) {
  7018. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "Failed to load pixel format for OpenGL");
  7019. void* subAttrs = RGFW_initFormatAttribs(1);
  7020. format = NSOpenGLPixelFormat_initWithAttributes((uint32_t*)subAttrs);
  7021. if (format == NULL)
  7022. RGFW_sendDebugInfo(RGFW_typeError, RGFW_errOpenglContext, RGFW_DEBUG_CTX(win, 0), "and loading software rendering OpenGL failed");
  7023. else
  7024. RGFW_sendDebugInfo(RGFW_typeWarning, RGFW_warningOpenGL, RGFW_DEBUG_CTX(win, 0), "Switching to software rendering");
  7025. }
  7026. /* the pixel format can be passed directly to opengl context creation to create a context
  7027. this is because the format also includes information about the opengl version (which may be a bad thing) */
  7028. win->src.view = (id) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend) (RGFW__osx_generateViewClass("NSOpenGLView", win),
  7029. sel_registerName("initWithFrame:pixelFormat:"), (NSRect){{0, 0}, {win->r.w, win->r.h}}, (uint32_t*)format);
  7030. objc_msgSend_void(win->src.view, sel_registerName("prepareOpenGL"));
  7031. win->src.ctx = objc_msgSend_id(win->src.view, sel_registerName("openGLContext"));
  7032. if (win->_flags & RGFW_windowTransparent) {
  7033. i32 opacity = 0;
  7034. #define NSOpenGLCPSurfaceOpacity 236
  7035. NSOpenGLContext_setValues((id)win->src.ctx, &opacity, NSOpenGLCPSurfaceOpacity);
  7036. }
  7037. objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
  7038. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
  7039. #else
  7040. RGFW_UNUSED(win); RGFW_UNUSED(software);
  7041. #endif
  7042. }
  7043. void RGFW_window_freeOpenGL(RGFW_window* win) {
  7044. #ifdef RGFW_OPENGL
  7045. if (win->src.ctx == NULL) return;
  7046. objc_msgSend_void(win->src.ctx, sel_registerName("release"));
  7047. win->src.ctx = NULL;
  7048. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
  7049. #else
  7050. RGFW_UNUSED(win);
  7051. #endif
  7052. }
  7053. #endif
  7054. i32 RGFW_init(void) {
  7055. /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea???
  7056. Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance).
  7057. */
  7058. si_func_to_SEL_with_name("NSObject", "windowShouldClose", (void*)RGFW_OnClose);
  7059. /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */
  7060. si_func_to_SEL("NSWindow", acceptsFirstResponder);
  7061. si_func_to_SEL("NSWindow", performKeyEquivalent);
  7062. if (NSApp == NULL) {
  7063. NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
  7064. ((void (*)(id, SEL, NSUInteger))objc_msgSend)
  7065. (NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
  7066. #ifndef RGFW_NO_IOKIT
  7067. RGFW_osxInitIOKit();
  7068. #endif
  7069. }
  7070. _RGFW.windowCount = 0;
  7071. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, (RGFW_debugContext){0}, "global context initialized");
  7072. return 0;
  7073. }
  7074. RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
  7075. static u8 RGFW_loaded = 0;
  7076. RGFW_window_basic_init(win, rect, flags);
  7077. /* RR Create an autorelease pool */
  7078. id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
  7079. pool = objc_msgSend_id(pool, sel_registerName("init"));
  7080. RGFW_window_setMouseDefault(win);
  7081. NSRect windowRect;
  7082. windowRect.origin.x = win->r.x;
  7083. windowRect.origin.y = win->r.y;
  7084. windowRect.size.width = win->r.w;
  7085. windowRect.size.height = win->r.h;
  7086. NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled;
  7087. if (!(flags & RGFW_windowNoResize))
  7088. macArgs |= NSWindowStyleMaskResizable;
  7089. if (!(flags & RGFW_windowNoBorder))
  7090. macArgs |= NSWindowStyleMaskTitled;
  7091. {
  7092. void* nsclass = objc_getClass("NSWindow");
  7093. SEL func = sel_registerName("initWithContentRect:styleMask:backing:defer:");
  7094. win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)
  7095. (NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false);
  7096. }
  7097. id str = NSString_stringWithUTF8String(name);
  7098. objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
  7099. if ((flags & RGFW_windowNoInitAPI) == 0) {
  7100. RGFW_window_initOpenGL(win, RGFW_BOOL(flags & RGFW_windowOpenglSoftware));
  7101. RGFW_window_initBuffer(win);
  7102. }
  7103. #ifdef RGFW_OPENGL
  7104. else
  7105. #endif
  7106. {
  7107. NSRect contentRect = (NSRect){{0, 0}, {win->r.w, win->r.h}};
  7108. win->src.view = ((id(*)(id, SEL, NSRect))objc_msgSend) (NSAlloc(objc_getClass("NSView")), sel_registerName("initWithFrame:"), contentRect);
  7109. }
  7110. void* contentView = NSWindow_contentView((id)win->src.window);
  7111. objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true);
  7112. objc_msgSend_int((id)win->src.view, sel_registerName("setLayerContentsPlacement:"), 4);
  7113. objc_msgSend_void_id((id)win->src.window, sel_registerName("setContentView:"), win->src.view);
  7114. if (flags & RGFW_windowTransparent) {
  7115. objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false);
  7116. objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"),
  7117. NSColor_colorWithSRGB(0, 0, 0, 0));
  7118. }
  7119. Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
  7120. class_addIvar(
  7121. delegateClass, "RGFW_window",
  7122. sizeof(RGFW_window*), (u8)rint(log2(sizeof(RGFW_window*))),
  7123. "L"
  7124. );
  7125. class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) RGFW__osxWindowResize, "{NSSize=ff}@:{NSSize=ff}");
  7126. class_addMethod(delegateClass, sel_registerName("windowWillMove:"), (IMP) RGFW__osxWindowMove, "");
  7127. class_addMethod(delegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, "");
  7128. class_addMethod(delegateClass, sel_registerName("windowDidMiniaturize:"), (IMP) RGFW__osxWindowMiniaturize, "");
  7129. class_addMethod(delegateClass, sel_registerName("windowDidDeminiaturize:"), (IMP) RGFW__osxWindowDeminiaturize, "");
  7130. class_addMethod(delegateClass, sel_registerName("windowDidBecomeKey:"), (IMP) RGFW__osxWindowBecameKey, "");
  7131. class_addMethod(delegateClass, sel_registerName("windowDidResignKey:"), (IMP) RGFW__osxWindowResignKey, "");
  7132. class_addMethod(delegateClass, sel_registerName("draggingEntered:"), (IMP)draggingEntered, "l@:@");
  7133. class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@");
  7134. class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
  7135. class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
  7136. class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@");
  7137. class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@");
  7138. id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init"));
  7139. if (RGFW_COCOA_FRAME_NAME)
  7140. objc_msgSend_ptr(win->src.view, sel_registerName("setFrameAutosaveName:"), RGFW_COCOA_FRAME_NAME);
  7141. object_setInstanceVariable(delegate, "RGFW_window", win);
  7142. objc_msgSend_void_id((id)win->src.window, sel_registerName("setDelegate:"), delegate);
  7143. if (flags & RGFW_windowAllowDND) {
  7144. win->_flags |= RGFW_windowAllowDND;
  7145. NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString};
  7146. NSregisterForDraggedTypes((id)win->src.window, types, 3);
  7147. }
  7148. RGFW_window_setFlags(win, flags);
  7149. /* Show the window */
  7150. objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
  7151. ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
  7152. RGFW_window_show(win);
  7153. if (!RGFW_loaded) {
  7154. objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));
  7155. RGFW_loaded = 1;
  7156. }
  7157. objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));
  7158. objc_msgSend_void(NSApp, sel_registerName("finishLaunching"));
  7159. NSRetain(win->src.window);
  7160. NSRetain(NSApp);
  7161. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
  7162. return win;
  7163. }
  7164. void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) {
  7165. NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
  7166. NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
  7167. float offset = 0;
  7168. RGFW_setBit(&win->_flags, RGFW_windowNoBorder, !border);
  7169. NSBackingStoreType storeType = NSWindowStyleMaskBorderless | NSWindowStyleMaskFullSizeContentView;
  7170. if (border)
  7171. storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
  7172. if (!(win->_flags & RGFW_windowNoResize)) {
  7173. storeType |= NSWindowStyleMaskResizable;
  7174. }
  7175. ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)((id)win->src.window, sel_registerName("setStyleMask:"), storeType);
  7176. if (!border) {
  7177. id miniaturizeButton = objc_msgSend_int((id)win->src.window, sel_registerName("standardWindowButton:"), NSWindowMiniaturizeButton);
  7178. id titleBarView = objc_msgSend_id(miniaturizeButton, sel_registerName("superview"));
  7179. objc_msgSend_void_bool(titleBarView, sel_registerName("setHidden:"), true);
  7180. offset = (float)(frame.size.height - content.size.height);
  7181. }
  7182. RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h + offset));
  7183. win->r.h -= (i32)offset;
  7184. }
  7185. RGFW_area RGFW_getScreenSize(void) {
  7186. static CGDirectDisplayID display = 0;
  7187. if (display == 0)
  7188. display = CGMainDisplayID();
  7189. return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display));
  7190. }
  7191. RGFW_point RGFW_getGlobalMousePoint(void) {
  7192. RGFW_ASSERT(_RGFW.root != NULL);
  7193. CGEventRef e = CGEventCreate(NULL);
  7194. CGPoint point = CGEventGetLocation(e);
  7195. CFRelease(e);
  7196. return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */
  7197. }
  7198. typedef RGFW_ENUM(u32, NSEventType) { /* various types of events */
  7199. NSEventTypeLeftMouseDown = 1,
  7200. NSEventTypeLeftMouseUp = 2,
  7201. NSEventTypeRightMouseDown = 3,
  7202. NSEventTypeRightMouseUp = 4,
  7203. NSEventTypeMouseMoved = 5,
  7204. NSEventTypeLeftMouseDragged = 6,
  7205. NSEventTypeRightMouseDragged = 7,
  7206. NSEventTypeMouseEntered = 8,
  7207. NSEventTypeMouseExited = 9,
  7208. NSEventTypeKeyDown = 10,
  7209. NSEventTypeKeyUp = 11,
  7210. NSEventTypeFlagsChanged = 12,
  7211. NSEventTypeAppKitDefined = 13,
  7212. NSEventTypeSystemDefined = 14,
  7213. NSEventTypeApplicationDefined = 15,
  7214. NSEventTypePeriodic = 16,
  7215. NSEventTypeCursorUpdate = 17,
  7216. NSEventTypeScrollWheel = 22,
  7217. NSEventTypeTabletPoint = 23,
  7218. NSEventTypeTabletProximity = 24,
  7219. NSEventTypeOtherMouseDown = 25,
  7220. NSEventTypeOtherMouseUp = 26,
  7221. NSEventTypeOtherMouseDragged = 27,
  7222. /* The following event types are available on some hardware on 10.5.2 and later */
  7223. NSEventTypeGesture API_AVAILABLE(macos(10.5)) = 29,
  7224. NSEventTypeMagnify API_AVAILABLE(macos(10.5)) = 30,
  7225. NSEventTypeSwipe API_AVAILABLE(macos(10.5)) = 31,
  7226. NSEventTypeRotate API_AVAILABLE(macos(10.5)) = 18,
  7227. NSEventTypeBeginGesture API_AVAILABLE(macos(10.5)) = 19,
  7228. NSEventTypeEndGesture API_AVAILABLE(macos(10.5)) = 20,
  7229. NSEventTypeSmartMagnify API_AVAILABLE(macos(10.8)) = 32,
  7230. NSEventTypeQuickLook API_AVAILABLE(macos(10.8)) = 33,
  7231. NSEventTypePressure API_AVAILABLE(macos(10.10.3)) = 34,
  7232. NSEventTypeDirectTouch API_AVAILABLE(macos(10.10)) = 37,
  7233. NSEventTypeChangeMode API_AVAILABLE(macos(10.15)) = 38,
  7234. };
  7235. typedef unsigned long long NSEventMask;
  7236. typedef enum NSEventModifierFlags {
  7237. NSEventModifierFlagCapsLock = 1 << 16,
  7238. NSEventModifierFlagShift = 1 << 17,
  7239. NSEventModifierFlagControl = 1 << 18,
  7240. NSEventModifierFlagOption = 1 << 19,
  7241. NSEventModifierFlagCommand = 1 << 20,
  7242. NSEventModifierFlagNumericPad = 1 << 21
  7243. } NSEventModifierFlags;
  7244. void RGFW_stopCheckEvents(void) {
  7245. id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
  7246. eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
  7247. id e = (id) ((id(*)(Class, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend)
  7248. (objc_getClass("NSEvent"), sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
  7249. NSEventTypeApplicationDefined, (NSPoint){0, 0}, (NSEventModifierFlags)0, NULL, (NSInteger)0, NULL, 0, 0, 0);
  7250. ((void (*)(id, SEL, id, bool))objc_msgSend)
  7251. (NSApp, sel_registerName("postEvent:atStart:"), e, 1);
  7252. objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
  7253. }
  7254. void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
  7255. RGFW_UNUSED(win);
  7256. id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
  7257. eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
  7258. void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend)
  7259. (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS);
  7260. SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
  7261. id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
  7262. (NSApp, eventFunc,
  7263. ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
  7264. if (e) {
  7265. ((void (*)(id, SEL, id, bool))objc_msgSend)
  7266. (NSApp, sel_registerName("postEvent:atStart:"), e, 1);
  7267. }
  7268. objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
  7269. }
  7270. RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
  7271. if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
  7272. objc_msgSend_void((id)win->src.mouse, sel_registerName("set"));
  7273. RGFW_event* ev = RGFW_window_checkEventCore(win);
  7274. if (ev) {
  7275. ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
  7276. return ev;
  7277. }
  7278. id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
  7279. eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
  7280. SEL eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
  7281. void* date = NULL;
  7282. id e = (id) ((id(*)(id, SEL, NSEventMask, void*, id, bool))objc_msgSend)
  7283. (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
  7284. if (e == NULL) {
  7285. objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
  7286. objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
  7287. ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
  7288. return NULL;
  7289. }
  7290. if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) {
  7291. ((void (*)(id, SEL, id, bool))objc_msgSend)
  7292. (NSApp, sel_registerName("postEvent:atStart:"), e, 0);
  7293. objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
  7294. objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
  7295. ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
  7296. return NULL;
  7297. }
  7298. if (win->event.droppedFilesCount) {
  7299. u32 i;
  7300. for (i = 0; i < win->event.droppedFilesCount; i++)
  7301. win->event.droppedFiles[i][0] = '\0';
  7302. }
  7303. win->event.droppedFilesCount = 0;
  7304. win->event.type = 0;
  7305. u32 type = (u32)objc_msgSend_uint(e, sel_registerName("type"));
  7306. switch (type) {
  7307. case NSEventTypeMouseEntered: {
  7308. win->event.type = RGFW_mouseEnter;
  7309. NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
  7310. win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y));
  7311. RGFW_mouseNotifyCallback(win, win->event.point, 1);
  7312. break;
  7313. }
  7314. case NSEventTypeMouseExited:
  7315. win->event.type = RGFW_mouseLeave;
  7316. RGFW_mouseNotifyCallback(win, win->event.point, 0);
  7317. break;
  7318. case NSEventTypeKeyDown: {
  7319. u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
  7320. u32 mappedKey = (u32)*(((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers")))));
  7321. if (((u8)mappedKey) == 239)
  7322. mappedKey = 0;
  7323. win->event.keyChar = (u8)mappedKey;
  7324. win->event.key = (u8)RGFW_apiKeyToRGFW(key);
  7325. RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
  7326. win->event.type = RGFW_keyPressed;
  7327. win->event.repeat = RGFW_isPressed(win, win->event.key);
  7328. RGFW_keyboard[win->event.key].current = 1;
  7329. RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 1);
  7330. break;
  7331. }
  7332. case NSEventTypeKeyUp: {
  7333. u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
  7334. u32 mappedKey = (u32)*(((char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("charactersIgnoringModifiers")))));
  7335. if (((u8)mappedKey) == 239)
  7336. mappedKey = 0;
  7337. win->event.keyChar = (u8)mappedKey;
  7338. win->event.key = (u8)RGFW_apiKeyToRGFW(key);
  7339. RGFW_keyboard[win->event.key].prev = RGFW_keyboard[win->event.key].current;
  7340. win->event.type = RGFW_keyReleased;
  7341. RGFW_keyboard[win->event.key].current = 0;
  7342. RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, 0);
  7343. break;
  7344. }
  7345. case NSEventTypeFlagsChanged: {
  7346. u32 flags = (u32)objc_msgSend_uint(e, sel_registerName("modifierFlags"));
  7347. RGFW_updateKeyModsPro(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255),
  7348. ((flags & NSEventModifierFlagControl) % 255), ((flags & NSEventModifierFlagOption) % 255),
  7349. ((flags & NSEventModifierFlagShift) % 255), ((flags & NSEventModifierFlagCommand) % 255), 0);
  7350. u8 i;
  7351. for (i = 0; i < 9; i++)
  7352. RGFW_keyboard[i + RGFW_capsLock].prev = 0;
  7353. for (i = 0; i < 5; i++) {
  7354. u32 shift = (1 << (i + 16));
  7355. u32 key = i + RGFW_capsLock;
  7356. if ((flags & shift) && !RGFW_wasPressed(win, (u8)key)) {
  7357. RGFW_keyboard[key].current = 1;
  7358. if (key != RGFW_capsLock)
  7359. RGFW_keyboard[key+ 4].current = 1;
  7360. win->event.type = RGFW_keyPressed;
  7361. win->event.key = (u8)key;
  7362. break;
  7363. }
  7364. if (!(flags & shift) && RGFW_wasPressed(win, (u8)key)) {
  7365. RGFW_keyboard[key].current = 0;
  7366. if (key != RGFW_capsLock)
  7367. RGFW_keyboard[key + 4].current = 0;
  7368. win->event.type = RGFW_keyReleased;
  7369. win->event.key = (u8)key;
  7370. break;
  7371. }
  7372. }
  7373. RGFW_keyCallback(win, win->event.key, win->event.keyChar, win->event.keyMod, win->event.type == RGFW_keyPressed);
  7374. break;
  7375. }
  7376. case NSEventTypeLeftMouseDragged:
  7377. case NSEventTypeOtherMouseDragged:
  7378. case NSEventTypeRightMouseDragged:
  7379. case NSEventTypeMouseMoved: {
  7380. win->event.type = RGFW_mousePosChanged;
  7381. NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
  7382. win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
  7383. p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX"));
  7384. p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
  7385. win->event.vector = RGFW_POINT((i32)p.x, (i32)p.y);
  7386. win->_lastMousePoint = win->event.point;
  7387. RGFW_mousePosCallback(win, win->event.point, win->event.vector);
  7388. break;
  7389. }
  7390. case NSEventTypeLeftMouseDown: case NSEventTypeRightMouseDown: case NSEventTypeOtherMouseDown: {
  7391. u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber"));
  7392. switch (buttonNumber) {
  7393. case 0: win->event.button = RGFW_mouseLeft; break;
  7394. case 1: win->event.button = RGFW_mouseRight; break;
  7395. case 2: win->event.button = RGFW_mouseMiddle; break;
  7396. default: win->event.button = (u8)buttonNumber;
  7397. }
  7398. win->event.type = RGFW_mouseButtonPressed;
  7399. RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
  7400. RGFW_mouseButtons[win->event.button].current = 1;
  7401. RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
  7402. break;
  7403. }
  7404. case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp: {
  7405. u32 buttonNumber = (u32)objc_msgSend_uint(e, sel_registerName("buttonNumber"));
  7406. switch (buttonNumber) {
  7407. case 0: win->event.button = RGFW_mouseLeft; break;
  7408. case 1: win->event.button = RGFW_mouseRight; break;
  7409. case 2: win->event.button = RGFW_mouseMiddle; break;
  7410. default: win->event.button = (u8)buttonNumber;
  7411. }
  7412. RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
  7413. RGFW_mouseButtons[win->event.button].current = 0;
  7414. win->event.type = RGFW_mouseButtonReleased;
  7415. RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
  7416. break;
  7417. }
  7418. case NSEventTypeScrollWheel: {
  7419. double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
  7420. if (deltaY > 0) {
  7421. win->event.button = RGFW_mouseScrollUp;
  7422. }
  7423. else if (deltaY < 0) {
  7424. win->event.button = RGFW_mouseScrollDown;
  7425. }
  7426. RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
  7427. RGFW_mouseButtons[win->event.button].current = 1;
  7428. win->event.scroll = deltaY;
  7429. win->event.type = RGFW_mouseButtonPressed;
  7430. RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
  7431. break;
  7432. }
  7433. default:
  7434. objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
  7435. ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
  7436. return RGFW_window_checkEvent(win);
  7437. }
  7438. objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
  7439. ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
  7440. objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
  7441. return &win->event;
  7442. }
  7443. void RGFW_window_move(RGFW_window* win, RGFW_point v) {
  7444. RGFW_ASSERT(win != NULL);
  7445. win->r.x = v.x;
  7446. win->r.y = v.y;
  7447. ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
  7448. ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true);
  7449. }
  7450. void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
  7451. RGFW_ASSERT(win != NULL);
  7452. NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.window, sel_registerName("frame"));
  7453. NSRect content = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)((id)win->src.view, sel_registerName("frame"));
  7454. float offset = (float)(frame.size.height - content.size.height);
  7455. win->r.w = (i32)a.w;
  7456. win->r.h = (i32)a.h;
  7457. ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
  7458. ((id)win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h + offset}}, true, true);
  7459. }
  7460. void RGFW_window_focus(RGFW_window* win) {
  7461. RGFW_ASSERT(win);
  7462. objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
  7463. ((void (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyWindow"));
  7464. }
  7465. void RGFW_window_raise(RGFW_window* win) {
  7466. RGFW_ASSERT(win != NULL);
  7467. ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), (SEL)NULL);
  7468. objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
  7469. }
  7470. void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
  7471. RGFW_ASSERT(win != NULL);
  7472. if (fullscreen && (win->_flags & RGFW_windowFullscreen)) return;
  7473. if (!fullscreen && !(win->_flags & RGFW_windowFullscreen)) return;
  7474. if (fullscreen) {
  7475. win->_oldRect = win->r;
  7476. RGFW_monitor mon = RGFW_window_getMonitor(win);
  7477. win->r = RGFW_RECT(0, 0, mon.x, mon.y);
  7478. win->_flags |= RGFW_windowFullscreen;
  7479. RGFW_window_resize(win, RGFW_AREA(mon.mode.area.w, mon.mode.area.h));
  7480. RGFW_window_move(win, RGFW_POINT(0, 0));
  7481. }
  7482. objc_msgSend_void_SEL(win->src.window, sel_registerName("toggleFullScreen:"), NULL);
  7483. if (!fullscreen) {
  7484. win->r = win->_oldRect;
  7485. win->_flags &= ~(u32)RGFW_windowFullscreen;
  7486. RGFW_window_resize(win, RGFW_AREA(win->r.w, win->r.h));
  7487. RGFW_window_move(win, RGFW_POINT(win->r.x, win->r.y));
  7488. }
  7489. }
  7490. void RGFW_window_maximize(RGFW_window* win) {
  7491. RGFW_ASSERT(win != NULL);
  7492. if (RGFW_window_isMaximized(win)) return;
  7493. win->_flags |= RGFW_windowMaximize;
  7494. objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
  7495. }
  7496. void RGFW_window_minimize(RGFW_window* win) {
  7497. RGFW_ASSERT(win != NULL);
  7498. objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);
  7499. }
  7500. void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) {
  7501. RGFW_ASSERT(win != NULL);
  7502. if (floating) objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGFloatingWindowLevelKey);
  7503. else objc_msgSend_void_id(win->src.window, sel_registerName("setLevel:"), kCGNormalWindowLevelKey);
  7504. }
  7505. void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
  7506. objc_msgSend_int(win->src.window, sel_registerName("setAlphaValue:"), opacity);
  7507. objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), (opacity < (u8)255));
  7508. if (opacity)
  7509. objc_msgSend_void_id((id)win->src.window, sel_registerName("setBackgroundColor:"), NSColor_colorWithSRGB(0, 0, 0, opacity));
  7510. }
  7511. void RGFW_window_restore(RGFW_window* win) {
  7512. RGFW_ASSERT(win != NULL);
  7513. if (RGFW_window_isMaximized(win))
  7514. objc_msgSend_void_SEL(win->src.window, sel_registerName("zoom:"), NULL);
  7515. objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);
  7516. RGFW_window_show(win);
  7517. }
  7518. RGFW_bool RGFW_window_isFloating(RGFW_window* win) {
  7519. RGFW_ASSERT(win != NULL);
  7520. int level = ((int (*)(id, SEL))objc_msgSend) ((id)(win->src.window), (SEL)sel_registerName("level"));
  7521. return level > kCGNormalWindowLevelKey;
  7522. }
  7523. void RGFW_window_setName(RGFW_window* win, const char* name) {
  7524. RGFW_ASSERT(win != NULL);
  7525. id str = NSString_stringWithUTF8String(name);
  7526. objc_msgSend_void_id((id)win->src.window, sel_registerName("setTitle:"), str);
  7527. }
  7528. #ifndef RGFW_NO_PASSTHROUGH
  7529. void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
  7530. objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough);
  7531. }
  7532. #endif
  7533. void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) {
  7534. if (a.w == 0 && a.h == 0) a = RGFW_AREA(1, 1);
  7535. ((void (*)(id, SEL, NSSize))objc_msgSend)
  7536. ((id)win->src.window, sel_registerName("setContentAspectRatio:"), (NSSize){a.w, a.h});
  7537. }
  7538. void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
  7539. ((void (*)(id, SEL, NSSize))objc_msgSend)
  7540. ((id)win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h});
  7541. }
  7542. void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
  7543. if (a.w == 0 && a.h == 0) {
  7544. a = RGFW_getScreenSize();
  7545. }
  7546. ((void (*)(id, SEL, NSSize))objc_msgSend)
  7547. ((id)win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h});
  7548. }
  7549. RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* data, RGFW_area area, i32 channels, u8 type) {
  7550. RGFW_ASSERT(win != NULL);
  7551. RGFW_UNUSED(type);
  7552. if (data == NULL) {
  7553. objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), NULL);
  7554. return RGFW_TRUE;
  7555. }
  7556. /* code by EimaMei: Make a bitmap representation, then copy the loaded image into it. */
  7557. id representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * (u32)channels, 8 * (u32)channels);
  7558. RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * (u32)channels);
  7559. /* Add ze representation. */
  7560. id dock_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){area.w, area.h}));
  7561. objc_msgSend_void_id(dock_image, sel_registerName("addRepresentation:"), representation);
  7562. /* Finally, set the dock image to it. */
  7563. objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image);
  7564. /* Free the garbage. */
  7565. NSRelease(dock_image);
  7566. NSRelease(representation);
  7567. return RGFW_TRUE;
  7568. }
  7569. id NSCursor_arrowStr(const char* str) {
  7570. void* nclass = objc_getClass("NSCursor");
  7571. SEL func = sel_registerName(str);
  7572. return (id) objc_msgSend_id(nclass, func);
  7573. }
  7574. RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) {
  7575. if (icon == NULL) {
  7576. objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));
  7577. return NULL;
  7578. }
  7579. /* NOTE(EimaMei): Code by yours truly. */
  7580. /* Make a bitmap representation, then copy the loaded image into it. */
  7581. id representation = (id)NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * (u32)channels, 8 * (u32)channels);
  7582. RGFW_MEMCPY(NSBitmapImageRep_bitmapData(representation), icon, a.w * a.h * (u32)channels);
  7583. /* Add ze representation. */
  7584. id cursor_image = ((id(*)(id, SEL, NSSize))objc_msgSend) (NSAlloc((id)objc_getClass("NSImage")), sel_registerName("initWithSize:"), ((NSSize){a.w, a.h}));
  7585. objc_msgSend_void_id(cursor_image, sel_registerName("addRepresentation:"), representation);
  7586. /* Finally, set the cursor image. */
  7587. id cursor = (id) ((id(*)(id, SEL, id, NSPoint))objc_msgSend)
  7588. (NSAlloc(objc_getClass("NSCursor")), sel_registerName("initWithImage:hotSpot:"), cursor_image, (NSPoint){0.0, 0.0});
  7589. /* Free the garbage. */
  7590. NSRelease(cursor_image);
  7591. NSRelease(representation);
  7592. return (void*)cursor;
  7593. }
  7594. void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) {
  7595. RGFW_ASSERT(win != NULL); RGFW_ASSERT(mouse);
  7596. CGDisplayShowCursor(kCGDirectMainDisplay);
  7597. objc_msgSend_void((id)mouse, sel_registerName("set"));
  7598. win->src.mouse = mouse;
  7599. }
  7600. void RGFW_freeMouse(RGFW_mouse* mouse) {
  7601. RGFW_ASSERT(mouse);
  7602. NSRelease((id)mouse);
  7603. }
  7604. RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
  7605. return RGFW_window_setMouseStandard(win, RGFW_mouseArrow);
  7606. }
  7607. void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
  7608. RGFW_window_showMouseFlags(win, show);
  7609. if (show) CGDisplayShowCursor(kCGDirectMainDisplay);
  7610. else CGDisplayHideCursor(kCGDirectMainDisplay);
  7611. }
  7612. RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouses) {
  7613. static const char* mouseIconSrc[16] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"};
  7614. if (stdMouses > ((sizeof(mouseIconSrc)) / (sizeof(char*))))
  7615. return RGFW_FALSE;
  7616. const char* mouseStr = mouseIconSrc[stdMouses];
  7617. id mouse = NSCursor_arrowStr(mouseStr);
  7618. if (mouse == NULL)
  7619. return RGFW_FALSE;
  7620. RGFW_UNUSED(win);
  7621. CGDisplayShowCursor(kCGDirectMainDisplay);
  7622. objc_msgSend_void(mouse, sel_registerName("set"));
  7623. win->src.mouse = mouse;
  7624. return RGFW_TRUE;
  7625. }
  7626. void RGFW_releaseCursor(RGFW_window* win) {
  7627. RGFW_UNUSED(win);
  7628. CGAssociateMouseAndMouseCursorPosition(1);
  7629. }
  7630. void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
  7631. RGFW_UNUSED(win);
  7632. CGWarpMouseCursorPosition((CGPoint){r.x + (r.w / 2), r.y + (r.h / 2)});
  7633. CGAssociateMouseAndMouseCursorPosition(0);
  7634. }
  7635. void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) {
  7636. RGFW_UNUSED(win);
  7637. win->_lastMousePoint = RGFW_POINT(v.x - win->r.x, v.y - win->r.y);
  7638. CGWarpMouseCursorPosition((CGPoint){v.x, v.y});
  7639. }
  7640. void RGFW_window_hide(RGFW_window* win) {
  7641. objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);
  7642. }
  7643. void RGFW_window_show(RGFW_window* win) {
  7644. if (win->_flags & RGFW_windowFocusOnShow)
  7645. ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
  7646. ((id(*)(id, SEL, SEL))objc_msgSend)((id)win->src.window, sel_registerName("orderFront:"), NULL);
  7647. objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);
  7648. }
  7649. RGFW_bool RGFW_window_isHidden(RGFW_window* win) {
  7650. RGFW_ASSERT(win != NULL);
  7651. bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));
  7652. return visible == NO && !RGFW_window_isMinimized(win);
  7653. }
  7654. RGFW_bool RGFW_window_isMinimized(RGFW_window* win) {
  7655. RGFW_ASSERT(win != NULL);
  7656. return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;
  7657. }
  7658. RGFW_bool RGFW_window_isMaximized(RGFW_window* win) {
  7659. RGFW_ASSERT(win != NULL);
  7660. RGFW_bool b = (RGFW_bool)objc_msgSend_bool(win->src.window, sel_registerName("isZoomed"));
  7661. return b;
  7662. }
  7663. id RGFW_getNSScreenForDisplayID(CGDirectDisplayID display) {
  7664. Class NSScreenClass = objc_getClass("NSScreen");
  7665. id screens = objc_msgSend_id(NSScreenClass, sel_registerName("screens"));
  7666. NSUInteger count = (NSUInteger)objc_msgSend_uint(screens, sel_registerName("count"));
  7667. NSUInteger i;
  7668. for (i = 0; i < count; i++) {
  7669. id screen = ((id (*)(id, SEL, int))objc_msgSend) (screens, sel_registerName("objectAtIndex:"), (int)i);
  7670. id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
  7671. id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
  7672. id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
  7673. if ((CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue")) == display) {
  7674. return screen;
  7675. }
  7676. }
  7677. return NULL;
  7678. }
  7679. u32 RGFW_osx_getRefreshRate(CGDirectDisplayID display, CGDisplayModeRef mode) {
  7680. if (mode) {
  7681. u32 refreshRate = (u32)CGDisplayModeGetRefreshRate(mode);
  7682. if (refreshRate != 0) return refreshRate;
  7683. }
  7684. CVDisplayLinkRef link;
  7685. CVDisplayLinkCreateWithCGDisplay(display, &link);
  7686. const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
  7687. if (!(time.flags & kCVTimeIsIndefinite))
  7688. return (u32) (time.timeScale / (double) time.timeValue);
  7689. return 0;
  7690. }
  7691. RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display, id screen) {
  7692. RGFW_monitor monitor;
  7693. const char name[] = "MacOS\0";
  7694. RGFW_MEMCPY(monitor.name, name, 6);
  7695. CGRect bounds = CGDisplayBounds(display);
  7696. monitor.x = (i32)bounds.origin.x;
  7697. monitor.y = (i32)bounds.origin.y;
  7698. monitor.mode.area = RGFW_AREA((int) bounds.size.width, (int) bounds.size.height);
  7699. monitor.mode.red = 8; monitor.mode.green = 8; monitor.mode.blue = 8;
  7700. CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display);
  7701. monitor.mode.refreshRate = RGFW_osx_getRefreshRate(display, mode);
  7702. CFRelease(mode);
  7703. CGSize screenSizeMM = CGDisplayScreenSize(display);
  7704. monitor.physW = (float)screenSizeMM.width / 25.4f;
  7705. monitor.physH = (float)screenSizeMM.height / 25.4f;
  7706. float ppi_width = (monitor.mode.area.w/monitor.physW);
  7707. float ppi_height = (monitor.mode.area.h/monitor.physH);
  7708. monitor.pixelRatio = (float)((CGFloat (*)(id, SEL))abi_objc_msgSend_fpret) (screen, sel_registerName("backingScaleFactor"));
  7709. float dpi = 96.0f * monitor.pixelRatio;
  7710. monitor.scaleX = ((i32)(((float) (ppi_width) / dpi) * 10.0f)) / 10.0f;
  7711. monitor.scaleY = ((i32)(((float) (ppi_height) / dpi) * 10.0f)) / 10.0f;
  7712. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoMonitor, RGFW_DEBUG_CTX_MON(monitor), "monitor found");
  7713. return monitor;
  7714. }
  7715. RGFW_monitor* RGFW_getMonitors(size_t* len) {
  7716. static CGDirectDisplayID displays[7];
  7717. u32 count;
  7718. if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess)
  7719. return NULL;
  7720. if (count > 6) count = 6;
  7721. static RGFW_monitor monitors[7];
  7722. u32 i;
  7723. for (i = 0; i < count; i++)
  7724. monitors[i] = RGFW_NSCreateMonitor(displays[i], RGFW_getNSScreenForDisplayID(displays[i]));
  7725. if (len != NULL) *len = count;
  7726. return monitors;
  7727. }
  7728. RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) {
  7729. CGPoint point = { mon.x, mon.y };
  7730. CGDirectDisplayID display;
  7731. uint32_t displayCount = 0;
  7732. CGError err = CGGetDisplaysWithPoint(point, 1, &display, &displayCount);
  7733. if (err != kCGErrorSuccess || displayCount != 1)
  7734. return RGFW_FALSE;
  7735. CFArrayRef allModes = CGDisplayCopyAllDisplayModes(display, NULL);
  7736. if (allModes == NULL)
  7737. return RGFW_FALSE;
  7738. CFIndex i;
  7739. for (i = 0; i < CFArrayGetCount(allModes); i++) {
  7740. CGDisplayModeRef cmode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
  7741. RGFW_monitorMode foundMode;
  7742. foundMode.area = RGFW_AREA(CGDisplayModeGetWidth(cmode), CGDisplayModeGetHeight(cmode));
  7743. foundMode.refreshRate = RGFW_osx_getRefreshRate(display, cmode);
  7744. foundMode.red = 8; foundMode.green = 8; foundMode.blue = 8;
  7745. if (RGFW_monitorModeCompare(mode, foundMode, request)) {
  7746. if (CGDisplaySetDisplayMode(display, cmode, NULL) == kCGErrorSuccess) {
  7747. CFRelease(allModes);
  7748. return RGFW_TRUE;
  7749. }
  7750. break;
  7751. }
  7752. }
  7753. CFRelease(allModes);
  7754. return RGFW_FALSE;
  7755. }
  7756. RGFW_monitor RGFW_getPrimaryMonitor(void) {
  7757. CGDirectDisplayID primary = CGMainDisplayID();
  7758. return RGFW_NSCreateMonitor(primary, RGFW_getNSScreenForDisplayID(primary));
  7759. }
  7760. RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
  7761. id screen = objc_msgSend_id(win->src.window, sel_registerName("screen"));
  7762. id description = objc_msgSend_id(screen, sel_registerName("deviceDescription"));
  7763. id screenNumberKey = NSString_stringWithUTF8String("NSScreenNumber");
  7764. id screenNumber = objc_msgSend_id_id(description, sel_registerName("objectForKey:"), screenNumberKey);
  7765. CGDirectDisplayID display = (CGDirectDisplayID)objc_msgSend_uint(screenNumber, sel_registerName("unsignedIntValue"));
  7766. return RGFW_NSCreateMonitor(display, screen);
  7767. }
  7768. RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
  7769. size_t clip_len;
  7770. char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString, &clip_len);
  7771. if (clip == NULL) return -1;
  7772. if (str != NULL) {
  7773. if (strCapacity < clip_len)
  7774. return 0;
  7775. RGFW_MEMCPY(str, clip, clip_len);
  7776. str[clip_len] = '\0';
  7777. }
  7778. return (RGFW_ssize_t)clip_len;
  7779. }
  7780. void RGFW_writeClipboard(const char* text, u32 textLen) {
  7781. RGFW_UNUSED(textLen);
  7782. NSPasteboardType array[] = { NSPasteboardTypeString, NULL };
  7783. NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);
  7784. SEL func = sel_registerName("setString:forType:");
  7785. ((bool (*)(id, SEL, id, id))objc_msgSend)
  7786. (NSPasteboard_generalPasteboard(), func, NSString_stringWithUTF8String(text), NSString_stringWithUTF8String(NSPasteboardTypeString));
  7787. }
  7788. #ifdef RGFW_OPENGL
  7789. void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
  7790. if (win != NULL)
  7791. objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
  7792. else
  7793. objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("clearCurrentContext"));
  7794. }
  7795. void* RGFW_getCurrent_OpenGL(void) {
  7796. return objc_msgSend_id(objc_getClass("NSOpenGLContext"), sel_registerName("currentContext"));
  7797. }
  7798. void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
  7799. objc_msgSend_void(win->src.ctx, sel_registerName("flushBuffer"));
  7800. }
  7801. #endif
  7802. #if !defined(RGFW_EGL)
  7803. void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
  7804. RGFW_ASSERT(win != NULL);
  7805. #if defined(RGFW_OPENGL)
  7806. NSOpenGLContext_setValues((id)win->src.ctx, &swapInterval, 222);
  7807. #else
  7808. RGFW_UNUSED(swapInterval);
  7809. #endif
  7810. }
  7811. #endif
  7812. void RGFW_window_swapBuffers_software(RGFW_window* win) {
  7813. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  7814. RGFW_RGB_to_BGR(win, win->buffer);
  7815. i32 channels = 4;
  7816. id image = ((id (*)(Class, SEL))objc_msgSend)(objc_getClass("NSImage"), sel_getUid("alloc"));
  7817. NSSize size = (NSSize){win->bufferSize.w, win->bufferSize.h};
  7818. image = ((id (*)(id, SEL, NSSize))objc_msgSend)((id)image, sel_getUid("initWithSize:"), size);
  7819. id rep = NSBitmapImageRep_initWithBitmapData(&win->buffer, win->r.w, win->r.h , 8, channels, (channels == 4), false,
  7820. "NSDeviceRGBColorSpace", 1 << 1, (u32)win->bufferSize.w * (u32)channels, 8 * (u32)channels);
  7821. ((void (*)(id, SEL, id))objc_msgSend)((id)image, sel_getUid("addRepresentation:"), rep);
  7822. id contentView = ((id (*)(id, SEL))objc_msgSend)((id)win->src.window, sel_getUid("contentView"));
  7823. ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setWantsLayer:"), YES);
  7824. id layer = ((id (*)(id, SEL))objc_msgSend)(contentView, sel_getUid("layer"));
  7825. ((void (*)(id, SEL, id))objc_msgSend)(layer, sel_getUid("setContents:"), (id)image);
  7826. ((void (*)(id, SEL, BOOL))objc_msgSend)(contentView, sel_getUid("setNeedsDisplay:"), YES);
  7827. NSRelease(rep);
  7828. NSRelease(image);
  7829. #else
  7830. RGFW_UNUSED(win);
  7831. #endif
  7832. }
  7833. void RGFW_deinit(void) {
  7834. _RGFW.windowCount = -1;
  7835. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, (RGFW_debugContext){0}, "global context deinitialized");
  7836. }
  7837. void RGFW_window_close(RGFW_window* win) {
  7838. RGFW_ASSERT(win != NULL);
  7839. NSRelease(win->src.view);
  7840. if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
  7841. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  7842. if ((win->_flags & RGFW_BUFFER_ALLOC))
  7843. RGFW_FREE(win->buffer);
  7844. #endif
  7845. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, (RGFW_debugContext){0}, "global context deinitialized");
  7846. _RGFW.windowCount--;
  7847. if (_RGFW.windowCount == 0) RGFW_deinit();
  7848. RGFW_clipboard_switch(NULL);
  7849. RGFW_FREE(win->event.droppedFiles);
  7850. if ((win->_flags & RGFW_WINDOW_ALLOC)) {
  7851. RGFW_FREE(win);
  7852. win = NULL;
  7853. }
  7854. }
  7855. u64 RGFW_getTimerFreq(void) {
  7856. static u64 freq = 0;
  7857. if (freq == 0) {
  7858. mach_timebase_info_data_t info;
  7859. mach_timebase_info(&info);
  7860. freq = (u64)((info.denom * 1e9) / info.numer);
  7861. }
  7862. return freq;
  7863. }
  7864. u64 RGFW_getTimerValue(void) { return (u64)mach_absolute_time(); }
  7865. #endif /* RGFW_MACOS */
  7866. /*
  7867. End of MaOS defines
  7868. */
  7869. /*
  7870. WASM defines
  7871. */
  7872. #ifdef RGFW_WASM
  7873. EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* e, void* userData) {
  7874. RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
  7875. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowResized, ._win = _RGFW.root});
  7876. RGFW_windowResizedCallback(_RGFW.root, RGFW_RECT(0, 0, e->windowInnerWidth, e->windowInnerHeight));
  7877. return EM_TRUE;
  7878. }
  7879. EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* e, void* userData) {
  7880. RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
  7881. static u8 fullscreen = RGFW_FALSE;
  7882. static RGFW_rect ogRect;
  7883. if (fullscreen == RGFW_FALSE) {
  7884. ogRect = _RGFW.root->r;
  7885. }
  7886. fullscreen = !fullscreen;
  7887. RGFW_eventQueuePush((RGFW_event){.type = RGFW_windowResized, ._win = _RGFW.root});
  7888. _RGFW.root->r = RGFW_RECT(0, 0, e->screenWidth, e->screenHeight);
  7889. EM_ASM("Module.canvas.focus();");
  7890. if (fullscreen == RGFW_FALSE) {
  7891. _RGFW.root->r = RGFW_RECT(0, 0, ogRect.w, ogRect.h);
  7892. /* emscripten_request_fullscreen("#canvas", 0); */
  7893. } else {
  7894. #if __EMSCRIPTEN_major__ >= 1 && __EMSCRIPTEN_minor__ >= 29 && __EMSCRIPTEN_tiny__ >= 0
  7895. EmscriptenFullscreenStrategy FSStrat = {0};
  7896. FSStrat.scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; /* EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT : EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH; */
  7897. FSStrat.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF;
  7898. FSStrat.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT;
  7899. emscripten_request_fullscreen_strategy("#canvas", 1, &FSStrat);
  7900. #else
  7901. emscripten_request_fullscreen("#canvas", 1);
  7902. #endif
  7903. }
  7904. emscripten_set_canvas_element_size("#canvas", _RGFW.root->r.w, _RGFW.root->r.h);
  7905. RGFW_windowResizedCallback(_RGFW.root, _RGFW.root->r);
  7906. return EM_TRUE;
  7907. }
  7908. EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* e, void* userData) {
  7909. RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e);
  7910. RGFW_eventQueuePush((RGFW_event){.type = RGFW_focusIn, ._win = _RGFW.root});
  7911. _RGFW.root->_flags |= RGFW_windowFocus;
  7912. RGFW_focusCallback(_RGFW.root, 1);
  7913. return EM_TRUE;
  7914. }
  7915. EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* e, void* userData) {
  7916. RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e);
  7917. RGFW_eventQueuePush((RGFW_event){.type = RGFW_focusOut, ._win = _RGFW.root});
  7918. _RGFW.root->_flags &= ~(u32)RGFW_windowFocus;
  7919. RGFW_focusCallback(_RGFW.root, 0);
  7920. return EM_TRUE;
  7921. }
  7922. EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* e, void* userData) {
  7923. RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
  7924. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mousePosChanged,
  7925. .point = RGFW_POINT(e->targetX, e->targetY),
  7926. .vector = RGFW_POINT(e->movementX, e->movementY),
  7927. ._win = _RGFW.root});
  7928. _RGFW.root->_lastMousePoint = RGFW_POINT(e->targetX, e->targetY);
  7929. RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(e->targetX, e->targetY), RGFW_POINT(e->movementX, e->movementY));
  7930. return EM_TRUE;
  7931. }
  7932. EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* e, void* userData) {
  7933. RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
  7934. int button = e->button;
  7935. if (button > 2)
  7936. button += 2;
  7937. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mouseButtonPressed,
  7938. .point = RGFW_POINT(e->targetX, e->targetY),
  7939. .vector = RGFW_POINT(e->movementX, e->movementY),
  7940. .button = (u8)button,
  7941. .scroll = 0,
  7942. ._win = _RGFW.root});
  7943. RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
  7944. RGFW_mouseButtons[button].current = 1;
  7945. RGFW_mouseButtonCallback(_RGFW.root, button, 0, 1);
  7946. return EM_TRUE;
  7947. }
  7948. EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* e, void* userData) {
  7949. RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
  7950. int button = e->button;
  7951. if (button > 2)
  7952. button += 2;
  7953. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mouseButtonReleased,
  7954. .point = RGFW_POINT(e->targetX, e->targetY),
  7955. .vector = RGFW_POINT(e->movementX, e->movementY),
  7956. .button = (u8)button,
  7957. .scroll = 0,
  7958. ._win = _RGFW.root});
  7959. RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
  7960. RGFW_mouseButtons[button].current = 0;
  7961. RGFW_mouseButtonCallback(_RGFW.root, button, 0, 0);
  7962. return EM_TRUE;
  7963. }
  7964. EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* e, void* userData) {
  7965. RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
  7966. int button = RGFW_mouseScrollUp + (e->deltaY < 0);
  7967. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mouseButtonPressed,
  7968. .button = (u8)button,
  7969. .scroll = (double)(e->deltaY < 0 ? 1 : -1),
  7970. ._win = _RGFW.root});
  7971. RGFW_mouseButtons[button].prev = RGFW_mouseButtons[button].current;
  7972. RGFW_mouseButtons[button].current = 1;
  7973. RGFW_mouseButtonCallback(_RGFW.root, button, e->deltaY < 0 ? 1 : -1, 1);
  7974. return EM_TRUE;
  7975. }
  7976. EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* e, void* userData) {
  7977. RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
  7978. size_t i;
  7979. for (i = 0; i < (size_t)e->numTouches; i++) {
  7980. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mouseButtonPressed,
  7981. .point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY),
  7982. .button = RGFW_mouseLeft,
  7983. ._win = _RGFW.root});
  7984. RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current;
  7985. RGFW_mouseButtons[RGFW_mouseLeft].current = 1;
  7986. _RGFW.root->_lastMousePoint = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY);
  7987. RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY), _RGFW.root->event.vector);
  7988. RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 1);
  7989. }
  7990. return EM_TRUE;
  7991. }
  7992. EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* e, void* userData) {
  7993. RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
  7994. size_t i;
  7995. for (i = 0; i < (size_t)e->numTouches; i++) {
  7996. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mousePosChanged,
  7997. .point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY),
  7998. .button = RGFW_mouseLeft,
  7999. ._win = _RGFW.root});
  8000. _RGFW.root->_lastMousePoint = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY);
  8001. RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY), _RGFW.root->event.vector);
  8002. }
  8003. return EM_TRUE;
  8004. }
  8005. EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* e, void* userData) {
  8006. RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
  8007. size_t i;
  8008. for (i = 0; i < (size_t)e->numTouches; i++) {
  8009. RGFW_eventQueuePush((RGFW_event){.type = RGFW_mouseButtonReleased,
  8010. .point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY),
  8011. .button = RGFW_mouseLeft,
  8012. ._win = _RGFW.root});
  8013. RGFW_mouseButtons[RGFW_mouseLeft].prev = RGFW_mouseButtons[RGFW_mouseLeft].current;
  8014. RGFW_mouseButtons[RGFW_mouseLeft].current = 0;
  8015. _RGFW.root->_lastMousePoint = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY);
  8016. RGFW_mousePosCallback(_RGFW.root, RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY), _RGFW.root->event.vector);
  8017. RGFW_mouseButtonCallback(_RGFW.root, RGFW_mouseLeft, 0, 0);
  8018. }
  8019. return EM_TRUE;
  8020. }
  8021. EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* e, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e); return EM_TRUE; }
  8022. EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) {
  8023. RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
  8024. if (gamepadEvent->index >= 4)
  8025. return 0;
  8026. size_t i = gamepadEvent->index;
  8027. if (gamepadEvent->connected) {
  8028. RGFW_MEMCPY(RGFW_gamepads_name[gamepadEvent->index], gamepadEvent->id, sizeof(RGFW_gamepads_name[gamepadEvent->index]));
  8029. RGFW_gamepads_type[i] = RGFW_gamepadUnknown;
  8030. if (RGFW_STRSTR(RGFW_gamepads_name[i], "Microsoft") || RGFW_STRSTR(RGFW_gamepads_name[i], "X-Box"))
  8031. RGFW_gamepads_type[i] = RGFW_gamepadMicrosoft;
  8032. else if (RGFW_STRSTR(RGFW_gamepads_name[i], "PlayStation") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS3") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS4") || RGFW_STRSTR(RGFW_gamepads_name[i], "PS5"))
  8033. RGFW_gamepads_type[i] = RGFW_gamepadSony;
  8034. else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Nintendo"))
  8035. RGFW_gamepads_type[i] = RGFW_gamepadNintendo;
  8036. else if (RGFW_STRSTR(RGFW_gamepads_name[i], "Logitech"))
  8037. RGFW_gamepads_type[i] = RGFW_gamepadLogitech;
  8038. RGFW_gamepadCount++;
  8039. } else {
  8040. RGFW_gamepadCount--;
  8041. }
  8042. RGFW_eventQueuePush((RGFW_event){.type = (RGFW_eventType)(gamepadEvent->connected ? RGFW_gamepadConnected : RGFW_gamepadConnected),
  8043. .gamepad = (u16)gamepadEvent->index,
  8044. ._win = _RGFW.root});
  8045. RGFW_gamepadCallback(_RGFW.root, gamepadEvent->index, gamepadEvent->connected);
  8046. RGFW_gamepads[gamepadEvent->index] = gamepadEvent->connected;
  8047. return 1; /* The event was consumed by the callback handler */
  8048. }
  8049. u32 RGFW_wASMPhysicalToRGFW(u32 hash) {
  8050. switch(hash) { /* 0x0000 */
  8051. case 0x67243A2DU /* Escape */: return RGFW_escape; /* 0x0001 */
  8052. case 0x67251058U /* Digit0 */: return RGFW_0; /* 0x0002 */
  8053. case 0x67251059U /* Digit1 */: return RGFW_1; /* 0x0003 */
  8054. case 0x6725105AU /* Digit2 */: return RGFW_2; /* 0x0004 */
  8055. case 0x6725105BU /* Digit3 */: return RGFW_3; /* 0x0005 */
  8056. case 0x6725105CU /* Digit4 */: return RGFW_4; /* 0x0006 */
  8057. case 0x6725105DU /* Digit5 */: return RGFW_5; /* 0x0007 */
  8058. case 0x6725105EU /* Digit6 */: return RGFW_6; /* 0x0008 */
  8059. case 0x6725105FU /* Digit7 */: return RGFW_7; /* 0x0009 */
  8060. case 0x67251050U /* Digit8 */: return RGFW_8; /* 0x000A */
  8061. case 0x67251051U /* Digit9 */: return RGFW_9; /* 0x000B */
  8062. case 0x92E14DD3U /* Minus */: return RGFW_minus; /* 0x000C */
  8063. case 0x92E1FBACU /* Equal */: return RGFW_equals; /* 0x000D */
  8064. case 0x36BF1CB5U /* Backspace */: return RGFW_backSpace; /* 0x000E */
  8065. case 0x7B8E51E2U /* Tab */: return RGFW_tab; /* 0x000F */
  8066. case 0x2C595B51U /* KeyQ */: return RGFW_q; /* 0x0010 */
  8067. case 0x2C595B57U /* KeyW */: return RGFW_w; /* 0x0011 */
  8068. case 0x2C595B45U /* KeyE */: return RGFW_e; /* 0x0012 */
  8069. case 0x2C595B52U /* KeyR */: return RGFW_r; /* 0x0013 */
  8070. case 0x2C595B54U /* KeyT */: return RGFW_t; /* 0x0014 */
  8071. case 0x2C595B59U /* KeyY */: return RGFW_y; /* 0x0015 */
  8072. case 0x2C595B55U /* KeyU */: return RGFW_u; /* 0x0016 */
  8073. case 0x2C595B4FU /* KeyO */: return RGFW_o; /* 0x0018 */
  8074. case 0x2C595B50U /* KeyP */: return RGFW_p; /* 0x0019 */
  8075. case 0x45D8158CU /* BracketLeft */: return RGFW_closeBracket; /* 0x001A */
  8076. case 0xDEEABF7CU /* BracketRight */: return RGFW_bracket; /* 0x001B */
  8077. case 0x92E1C5D2U /* Enter */: return RGFW_return; /* 0x001C */
  8078. case 0xE058958CU /* ControlLeft */: return RGFW_controlL; /* 0x001D */
  8079. case 0x2C595B41U /* KeyA */: return RGFW_a; /* 0x001E */
  8080. case 0x2C595B53U /* KeyS */: return RGFW_s; /* 0x001F */
  8081. case 0x2C595B44U /* KeyD */: return RGFW_d; /* 0x0020 */
  8082. case 0x2C595B46U /* KeyF */: return RGFW_f; /* 0x0021 */
  8083. case 0x2C595B47U /* KeyG */: return RGFW_g; /* 0x0022 */
  8084. case 0x2C595B48U /* KeyH */: return RGFW_h; /* 0x0023 */
  8085. case 0x2C595B4AU /* KeyJ */: return RGFW_j; /* 0x0024 */
  8086. case 0x2C595B4BU /* KeyK */: return RGFW_k; /* 0x0025 */
  8087. case 0x2C595B4CU /* KeyL */: return RGFW_l; /* 0x0026 */
  8088. case 0x2707219EU /* Semicolon */: return RGFW_semicolon; /* 0x0027 */
  8089. case 0x92E0B58DU /* Quote */: return RGFW_apostrophe; /* 0x0028 */
  8090. case 0x36BF358DU /* Backquote */: return RGFW_backtick; /* 0x0029 */
  8091. case 0x26B1958CU /* ShiftLeft */: return RGFW_shiftL; /* 0x002A */
  8092. case 0x36BF2438U /* Backslash */: return RGFW_backSlash; /* 0x002B */
  8093. case 0x2C595B5AU /* KeyZ */: return RGFW_z; /* 0x002C */
  8094. case 0x2C595B58U /* KeyX */: return RGFW_x; /* 0x002D */
  8095. case 0x2C595B43U /* KeyC */: return RGFW_c; /* 0x002E */
  8096. case 0x2C595B56U /* KeyV */: return RGFW_v; /* 0x002F */
  8097. case 0x2C595B42U /* KeyB */: return RGFW_b; /* 0x0030 */
  8098. case 0x2C595B4EU /* KeyN */: return RGFW_n; /* 0x0031 */
  8099. case 0x2C595B4DU /* KeyM */: return RGFW_m; /* 0x0032 */
  8100. case 0x92E1A1C1U /* Comma */: return RGFW_comma; /* 0x0033 */
  8101. case 0x672FFAD4U /* Period */: return RGFW_period; /* 0x0034 */
  8102. case 0x92E0A438U /* Slash */: return RGFW_slash; /* 0x0035 */
  8103. case 0xC5A6BF7CU /* ShiftRight */: return RGFW_shiftR;
  8104. case 0x5D64DA91U /* NumpadMultiply */: return RGFW_multiply;
  8105. case 0xC914958CU /* AltLeft */: return RGFW_altL; /* 0x0038 */
  8106. case 0x92E09CB5U /* Space */: return RGFW_space; /* 0x0039 */
  8107. case 0xB8FAE73BU /* CapsLock */: return RGFW_capsLock; /* 0x003A */
  8108. case 0x7174B789U /* F1 */: return RGFW_F1; /* 0x003B */
  8109. case 0x7174B78AU /* F2 */: return RGFW_F2; /* 0x003C */
  8110. case 0x7174B78BU /* F3 */: return RGFW_F3; /* 0x003D */
  8111. case 0x7174B78CU /* F4 */: return RGFW_F4; /* 0x003E */
  8112. case 0x7174B78DU /* F5 */: return RGFW_F5; /* 0x003F */
  8113. case 0x7174B78EU /* F6 */: return RGFW_F6; /* 0x0040 */
  8114. case 0x7174B78FU /* F7 */: return RGFW_F7; /* 0x0041 */
  8115. case 0x7174B780U /* F8 */: return RGFW_F8; /* 0x0042 */
  8116. case 0x7174B781U /* F9 */: return RGFW_F9; /* 0x0043 */
  8117. case 0x7B8E57B0U /* F10 */: return RGFW_F10; /* 0x0044 */
  8118. case 0xC925FCDFU /* Numpad7 */: return RGFW_multiply; /* 0x0047 */
  8119. case 0xC925FCD0U /* Numpad8 */: return RGFW_KP_8; /* 0x0048 */
  8120. case 0xC925FCD1U /* Numpad9 */: return RGFW_KP_9; /* 0x0049 */
  8121. case 0x5EA3E8A4U /* NumpadSubtract */: return RGFW_minus; /* 0x004A */
  8122. case 0xC925FCDCU /* Numpad4 */: return RGFW_KP_4; /* 0x004B */
  8123. case 0xC925FCDDU /* Numpad5 */: return RGFW_KP_5; /* 0x004C */
  8124. case 0xC925FCDEU /* Numpad6 */: return RGFW_KP_6; /* 0x004D */
  8125. case 0xC925FCD9U /* Numpad1 */: return RGFW_KP_1; /* 0x004F */
  8126. case 0xC925FCDAU /* Numpad2 */: return RGFW_KP_2; /* 0x0050 */
  8127. case 0xC925FCDBU /* Numpad3 */: return RGFW_KP_3; /* 0x0051 */
  8128. case 0xC925FCD8U /* Numpad0 */: return RGFW_KP_0; /* 0x0052 */
  8129. case 0x95852DACU /* NumpadDecimal */: return RGFW_period; /* 0x0053 */
  8130. case 0x7B8E57B1U /* F11 */: return RGFW_F11; /* 0x0057 */
  8131. case 0x7B8E57B2U /* F12 */: return RGFW_F12; /* 0x0058 */
  8132. case 0x7393FBACU /* NumpadEqual */: return RGFW_KP_Return;
  8133. case 0xB88EBF7CU /* AltRight */: return RGFW_altR; /* 0xE038 */
  8134. case 0xC925873BU /* NumLock */: return RGFW_numLock; /* 0xE045 */
  8135. case 0x2C595F45U /* Home */: return RGFW_home; /* 0xE047 */
  8136. case 0xC91BB690U /* ArrowUp */: return RGFW_up; /* 0xE048 */
  8137. case 0x672F9210U /* PageUp */: return RGFW_pageUp; /* 0xE049 */
  8138. case 0x3799258CU /* ArrowLeft */: return RGFW_left; /* 0xE04B */
  8139. case 0x4CE33F7CU /* ArrowRight */: return RGFW_right; /* 0xE04D */
  8140. case 0x7B8E55DCU /* End */: return RGFW_end; /* 0xE04F */
  8141. case 0x3799379EU /* ArrowDown */: return RGFW_down; /* 0xE050 */
  8142. case 0xBA90179EU /* PageDown */: return RGFW_pageDown; /* 0xE051 */
  8143. case 0x6723CB2CU /* Insert */: return RGFW_insert; /* 0xE052 */
  8144. case 0x6725C50DU /* Delete */: return RGFW_delete; /* 0xE053 */
  8145. case 0x6723658CU /* OSLeft */: return RGFW_superL; /* 0xE05B */
  8146. case 0x39643F7CU /* MetaRight */: return RGFW_superR; /* 0xE05C */
  8147. }
  8148. return 0;
  8149. }
  8150. void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyEvent(char* key, char* code, RGFW_bool press) {
  8151. const char* iCode = code;
  8152. u32 hash = 0;
  8153. while(*iCode) hash = ((hash ^ 0x7E057D79U) << 3) ^ (unsigned int)*iCode++;
  8154. u32 physicalKey = RGFW_wASMPhysicalToRGFW(hash);
  8155. u8 mappedKey = (u8)(*((u32*)key));
  8156. if (*((u16*)key) != mappedKey) {
  8157. mappedKey = 0;
  8158. if (*((u32*)key) == *((u32*)"Tab")) mappedKey = RGFW_tab;
  8159. }
  8160. RGFW_eventQueuePush((RGFW_event){.type = (RGFW_eventType)(press ? RGFW_keyPressed : RGFW_keyReleased),
  8161. .key = (u8)physicalKey,
  8162. .keyChar = (u8)mappedKey,
  8163. .keyMod = _RGFW.root->event.keyMod,
  8164. ._win = _RGFW.root});
  8165. RGFW_keyboard[physicalKey].prev = RGFW_keyboard[physicalKey].current;
  8166. RGFW_keyboard[physicalKey].current = press;
  8167. RGFW_keyCallback(_RGFW.root, physicalKey, mappedKey, _RGFW.root->event.keyMod, press);
  8168. }
  8169. void EMSCRIPTEN_KEEPALIVE RGFW_handleKeyMods(RGFW_bool capital, RGFW_bool numlock, RGFW_bool control, RGFW_bool alt, RGFW_bool shift, RGFW_bool super, RGFW_bool scroll) {
  8170. RGFW_updateKeyModsPro(_RGFW.root, capital, numlock, control, alt, shift, super, scroll);
  8171. }
  8172. void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) {
  8173. if (!(_RGFW.root->_flags & RGFW_windowAllowDND))
  8174. return;
  8175. RGFW_eventQueuePush((RGFW_event){.type = RGFW_DND,
  8176. .droppedFilesCount = count,
  8177. ._win = _RGFW.root});
  8178. RGFW_dndCallback(_RGFW.root, _RGFW.root->event.droppedFiles, count);
  8179. }
  8180. RGFW_bool RGFW_stopCheckEvents_bool = RGFW_FALSE;
  8181. void RGFW_stopCheckEvents(void) {
  8182. RGFW_stopCheckEvents_bool = RGFW_TRUE;
  8183. }
  8184. void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
  8185. RGFW_UNUSED(win);
  8186. if (waitMS == 0) return;
  8187. u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6);
  8188. while ((_RGFW.eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE && (RGFW_getTimeNS() / 1e+6) - start < waitMS)
  8189. emscripten_sleep(0);
  8190. RGFW_stopCheckEvents_bool = RGFW_FALSE;
  8191. }
  8192. void RGFW_window_initBufferPtr(RGFW_window* win, u8* buffer, RGFW_area area){
  8193. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  8194. win->buffer = buffer;
  8195. win->bufferSize = area;
  8196. #ifdef RGFW_OSMESA
  8197. win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
  8198. OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, area.w, area.h);
  8199. OSMesaPixelStore(OSMESA_Y_UP, 0);
  8200. #endif
  8201. #else
  8202. RGFW_UNUSED(win); RGFW_UNUSED(buffer); RGFW_UNUSED(area); /*!< if buffer rendering is not being used */
  8203. #endif
  8204. }
  8205. void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) {
  8206. /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */
  8207. /* TODO: find a better way to do this
  8208. */
  8209. RGFW_MEMCPY((char*)_RGFW.root->event.droppedFiles[index], file, RGFW_MAX_PATH);
  8210. }
  8211. #include <sys/stat.h>
  8212. #include <sys/types.h>
  8213. #include <errno.h>
  8214. #include <stdio.h>
  8215. void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); }
  8216. void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) {
  8217. FILE* file = fopen(path, "w+");
  8218. if (file == NULL)
  8219. return;
  8220. fwrite(data, sizeof(char), len, file);
  8221. fclose(file);
  8222. }
  8223. void RGFW_window_initOpenGL(RGFW_window* win, RGFW_bool software) {
  8224. #if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_BUFFER)
  8225. EmscriptenWebGLContextAttributes attrs;
  8226. attrs.alpha = RGFW_GL_HINTS[RGFW_glDepth];
  8227. attrs.depth = RGFW_GL_HINTS[RGFW_glAlpha];
  8228. attrs.stencil = RGFW_GL_HINTS[RGFW_glStencil];
  8229. attrs.antialias = RGFW_GL_HINTS[RGFW_glSamples];
  8230. attrs.premultipliedAlpha = EM_TRUE;
  8231. attrs.preserveDrawingBuffer = EM_FALSE;
  8232. if (RGFW_GL_HINTS[RGFW_glDoubleBuffer] == 0)
  8233. attrs.renderViaOffscreenBackBuffer = 0;
  8234. else
  8235. attrs.renderViaOffscreenBackBuffer = RGFW_GL_HINTS[RGFW_glAuxBuffers];
  8236. attrs.failIfMajorPerformanceCaveat = EM_FALSE;
  8237. attrs.majorVersion = (RGFW_GL_HINTS[RGFW_glMajor] == 0) ? 1 : RGFW_GL_HINTS[RGFW_glMajor];
  8238. attrs.minorVersion = RGFW_GL_HINTS[RGFW_glMinor];
  8239. attrs.enableExtensionsByDefault = EM_TRUE;
  8240. attrs.explicitSwapControl = EM_TRUE;
  8241. emscripten_webgl_init_context_attributes(&attrs);
  8242. win->src.ctx = emscripten_webgl_create_context("#canvas", &attrs);
  8243. emscripten_webgl_make_context_current(win->src.ctx);
  8244. #ifdef LEGACY_GL_EMULATION
  8245. EM_ASM("Module.useWebGL = true; GLImmediate.init();");
  8246. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context initalized");
  8247. #endif
  8248. glViewport(0, 0, win->r.w, win->r.h);
  8249. #endif
  8250. }
  8251. void RGFW_window_freeOpenGL(RGFW_window* win) {
  8252. #if defined(RGFW_OPENGL) && !defined(RGFW_WEBGPU) && !defined(RGFW_OSMESA) && !defined(RGFW_OSMESA)
  8253. if (win->src.ctx == 0) return;
  8254. emscripten_webgl_destroy_context(win->src.ctx);
  8255. win->src.ctx = 0;
  8256. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoOpenGL, RGFW_DEBUG_CTX(win, 0), "opengl context freed");
  8257. #elif defined(RGFW_OPENGL) && defined(RGFW_OSMESA)
  8258. if(win->src.ctx == 0) return;
  8259. OSMesaDestroyContext(win->src.ctx);
  8260. win->src.ctx = 0;
  8261. #else
  8262. RGFW_UNUSED(win);
  8263. #endif
  8264. }
  8265. i32 RGFW_init(void) { _RGFW.windowCount = 0; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, (RGFW_debugContext){0}, "global context initialized"); return 0; }
  8266. RGFW_window* RGFW_createWindowPtr(const char* name, RGFW_rect rect, RGFW_windowFlags flags, RGFW_window* win) {
  8267. RGFW_window_basic_init(win, rect, flags);
  8268. RGFW_window_initOpenGL(win, 0);
  8269. #if defined(RGFW_WEBGPU)
  8270. win->src.ctx = wgpuCreateInstance(NULL);
  8271. win->src.device = emscripten_webgpu_get_device();
  8272. win->src.queue = wgpuDeviceGetQueue(win->src.device);
  8273. #endif
  8274. emscripten_set_canvas_element_size("#canvas", rect.w, rect.h);
  8275. emscripten_set_window_title(name);
  8276. /* load callbacks */
  8277. emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize);
  8278. emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange);
  8279. emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove);
  8280. emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart);
  8281. emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend);
  8282. emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove);
  8283. emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel);
  8284. emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown);
  8285. emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup);
  8286. emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel);
  8287. emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin);
  8288. emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout);
  8289. emscripten_set_gamepadconnected_callback(NULL, 1, Emscripten_on_gamepad);
  8290. emscripten_set_gamepaddisconnected_callback(NULL, 1, Emscripten_on_gamepad);
  8291. if (flags & RGFW_windowAllowDND) {
  8292. win->_flags |= RGFW_windowAllowDND;
  8293. }
  8294. EM_ASM({
  8295. window.addEventListener("keydown",
  8296. (event) => {
  8297. var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code);
  8298. Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
  8299. Module._RGFW_handleKeyEvent(key, code, 1);
  8300. _free(key); _free(code);
  8301. },
  8302. true);
  8303. window.addEventListener("keyup",
  8304. (event) => {
  8305. var key = stringToNewUTF8(event.key); var code = stringToNewUTF8(event.code);
  8306. Module._RGFW_handleKeyMods(event.getModifierState("CapsLock"), event.getModifierState("NumLock"), event.getModifierState("Control"), event.getModifierState("Alt"), event.getModifierState("Shift"), event.getModifierState("Meta"), event.getModifierState("ScrollLock"));
  8307. Module._RGFW_handleKeyEvent(key, code, 0);
  8308. _free(key); _free(code);
  8309. },
  8310. true);
  8311. });
  8312. EM_ASM({
  8313. var canvas = document.getElementById('canvas');
  8314. canvas.addEventListener('drop', function(e) {
  8315. e.preventDefault();
  8316. if (e.dataTransfer.file < 0)
  8317. return;
  8318. var filenamesArray = [];
  8319. var count = e.dataTransfer.files.length;
  8320. /* Read and save the files to emscripten's files */
  8321. var drop_dir = '.rgfw_dropped_files';
  8322. Module._RGFW_mkdir(drop_dir);
  8323. for (var i = 0; i < count; i++) {
  8324. var file = e.dataTransfer.files[i];
  8325. var path = '/' + drop_dir + '/' + file.name.replace("//", '_');
  8326. var reader = new FileReader();
  8327. reader.onloadend = (e) => {
  8328. if (reader.readyState != 2) {
  8329. out('failed to read dropped file: '+file.name+': '+reader.error);
  8330. }
  8331. else {
  8332. var data = e.target.result;
  8333. _RGFW_writeFile(path, new Uint8Array(data), file.size);
  8334. }
  8335. };
  8336. reader.readAsArrayBuffer(file);
  8337. /* This works weird on modern opengl */
  8338. var filename = stringToNewUTF8(path);
  8339. filenamesArray.push(filename);
  8340. Module._RGFW_makeSetValue(i, filename);
  8341. }
  8342. Module._Emscripten_onDrop(count);
  8343. for (var i = 0; i < count; ++i) {
  8344. _free(filenamesArray[i]);
  8345. }
  8346. }, true);
  8347. canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true);
  8348. });
  8349. RGFW_window_setFlags(win, flags);
  8350. if ((flags & RGFW_windowNoInitAPI) == 0) {
  8351. RGFW_window_initBuffer(win);
  8352. }
  8353. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a new window was created");
  8354. return win;
  8355. }
  8356. RGFW_event* RGFW_window_checkEvent(RGFW_window* win) {
  8357. if (win == NULL || ((win->_flags & RGFW_windowFreeOnClose) && (win->_flags & RGFW_EVENT_QUIT))) return NULL;
  8358. RGFW_event* ev = RGFW_window_checkEventCore(win);
  8359. if (ev) return ev;
  8360. emscripten_sample_gamepad_data();
  8361. /* check gamepads */
  8362. int i;
  8363. for (i = 0; (i < emscripten_get_num_gamepads()) && (i < 4); i++) {
  8364. if (RGFW_gamepads[i] == 0)
  8365. continue;
  8366. EmscriptenGamepadEvent gamepadState;
  8367. if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS)
  8368. break;
  8369. /* Register buttons data for every connected gamepad */
  8370. int j;
  8371. for (j = 0; (j < gamepadState.numButtons) && (j < 16); j++) {
  8372. u32 map[] = {
  8373. RGFW_gamepadA, RGFW_gamepadB, RGFW_gamepadX, RGFW_gamepadY,
  8374. RGFW_gamepadL1, RGFW_gamepadR1, RGFW_gamepadL2, RGFW_gamepadR2,
  8375. RGFW_gamepadSelect, RGFW_gamepadStart,
  8376. RGFW_gamepadL3, RGFW_gamepadR3,
  8377. RGFW_gamepadUp, RGFW_gamepadDown, RGFW_gamepadLeft, RGFW_gamepadRight, RGFW_gamepadHome
  8378. };
  8379. u32 button = map[j];
  8380. if (button == 404)
  8381. continue;
  8382. if (RGFW_gamepadPressed[i][button].current != gamepadState.digitalButton[j]) {
  8383. if (gamepadState.digitalButton[j])
  8384. win->event.type = RGFW_gamepadButtonPressed;
  8385. else
  8386. win->event.type = RGFW_gamepadButtonReleased;
  8387. win->event.gamepad = i;
  8388. win->event.button = map[j];
  8389. RGFW_gamepadPressed[i][button].prev = RGFW_gamepadPressed[i][button].current;
  8390. RGFW_gamepadPressed[i][button].current = gamepadState.digitalButton[j];
  8391. RGFW_gamepadButtonCallback(win, win->event.gamepad, win->event.button, gamepadState.digitalButton[j]);
  8392. return &win->event;
  8393. }
  8394. }
  8395. for (j = 0; (j < gamepadState.numAxes) && (j < 4); j += 2) {
  8396. win->event.axisesCount = gamepadState.numAxes / 2;
  8397. if (RGFW_gamepadAxes[i][(size_t)(j / 2)].x != (i8)(gamepadState.axis[j] * 100.0f) ||
  8398. RGFW_gamepadAxes[i][(size_t)(j / 2)].y != (i8)(gamepadState.axis[j + 1] * 100.0f)
  8399. ) {
  8400. RGFW_gamepadAxes[i][(size_t)(j / 2)].x = (i8)(gamepadState.axis[j] * 100.0f);
  8401. RGFW_gamepadAxes[i][(size_t)(j / 2)].y = (i8)(gamepadState.axis[j + 1] * 100.0f);
  8402. win->event.axis[(size_t)(j / 2)] = RGFW_gamepadAxes[i][(size_t)(j / 2)];
  8403. win->event.type = RGFW_gamepadAxisMove;
  8404. win->event.gamepad = i;
  8405. win->event.whichAxis = j / 2;
  8406. RGFW_gamepadAxisCallback(win, win->event.gamepad, win->event.axis, win->event.axisesCount, win->event.whichAxis);
  8407. return &win->event;
  8408. }
  8409. }
  8410. }
  8411. return NULL;
  8412. }
  8413. void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
  8414. RGFW_UNUSED(win);
  8415. emscripten_set_canvas_element_size("#canvas", a.w, a.h);
  8416. }
  8417. /* NOTE: I don't know if this is possible */
  8418. void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); }
  8419. /* this one might be possible but it looks iffy */
  8420. RGFW_mouse* RGFW_loadMouse(u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(channels); RGFW_UNUSED(a); RGFW_UNUSED(icon); return NULL; }
  8421. void RGFW_window_setMouse(RGFW_window* win, RGFW_mouse* mouse) { RGFW_UNUSED(win); RGFW_UNUSED(mouse); }
  8422. void RGFW_freeMouse(RGFW_mouse* mouse) { RGFW_UNUSED(mouse); }
  8423. RGFW_bool RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
  8424. static const char cursors[16][16] = {
  8425. "default", "default", "text", "crosshair",
  8426. "pointer", "ew-resize", "ns-resize", "nwse-resize", "nesw-resize",
  8427. "move", "not-allowed"
  8428. };
  8429. RGFW_UNUSED(win);
  8430. EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, cursors[mouse]);
  8431. return RGFW_TRUE;
  8432. }
  8433. RGFW_bool RGFW_window_setMouseDefault(RGFW_window* win) {
  8434. return RGFW_window_setMouseStandard(win, RGFW_mouseNormal);
  8435. }
  8436. void RGFW_window_showMouse(RGFW_window* win, RGFW_bool show) {
  8437. RGFW_window_showMouseFlags(win, show);
  8438. if (show)
  8439. RGFW_window_setMouseDefault(win);
  8440. else
  8441. EM_ASM(document.getElementById('canvas').style.cursor = 'none';);
  8442. }
  8443. RGFW_point RGFW_getGlobalMousePoint(void) {
  8444. RGFW_point point;
  8445. point.x = EM_ASM_INT({
  8446. return window.mouseX || 0;
  8447. });
  8448. point.y = EM_ASM_INT({
  8449. return window.mouseY || 0;
  8450. });
  8451. return point;
  8452. }
  8453. void RGFW_window_setMousePassthrough(RGFW_window* win, RGFW_bool passthrough) {
  8454. RGFW_UNUSED(win);
  8455. EM_ASM_({
  8456. var canvas = document.getElementById('canvas');
  8457. if ($0) {
  8458. canvas.style.pointerEvents = 'none';
  8459. } else {
  8460. canvas.style.pointerEvents = 'auto';
  8461. }
  8462. }, passthrough);
  8463. }
  8464. void RGFW_writeClipboard(const char* text, u32 textLen) {
  8465. RGFW_UNUSED(textLen);
  8466. EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
  8467. }
  8468. RGFW_ssize_t RGFW_readClipboardPtr(char* str, size_t strCapacity) {
  8469. RGFW_UNUSED(str); RGFW_UNUSED(strCapacity);
  8470. /*
  8471. placeholder code for later
  8472. I'm not sure if this is possible do the the async stuff
  8473. */
  8474. return 0;
  8475. }
  8476. void RGFW_window_swapBuffers_software(RGFW_window* win) {
  8477. #if defined(RGFW_OSMESA)
  8478. EM_ASM_({
  8479. var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
  8480. let context = document.getElementById("canvas").getContext("2d");
  8481. let image = context.getImageData(0, 0, $1, $2);
  8482. image.data.set(data);
  8483. context.putImageData(image, 0, $4 - $2);
  8484. }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h);
  8485. #elif defined(RGFW_BUFFER)
  8486. EM_ASM_({
  8487. var data = Module.HEAPU8.slice($0, $0 + $1 * $2 * 4);
  8488. let context = document.getElementById("canvas").getContext("2d");
  8489. let image = context.getImageData(0, 0, $1, $2);
  8490. image.data.set(data);
  8491. context.putImageData(image, 0, 0);
  8492. }, win->buffer, win->bufferSize.w, win->bufferSize.h, win->r.w, win->r.h);
  8493. emscripten_sleep(0);
  8494. #else
  8495. RGFW_UNUSED(win);
  8496. #endif
  8497. }
  8498. void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
  8499. #if !defined(RGFW_WEBGPU) && !(defined(RGFW_OSMESA) || defined(RGFW_BUFFER))
  8500. if (win == NULL)
  8501. emscripten_webgl_make_context_current(0);
  8502. else
  8503. emscripten_webgl_make_context_current(win->src.ctx);
  8504. #endif
  8505. }
  8506. void RGFW_window_swapBuffers_OpenGL(RGFW_window* win) {
  8507. #ifndef RGFW_WEBGPU
  8508. emscripten_webgl_commit_frame();
  8509. #endif
  8510. emscripten_sleep(0);
  8511. }
  8512. #ifndef RGFW_WEBGPU
  8513. void* RGFW_getCurrent_OpenGL(void) { return (void*)emscripten_webgl_get_current_context(); }
  8514. #endif
  8515. #ifndef RGFW_EGL
  8516. void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
  8517. #endif
  8518. void RGFW_deinit(void) { _RGFW.windowCount = -1; RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoGlobal, (RGFW_debugContext){0}, "global context deinitialized"); }
  8519. void RGFW_window_close(RGFW_window* win) {
  8520. if ((win->_flags & RGFW_windowNoInitAPI) == 0) RGFW_window_freeOpenGL(win);
  8521. #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
  8522. if ((win->_flags & RGFW_BUFFER_ALLOC))
  8523. RGFW_FREE(win->buffer);
  8524. #endif
  8525. RGFW_sendDebugInfo(RGFW_typeInfo, RGFW_infoWindow, RGFW_DEBUG_CTX(win, 0), "a window was freed");
  8526. _RGFW.windowCount--;
  8527. if (_RGFW.windowCount == 0) RGFW_deinit();
  8528. RGFW_clipboard_switch(NULL);
  8529. RGFW_FREE(win->event.droppedFiles);
  8530. if ((win->_flags & RGFW_WINDOW_ALLOC)) {
  8531. RGFW_FREE(win);
  8532. win = NULL;
  8533. }
  8534. }
  8535. int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); }
  8536. int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); }
  8537. RGFW_area RGFW_getScreenSize(void) {
  8538. return RGFW_AREA(RGFW_innerWidth(), RGFW_innerHeight());
  8539. }
  8540. RGFW_proc RGFW_getProcAddress(const char* procname) {
  8541. return (RGFW_proc)emscripten_webgl_get_proc_address(procname);
  8542. }
  8543. void RGFW_sleep(u64 milisecond) {
  8544. emscripten_sleep(milisecond);
  8545. }
  8546. u64 RGFW_getTimerFreq(void) { return (u64)1000; }
  8547. u64 RGFW_getTimerValue(void) { return emscripten_get_now() * 1e+6; }
  8548. void RGFW_releaseCursor(RGFW_window* win) {
  8549. RGFW_UNUSED(win);
  8550. emscripten_exit_pointerlock();
  8551. }
  8552. void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
  8553. RGFW_UNUSED(win); RGFW_UNUSED(r);
  8554. emscripten_request_pointerlock("#canvas", 1);
  8555. }
  8556. void RGFW_window_setName(RGFW_window* win, const char* name) {
  8557. RGFW_UNUSED(win);
  8558. emscripten_set_window_title(name);
  8559. }
  8560. void RGFW_window_maximize(RGFW_window* win) {
  8561. RGFW_ASSERT(win != NULL);
  8562. RGFW_area screen = RGFW_getScreenSize();
  8563. RGFW_window_move(win, RGFW_POINT(0, 0));
  8564. RGFW_window_resize(win, screen);
  8565. }
  8566. void RGFW_window_setFullscreen(RGFW_window* win, RGFW_bool fullscreen) {
  8567. RGFW_ASSERT(win != NULL);
  8568. if (fullscreen) {
  8569. win->_flags |= RGFW_windowFullscreen;
  8570. EM_ASM( Module.requestFullscreen(false, true); );
  8571. return;
  8572. }
  8573. win->_flags &= ~(u32)RGFW_windowFullscreen;
  8574. EM_ASM( Module.exitFullscreen(false, true); );
  8575. }
  8576. void RGFW_window_setOpacity(RGFW_window* win, u8 opacity) {
  8577. RGFW_UNUSED(win);
  8578. EM_ASM({
  8579. var element = document.getElementById("canvas");
  8580. if (element)
  8581. element.style.opacity = $1;
  8582. }, "elementId", opacity);
  8583. }
  8584. /* unsupported functions */
  8585. void RGFW_window_focus(RGFW_window* win) { RGFW_UNUSED(win); }
  8586. void RGFW_window_raise(RGFW_window* win) { RGFW_UNUSED(win); }
  8587. RGFW_bool RGFW_monitor_requestMode(RGFW_monitor mon, RGFW_monitorMode mode, RGFW_modeRequest request) { RGFW_UNUSED(mon); RGFW_UNUSED(mode); RGFW_UNUSED(request); return RGFW_FALSE; }
  8588. RGFW_monitor* RGFW_getMonitors(size_t* len) { RGFW_UNUSED(len); return NULL; }
  8589. RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; }
  8590. void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); }
  8591. void RGFW_window_setAspectRatio(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); }
  8592. void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); }
  8593. void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win); RGFW_UNUSED(a); }
  8594. void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win); }
  8595. void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win); }
  8596. void RGFW_window_setFloating(RGFW_window* win, RGFW_bool floating) { RGFW_UNUSED(win); RGFW_UNUSED(floating); }
  8597. void RGFW_window_setBorder(RGFW_window* win, RGFW_bool border) { RGFW_UNUSED(win); RGFW_UNUSED(border); }
  8598. RGFW_bool RGFW_window_setIconEx(RGFW_window* win, u8* icon, RGFW_area a, i32 channels, u8 type) { RGFW_UNUSED(win); RGFW_UNUSED(icon); RGFW_UNUSED(a); RGFW_UNUSED(channels); RGFW_UNUSED(type); return RGFW_FALSE; }
  8599. void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win); }
  8600. void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win); }
  8601. RGFW_bool RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
  8602. RGFW_bool RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
  8603. RGFW_bool RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
  8604. RGFW_bool RGFW_window_isFloating(RGFW_window* win) { RGFW_UNUSED(win); return RGFW_FALSE; }
  8605. RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win); return (RGFW_monitor){}; }
  8606. #endif
  8607. /* end of web asm defines */
  8608. /* unix (macOS, linux, web asm) only stuff */
  8609. #if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WASM) || defined(RGFW_WAYLAND)
  8610. #ifndef RGFW_NO_THREADS
  8611. #include <pthread.h>
  8612. RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) {
  8613. RGFW_thread t;
  8614. pthread_create((pthread_t*) &t, NULL, *ptr, args);
  8615. return t;
  8616. }
  8617. void RGFW_cancelThread(RGFW_thread thread) { pthread_cancel((pthread_t) thread); }
  8618. void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); }
  8619. #if defined(__linux__)
  8620. void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { pthread_setschedprio((pthread_t)thread, priority); }
  8621. #else
  8622. void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { RGFW_UNUSED(thread); RGFW_UNUSED(priority); }
  8623. #endif
  8624. #endif
  8625. #ifndef RGFW_WASM
  8626. void RGFW_sleep(u64 ms) {
  8627. struct timespec time;
  8628. time.tv_sec = 0;
  8629. time.tv_nsec = (long int)((double)ms * 1e+6);
  8630. #ifndef RGFW_NO_UNIX_CLOCK
  8631. nanosleep(&time, NULL);
  8632. #endif
  8633. }
  8634. #endif
  8635. #endif /* end of unix / mac stuff */
  8636. #endif /* RGFW_IMPLEMENTATION */
  8637. #if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
  8638. }
  8639. #endif
  8640. #if _MSC_VER
  8641. #pragma warning( pop )
  8642. #endif