display_server_osx.mm 115 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937
  1. /*************************************************************************/
  2. /* display_server_osx.mm */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "display_server_osx.h"
  31. #include "os_osx.h"
  32. #include "core/io/marshalls.h"
  33. #include "core/math/geometry_2d.h"
  34. #include "core/os/keyboard.h"
  35. #include "main/main.h"
  36. #include "scene/resources/texture.h"
  37. #include <Carbon/Carbon.h>
  38. #include <Cocoa/Cocoa.h>
  39. #include <IOKit/IOCFPlugIn.h>
  40. #include <IOKit/IOKitLib.h>
  41. #include <IOKit/hid/IOHIDKeys.h>
  42. #include <IOKit/hid/IOHIDLib.h>
  43. #if defined(OPENGL_ENABLED)
  44. //TODO - reimplement OpenGLES
  45. #import <AppKit/NSOpenGLView.h>
  46. #endif
  47. #if defined(VULKAN_ENABLED)
  48. #include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
  49. #include <QuartzCore/CAMetalLayer.h>
  50. #endif
  51. #ifndef NSAppKitVersionNumber10_14
  52. #define NSAppKitVersionNumber10_14 1671
  53. #endif
  54. #define DS_OSX ((DisplayServerOSX *)(DisplayServerOSX::get_singleton()))
  55. static bool ignore_momentum_scroll = false;
  56. static void _get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithModifiers> r_state) {
  57. r_state->set_shift((p_osx_state & NSEventModifierFlagShift));
  58. r_state->set_control((p_osx_state & NSEventModifierFlagControl));
  59. r_state->set_alt((p_osx_state & NSEventModifierFlagOption));
  60. r_state->set_metakey((p_osx_state & NSEventModifierFlagCommand));
  61. }
  62. static Vector2i _get_mouse_pos(DisplayServerOSX::WindowData &p_wd, NSPoint p_locationInWindow) {
  63. const NSRect contentRect = [p_wd.window_view frame];
  64. const float scale = DS_OSX->screen_get_max_scale();
  65. p_wd.mouse_pos.x = p_locationInWindow.x * scale;
  66. p_wd.mouse_pos.y = (contentRect.size.height - p_locationInWindow.y) * scale;
  67. DS_OSX->last_mouse_pos = p_wd.mouse_pos;
  68. Input::get_singleton()->set_mouse_position(p_wd.mouse_pos);
  69. return p_wd.mouse_pos;
  70. }
  71. static void _push_to_key_event_buffer(const DisplayServerOSX::KeyEvent &p_event) {
  72. Vector<DisplayServerOSX::KeyEvent> &buffer = DS_OSX->key_event_buffer;
  73. if (DS_OSX->key_event_pos >= buffer.size()) {
  74. buffer.resize(1 + DS_OSX->key_event_pos);
  75. }
  76. buffer.write[DS_OSX->key_event_pos++] = p_event;
  77. }
  78. static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
  79. if ([NSCursor respondsToSelector:selector]) {
  80. id object = [NSCursor performSelector:selector];
  81. if ([object isKindOfClass:[NSCursor class]]) {
  82. return object;
  83. }
  84. }
  85. if (fallback) {
  86. // Fallback should be a reasonable default, no need to check.
  87. return [NSCursor performSelector:fallback];
  88. }
  89. return [NSCursor arrowCursor];
  90. }
  91. /*************************************************************************/
  92. /* GodotApplication */
  93. /*************************************************************************/
  94. @interface GodotApplication : NSApplication
  95. @end
  96. @implementation GodotApplication
  97. - (void)sendEvent:(NSEvent *)event {
  98. // special case handling of command-period, which is traditionally a special
  99. // shortcut in macOS and doesn't arrive at our regular keyDown handler.
  100. if ([event type] == NSEventTypeKeyDown) {
  101. if (([event modifierFlags] & NSEventModifierFlagCommand) && [event keyCode] == 0x2f) {
  102. Ref<InputEventKey> k;
  103. k.instance();
  104. _get_key_modifier_state([event modifierFlags], k);
  105. k->set_window_id(DisplayServerOSX::INVALID_WINDOW_ID);
  106. k->set_pressed(true);
  107. k->set_keycode(KEY_PERIOD);
  108. k->set_physical_keycode(KEY_PERIOD);
  109. k->set_echo([event isARepeat]);
  110. Input::get_singleton()->accumulate_input_event(k);
  111. }
  112. }
  113. // From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost
  114. // This works around an AppKit bug, where key up events while holding
  115. // down the command key don't get sent to the key window.
  116. if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand)) {
  117. [[self keyWindow] sendEvent:event];
  118. } else {
  119. [super sendEvent:event];
  120. }
  121. }
  122. @end
  123. /*************************************************************************/
  124. /* GlobalMenuItem */
  125. /*************************************************************************/
  126. @interface GlobalMenuItem : NSObject {
  127. @public
  128. Callable callback;
  129. Variant meta;
  130. bool checkable;
  131. }
  132. @end
  133. @implementation GlobalMenuItem
  134. @end
  135. /*************************************************************************/
  136. /* GodotApplicationDelegate */
  137. /*************************************************************************/
  138. @interface GodotApplicationDelegate : NSObject
  139. - (void)forceUnbundledWindowActivationHackStep1;
  140. - (void)forceUnbundledWindowActivationHackStep2;
  141. - (void)forceUnbundledWindowActivationHackStep3;
  142. @end
  143. @implementation GodotApplicationDelegate
  144. - (void)forceUnbundledWindowActivationHackStep1 {
  145. // Step1: Switch focus to macOS Dock.
  146. // Required to perform step 2, TransformProcessType will fail if app is already the in focus.
  147. for (NSRunningApplication *app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
  148. [app activateWithOptions:NSApplicationActivateIgnoringOtherApps];
  149. break;
  150. }
  151. [self performSelector:@selector(forceUnbundledWindowActivationHackStep2) withObject:nil afterDelay:0.02];
  152. }
  153. - (void)forceUnbundledWindowActivationHackStep2 {
  154. // Step 2: Register app as foreground process.
  155. ProcessSerialNumber psn = { 0, kCurrentProcess };
  156. (void)TransformProcessType(&psn, kProcessTransformToForegroundApplication);
  157. [self performSelector:@selector(forceUnbundledWindowActivationHackStep3) withObject:nil afterDelay:0.02];
  158. }
  159. - (void)forceUnbundledWindowActivationHackStep3 {
  160. // Step 3: Switch focus back to app window.
  161. [[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
  162. }
  163. - (void)applicationDidFinishLaunching:(NSNotification *)notice {
  164. NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
  165. if (nsappname == nil) {
  166. // If executable is not a bundled, macOS WindowServer won't register and activate app window correctly (menu and title bar are grayed out and input ignored).
  167. [self performSelector:@selector(forceUnbundledWindowActivationHackStep1) withObject:nil afterDelay:0.02];
  168. }
  169. }
  170. - (void)applicationDidResignActive:(NSNotification *)notification {
  171. if (OS_OSX::get_singleton()->get_main_loop()) {
  172. OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
  173. }
  174. }
  175. - (void)applicationDidBecomeActive:(NSNotification *)notification {
  176. if (OS_OSX::get_singleton()->get_main_loop()) {
  177. OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
  178. }
  179. }
  180. - (void)globalMenuCallback:(id)sender {
  181. if (![sender representedObject]) {
  182. return;
  183. }
  184. GlobalMenuItem *value = [sender representedObject];
  185. if (value) {
  186. if (value->checkable) {
  187. if ([sender state] == NSControlStateValueOff) {
  188. [sender setState:NSControlStateValueOn];
  189. } else {
  190. [sender setState:NSControlStateValueOff];
  191. }
  192. }
  193. if (value->callback != Callable()) {
  194. Variant tag = value->meta;
  195. Variant *tagp = &tag;
  196. Variant ret;
  197. Callable::CallError ce;
  198. value->callback.call((const Variant **)&tagp, 1, ret, ce);
  199. }
  200. }
  201. }
  202. - (NSMenu *)applicationDockMenu:(NSApplication *)sender {
  203. return DS_OSX->dock_menu;
  204. }
  205. - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
  206. // Note: may be called called before main loop init!
  207. char *utfs = strdup([filename UTF8String]);
  208. ((OS_OSX *)(OS_OSX::get_singleton()))->open_with_filename.parse_utf8(utfs);
  209. free(utfs);
  210. #ifdef TOOLS_ENABLED
  211. // Open new instance
  212. if (OS_OSX::get_singleton()->get_main_loop()) {
  213. List<String> args;
  214. args.push_back(((OS_OSX *)(OS_OSX::get_singleton()))->open_with_filename);
  215. String exec = OS::get_singleton()->get_executable_path();
  216. OS::get_singleton()->create_process(exec, args);
  217. }
  218. #endif
  219. return YES;
  220. }
  221. - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
  222. DS_OSX->_send_window_event(DS_OSX->windows[DisplayServerOSX::MAIN_WINDOW_ID], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
  223. return NSTerminateCancel;
  224. }
  225. - (void)showAbout:(id)sender {
  226. if (OS_OSX::get_singleton()->get_main_loop()) {
  227. OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_ABOUT);
  228. }
  229. }
  230. @end
  231. /*************************************************************************/
  232. /* GodotWindowDelegate */
  233. /*************************************************************************/
  234. @interface GodotWindowDelegate : NSObject {
  235. DisplayServerOSX::WindowID window_id;
  236. }
  237. - (void)windowWillClose:(NSNotification *)notification;
  238. - (void)setWindowID:(DisplayServerOSX::WindowID)wid;
  239. @end
  240. @implementation GodotWindowDelegate
  241. - (void)setWindowID:(DisplayServerOSX::WindowID)wid {
  242. window_id = wid;
  243. }
  244. - (BOOL)windowShouldClose:(id)sender {
  245. if (!DS_OSX || !DS_OSX->windows.has(window_id)) {
  246. return YES;
  247. }
  248. DS_OSX->_send_window_event(DS_OSX->windows[window_id], DisplayServerOSX::WINDOW_EVENT_CLOSE_REQUEST);
  249. return NO;
  250. }
  251. - (void)windowWillClose:(NSNotification *)notification {
  252. if (!DS_OSX || !DS_OSX->windows.has(window_id)) {
  253. return;
  254. }
  255. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  256. while (wd.transient_children.size()) {
  257. DS_OSX->window_set_transient(wd.transient_children.front()->get(), DisplayServerOSX::INVALID_WINDOW_ID);
  258. }
  259. if (wd.transient_parent != DisplayServerOSX::INVALID_WINDOW_ID) {
  260. DisplayServerOSX::WindowData &pwd = DS_OSX->windows[wd.transient_parent];
  261. [pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to parent.
  262. DS_OSX->window_set_transient(window_id, DisplayServerOSX::INVALID_WINDOW_ID);
  263. } else if ((window_id != DisplayServerOSX::MAIN_WINDOW_ID) && (DS_OSX->windows.size() == 1)) {
  264. DisplayServerOSX::WindowData &pwd = DS_OSX->windows[DisplayServerOSX::MAIN_WINDOW_ID];
  265. [pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to main window if there is no parent or other windows left.
  266. }
  267. #if defined(OPENGL_ENABLED)
  268. if (DS_OSX->rendering_driver == "opengl_es") {
  269. //TODO - reimplement OpenGLES
  270. }
  271. #endif
  272. #ifdef VULKAN_ENABLED
  273. if (DS_OSX->rendering_driver == "vulkan") {
  274. DS_OSX->context_vulkan->window_destroy(window_id);
  275. }
  276. #endif
  277. DS_OSX->windows.erase(window_id);
  278. }
  279. - (void)windowDidEnterFullScreen:(NSNotification *)notification {
  280. if (!DS_OSX || !DS_OSX->windows.has(window_id)) {
  281. return;
  282. }
  283. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  284. wd.fullscreen = true;
  285. [wd.window_object setContentMinSize:NSMakeSize(0, 0)];
  286. [wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
  287. }
  288. - (void)windowDidExitFullScreen:(NSNotification *)notification {
  289. if (!DS_OSX || !DS_OSX->windows.has(window_id)) {
  290. return;
  291. }
  292. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  293. wd.fullscreen = false;
  294. const float scale = DS_OSX->screen_get_max_scale();
  295. if (wd.min_size != Size2i()) {
  296. Size2i size = wd.min_size / scale;
  297. [wd.window_object setContentMinSize:NSMakeSize(size.x, size.y)];
  298. }
  299. if (wd.max_size != Size2i()) {
  300. Size2i size = wd.max_size / scale;
  301. [wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
  302. }
  303. if (wd.resize_disabled) {
  304. [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable];
  305. }
  306. }
  307. - (void)windowDidChangeBackingProperties:(NSNotification *)notification {
  308. if (!DisplayServerOSX::get_singleton()) {
  309. return;
  310. }
  311. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  312. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  313. CGFloat newBackingScaleFactor = [wd.window_object backingScaleFactor];
  314. CGFloat oldBackingScaleFactor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue];
  315. if (newBackingScaleFactor != oldBackingScaleFactor) {
  316. //Set new display scale and window size
  317. const float scale = DS_OSX->screen_get_max_scale();
  318. const NSRect contentRect = [wd.window_view frame];
  319. wd.size.width = contentRect.size.width * scale;
  320. wd.size.height = contentRect.size.height * scale;
  321. DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_DPI_CHANGE);
  322. CALayer *layer = [wd.window_view layer];
  323. if (layer) {
  324. layer.contentsScale = scale;
  325. }
  326. //Force window resize event
  327. [self windowDidResize:notification];
  328. }
  329. }
  330. - (void)windowDidResize:(NSNotification *)notification {
  331. if (!DS_OSX || !DS_OSX->windows.has(window_id)) {
  332. return;
  333. }
  334. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  335. const NSRect contentRect = [wd.window_view frame];
  336. const float scale = DS_OSX->screen_get_max_scale();
  337. wd.size.width = contentRect.size.width * scale;
  338. wd.size.height = contentRect.size.height * scale;
  339. CALayer *layer = [wd.window_view layer];
  340. if (layer) {
  341. layer.contentsScale = scale;
  342. }
  343. #if defined(OPENGL_ENABLED)
  344. if (DS_OSX->rendering_driver == "opengl_es") {
  345. //TODO - reimplement OpenGLES
  346. }
  347. #endif
  348. #if defined(VULKAN_ENABLED)
  349. if (DS_OSX->rendering_driver == "vulkan") {
  350. DS_OSX->context_vulkan->window_resize(window_id, wd.size.width, wd.size.height);
  351. }
  352. #endif
  353. if (!wd.rect_changed_callback.is_null()) {
  354. Variant size = Rect2i(DS_OSX->window_get_position(window_id), DS_OSX->window_get_size(window_id));
  355. Variant *sizep = &size;
  356. Variant ret;
  357. Callable::CallError ce;
  358. wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce);
  359. }
  360. if (OS_OSX::get_singleton()->get_main_loop()) {
  361. Main::force_redraw();
  362. //Event retrieval blocks until resize is over. Call Main::iteration() directly.
  363. if (!Main::is_iterating()) { //avoid cyclic loop
  364. Main::iteration();
  365. }
  366. }
  367. }
  368. - (void)windowDidMove:(NSNotification *)notification {
  369. if (!DS_OSX || !DS_OSX->windows.has(window_id)) {
  370. return;
  371. }
  372. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  373. DS_OSX->_release_pressed_events();
  374. if (!wd.rect_changed_callback.is_null()) {
  375. Variant size = Rect2i(DS_OSX->window_get_position(window_id), DS_OSX->window_get_size(window_id));
  376. Variant *sizep = &size;
  377. Variant ret;
  378. Callable::CallError ce;
  379. wd.rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce);
  380. }
  381. }
  382. - (void)windowDidBecomeKey:(NSNotification *)notification {
  383. if (!DS_OSX || !DS_OSX->windows.has(window_id)) {
  384. return;
  385. }
  386. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  387. _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
  388. Input::get_singleton()->set_mouse_position(wd.mouse_pos);
  389. DS_OSX->window_focused = true;
  390. DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN);
  391. }
  392. - (void)windowDidResignKey:(NSNotification *)notification {
  393. if (!DS_OSX || !DS_OSX->windows.has(window_id)) {
  394. return;
  395. }
  396. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  397. DS_OSX->window_focused = false;
  398. DS_OSX->_release_pressed_events();
  399. DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT);
  400. }
  401. - (void)windowDidMiniaturize:(NSNotification *)notification {
  402. if (!DS_OSX || !DS_OSX->windows.has(window_id)) {
  403. return;
  404. }
  405. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  406. DS_OSX->window_focused = false;
  407. DS_OSX->_release_pressed_events();
  408. DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_OUT);
  409. }
  410. - (void)windowDidDeminiaturize:(NSNotification *)notification {
  411. if (!DS_OSX || !DS_OSX->windows.has(window_id)) {
  412. return;
  413. }
  414. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  415. DS_OSX->window_focused = true;
  416. DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN);
  417. }
  418. @end
  419. /*************************************************************************/
  420. /* GodotContentView */
  421. /*************************************************************************/
  422. @interface GodotContentView : NSView <NSTextInputClient> {
  423. DisplayServerOSX::WindowID window_id;
  424. NSTrackingArea *trackingArea;
  425. NSMutableAttributedString *markedText;
  426. bool imeInputEventInProgress;
  427. }
  428. - (void)cancelComposition;
  429. - (CALayer *)makeBackingLayer;
  430. - (BOOL)wantsUpdateLayer;
  431. - (void)updateLayer;
  432. - (void)setWindowID:(DisplayServerOSX::WindowID)wid;
  433. @end
  434. @implementation GodotContentView
  435. - (void)setWindowID:(DisplayServerOSX::WindowID)wid {
  436. window_id = wid;
  437. }
  438. + (void)initialize {
  439. if (self == [GodotContentView class]) {
  440. // nothing left to do here at the moment..
  441. }
  442. }
  443. - (CALayer *)makeBackingLayer {
  444. #if defined(OPENGL_ENABLED)
  445. if (DS_OSX->rendering_driver == "opengl_es") {
  446. CALayer *layer = [[NSOpenGLLayer class] layer];
  447. return layer;
  448. }
  449. #endif
  450. #if defined(VULKAN_ENABLED)
  451. if (DS_OSX->rendering_driver == "vulkan") {
  452. CALayer *layer = [[CAMetalLayer class] layer];
  453. return layer;
  454. }
  455. #endif
  456. return [super makeBackingLayer];
  457. }
  458. - (void)updateLayer {
  459. #if defined(OPENGL_ENABLED)
  460. if (DS_OSX->rendering_driver == "opengl_es") {
  461. [super updateLayer];
  462. //TODO - reimplement OpenGLES
  463. }
  464. #endif
  465. #if defined(VULKAN_ENABLED)
  466. if (DS_OSX->rendering_driver == "vulkan") {
  467. [super updateLayer];
  468. }
  469. #endif
  470. }
  471. - (BOOL)wantsUpdateLayer {
  472. return YES;
  473. }
  474. - (id)init {
  475. self = [super init];
  476. trackingArea = nil;
  477. imeInputEventInProgress = false;
  478. [self updateTrackingAreas];
  479. #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
  480. [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeFileURL]];
  481. #else
  482. [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
  483. #endif
  484. markedText = [[NSMutableAttributedString alloc] init];
  485. return self;
  486. }
  487. - (void)dealloc {
  488. [trackingArea release];
  489. [markedText release];
  490. [super dealloc];
  491. }
  492. static const NSRange kEmptyRange = { NSNotFound, 0 };
  493. - (BOOL)hasMarkedText {
  494. return (markedText.length > 0);
  495. }
  496. - (NSRange)markedRange {
  497. return NSMakeRange(0, markedText.length);
  498. }
  499. - (NSRange)selectedRange {
  500. return kEmptyRange;
  501. }
  502. - (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange {
  503. if ([aString isKindOfClass:[NSAttributedString class]]) {
  504. [markedText initWithAttributedString:aString];
  505. } else {
  506. [markedText initWithString:aString];
  507. }
  508. if (markedText.length == 0) {
  509. [self unmarkText];
  510. return;
  511. }
  512. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  513. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  514. if (wd.im_active) {
  515. imeInputEventInProgress = true;
  516. DS_OSX->im_text.parse_utf8([[markedText mutableString] UTF8String]);
  517. DS_OSX->im_selection = Point2i(selectedRange.location, selectedRange.length);
  518. OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
  519. }
  520. }
  521. - (void)doCommandBySelector:(SEL)aSelector {
  522. if ([self respondsToSelector:aSelector]) {
  523. [self performSelector:aSelector];
  524. }
  525. }
  526. - (void)unmarkText {
  527. imeInputEventInProgress = false;
  528. [[markedText mutableString] setString:@""];
  529. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  530. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  531. if (wd.im_active) {
  532. DS_OSX->im_text = String();
  533. DS_OSX->im_selection = Point2i();
  534. OS_OSX::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
  535. }
  536. }
  537. - (NSArray *)validAttributesForMarkedText {
  538. return [NSArray array];
  539. }
  540. - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange {
  541. return nil;
  542. }
  543. - (NSUInteger)characterIndexForPoint:(NSPoint)aPoint {
  544. return 0;
  545. }
  546. - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange {
  547. ERR_FAIL_COND_V(!DS_OSX->windows.has(window_id), NSMakeRect(0, 0, 0, 0));
  548. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  549. const NSRect contentRect = [wd.window_view frame];
  550. const float scale = DS_OSX->screen_get_max_scale();
  551. NSRect pointInWindowRect = NSMakeRect(wd.im_position.x / scale, contentRect.size.height - (wd.im_position.y / scale) - 1, 0, 0);
  552. NSPoint pointOnScreen = [wd.window_object convertRectToScreen:pointInWindowRect].origin;
  553. return NSMakeRect(pointOnScreen.x, pointOnScreen.y, 0, 0);
  554. }
  555. - (void)cancelComposition {
  556. [self unmarkText];
  557. NSTextInputContext *currentInputContext = [NSTextInputContext currentInputContext];
  558. [currentInputContext discardMarkedText];
  559. }
  560. - (void)insertText:(id)aString {
  561. [self insertText:aString replacementRange:NSMakeRange(0, 0)];
  562. }
  563. - (void)insertText:(id)aString replacementRange:(NSRange)replacementRange {
  564. NSEvent *event = [NSApp currentEvent];
  565. NSString *characters;
  566. if ([aString isKindOfClass:[NSAttributedString class]]) {
  567. characters = [aString string];
  568. } else {
  569. characters = (NSString *)aString;
  570. }
  571. NSCharacterSet *ctrlChars = [NSCharacterSet controlCharacterSet];
  572. NSCharacterSet *wsnlChars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
  573. if ([characters rangeOfCharacterFromSet:ctrlChars].length && [characters rangeOfCharacterFromSet:wsnlChars].length == 0) {
  574. NSTextInputContext *currentInputContext = [NSTextInputContext currentInputContext];
  575. [currentInputContext discardMarkedText];
  576. [self cancelComposition];
  577. return;
  578. }
  579. Char16String text;
  580. text.resize([characters length] + 1);
  581. [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
  582. String u32text;
  583. u32text.parse_utf16(text.ptr(), text.length());
  584. for (int i = 0; i < u32text.length(); i++) {
  585. const char32_t codepoint = u32text[i];
  586. if ((codepoint & 0xFF00) == 0xF700) {
  587. continue;
  588. }
  589. DisplayServerOSX::KeyEvent ke;
  590. ke.window_id = window_id;
  591. ke.osx_state = [event modifierFlags];
  592. ke.pressed = true;
  593. ke.echo = false;
  594. ke.raw = false; // IME input event
  595. ke.keycode = 0;
  596. ke.physical_keycode = 0;
  597. ke.unicode = codepoint;
  598. _push_to_key_event_buffer(ke);
  599. }
  600. [self cancelComposition];
  601. }
  602. - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
  603. return NSDragOperationCopy;
  604. }
  605. - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
  606. return NSDragOperationCopy;
  607. }
  608. - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
  609. ERR_FAIL_COND_V(!DS_OSX->windows.has(window_id), NO);
  610. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  611. if (!wd.drop_files_callback.is_null()) {
  612. Vector<String> files;
  613. NSPasteboard *pboard = [sender draggingPasteboard];
  614. #if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
  615. NSArray *items = pboard.pasteboardItems;
  616. for (NSPasteboardItem *item in items) {
  617. NSString *path = [item stringForType:NSPasteboardTypeFileURL];
  618. NSString *ns = [NSURL URLWithString:path].path;
  619. char *utfs = strdup([ns UTF8String]);
  620. String ret;
  621. ret.parse_utf8(utfs);
  622. free(utfs);
  623. files.push_back(ret);
  624. }
  625. #else
  626. NSArray *filenames = [pboard propertyListForType:NSFilenamesPboardType];
  627. for (NSString *ns in filenames) {
  628. char *utfs = strdup([ns UTF8String]);
  629. String ret;
  630. ret.parse_utf8(utfs);
  631. free(utfs);
  632. files.push_back(ret);
  633. }
  634. #endif
  635. Variant v = files;
  636. Variant *vp = &v;
  637. Variant ret;
  638. Callable::CallError ce;
  639. wd.drop_files_callback.call((const Variant **)&vp, 1, ret, ce);
  640. }
  641. return NO;
  642. }
  643. - (BOOL)isOpaque {
  644. return YES;
  645. }
  646. - (BOOL)canBecomeKeyView {
  647. if (DS_OSX->windows.has(window_id)) {
  648. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  649. if (wd.no_focus) {
  650. return NO;
  651. }
  652. }
  653. return YES;
  654. }
  655. - (BOOL)acceptsFirstResponder {
  656. return YES;
  657. }
  658. - (void)cursorUpdate:(NSEvent *)event {
  659. DisplayServer::CursorShape p_shape = DS_OSX->cursor_shape;
  660. DS_OSX->cursor_shape = DisplayServer::CURSOR_MAX;
  661. DS_OSX->cursor_set_shape(p_shape);
  662. }
  663. static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, int index, int mask, bool pressed) {
  664. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  665. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  666. if (pressed) {
  667. DS_OSX->last_button_state |= mask;
  668. } else {
  669. DS_OSX->last_button_state &= ~mask;
  670. }
  671. Ref<InputEventMouseButton> mb;
  672. mb.instance();
  673. mb->set_window_id(window_id);
  674. const Vector2 pos = _get_mouse_pos(wd, [event locationInWindow]);
  675. _get_key_modifier_state([event modifierFlags], mb);
  676. mb->set_button_index(index);
  677. mb->set_pressed(pressed);
  678. mb->set_position(pos);
  679. mb->set_global_position(pos);
  680. mb->set_button_mask(DS_OSX->last_button_state);
  681. if (index == BUTTON_LEFT && pressed) {
  682. mb->set_doubleclick([event clickCount] == 2);
  683. }
  684. Input::get_singleton()->accumulate_input_event(mb);
  685. }
  686. - (void)mouseDown:(NSEvent *)event {
  687. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  688. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  689. if (([event modifierFlags] & NSEventModifierFlagControl)) {
  690. wd.mouse_down_control = true;
  691. _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
  692. } else {
  693. wd.mouse_down_control = false;
  694. _mouseDownEvent(window_id, event, BUTTON_LEFT, BUTTON_MASK_LEFT, true);
  695. }
  696. }
  697. - (void)mouseDragged:(NSEvent *)event {
  698. [self mouseMoved:event];
  699. }
  700. - (void)mouseUp:(NSEvent *)event {
  701. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  702. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  703. if (wd.mouse_down_control) {
  704. _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
  705. } else {
  706. _mouseDownEvent(window_id, event, BUTTON_LEFT, BUTTON_MASK_LEFT, false);
  707. }
  708. }
  709. - (void)mouseMoved:(NSEvent *)event {
  710. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  711. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  712. NSPoint delta = NSMakePoint([event deltaX], [event deltaY]);
  713. NSPoint mpos = [event locationInWindow];
  714. if (DS_OSX->ignore_warp) {
  715. // Discard late events, before warp
  716. if (([event timestamp]) < DS_OSX->last_warp) {
  717. return;
  718. }
  719. DS_OSX->ignore_warp = false;
  720. return;
  721. }
  722. if (DS_OSX->mouse_mode == DisplayServer::MOUSE_MODE_CONFINED) {
  723. // Discard late events
  724. if (([event timestamp]) < DS_OSX->last_warp) {
  725. return;
  726. }
  727. // Warp affects next event delta, subtract previous warp deltas
  728. List<DisplayServerOSX::WarpEvent>::Element *F = DS_OSX->warp_events.front();
  729. while (F) {
  730. if (F->get().timestamp < [event timestamp]) {
  731. List<DisplayServerOSX::WarpEvent>::Element *E = F;
  732. delta.x -= E->get().delta.x;
  733. delta.y -= E->get().delta.y;
  734. F = F->next();
  735. DS_OSX->warp_events.erase(E);
  736. } else {
  737. F = F->next();
  738. }
  739. }
  740. // Confine mouse position to the window, and update delta
  741. NSRect frame = [wd.window_object frame];
  742. NSPoint conf_pos = mpos;
  743. conf_pos.x = CLAMP(conf_pos.x + delta.x, 0.f, frame.size.width);
  744. conf_pos.y = CLAMP(conf_pos.y - delta.y, 0.f, frame.size.height);
  745. delta.x = conf_pos.x - mpos.x;
  746. delta.y = mpos.y - conf_pos.y;
  747. mpos = conf_pos;
  748. // Move mouse cursor
  749. NSRect pointInWindowRect = NSMakeRect(conf_pos.x, conf_pos.y, 0, 0);
  750. conf_pos = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin;
  751. conf_pos.y = CGDisplayBounds(CGMainDisplayID()).size.height - conf_pos.y;
  752. CGWarpMouseCursorPosition(conf_pos);
  753. // Save warp data
  754. DS_OSX->last_warp = [[NSProcessInfo processInfo] systemUptime];
  755. DisplayServerOSX::WarpEvent ev;
  756. ev.timestamp = DS_OSX->last_warp;
  757. ev.delta = delta;
  758. DS_OSX->warp_events.push_back(ev);
  759. }
  760. Ref<InputEventMouseMotion> mm;
  761. mm.instance();
  762. mm->set_window_id(window_id);
  763. mm->set_button_mask(DS_OSX->last_button_state);
  764. const Vector2i pos = _get_mouse_pos(wd, mpos);
  765. mm->set_position(pos);
  766. mm->set_pressure([event pressure]);
  767. if ([event subtype] == NSEventSubtypeTabletPoint) {
  768. const NSPoint p = [event tilt];
  769. mm->set_tilt(Vector2(p.x, p.y));
  770. }
  771. mm->set_global_position(pos);
  772. mm->set_speed(Input::get_singleton()->get_last_mouse_speed());
  773. const Vector2i relativeMotion = Vector2i(delta.x, delta.y) * DS_OSX->screen_get_max_scale();
  774. mm->set_relative(relativeMotion);
  775. _get_key_modifier_state([event modifierFlags], mm);
  776. Input::get_singleton()->set_mouse_position(wd.mouse_pos);
  777. Input::get_singleton()->accumulate_input_event(mm);
  778. }
  779. - (void)rightMouseDown:(NSEvent *)event {
  780. _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
  781. }
  782. - (void)rightMouseDragged:(NSEvent *)event {
  783. [self mouseMoved:event];
  784. }
  785. - (void)rightMouseUp:(NSEvent *)event {
  786. _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
  787. }
  788. - (void)otherMouseDown:(NSEvent *)event {
  789. if ((int)[event buttonNumber] == 2) {
  790. _mouseDownEvent(window_id, event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, true);
  791. } else if ((int)[event buttonNumber] == 3) {
  792. _mouseDownEvent(window_id, event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, true);
  793. } else if ((int)[event buttonNumber] == 4) {
  794. _mouseDownEvent(window_id, event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, true);
  795. } else {
  796. return;
  797. }
  798. }
  799. - (void)otherMouseDragged:(NSEvent *)event {
  800. [self mouseMoved:event];
  801. }
  802. - (void)otherMouseUp:(NSEvent *)event {
  803. if ((int)[event buttonNumber] == 2) {
  804. _mouseDownEvent(window_id, event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, false);
  805. } else if ((int)[event buttonNumber] == 3) {
  806. _mouseDownEvent(window_id, event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, false);
  807. } else if ((int)[event buttonNumber] == 4) {
  808. _mouseDownEvent(window_id, event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, false);
  809. } else {
  810. return;
  811. }
  812. }
  813. - (void)mouseExited:(NSEvent *)event {
  814. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  815. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  816. if (DS_OSX->mouse_mode != DisplayServer::MOUSE_MODE_CAPTURED) {
  817. DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_EXIT);
  818. }
  819. }
  820. - (void)mouseEntered:(NSEvent *)event {
  821. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  822. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  823. if (DS_OSX->mouse_mode != DisplayServer::MOUSE_MODE_CAPTURED) {
  824. DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_MOUSE_ENTER);
  825. }
  826. DisplayServer::CursorShape p_shape = DS_OSX->cursor_shape;
  827. DS_OSX->cursor_shape = DisplayServer::CURSOR_MAX;
  828. DS_OSX->cursor_set_shape(p_shape);
  829. }
  830. - (void)magnifyWithEvent:(NSEvent *)event {
  831. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  832. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  833. Ref<InputEventMagnifyGesture> ev;
  834. ev.instance();
  835. ev->set_window_id(window_id);
  836. _get_key_modifier_state([event modifierFlags], ev);
  837. ev->set_position(_get_mouse_pos(wd, [event locationInWindow]));
  838. ev->set_factor([event magnification] + 1.0);
  839. Input::get_singleton()->accumulate_input_event(ev);
  840. }
  841. - (void)viewDidChangeBackingProperties {
  842. // nothing left to do here
  843. }
  844. - (void)updateTrackingAreas {
  845. if (trackingArea != nil) {
  846. [self removeTrackingArea:trackingArea];
  847. [trackingArea release];
  848. }
  849. NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingCursorUpdate | NSTrackingInVisibleRect;
  850. trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil];
  851. [self addTrackingArea:trackingArea];
  852. [super updateTrackingAreas];
  853. }
  854. static bool isNumpadKey(unsigned int key) {
  855. static const unsigned int table[] = {
  856. 0x41, /* kVK_ANSI_KeypadDecimal */
  857. 0x43, /* kVK_ANSI_KeypadMultiply */
  858. 0x45, /* kVK_ANSI_KeypadPlus */
  859. 0x47, /* kVK_ANSI_KeypadClear */
  860. 0x4b, /* kVK_ANSI_KeypadDivide */
  861. 0x4c, /* kVK_ANSI_KeypadEnter */
  862. 0x4e, /* kVK_ANSI_KeypadMinus */
  863. 0x51, /* kVK_ANSI_KeypadEquals */
  864. 0x52, /* kVK_ANSI_Keypad0 */
  865. 0x53, /* kVK_ANSI_Keypad1 */
  866. 0x54, /* kVK_ANSI_Keypad2 */
  867. 0x55, /* kVK_ANSI_Keypad3 */
  868. 0x56, /* kVK_ANSI_Keypad4 */
  869. 0x57, /* kVK_ANSI_Keypad5 */
  870. 0x58, /* kVK_ANSI_Keypad6 */
  871. 0x59, /* kVK_ANSI_Keypad7 */
  872. 0x5b, /* kVK_ANSI_Keypad8 */
  873. 0x5c, /* kVK_ANSI_Keypad9 */
  874. 0x5f, /* kVK_JIS_KeypadComma */
  875. 0x00
  876. };
  877. for (int i = 0; table[i] != 0; i++) {
  878. if (key == table[i]) {
  879. return true;
  880. }
  881. }
  882. return false;
  883. }
  884. // Translates a OS X keycode to a Godot keycode
  885. //
  886. static int translateKey(unsigned int key) {
  887. // Keyboard symbol translation table
  888. static const unsigned int table[128] = {
  889. /* 00 */ KEY_A,
  890. /* 01 */ KEY_S,
  891. /* 02 */ KEY_D,
  892. /* 03 */ KEY_F,
  893. /* 04 */ KEY_H,
  894. /* 05 */ KEY_G,
  895. /* 06 */ KEY_Z,
  896. /* 07 */ KEY_X,
  897. /* 08 */ KEY_C,
  898. /* 09 */ KEY_V,
  899. /* 0a */ KEY_SECTION, /* ISO Section */
  900. /* 0b */ KEY_B,
  901. /* 0c */ KEY_Q,
  902. /* 0d */ KEY_W,
  903. /* 0e */ KEY_E,
  904. /* 0f */ KEY_R,
  905. /* 10 */ KEY_Y,
  906. /* 11 */ KEY_T,
  907. /* 12 */ KEY_1,
  908. /* 13 */ KEY_2,
  909. /* 14 */ KEY_3,
  910. /* 15 */ KEY_4,
  911. /* 16 */ KEY_6,
  912. /* 17 */ KEY_5,
  913. /* 18 */ KEY_EQUAL,
  914. /* 19 */ KEY_9,
  915. /* 1a */ KEY_7,
  916. /* 1b */ KEY_MINUS,
  917. /* 1c */ KEY_8,
  918. /* 1d */ KEY_0,
  919. /* 1e */ KEY_BRACERIGHT,
  920. /* 1f */ KEY_O,
  921. /* 20 */ KEY_U,
  922. /* 21 */ KEY_BRACELEFT,
  923. /* 22 */ KEY_I,
  924. /* 23 */ KEY_P,
  925. /* 24 */ KEY_ENTER,
  926. /* 25 */ KEY_L,
  927. /* 26 */ KEY_J,
  928. /* 27 */ KEY_APOSTROPHE,
  929. /* 28 */ KEY_K,
  930. /* 29 */ KEY_SEMICOLON,
  931. /* 2a */ KEY_BACKSLASH,
  932. /* 2b */ KEY_COMMA,
  933. /* 2c */ KEY_SLASH,
  934. /* 2d */ KEY_N,
  935. /* 2e */ KEY_M,
  936. /* 2f */ KEY_PERIOD,
  937. /* 30 */ KEY_TAB,
  938. /* 31 */ KEY_SPACE,
  939. /* 32 */ KEY_QUOTELEFT,
  940. /* 33 */ KEY_BACKSPACE,
  941. /* 34 */ KEY_UNKNOWN,
  942. /* 35 */ KEY_ESCAPE,
  943. /* 36 */ KEY_META,
  944. /* 37 */ KEY_META,
  945. /* 38 */ KEY_SHIFT,
  946. /* 39 */ KEY_CAPSLOCK,
  947. /* 3a */ KEY_ALT,
  948. /* 3b */ KEY_CONTROL,
  949. /* 3c */ KEY_SHIFT,
  950. /* 3d */ KEY_ALT,
  951. /* 3e */ KEY_CONTROL,
  952. /* 3f */ KEY_UNKNOWN, /* Function */
  953. /* 40 */ KEY_UNKNOWN, /* F17 */
  954. /* 41 */ KEY_KP_PERIOD,
  955. /* 42 */ KEY_UNKNOWN,
  956. /* 43 */ KEY_KP_MULTIPLY,
  957. /* 44 */ KEY_UNKNOWN,
  958. /* 45 */ KEY_KP_ADD,
  959. /* 46 */ KEY_UNKNOWN,
  960. /* 47 */ KEY_NUMLOCK, /* Really KeypadClear... */
  961. /* 48 */ KEY_VOLUMEUP, /* VolumeUp */
  962. /* 49 */ KEY_VOLUMEDOWN, /* VolumeDown */
  963. /* 4a */ KEY_VOLUMEMUTE, /* Mute */
  964. /* 4b */ KEY_KP_DIVIDE,
  965. /* 4c */ KEY_KP_ENTER,
  966. /* 4d */ KEY_UNKNOWN,
  967. /* 4e */ KEY_KP_SUBTRACT,
  968. /* 4f */ KEY_UNKNOWN, /* F18 */
  969. /* 50 */ KEY_UNKNOWN, /* F19 */
  970. /* 51 */ KEY_EQUAL, /* KeypadEqual */
  971. /* 52 */ KEY_KP_0,
  972. /* 53 */ KEY_KP_1,
  973. /* 54 */ KEY_KP_2,
  974. /* 55 */ KEY_KP_3,
  975. /* 56 */ KEY_KP_4,
  976. /* 57 */ KEY_KP_5,
  977. /* 58 */ KEY_KP_6,
  978. /* 59 */ KEY_KP_7,
  979. /* 5a */ KEY_UNKNOWN, /* F20 */
  980. /* 5b */ KEY_KP_8,
  981. /* 5c */ KEY_KP_9,
  982. /* 5d */ KEY_YEN, /* JIS Yen */
  983. /* 5e */ KEY_UNDERSCORE, /* JIS Underscore */
  984. /* 5f */ KEY_COMMA, /* JIS KeypadComma */
  985. /* 60 */ KEY_F5,
  986. /* 61 */ KEY_F6,
  987. /* 62 */ KEY_F7,
  988. /* 63 */ KEY_F3,
  989. /* 64 */ KEY_F8,
  990. /* 65 */ KEY_F9,
  991. /* 66 */ KEY_UNKNOWN, /* JIS Eisu */
  992. /* 67 */ KEY_F11,
  993. /* 68 */ KEY_UNKNOWN, /* JIS Kana */
  994. /* 69 */ KEY_F13,
  995. /* 6a */ KEY_F16,
  996. /* 6b */ KEY_F14,
  997. /* 6c */ KEY_UNKNOWN,
  998. /* 6d */ KEY_F10,
  999. /* 6e */ KEY_MENU,
  1000. /* 6f */ KEY_F12,
  1001. /* 70 */ KEY_UNKNOWN,
  1002. /* 71 */ KEY_F15,
  1003. /* 72 */ KEY_INSERT, /* Really Help... */
  1004. /* 73 */ KEY_HOME,
  1005. /* 74 */ KEY_PAGEUP,
  1006. /* 75 */ KEY_DELETE,
  1007. /* 76 */ KEY_F4,
  1008. /* 77 */ KEY_END,
  1009. /* 78 */ KEY_F2,
  1010. /* 79 */ KEY_PAGEDOWN,
  1011. /* 7a */ KEY_F1,
  1012. /* 7b */ KEY_LEFT,
  1013. /* 7c */ KEY_RIGHT,
  1014. /* 7d */ KEY_DOWN,
  1015. /* 7e */ KEY_UP,
  1016. /* 7f */ KEY_UNKNOWN,
  1017. };
  1018. if (key >= 128) {
  1019. return KEY_UNKNOWN;
  1020. }
  1021. return table[key];
  1022. }
  1023. struct _KeyCodeMap {
  1024. UniChar kchar;
  1025. int kcode;
  1026. };
  1027. static const _KeyCodeMap _keycodes[55] = {
  1028. { '`', KEY_QUOTELEFT },
  1029. { '~', KEY_ASCIITILDE },
  1030. { '0', KEY_0 },
  1031. { '1', KEY_1 },
  1032. { '2', KEY_2 },
  1033. { '3', KEY_3 },
  1034. { '4', KEY_4 },
  1035. { '5', KEY_5 },
  1036. { '6', KEY_6 },
  1037. { '7', KEY_7 },
  1038. { '8', KEY_8 },
  1039. { '9', KEY_9 },
  1040. { '-', KEY_MINUS },
  1041. { '_', KEY_UNDERSCORE },
  1042. { '=', KEY_EQUAL },
  1043. { '+', KEY_PLUS },
  1044. { 'q', KEY_Q },
  1045. { 'w', KEY_W },
  1046. { 'e', KEY_E },
  1047. { 'r', KEY_R },
  1048. { 't', KEY_T },
  1049. { 'y', KEY_Y },
  1050. { 'u', KEY_U },
  1051. { 'i', KEY_I },
  1052. { 'o', KEY_O },
  1053. { 'p', KEY_P },
  1054. { '[', KEY_BRACELEFT },
  1055. { ']', KEY_BRACERIGHT },
  1056. { '{', KEY_BRACELEFT },
  1057. { '}', KEY_BRACERIGHT },
  1058. { 'a', KEY_A },
  1059. { 's', KEY_S },
  1060. { 'd', KEY_D },
  1061. { 'f', KEY_F },
  1062. { 'g', KEY_G },
  1063. { 'h', KEY_H },
  1064. { 'j', KEY_J },
  1065. { 'k', KEY_K },
  1066. { 'l', KEY_L },
  1067. { ';', KEY_SEMICOLON },
  1068. { ':', KEY_COLON },
  1069. { '\'', KEY_APOSTROPHE },
  1070. { '\"', KEY_QUOTEDBL },
  1071. { '\\', KEY_BACKSLASH },
  1072. { '#', KEY_NUMBERSIGN },
  1073. { 'z', KEY_Z },
  1074. { 'x', KEY_X },
  1075. { 'c', KEY_C },
  1076. { 'v', KEY_V },
  1077. { 'b', KEY_B },
  1078. { 'n', KEY_N },
  1079. { 'm', KEY_M },
  1080. { ',', KEY_COMMA },
  1081. { '.', KEY_PERIOD },
  1082. { '/', KEY_SLASH }
  1083. };
  1084. static int remapKey(unsigned int key, unsigned int state) {
  1085. if (isNumpadKey(key)) {
  1086. return translateKey(key);
  1087. }
  1088. TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
  1089. if (!currentKeyboard) {
  1090. return translateKey(key);
  1091. }
  1092. CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
  1093. if (!layoutData) {
  1094. return translateKey(key);
  1095. }
  1096. const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
  1097. UInt32 keysDown = 0;
  1098. UniChar chars[4];
  1099. UniCharCount realLength;
  1100. OSStatus err = UCKeyTranslate(keyboardLayout,
  1101. key,
  1102. kUCKeyActionDisplay,
  1103. (state >> 8) & 0xFF,
  1104. LMGetKbdType(),
  1105. kUCKeyTranslateNoDeadKeysBit,
  1106. &keysDown,
  1107. sizeof(chars) / sizeof(chars[0]),
  1108. &realLength,
  1109. chars);
  1110. if (err != noErr) {
  1111. return translateKey(key);
  1112. }
  1113. for (unsigned int i = 0; i < 55; i++) {
  1114. if (_keycodes[i].kchar == chars[0]) {
  1115. return _keycodes[i].kcode;
  1116. }
  1117. }
  1118. return translateKey(key);
  1119. }
  1120. - (void)keyDown:(NSEvent *)event {
  1121. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  1122. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  1123. ignore_momentum_scroll = true;
  1124. // Ignore all input if IME input is in progress
  1125. if (!imeInputEventInProgress) {
  1126. NSString *characters = [event characters];
  1127. NSUInteger length = [characters length];
  1128. if (!wd.im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode], [event modifierFlags]))) {
  1129. // Fallback unicode character handler used if IME is not active
  1130. Char16String text;
  1131. text.resize([characters length] + 1);
  1132. [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
  1133. String u32text;
  1134. u32text.parse_utf16(text.ptr(), text.length());
  1135. for (int i = 0; i < u32text.length(); i++) {
  1136. const char32_t codepoint = u32text[i];
  1137. DisplayServerOSX::KeyEvent ke;
  1138. ke.window_id = window_id;
  1139. ke.osx_state = [event modifierFlags];
  1140. ke.pressed = true;
  1141. ke.echo = [event isARepeat];
  1142. ke.keycode = remapKey([event keyCode], [event modifierFlags]);
  1143. ke.physical_keycode = translateKey([event keyCode]);
  1144. ke.raw = true;
  1145. ke.unicode = codepoint;
  1146. _push_to_key_event_buffer(ke);
  1147. }
  1148. } else {
  1149. DisplayServerOSX::KeyEvent ke;
  1150. ke.window_id = window_id;
  1151. ke.osx_state = [event modifierFlags];
  1152. ke.pressed = true;
  1153. ke.echo = [event isARepeat];
  1154. ke.keycode = remapKey([event keyCode], [event modifierFlags]);
  1155. ke.physical_keycode = translateKey([event keyCode]);
  1156. ke.raw = false;
  1157. ke.unicode = 0;
  1158. _push_to_key_event_buffer(ke);
  1159. }
  1160. }
  1161. // Pass events to IME handler
  1162. if (wd.im_active) {
  1163. [self interpretKeyEvents:[NSArray arrayWithObject:event]];
  1164. }
  1165. }
  1166. - (void)flagsChanged:(NSEvent *)event {
  1167. ignore_momentum_scroll = true;
  1168. // Ignore all input if IME input is in progress
  1169. if (!imeInputEventInProgress) {
  1170. DisplayServerOSX::KeyEvent ke;
  1171. ke.window_id = window_id;
  1172. ke.echo = false;
  1173. ke.raw = true;
  1174. int key = [event keyCode];
  1175. int mod = [event modifierFlags];
  1176. if (key == 0x36 || key == 0x37) {
  1177. if (mod & NSEventModifierFlagCommand) {
  1178. mod &= ~NSEventModifierFlagCommand;
  1179. ke.pressed = true;
  1180. } else {
  1181. ke.pressed = false;
  1182. }
  1183. } else if (key == 0x38 || key == 0x3c) {
  1184. if (mod & NSEventModifierFlagShift) {
  1185. mod &= ~NSEventModifierFlagShift;
  1186. ke.pressed = true;
  1187. } else {
  1188. ke.pressed = false;
  1189. }
  1190. } else if (key == 0x3a || key == 0x3d) {
  1191. if (mod & NSEventModifierFlagOption) {
  1192. mod &= ~NSEventModifierFlagOption;
  1193. ke.pressed = true;
  1194. } else {
  1195. ke.pressed = false;
  1196. }
  1197. } else if (key == 0x3b || key == 0x3e) {
  1198. if (mod & NSEventModifierFlagControl) {
  1199. mod &= ~NSEventModifierFlagControl;
  1200. ke.pressed = true;
  1201. } else {
  1202. ke.pressed = false;
  1203. }
  1204. } else {
  1205. return;
  1206. }
  1207. ke.osx_state = mod;
  1208. ke.keycode = remapKey(key, mod);
  1209. ke.physical_keycode = translateKey(key);
  1210. ke.unicode = 0;
  1211. _push_to_key_event_buffer(ke);
  1212. }
  1213. }
  1214. - (void)keyUp:(NSEvent *)event {
  1215. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  1216. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  1217. // Ignore all input if IME input is in progress
  1218. if (!imeInputEventInProgress) {
  1219. NSString *characters = [event characters];
  1220. NSUInteger length = [characters length];
  1221. // Fallback unicode character handler used if IME is not active
  1222. if (!wd.im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode], [event modifierFlags]))) {
  1223. Char16String text;
  1224. text.resize([characters length] + 1);
  1225. [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
  1226. String u32text;
  1227. u32text.parse_utf16(text.ptr(), text.length());
  1228. for (int i = 0; i < u32text.length(); i++) {
  1229. const char32_t codepoint = u32text[i];
  1230. DisplayServerOSX::KeyEvent ke;
  1231. ke.window_id = window_id;
  1232. ke.osx_state = [event modifierFlags];
  1233. ke.pressed = false;
  1234. ke.echo = [event isARepeat];
  1235. ke.keycode = remapKey([event keyCode], [event modifierFlags]);
  1236. ke.physical_keycode = translateKey([event keyCode]);
  1237. ke.raw = true;
  1238. ke.unicode = codepoint;
  1239. _push_to_key_event_buffer(ke);
  1240. }
  1241. } else {
  1242. DisplayServerOSX::KeyEvent ke;
  1243. ke.window_id = window_id;
  1244. ke.osx_state = [event modifierFlags];
  1245. ke.pressed = false;
  1246. ke.echo = [event isARepeat];
  1247. ke.keycode = remapKey([event keyCode], [event modifierFlags]);
  1248. ke.physical_keycode = translateKey([event keyCode]);
  1249. ke.raw = true;
  1250. ke.unicode = 0;
  1251. _push_to_key_event_buffer(ke);
  1252. }
  1253. }
  1254. }
  1255. inline void sendScrollEvent(DisplayServer::WindowID window_id, int button, double factor, int modifierFlags) {
  1256. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  1257. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  1258. unsigned int mask = 1 << (button - 1);
  1259. Ref<InputEventMouseButton> sc;
  1260. sc.instance();
  1261. sc->set_window_id(window_id);
  1262. _get_key_modifier_state(modifierFlags, sc);
  1263. sc->set_button_index(button);
  1264. sc->set_factor(factor);
  1265. sc->set_pressed(true);
  1266. sc->set_position(wd.mouse_pos);
  1267. sc->set_global_position(wd.mouse_pos);
  1268. DS_OSX->last_button_state |= mask;
  1269. sc->set_button_mask(DS_OSX->last_button_state);
  1270. Input::get_singleton()->accumulate_input_event(sc);
  1271. sc.instance();
  1272. sc->set_window_id(window_id);
  1273. sc->set_button_index(button);
  1274. sc->set_factor(factor);
  1275. sc->set_pressed(false);
  1276. sc->set_position(wd.mouse_pos);
  1277. sc->set_global_position(wd.mouse_pos);
  1278. DS_OSX->last_button_state &= ~mask;
  1279. sc->set_button_mask(DS_OSX->last_button_state);
  1280. Input::get_singleton()->accumulate_input_event(sc);
  1281. }
  1282. inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy, int modifierFlags) {
  1283. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  1284. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  1285. Ref<InputEventPanGesture> pg;
  1286. pg.instance();
  1287. pg->set_window_id(window_id);
  1288. _get_key_modifier_state(modifierFlags, pg);
  1289. pg->set_position(wd.mouse_pos);
  1290. pg->set_delta(Vector2(-dx, -dy));
  1291. Input::get_singleton()->accumulate_input_event(pg);
  1292. }
  1293. - (void)scrollWheel:(NSEvent *)event {
  1294. ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
  1295. DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
  1296. double deltaX, deltaY;
  1297. _get_mouse_pos(wd, [event locationInWindow]);
  1298. deltaX = [event scrollingDeltaX];
  1299. deltaY = [event scrollingDeltaY];
  1300. if ([event hasPreciseScrollingDeltas]) {
  1301. deltaX *= 0.03;
  1302. deltaY *= 0.03;
  1303. }
  1304. if ([event momentumPhase] != NSEventPhaseNone) {
  1305. if (ignore_momentum_scroll) {
  1306. return;
  1307. }
  1308. } else {
  1309. ignore_momentum_scroll = false;
  1310. }
  1311. if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) {
  1312. sendPanEvent(window_id, deltaX, deltaY, [event modifierFlags]);
  1313. } else {
  1314. if (fabs(deltaX)) {
  1315. sendScrollEvent(window_id, 0 > deltaX ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
  1316. }
  1317. if (fabs(deltaY)) {
  1318. sendScrollEvent(window_id, 0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
  1319. }
  1320. }
  1321. }
  1322. @end
  1323. /*************************************************************************/
  1324. /* GodotWindow */
  1325. /*************************************************************************/
  1326. @interface GodotWindow : NSWindow {
  1327. }
  1328. @end
  1329. @implementation GodotWindow
  1330. - (BOOL)canBecomeKeyWindow {
  1331. // Required for NSBorderlessWindowMask windows
  1332. for (Map<DisplayServer::WindowID, DisplayServerOSX::WindowData>::Element *E = DS_OSX->windows.front(); E; E = E->next()) {
  1333. if (E->get().window_object == self) {
  1334. if (E->get().no_focus) {
  1335. return NO;
  1336. }
  1337. }
  1338. }
  1339. return YES;
  1340. }
  1341. - (BOOL)canBecomeMainWindow {
  1342. // Required for NSBorderlessWindowMask windows
  1343. for (Map<DisplayServer::WindowID, DisplayServerOSX::WindowData>::Element *E = DS_OSX->windows.front(); E; E = E->next()) {
  1344. if (E->get().window_object == self) {
  1345. if (E->get().no_focus) {
  1346. return NO;
  1347. }
  1348. }
  1349. }
  1350. return YES;
  1351. }
  1352. @end
  1353. /*************************************************************************/
  1354. /* DisplayServerOSX */
  1355. /*************************************************************************/
  1356. bool DisplayServerOSX::has_feature(Feature p_feature) const {
  1357. switch (p_feature) {
  1358. case FEATURE_GLOBAL_MENU:
  1359. case FEATURE_SUBWINDOWS:
  1360. //case FEATURE_TOUCHSCREEN:
  1361. case FEATURE_MOUSE:
  1362. case FEATURE_MOUSE_WARP:
  1363. case FEATURE_CLIPBOARD:
  1364. case FEATURE_CURSOR_SHAPE:
  1365. case FEATURE_CUSTOM_CURSOR_SHAPE:
  1366. case FEATURE_NATIVE_DIALOG:
  1367. //case FEATURE_CONSOLE_WINDOW:
  1368. case FEATURE_IME:
  1369. case FEATURE_WINDOW_TRANSPARENCY:
  1370. case FEATURE_HIDPI:
  1371. case FEATURE_ICON:
  1372. case FEATURE_NATIVE_ICON:
  1373. //case FEATURE_KEEP_SCREEN_ON:
  1374. case FEATURE_SWAP_BUFFERS:
  1375. return true;
  1376. default: {
  1377. }
  1378. }
  1379. return false;
  1380. }
  1381. String DisplayServerOSX::get_name() const {
  1382. return "OSX";
  1383. }
  1384. const NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) const {
  1385. const NSMenu *menu = NULL;
  1386. if (p_menu_root == "") {
  1387. // Main menu.x
  1388. menu = [NSApp mainMenu];
  1389. } else if (p_menu_root.to_lower() == "_dock") {
  1390. // macOS dock menu.
  1391. menu = dock_menu;
  1392. } else {
  1393. // Submenu.
  1394. if (submenu.has(p_menu_root)) {
  1395. menu = submenu[p_menu_root];
  1396. }
  1397. }
  1398. if (menu == apple_menu) {
  1399. // Do not allow to change Apple menu.
  1400. return NULL;
  1401. }
  1402. return menu;
  1403. }
  1404. NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) {
  1405. NSMenu *menu = NULL;
  1406. if (p_menu_root == "") {
  1407. // Main menu.
  1408. menu = [NSApp mainMenu];
  1409. } else if (p_menu_root.to_lower() == "_dock") {
  1410. // macOS dock menu.
  1411. menu = dock_menu;
  1412. } else {
  1413. // Submenu.
  1414. if (!submenu.has(p_menu_root)) {
  1415. NSMenu *n_menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:p_menu_root.utf8().get_data()]];
  1416. submenu[p_menu_root] = n_menu;
  1417. }
  1418. menu = submenu[p_menu_root];
  1419. }
  1420. if (menu == apple_menu) {
  1421. // Do not allow to change Apple menu.
  1422. return NULL;
  1423. }
  1424. return menu;
  1425. }
  1426. void DisplayServerOSX::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag) {
  1427. _THREAD_SAFE_METHOD_
  1428. NSMenu *menu = _get_menu_root(p_menu_root);
  1429. if (menu) {
  1430. NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""];
  1431. GlobalMenuItem *obj = [[[GlobalMenuItem alloc] init] autorelease];
  1432. obj->callback = p_callback;
  1433. obj->meta = p_tag;
  1434. obj->checkable = false;
  1435. [menu_item setRepresentedObject:obj];
  1436. }
  1437. }
  1438. void DisplayServerOSX::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag) {
  1439. _THREAD_SAFE_METHOD_
  1440. NSMenu *menu = _get_menu_root(p_menu_root);
  1441. if (menu) {
  1442. NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""];
  1443. GlobalMenuItem *obj = [[[GlobalMenuItem alloc] init] autorelease];
  1444. obj->callback = p_callback;
  1445. obj->meta = p_tag;
  1446. obj->checkable = true;
  1447. [menu_item setRepresentedObject:obj];
  1448. }
  1449. }
  1450. void DisplayServerOSX::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu) {
  1451. _THREAD_SAFE_METHOD_
  1452. NSMenu *menu = _get_menu_root(p_menu_root);
  1453. NSMenu *sub_menu = _get_menu_root(p_submenu);
  1454. if (menu && sub_menu) {
  1455. if (sub_menu == menu) {
  1456. ERR_PRINT("Can't set submenu to self!");
  1457. return;
  1458. }
  1459. if ([sub_menu supermenu]) {
  1460. ERR_PRINT("Can't set submenu to menu that is already a submenu of some other menu!");
  1461. return;
  1462. }
  1463. NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@""];
  1464. [menu setSubmenu:sub_menu forItem:menu_item];
  1465. }
  1466. }
  1467. void DisplayServerOSX::global_menu_add_separator(const String &p_menu_root) {
  1468. _THREAD_SAFE_METHOD_
  1469. NSMenu *menu = _get_menu_root(p_menu_root);
  1470. if (menu) {
  1471. [menu addItem:[NSMenuItem separatorItem]];
  1472. }
  1473. }
  1474. bool DisplayServerOSX::global_menu_is_item_checked(const String &p_menu_root, int p_idx) const {
  1475. _THREAD_SAFE_METHOD_
  1476. const NSMenu *menu = _get_menu_root(p_menu_root);
  1477. if (menu) {
  1478. const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1479. if (menu_item) {
  1480. return ([menu_item state] == NSControlStateValueOn);
  1481. }
  1482. }
  1483. return false;
  1484. }
  1485. bool DisplayServerOSX::global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const {
  1486. _THREAD_SAFE_METHOD_
  1487. const NSMenu *menu = _get_menu_root(p_menu_root);
  1488. if (menu) {
  1489. const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1490. if (menu_item) {
  1491. GlobalMenuItem *obj = [menu_item representedObject];
  1492. if (obj) {
  1493. return obj->checkable;
  1494. }
  1495. }
  1496. }
  1497. return false;
  1498. }
  1499. Callable DisplayServerOSX::global_menu_get_item_callback(const String &p_menu_root, int p_idx) {
  1500. _THREAD_SAFE_METHOD_
  1501. const NSMenu *menu = _get_menu_root(p_menu_root);
  1502. if (menu) {
  1503. const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1504. if (menu_item) {
  1505. GlobalMenuItem *obj = [menu_item representedObject];
  1506. if (obj) {
  1507. return obj->callback;
  1508. }
  1509. }
  1510. }
  1511. return Callable();
  1512. }
  1513. Variant DisplayServerOSX::global_menu_get_item_tag(const String &p_menu_root, int p_idx) {
  1514. _THREAD_SAFE_METHOD_
  1515. const NSMenu *menu = _get_menu_root(p_menu_root);
  1516. if (menu) {
  1517. const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1518. if (menu_item) {
  1519. GlobalMenuItem *obj = [menu_item representedObject];
  1520. if (obj) {
  1521. return obj->meta;
  1522. }
  1523. }
  1524. }
  1525. return Variant();
  1526. }
  1527. String DisplayServerOSX::global_menu_get_item_text(const String &p_menu_root, int p_idx) {
  1528. _THREAD_SAFE_METHOD_
  1529. const NSMenu *menu = _get_menu_root(p_menu_root);
  1530. if (menu) {
  1531. const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1532. if (menu_item) {
  1533. char *utfs = strdup([[menu_item title] UTF8String]);
  1534. String ret;
  1535. ret.parse_utf8(utfs);
  1536. free(utfs);
  1537. return ret;
  1538. }
  1539. }
  1540. return String();
  1541. }
  1542. String DisplayServerOSX::global_menu_get_item_submenu(const String &p_menu_root, int p_idx) {
  1543. _THREAD_SAFE_METHOD_
  1544. const NSMenu *menu = _get_menu_root(p_menu_root);
  1545. if (menu) {
  1546. const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1547. if (menu_item) {
  1548. const NSMenu *sub_menu = [menu_item submenu];
  1549. if (sub_menu) {
  1550. for (Map<String, NSMenu *>::Element *E = submenu.front(); E; E = E->next()) {
  1551. if (E->get() == sub_menu)
  1552. return E->key();
  1553. }
  1554. }
  1555. }
  1556. }
  1557. return String();
  1558. }
  1559. void DisplayServerOSX::global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) {
  1560. _THREAD_SAFE_METHOD_
  1561. NSMenu *menu = _get_menu_root(p_menu_root);
  1562. if (menu) {
  1563. if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
  1564. return;
  1565. }
  1566. NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1567. if (menu_item) {
  1568. if (p_checked) {
  1569. [menu_item setState:NSControlStateValueOn];
  1570. } else {
  1571. [menu_item setState:NSControlStateValueOff];
  1572. }
  1573. }
  1574. }
  1575. }
  1576. void DisplayServerOSX::global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) {
  1577. _THREAD_SAFE_METHOD_
  1578. NSMenu *menu = _get_menu_root(p_menu_root);
  1579. if (menu) {
  1580. if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
  1581. return;
  1582. }
  1583. NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1584. if (menu_item) {
  1585. GlobalMenuItem *obj = [menu_item representedObject];
  1586. obj->checkable = p_checkable;
  1587. }
  1588. }
  1589. }
  1590. void DisplayServerOSX::global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) {
  1591. _THREAD_SAFE_METHOD_
  1592. NSMenu *menu = _get_menu_root(p_menu_root);
  1593. if (menu) {
  1594. if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
  1595. return;
  1596. }
  1597. NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1598. if (menu_item) {
  1599. GlobalMenuItem *obj = [menu_item representedObject];
  1600. obj->callback = p_callback;
  1601. }
  1602. }
  1603. }
  1604. void DisplayServerOSX::global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) {
  1605. _THREAD_SAFE_METHOD_
  1606. NSMenu *menu = _get_menu_root(p_menu_root);
  1607. if (menu) {
  1608. if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
  1609. return;
  1610. }
  1611. NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1612. if (menu_item) {
  1613. GlobalMenuItem *obj = [menu_item representedObject];
  1614. obj->meta = p_tag;
  1615. }
  1616. }
  1617. }
  1618. void DisplayServerOSX::global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) {
  1619. _THREAD_SAFE_METHOD_
  1620. NSMenu *menu = _get_menu_root(p_menu_root);
  1621. if (menu) {
  1622. if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
  1623. return;
  1624. }
  1625. NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1626. if (menu_item) {
  1627. [menu_item setTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]];
  1628. }
  1629. }
  1630. }
  1631. void DisplayServerOSX::global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) {
  1632. _THREAD_SAFE_METHOD_
  1633. NSMenu *menu = _get_menu_root(p_menu_root);
  1634. NSMenu *sub_menu = _get_menu_root(p_submenu);
  1635. if (menu && sub_menu) {
  1636. if (sub_menu == menu) {
  1637. ERR_PRINT("Can't set submenu to self!");
  1638. return;
  1639. }
  1640. if ([sub_menu supermenu]) {
  1641. ERR_PRINT("Can't set submenu to menu that is already a submenu of some other menu!");
  1642. return;
  1643. }
  1644. if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
  1645. return;
  1646. }
  1647. NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
  1648. if (menu_item) {
  1649. [menu setSubmenu:sub_menu forItem:menu_item];
  1650. }
  1651. }
  1652. }
  1653. int DisplayServerOSX::global_menu_get_item_count(const String &p_menu_root) const {
  1654. _THREAD_SAFE_METHOD_
  1655. const NSMenu *menu = _get_menu_root(p_menu_root);
  1656. if (menu) {
  1657. return [menu numberOfItems];
  1658. } else {
  1659. return 0;
  1660. }
  1661. }
  1662. void DisplayServerOSX::global_menu_remove_item(const String &p_menu_root, int p_idx) {
  1663. _THREAD_SAFE_METHOD_
  1664. NSMenu *menu = _get_menu_root(p_menu_root);
  1665. if (menu) {
  1666. if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not delete Apple menu.
  1667. return;
  1668. }
  1669. [menu removeItemAtIndex:p_idx];
  1670. }
  1671. }
  1672. void DisplayServerOSX::global_menu_clear(const String &p_menu_root) {
  1673. _THREAD_SAFE_METHOD_
  1674. NSMenu *menu = _get_menu_root(p_menu_root);
  1675. if (menu) {
  1676. [menu removeAllItems];
  1677. // Restore Apple menu.
  1678. if (menu == [NSApp mainMenu]) {
  1679. NSMenuItem *menu_item = [menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
  1680. [menu setSubmenu:apple_menu forItem:menu_item];
  1681. }
  1682. }
  1683. }
  1684. void DisplayServerOSX::alert(const String &p_alert, const String &p_title) {
  1685. _THREAD_SAFE_METHOD_
  1686. NSAlert *window = [[NSAlert alloc] init];
  1687. NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
  1688. NSString *ns_alert = [NSString stringWithUTF8String:p_alert.utf8().get_data()];
  1689. [window addButtonWithTitle:@"OK"];
  1690. [window setMessageText:ns_title];
  1691. [window setInformativeText:ns_alert];
  1692. [window setAlertStyle:NSAlertStyleWarning];
  1693. id key_window = [[NSApplication sharedApplication] keyWindow];
  1694. [window runModal];
  1695. [window release];
  1696. if (key_window) {
  1697. [key_window makeKeyAndOrderFront:nil];
  1698. }
  1699. }
  1700. Error DisplayServerOSX::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) {
  1701. _THREAD_SAFE_METHOD_
  1702. NSAlert *window = [[NSAlert alloc] init];
  1703. NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
  1704. NSString *ns_description = [NSString stringWithUTF8String:p_description.utf8().get_data()];
  1705. for (int i = 0; i < p_buttons.size(); i++) {
  1706. NSString *ns_button = [NSString stringWithUTF8String:p_buttons[i].utf8().get_data()];
  1707. [window addButtonWithTitle:ns_button];
  1708. }
  1709. [window setMessageText:ns_title];
  1710. [window setInformativeText:ns_description];
  1711. [window setAlertStyle:NSAlertStyleInformational];
  1712. int button_pressed;
  1713. NSInteger ret = [window runModal];
  1714. if (ret == NSAlertFirstButtonReturn) {
  1715. button_pressed = 0;
  1716. } else if (ret == NSAlertSecondButtonReturn) {
  1717. button_pressed = 1;
  1718. } else if (ret == NSAlertThirdButtonReturn) {
  1719. button_pressed = 2;
  1720. } else {
  1721. button_pressed = 2 + (ret - NSAlertThirdButtonReturn);
  1722. }
  1723. if (!p_callback.is_null()) {
  1724. Variant button = button_pressed;
  1725. Variant *buttonp = &button;
  1726. Variant ret;
  1727. Callable::CallError ce;
  1728. p_callback.call((const Variant **)&buttonp, 1, ret, ce);
  1729. }
  1730. [window release];
  1731. return OK;
  1732. }
  1733. Error DisplayServerOSX::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) {
  1734. _THREAD_SAFE_METHOD_
  1735. NSAlert *window = [[NSAlert alloc] init];
  1736. NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
  1737. NSString *ns_description = [NSString stringWithUTF8String:p_description.utf8().get_data()];
  1738. NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 250, 30)];
  1739. [window addButtonWithTitle:@"OK"];
  1740. [window setMessageText:ns_title];
  1741. [window setInformativeText:ns_description];
  1742. [window setAlertStyle:NSAlertStyleInformational];
  1743. [input setStringValue:[NSString stringWithUTF8String:p_partial.utf8().get_data()]];
  1744. [window setAccessoryView:input];
  1745. [window runModal];
  1746. char *utfs = strdup([[input stringValue] UTF8String]);
  1747. String ret;
  1748. ret.parse_utf8(utfs);
  1749. free(utfs);
  1750. if (!p_callback.is_null()) {
  1751. Variant text = ret;
  1752. Variant *textp = &text;
  1753. Variant ret;
  1754. Callable::CallError ce;
  1755. p_callback.call((const Variant **)&textp, 1, ret, ce);
  1756. }
  1757. [window release];
  1758. return OK;
  1759. }
  1760. void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) {
  1761. _THREAD_SAFE_METHOD_
  1762. if (p_mode == mouse_mode) {
  1763. return;
  1764. }
  1765. if (p_mode == MOUSE_MODE_CAPTURED) {
  1766. // Apple Docs state that the display parameter is not used.
  1767. // "This parameter is not used. By default, you may pass kCGDirectMainDisplay."
  1768. // https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/Quartz_Services_Ref/Reference/reference.html
  1769. if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
  1770. CGDisplayHideCursor(kCGDirectMainDisplay);
  1771. }
  1772. CGAssociateMouseAndMouseCursorPosition(false);
  1773. WindowData &wd = windows[MAIN_WINDOW_ID];
  1774. const NSRect contentRect = [wd.window_view frame];
  1775. NSRect pointInWindowRect = NSMakeRect(contentRect.size.width / 2, contentRect.size.height / 2, 0, 0);
  1776. NSPoint pointOnScreen = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin;
  1777. CGPoint lMouseWarpPos = { pointOnScreen.x, CGDisplayBounds(CGMainDisplayID()).size.height - pointOnScreen.y };
  1778. CGWarpMouseCursorPosition(lMouseWarpPos);
  1779. } else if (p_mode == MOUSE_MODE_HIDDEN) {
  1780. if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
  1781. CGDisplayHideCursor(kCGDirectMainDisplay);
  1782. }
  1783. CGAssociateMouseAndMouseCursorPosition(true);
  1784. } else if (p_mode == MOUSE_MODE_CONFINED) {
  1785. CGDisplayShowCursor(kCGDirectMainDisplay);
  1786. CGAssociateMouseAndMouseCursorPosition(false);
  1787. } else {
  1788. CGDisplayShowCursor(kCGDirectMainDisplay);
  1789. CGAssociateMouseAndMouseCursorPosition(true);
  1790. }
  1791. last_warp = [[NSProcessInfo processInfo] systemUptime];
  1792. ignore_warp = true;
  1793. warp_events.clear();
  1794. mouse_mode = p_mode;
  1795. }
  1796. DisplayServer::MouseMode DisplayServerOSX::mouse_get_mode() const {
  1797. return mouse_mode;
  1798. }
  1799. void DisplayServerOSX::mouse_warp_to_position(const Point2i &p_to) {
  1800. _THREAD_SAFE_METHOD_
  1801. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  1802. last_mouse_pos = p_to;
  1803. } else {
  1804. WindowData &wd = windows[MAIN_WINDOW_ID];
  1805. //local point in window coords
  1806. const NSRect contentRect = [wd.window_view frame];
  1807. const float scale = screen_get_max_scale();
  1808. NSRect pointInWindowRect = NSMakeRect(p_to.x / scale, contentRect.size.height - (p_to.y / scale - 1), 0, 0);
  1809. NSPoint pointOnScreen = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin;
  1810. //point in scren coords
  1811. CGPoint lMouseWarpPos = { pointOnScreen.x, CGDisplayBounds(CGMainDisplayID()).size.height - pointOnScreen.y };
  1812. //do the warping
  1813. CGEventSourceRef lEventRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
  1814. CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0);
  1815. CGAssociateMouseAndMouseCursorPosition(false);
  1816. CGWarpMouseCursorPosition(lMouseWarpPos);
  1817. if (mouse_mode != MOUSE_MODE_CONFINED) {
  1818. CGAssociateMouseAndMouseCursorPosition(true);
  1819. }
  1820. }
  1821. }
  1822. Point2i DisplayServerOSX::mouse_get_position() const {
  1823. return last_mouse_pos;
  1824. }
  1825. Point2i DisplayServerOSX::mouse_get_absolute_position() const {
  1826. _THREAD_SAFE_METHOD_
  1827. const NSPoint mouse_pos = [NSEvent mouseLocation];
  1828. const float scale = screen_get_max_scale();
  1829. for (NSScreen *screen in [NSScreen screens]) {
  1830. NSRect frame = [screen frame];
  1831. if (NSMouseInRect(mouse_pos, frame, NO)) {
  1832. return Vector2i((int)mouse_pos.x, (int)-mouse_pos.y) * scale + _get_screens_origin();
  1833. }
  1834. }
  1835. return Vector2i();
  1836. }
  1837. int DisplayServerOSX::mouse_get_button_state() const {
  1838. return last_button_state;
  1839. }
  1840. void DisplayServerOSX::clipboard_set(const String &p_text) {
  1841. _THREAD_SAFE_METHOD_
  1842. NSString *copiedString = [NSString stringWithUTF8String:p_text.utf8().get_data()];
  1843. NSArray *copiedStringArray = [NSArray arrayWithObject:copiedString];
  1844. NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
  1845. [pasteboard clearContents];
  1846. [pasteboard writeObjects:copiedStringArray];
  1847. }
  1848. String DisplayServerOSX::clipboard_get() const {
  1849. _THREAD_SAFE_METHOD_
  1850. NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
  1851. NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
  1852. NSDictionary *options = [NSDictionary dictionary];
  1853. BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options];
  1854. if (!ok) {
  1855. return "";
  1856. }
  1857. NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options];
  1858. NSString *string = [objectsToPaste objectAtIndex:0];
  1859. char *utfs = strdup([string UTF8String]);
  1860. String ret;
  1861. ret.parse_utf8(utfs);
  1862. free(utfs);
  1863. return ret;
  1864. }
  1865. int DisplayServerOSX::get_screen_count() const {
  1866. _THREAD_SAFE_METHOD_
  1867. NSArray *screenArray = [NSScreen screens];
  1868. return [screenArray count];
  1869. }
  1870. // Returns the native top-left screen coordinate of the smallest rectangle
  1871. // that encompasses all screens. Needed in get_screen_position(),
  1872. // window_get_position, and window_set_position()
  1873. // to convert between OS X native screen coordinates and the ones expected by Godot
  1874. static bool displays_arrangement_dirty = true;
  1875. static bool displays_scale_dirty = true;
  1876. static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info) {
  1877. displays_arrangement_dirty = true;
  1878. displays_scale_dirty = true;
  1879. }
  1880. Point2i DisplayServerOSX::_get_screens_origin() const {
  1881. static Point2i origin;
  1882. if (displays_arrangement_dirty) {
  1883. origin = Point2i();
  1884. for (int i = 0; i < get_screen_count(); i++) {
  1885. Point2i position = _get_native_screen_position(i);
  1886. if (position.x < origin.x) {
  1887. origin.x = position.x;
  1888. }
  1889. if (position.y > origin.y) {
  1890. origin.y = position.y;
  1891. }
  1892. }
  1893. displays_arrangement_dirty = false;
  1894. }
  1895. return origin;
  1896. }
  1897. Point2i DisplayServerOSX::_get_native_screen_position(int p_screen) const {
  1898. NSArray *screenArray = [NSScreen screens];
  1899. if ((NSUInteger)p_screen < [screenArray count]) {
  1900. NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
  1901. // Return the top-left corner of the screen, for OS X the y starts at the bottom
  1902. return Point2i(nsrect.origin.x, nsrect.origin.y + nsrect.size.height) * screen_get_max_scale();
  1903. }
  1904. return Point2i();
  1905. }
  1906. Point2i DisplayServerOSX::screen_get_position(int p_screen) const {
  1907. _THREAD_SAFE_METHOD_
  1908. if (p_screen == SCREEN_OF_MAIN_WINDOW) {
  1909. p_screen = window_get_current_screen();
  1910. }
  1911. Point2i position = _get_native_screen_position(p_screen) - _get_screens_origin();
  1912. // OS X native y-coordinate relative to _get_screens_origin() is negative,
  1913. // Godot expects a positive value
  1914. position.y *= -1;
  1915. return position;
  1916. }
  1917. Size2i DisplayServerOSX::screen_get_size(int p_screen) const {
  1918. _THREAD_SAFE_METHOD_
  1919. if (p_screen == SCREEN_OF_MAIN_WINDOW) {
  1920. p_screen = window_get_current_screen();
  1921. }
  1922. NSArray *screenArray = [NSScreen screens];
  1923. if ((NSUInteger)p_screen < [screenArray count]) {
  1924. // Note: Use frame to get the whole screen size
  1925. NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame];
  1926. return Size2i(nsrect.size.width, nsrect.size.height) * screen_get_max_scale();
  1927. }
  1928. return Size2i();
  1929. }
  1930. int DisplayServerOSX::screen_get_dpi(int p_screen) const {
  1931. _THREAD_SAFE_METHOD_
  1932. if (p_screen == SCREEN_OF_MAIN_WINDOW) {
  1933. p_screen = window_get_current_screen();
  1934. }
  1935. NSArray *screenArray = [NSScreen screens];
  1936. if ((NSUInteger)p_screen < [screenArray count]) {
  1937. NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription];
  1938. const NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
  1939. const CGSize displayPhysicalSize = CGDisplayScreenSize([[description objectForKey:@"NSScreenNumber"] unsignedIntValue]);
  1940. float scale = [[screenArray objectAtIndex:p_screen] backingScaleFactor];
  1941. float den2 = (displayPhysicalSize.width / 25.4f) * (displayPhysicalSize.width / 25.4f) + (displayPhysicalSize.height / 25.4f) * (displayPhysicalSize.height / 25.4f);
  1942. if (den2 > 0.0f) {
  1943. return ceil(sqrt(displayPixelSize.width * displayPixelSize.width + displayPixelSize.height * displayPixelSize.height) / sqrt(den2) * scale);
  1944. }
  1945. }
  1946. return 72;
  1947. }
  1948. float DisplayServerOSX::screen_get_scale(int p_screen) const {
  1949. _THREAD_SAFE_METHOD_
  1950. if (p_screen == SCREEN_OF_MAIN_WINDOW) {
  1951. p_screen = window_get_current_screen();
  1952. }
  1953. if (OS::get_singleton()->is_hidpi_allowed()) {
  1954. NSArray *screenArray = [NSScreen screens];
  1955. if ((NSUInteger)p_screen < [screenArray count]) {
  1956. if ([[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) {
  1957. return fmax(1.0, [[screenArray objectAtIndex:p_screen] backingScaleFactor]);
  1958. }
  1959. }
  1960. }
  1961. return 1.f;
  1962. }
  1963. float DisplayServerOSX::screen_get_max_scale() const {
  1964. _THREAD_SAFE_METHOD_
  1965. static float scale = 1.f;
  1966. if (displays_scale_dirty) {
  1967. int screen_count = get_screen_count();
  1968. for (int i = 0; i < screen_count; i++) {
  1969. scale = fmax(scale, screen_get_scale(i));
  1970. }
  1971. displays_scale_dirty = false;
  1972. }
  1973. return scale;
  1974. }
  1975. Rect2i DisplayServerOSX::screen_get_usable_rect(int p_screen) const {
  1976. _THREAD_SAFE_METHOD_
  1977. if (p_screen == SCREEN_OF_MAIN_WINDOW) {
  1978. p_screen = window_get_current_screen();
  1979. }
  1980. NSArray *screenArray = [NSScreen screens];
  1981. if ((NSUInteger)p_screen < [screenArray count]) {
  1982. const float scale = screen_get_max_scale();
  1983. NSRect nsrect = [[screenArray objectAtIndex:p_screen] visibleFrame];
  1984. Point2i position = Point2i(nsrect.origin.x, nsrect.origin.y + nsrect.size.height) * scale - _get_screens_origin();
  1985. position.y *= -1;
  1986. Size2i size = Size2i(nsrect.size.width, nsrect.size.height) * scale;
  1987. return Rect2i(position, size);
  1988. }
  1989. return Rect2i();
  1990. }
  1991. Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const {
  1992. _THREAD_SAFE_METHOD_
  1993. Vector<int> ret;
  1994. for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
  1995. ret.push_back(E->key());
  1996. }
  1997. return ret;
  1998. }
  1999. DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
  2000. _THREAD_SAFE_METHOD_
  2001. WindowID id = _create_window(p_mode, p_rect);
  2002. for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
  2003. if (p_flags & (1 << i)) {
  2004. window_set_flag(WindowFlags(i), true, id);
  2005. }
  2006. }
  2007. return id;
  2008. }
  2009. void DisplayServerOSX::show_window(WindowID p_id) {
  2010. WindowData &wd = windows[p_id];
  2011. if (wd.no_focus) {
  2012. [wd.window_object orderFront:nil];
  2013. } else {
  2014. [wd.window_object makeKeyAndOrderFront:nil];
  2015. }
  2016. }
  2017. void DisplayServerOSX::_send_window_event(const WindowData &wd, WindowEvent p_event) {
  2018. _THREAD_SAFE_METHOD_
  2019. if (!wd.event_callback.is_null()) {
  2020. Variant event = int(p_event);
  2021. Variant *eventp = &event;
  2022. Variant ret;
  2023. Callable::CallError ce;
  2024. wd.event_callback.call((const Variant **)&eventp, 1, ret, ce);
  2025. }
  2026. }
  2027. DisplayServerOSX::WindowID DisplayServerOSX::_find_window_id(id p_window) {
  2028. for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
  2029. if (E->get().window_object == p_window) {
  2030. return E->key();
  2031. }
  2032. }
  2033. return INVALID_WINDOW_ID;
  2034. }
  2035. void DisplayServerOSX::_update_window(WindowData p_wd) {
  2036. bool borderless_full = false;
  2037. if (p_wd.borderless) {
  2038. NSRect frameRect = [p_wd.window_object frame];
  2039. NSRect screenRect = [[p_wd.window_object screen] frame];
  2040. // Check if our window covers up the screen
  2041. if (frameRect.origin.x <= screenRect.origin.x && frameRect.origin.y <= frameRect.origin.y &&
  2042. frameRect.size.width >= screenRect.size.width && frameRect.size.height >= screenRect.size.height) {
  2043. borderless_full = true;
  2044. }
  2045. }
  2046. if (borderless_full) {
  2047. // If the window covers up the screen set the level to above the main menu and hide on deactivate
  2048. [p_wd.window_object setLevel:NSMainMenuWindowLevel + 1];
  2049. [p_wd.window_object setHidesOnDeactivate:YES];
  2050. } else {
  2051. // Reset these when our window is not a borderless window that covers up the screen
  2052. if (p_wd.on_top) {
  2053. [p_wd.window_object setLevel:NSFloatingWindowLevel];
  2054. } else {
  2055. [p_wd.window_object setLevel:NSNormalWindowLevel];
  2056. }
  2057. [p_wd.window_object setHidesOnDeactivate:NO];
  2058. }
  2059. }
  2060. void DisplayServerOSX::delete_sub_window(WindowID p_id) {
  2061. _THREAD_SAFE_METHOD_
  2062. ERR_FAIL_COND(!windows.has(p_id));
  2063. ERR_FAIL_COND_MSG(p_id == MAIN_WINDOW_ID, "Main window can't be deleted");
  2064. WindowData &wd = windows[p_id];
  2065. [wd.window_object setContentView:nil];
  2066. [wd.window_object close];
  2067. }
  2068. void DisplayServerOSX::window_set_title(const String &p_title, WindowID p_window) {
  2069. _THREAD_SAFE_METHOD_
  2070. ERR_FAIL_COND(!windows.has(p_window));
  2071. WindowData &wd = windows[p_window];
  2072. [wd.window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]];
  2073. }
  2074. void DisplayServerOSX::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
  2075. _THREAD_SAFE_METHOD_
  2076. ERR_FAIL_COND(!windows.has(p_window));
  2077. WindowData &wd = windows[p_window];
  2078. wd.mpath = p_region;
  2079. }
  2080. void DisplayServerOSX::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
  2081. _THREAD_SAFE_METHOD_
  2082. ERR_FAIL_COND(!windows.has(p_window));
  2083. WindowData &wd = windows[p_window];
  2084. wd.rect_changed_callback = p_callable;
  2085. }
  2086. void DisplayServerOSX::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
  2087. _THREAD_SAFE_METHOD_
  2088. ERR_FAIL_COND(!windows.has(p_window));
  2089. WindowData &wd = windows[p_window];
  2090. wd.event_callback = p_callable;
  2091. }
  2092. void DisplayServerOSX::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) {
  2093. _THREAD_SAFE_METHOD_
  2094. ERR_FAIL_COND(!windows.has(p_window));
  2095. WindowData &wd = windows[p_window];
  2096. wd.input_event_callback = p_callable;
  2097. }
  2098. void DisplayServerOSX::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) {
  2099. _THREAD_SAFE_METHOD_
  2100. ERR_FAIL_COND(!windows.has(p_window));
  2101. WindowData &wd = windows[p_window];
  2102. wd.input_text_callback = p_callable;
  2103. }
  2104. void DisplayServerOSX::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) {
  2105. _THREAD_SAFE_METHOD_
  2106. ERR_FAIL_COND(!windows.has(p_window));
  2107. WindowData &wd = windows[p_window];
  2108. wd.drop_files_callback = p_callable;
  2109. }
  2110. int DisplayServerOSX::window_get_current_screen(WindowID p_window) const {
  2111. _THREAD_SAFE_METHOD_
  2112. ERR_FAIL_COND_V(!windows.has(p_window), -1);
  2113. const WindowData &wd = windows[p_window];
  2114. const NSUInteger index = [[NSScreen screens] indexOfObject:[wd.window_object screen]];
  2115. return (index == NSNotFound) ? 0 : index;
  2116. }
  2117. void DisplayServerOSX::window_set_current_screen(int p_screen, WindowID p_window) {
  2118. _THREAD_SAFE_METHOD_
  2119. Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
  2120. window_set_position(wpos + screen_get_position(p_screen), p_window);
  2121. }
  2122. void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent) {
  2123. _THREAD_SAFE_METHOD_
  2124. ERR_FAIL_COND(p_window == p_parent);
  2125. ERR_FAIL_COND(!windows.has(p_window));
  2126. WindowData &wd_window = windows[p_window];
  2127. ERR_FAIL_COND(wd_window.transient_parent == p_parent);
  2128. ERR_FAIL_COND_MSG(wd_window.on_top, "Windows with the 'on top' can't become transient.");
  2129. if (p_parent == INVALID_WINDOW_ID) {
  2130. //remove transient
  2131. ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID);
  2132. ERR_FAIL_COND(!windows.has(wd_window.transient_parent));
  2133. WindowData &wd_parent = windows[wd_window.transient_parent];
  2134. wd_window.transient_parent = INVALID_WINDOW_ID;
  2135. wd_parent.transient_children.erase(p_window);
  2136. [wd_parent.window_object removeChildWindow:wd_window.window_object];
  2137. } else {
  2138. ERR_FAIL_COND(!windows.has(p_parent));
  2139. ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
  2140. WindowData &wd_parent = windows[p_parent];
  2141. wd_window.transient_parent = p_parent;
  2142. wd_parent.transient_children.insert(p_window);
  2143. [wd_parent.window_object addChildWindow:wd_window.window_object ordered:NSWindowAbove];
  2144. }
  2145. }
  2146. Point2i DisplayServerOSX::window_get_position(WindowID p_window) const {
  2147. _THREAD_SAFE_METHOD_
  2148. ERR_FAIL_COND_V(!windows.has(p_window), Point2i());
  2149. const WindowData &wd = windows[p_window];
  2150. NSRect nsrect = [wd.window_object frame];
  2151. Point2i pos;
  2152. // Return the position of the top-left corner, for OS X the y starts at the bottom
  2153. const float scale = screen_get_max_scale();
  2154. pos.x = nsrect.origin.x;
  2155. pos.y = (nsrect.origin.y + nsrect.size.height);
  2156. pos *= scale;
  2157. pos -= _get_screens_origin();
  2158. // OS X native y-coordinate relative to _get_screens_origin() is negative,
  2159. // Godot expects a positive value
  2160. pos.y *= -1;
  2161. return pos;
  2162. }
  2163. void DisplayServerOSX::window_set_position(const Point2i &p_position, WindowID p_window) {
  2164. _THREAD_SAFE_METHOD_
  2165. ERR_FAIL_COND(!windows.has(p_window));
  2166. WindowData &wd = windows[p_window];
  2167. Point2i position = p_position;
  2168. // OS X native y-coordinate relative to _get_screens_origin() is negative,
  2169. // Godot passes a positive value
  2170. position.y *= -1;
  2171. position += _get_screens_origin();
  2172. position /= screen_get_max_scale();
  2173. [wd.window_object setFrameTopLeftPoint:NSMakePoint(position.x, position.y)];
  2174. _update_window(wd);
  2175. _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
  2176. }
  2177. void DisplayServerOSX::window_set_max_size(const Size2i p_size, WindowID p_window) {
  2178. _THREAD_SAFE_METHOD_
  2179. ERR_FAIL_COND(!windows.has(p_window));
  2180. WindowData &wd = windows[p_window];
  2181. if ((p_size != Size2i()) && ((p_size.x < wd.min_size.x) || (p_size.y < wd.min_size.y))) {
  2182. ERR_PRINT("Maximum window size can't be smaller than minimum window size!");
  2183. return;
  2184. }
  2185. wd.max_size = p_size;
  2186. if ((wd.max_size != Size2i()) && !wd.fullscreen) {
  2187. Size2i size = wd.max_size / screen_get_max_scale();
  2188. [wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
  2189. } else {
  2190. [wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
  2191. }
  2192. }
  2193. Size2i DisplayServerOSX::window_get_max_size(WindowID p_window) const {
  2194. _THREAD_SAFE_METHOD_
  2195. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  2196. const WindowData &wd = windows[p_window];
  2197. return wd.max_size;
  2198. }
  2199. void DisplayServerOSX::window_set_min_size(const Size2i p_size, WindowID p_window) {
  2200. _THREAD_SAFE_METHOD_
  2201. ERR_FAIL_COND(!windows.has(p_window));
  2202. WindowData &wd = windows[p_window];
  2203. if ((p_size != Size2i()) && (wd.max_size != Size2i()) && ((p_size.x > wd.max_size.x) || (p_size.y > wd.max_size.y))) {
  2204. ERR_PRINT("Minimum window size can't be larger than maximum window size!");
  2205. return;
  2206. }
  2207. wd.min_size = p_size;
  2208. if ((wd.min_size != Size2i()) && !wd.fullscreen) {
  2209. Size2i size = wd.min_size / screen_get_max_scale();
  2210. [wd.window_object setContentMinSize:NSMakeSize(size.x, size.y)];
  2211. } else {
  2212. [wd.window_object setContentMinSize:NSMakeSize(0, 0)];
  2213. }
  2214. }
  2215. Size2i DisplayServerOSX::window_get_min_size(WindowID p_window) const {
  2216. _THREAD_SAFE_METHOD_
  2217. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  2218. const WindowData &wd = windows[p_window];
  2219. return wd.min_size;
  2220. }
  2221. void DisplayServerOSX::window_set_size(const Size2i p_size, WindowID p_window) {
  2222. _THREAD_SAFE_METHOD_
  2223. ERR_FAIL_COND(!windows.has(p_window));
  2224. WindowData &wd = windows[p_window];
  2225. Size2i size = p_size / screen_get_max_scale();
  2226. NSPoint top_left;
  2227. NSRect old_frame = [wd.window_object frame];
  2228. top_left.x = old_frame.origin.x;
  2229. top_left.y = NSMaxY(old_frame);
  2230. NSRect new_frame = NSMakeRect(0, 0, size.x, size.y);
  2231. new_frame = [wd.window_object frameRectForContentRect:new_frame];
  2232. new_frame.origin.x = top_left.x;
  2233. new_frame.origin.y = top_left.y - new_frame.size.height;
  2234. [wd.window_object setFrame:new_frame display:YES];
  2235. _update_window(wd);
  2236. }
  2237. Size2i DisplayServerOSX::window_get_size(WindowID p_window) const {
  2238. _THREAD_SAFE_METHOD_
  2239. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  2240. const WindowData &wd = windows[p_window];
  2241. return wd.size;
  2242. }
  2243. Size2i DisplayServerOSX::window_get_real_size(WindowID p_window) const {
  2244. _THREAD_SAFE_METHOD_
  2245. ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
  2246. const WindowData &wd = windows[p_window];
  2247. NSRect frame = [wd.window_object frame];
  2248. return Size2i(frame.size.width, frame.size.height) * screen_get_max_scale();
  2249. }
  2250. bool DisplayServerOSX::window_is_maximize_allowed(WindowID p_window) const {
  2251. return true;
  2252. }
  2253. void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window) {
  2254. ERR_FAIL_COND(!windows.has(p_window));
  2255. WindowData &wd = windows[p_window];
  2256. if (!OS_OSX::get_singleton()->is_layered_allowed()) {
  2257. return;
  2258. }
  2259. if (wd.layered_window != p_enabled) {
  2260. if (p_enabled) {
  2261. [wd.window_object setBackgroundColor:[NSColor clearColor]];
  2262. [wd.window_object setOpaque:NO];
  2263. [wd.window_object setHasShadow:NO];
  2264. CALayer *layer = [wd.window_view layer];
  2265. if (layer) {
  2266. [layer setOpaque:NO];
  2267. }
  2268. #if defined(VULKAN_ENABLED)
  2269. if (rendering_driver == "vulkan") {
  2270. //TODO - implement transparency for Vulkan
  2271. }
  2272. #endif
  2273. #if defined(OPENGL_ENABLED)
  2274. if (rendering_driver == "opengl_es") {
  2275. //TODO - reimplement OpenGLES
  2276. }
  2277. #endif
  2278. wd.layered_window = true;
  2279. } else {
  2280. [wd.window_object setBackgroundColor:[NSColor colorWithCalibratedWhite:1 alpha:1]];
  2281. [wd.window_object setOpaque:YES];
  2282. [wd.window_object setHasShadow:YES];
  2283. CALayer *layer = [wd.window_view layer];
  2284. if (layer) {
  2285. [layer setOpaque:YES];
  2286. }
  2287. #if defined(VULKAN_ENABLED)
  2288. if (rendering_driver == "vulkan") {
  2289. //TODO - implement transparency for Vulkan
  2290. }
  2291. #endif
  2292. #if defined(OPENGL_ENABLED)
  2293. if (rendering_driver == "opengl_es") {
  2294. //TODO - reimplement OpenGLES
  2295. }
  2296. #endif
  2297. wd.layered_window = false;
  2298. }
  2299. #if defined(OPENGL_ENABLED)
  2300. if (rendering_driver == "opengl_es") {
  2301. //TODO - reimplement OpenGLES
  2302. }
  2303. #endif
  2304. #if defined(VULKAN_ENABLED)
  2305. if (rendering_driver == "vulkan") {
  2306. //TODO - implement transparency for Vulkan
  2307. }
  2308. #endif
  2309. NSRect frameRect = [wd.window_object frame];
  2310. [wd.window_object setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:YES];
  2311. [wd.window_object setFrame:frameRect display:YES];
  2312. }
  2313. }
  2314. void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) {
  2315. _THREAD_SAFE_METHOD_
  2316. ERR_FAIL_COND(!windows.has(p_window));
  2317. WindowData &wd = windows[p_window];
  2318. WindowMode old_mode = window_get_mode(p_window);
  2319. if (old_mode == p_mode) {
  2320. return; // do nothing
  2321. }
  2322. switch (old_mode) {
  2323. case WINDOW_MODE_WINDOWED: {
  2324. //do nothing
  2325. } break;
  2326. case WINDOW_MODE_MINIMIZED: {
  2327. [wd.window_object deminiaturize:nil];
  2328. } break;
  2329. case WINDOW_MODE_FULLSCREEN: {
  2330. if (wd.layered_window) {
  2331. _set_window_per_pixel_transparency_enabled(true, p_window);
  2332. }
  2333. if (wd.resize_disabled) { //restore resize disabled
  2334. [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable];
  2335. }
  2336. if (wd.min_size != Size2i()) {
  2337. Size2i size = wd.min_size / screen_get_max_scale();
  2338. [wd.window_object setContentMinSize:NSMakeSize(size.x, size.y)];
  2339. }
  2340. if (wd.max_size != Size2i()) {
  2341. Size2i size = wd.max_size / screen_get_max_scale();
  2342. [wd.window_object setContentMaxSize:NSMakeSize(size.x, size.y)];
  2343. }
  2344. [wd.window_object toggleFullScreen:nil];
  2345. wd.fullscreen = false;
  2346. } break;
  2347. case WINDOW_MODE_MAXIMIZED: {
  2348. if ([wd.window_object isZoomed]) {
  2349. [wd.window_object zoom:nil];
  2350. }
  2351. } break;
  2352. }
  2353. switch (p_mode) {
  2354. case WINDOW_MODE_WINDOWED: {
  2355. //do nothing
  2356. } break;
  2357. case WINDOW_MODE_MINIMIZED: {
  2358. [wd.window_object performMiniaturize:nil];
  2359. } break;
  2360. case WINDOW_MODE_FULLSCREEN: {
  2361. if (wd.layered_window)
  2362. _set_window_per_pixel_transparency_enabled(false, p_window);
  2363. if (wd.resize_disabled) //fullscreen window should be resizable to work
  2364. [wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskResizable];
  2365. [wd.window_object setContentMinSize:NSMakeSize(0, 0)];
  2366. [wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
  2367. [wd.window_object toggleFullScreen:nil];
  2368. wd.fullscreen = true;
  2369. } break;
  2370. case WINDOW_MODE_MAXIMIZED: {
  2371. if (![wd.window_object isZoomed]) {
  2372. [wd.window_object zoom:nil];
  2373. }
  2374. } break;
  2375. }
  2376. }
  2377. DisplayServer::WindowMode DisplayServerOSX::window_get_mode(WindowID p_window) const {
  2378. _THREAD_SAFE_METHOD_
  2379. ERR_FAIL_COND_V(!windows.has(p_window), WINDOW_MODE_WINDOWED);
  2380. const WindowData &wd = windows[p_window];
  2381. if (wd.fullscreen) { //if fullscreen, it's not in another mode
  2382. return WINDOW_MODE_FULLSCREEN;
  2383. }
  2384. if ([wd.window_object isZoomed] && !wd.resize_disabled) {
  2385. return WINDOW_MODE_MAXIMIZED;
  2386. }
  2387. if ([wd.window_object respondsToSelector:@selector(isMiniaturized)]) {
  2388. if ([wd.window_object isMiniaturized]) {
  2389. return WINDOW_MODE_MINIMIZED;
  2390. }
  2391. }
  2392. // all other discarded, return windowed.
  2393. return WINDOW_MODE_WINDOWED;
  2394. }
  2395. void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
  2396. _THREAD_SAFE_METHOD_
  2397. ERR_FAIL_COND(!windows.has(p_window));
  2398. WindowData &wd = windows[p_window];
  2399. switch (p_flag) {
  2400. case WINDOW_FLAG_RESIZE_DISABLED: {
  2401. wd.resize_disabled = p_enabled;
  2402. if (wd.fullscreen) { //fullscreen window should be resizable, style will be applied on exiting fs
  2403. return;
  2404. }
  2405. if (p_enabled) {
  2406. [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable];
  2407. } else {
  2408. [wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskResizable];
  2409. }
  2410. } break;
  2411. case WINDOW_FLAG_BORDERLESS: {
  2412. // OrderOut prevents a lose focus bug with the window
  2413. if ([wd.window_object isVisible]) {
  2414. [wd.window_object orderOut:nil];
  2415. }
  2416. wd.borderless = p_enabled;
  2417. if (p_enabled) {
  2418. [wd.window_object setStyleMask:NSWindowStyleMaskBorderless];
  2419. } else {
  2420. if (wd.layered_window)
  2421. _set_window_per_pixel_transparency_enabled(false, p_window);
  2422. [wd.window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (wd.resize_disabled ? 0 : NSWindowStyleMaskResizable)];
  2423. // Force update of the window styles
  2424. NSRect frameRect = [wd.window_object frame];
  2425. [wd.window_object setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:NO];
  2426. [wd.window_object setFrame:frameRect display:NO];
  2427. }
  2428. _update_window(wd);
  2429. if ([wd.window_object isVisible]) {
  2430. if (wd.no_focus) {
  2431. [wd.window_object orderFront:nil];
  2432. } else {
  2433. [wd.window_object makeKeyAndOrderFront:nil];
  2434. }
  2435. }
  2436. } break;
  2437. case WINDOW_FLAG_ALWAYS_ON_TOP: {
  2438. wd.on_top = p_enabled;
  2439. if (p_enabled) {
  2440. [wd.window_object setLevel:NSFloatingWindowLevel];
  2441. } else {
  2442. [wd.window_object setLevel:NSNormalWindowLevel];
  2443. }
  2444. } break;
  2445. case WINDOW_FLAG_TRANSPARENT: {
  2446. wd.layered_window = p_enabled;
  2447. if (p_enabled) {
  2448. [wd.window_object setStyleMask:NSWindowStyleMaskBorderless]; // force borderless
  2449. } else if (!wd.borderless) {
  2450. [wd.window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (wd.resize_disabled ? 0 : NSWindowStyleMaskResizable)];
  2451. }
  2452. _set_window_per_pixel_transparency_enabled(p_enabled, p_window);
  2453. } break;
  2454. case WINDOW_FLAG_NO_FOCUS: {
  2455. wd.no_focus = p_enabled;
  2456. } break;
  2457. default: {
  2458. }
  2459. }
  2460. }
  2461. bool DisplayServerOSX::window_get_flag(WindowFlags p_flag, WindowID p_window) const {
  2462. _THREAD_SAFE_METHOD_
  2463. ERR_FAIL_COND_V(!windows.has(p_window), false);
  2464. const WindowData &wd = windows[p_window];
  2465. switch (p_flag) {
  2466. case WINDOW_FLAG_RESIZE_DISABLED: {
  2467. return wd.resize_disabled;
  2468. } break;
  2469. case WINDOW_FLAG_BORDERLESS: {
  2470. return [wd.window_object styleMask] == NSWindowStyleMaskBorderless;
  2471. } break;
  2472. case WINDOW_FLAG_ALWAYS_ON_TOP: {
  2473. return [wd.window_object level] == NSFloatingWindowLevel;
  2474. } break;
  2475. case WINDOW_FLAG_TRANSPARENT: {
  2476. return wd.layered_window;
  2477. } break;
  2478. case WINDOW_FLAG_NO_FOCUS: {
  2479. return wd.no_focus;
  2480. } break;
  2481. default: {
  2482. }
  2483. }
  2484. return false;
  2485. }
  2486. void DisplayServerOSX::window_request_attention(WindowID p_window) {
  2487. // It's app global, ignore window id.
  2488. [NSApp requestUserAttention:NSCriticalRequest];
  2489. }
  2490. void DisplayServerOSX::window_move_to_foreground(WindowID p_window) {
  2491. _THREAD_SAFE_METHOD_
  2492. ERR_FAIL_COND(!windows.has(p_window));
  2493. const WindowData &wd = windows[p_window];
  2494. [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
  2495. if (wd.no_focus) {
  2496. [wd.window_object orderFront:nil];
  2497. } else {
  2498. [wd.window_object makeKeyAndOrderFront:nil];
  2499. }
  2500. }
  2501. bool DisplayServerOSX::window_can_draw(WindowID p_window) const {
  2502. return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED;
  2503. }
  2504. bool DisplayServerOSX::can_any_window_draw() const {
  2505. _THREAD_SAFE_METHOD_
  2506. for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
  2507. if (window_get_mode(E->key()) != WINDOW_MODE_MINIMIZED) {
  2508. return true;
  2509. }
  2510. }
  2511. return false;
  2512. }
  2513. void DisplayServerOSX::window_set_ime_active(const bool p_active, WindowID p_window) {
  2514. _THREAD_SAFE_METHOD_
  2515. ERR_FAIL_COND(!windows.has(p_window));
  2516. WindowData &wd = windows[p_window];
  2517. wd.im_active = p_active;
  2518. if (!p_active) {
  2519. [wd.window_view cancelComposition];
  2520. }
  2521. }
  2522. void DisplayServerOSX::window_set_ime_position(const Point2i &p_pos, WindowID p_window) {
  2523. _THREAD_SAFE_METHOD_
  2524. ERR_FAIL_COND(!windows.has(p_window));
  2525. WindowData &wd = windows[p_window];
  2526. wd.im_position = p_pos;
  2527. }
  2528. bool DisplayServerOSX::get_swap_cancel_ok() {
  2529. return false;
  2530. }
  2531. void DisplayServerOSX::cursor_set_shape(CursorShape p_shape) {
  2532. _THREAD_SAFE_METHOD_
  2533. ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
  2534. if (cursor_shape == p_shape) {
  2535. return;
  2536. }
  2537. if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) {
  2538. cursor_shape = p_shape;
  2539. return;
  2540. }
  2541. if (cursors[p_shape] != NULL) {
  2542. [cursors[p_shape] set];
  2543. } else {
  2544. switch (p_shape) {
  2545. case CURSOR_ARROW:
  2546. [[NSCursor arrowCursor] set];
  2547. break;
  2548. case CURSOR_IBEAM:
  2549. [[NSCursor IBeamCursor] set];
  2550. break;
  2551. case CURSOR_POINTING_HAND:
  2552. [[NSCursor pointingHandCursor] set];
  2553. break;
  2554. case CURSOR_CROSS:
  2555. [[NSCursor crosshairCursor] set];
  2556. break;
  2557. case CURSOR_WAIT:
  2558. [[NSCursor arrowCursor] set];
  2559. break;
  2560. case CURSOR_BUSY:
  2561. [[NSCursor arrowCursor] set];
  2562. break;
  2563. case CURSOR_DRAG:
  2564. [[NSCursor closedHandCursor] set];
  2565. break;
  2566. case CURSOR_CAN_DROP:
  2567. [[NSCursor openHandCursor] set];
  2568. break;
  2569. case CURSOR_FORBIDDEN:
  2570. [[NSCursor operationNotAllowedCursor] set];
  2571. break;
  2572. case CURSOR_VSIZE:
  2573. [_cursorFromSelector(@selector(_windowResizeNorthSouthCursor), @selector(resizeUpDownCursor)) set];
  2574. break;
  2575. case CURSOR_HSIZE:
  2576. [_cursorFromSelector(@selector(_windowResizeEastWestCursor), @selector(resizeLeftRightCursor)) set];
  2577. break;
  2578. case CURSOR_BDIAGSIZE:
  2579. [_cursorFromSelector(@selector(_windowResizeNorthEastSouthWestCursor)) set];
  2580. break;
  2581. case CURSOR_FDIAGSIZE:
  2582. [_cursorFromSelector(@selector(_windowResizeNorthWestSouthEastCursor)) set];
  2583. break;
  2584. case CURSOR_MOVE:
  2585. [[NSCursor arrowCursor] set];
  2586. break;
  2587. case CURSOR_VSPLIT:
  2588. [[NSCursor resizeUpDownCursor] set];
  2589. break;
  2590. case CURSOR_HSPLIT:
  2591. [[NSCursor resizeLeftRightCursor] set];
  2592. break;
  2593. case CURSOR_HELP:
  2594. [_cursorFromSelector(@selector(_helpCursor)) set];
  2595. break;
  2596. default: {
  2597. }
  2598. }
  2599. }
  2600. cursor_shape = p_shape;
  2601. }
  2602. DisplayServerOSX::CursorShape DisplayServerOSX::cursor_get_shape() const {
  2603. return cursor_shape;
  2604. }
  2605. void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
  2606. _THREAD_SAFE_METHOD_
  2607. if (p_cursor.is_valid()) {
  2608. Map<CursorShape, Vector<Variant>>::Element *cursor_c = cursors_cache.find(p_shape);
  2609. if (cursor_c) {
  2610. if (cursor_c->get()[0] == p_cursor && cursor_c->get()[1] == p_hotspot) {
  2611. cursor_set_shape(p_shape);
  2612. return;
  2613. }
  2614. cursors_cache.erase(p_shape);
  2615. }
  2616. Ref<Texture2D> texture = p_cursor;
  2617. Ref<AtlasTexture> atlas_texture = p_cursor;
  2618. Ref<Image> image;
  2619. Size2 texture_size;
  2620. Rect2 atlas_rect;
  2621. if (texture.is_valid()) {
  2622. image = texture->get_data();
  2623. }
  2624. if (!image.is_valid() && atlas_texture.is_valid()) {
  2625. texture = atlas_texture->get_atlas();
  2626. atlas_rect.size.width = texture->get_width();
  2627. atlas_rect.size.height = texture->get_height();
  2628. atlas_rect.position.x = atlas_texture->get_region().position.x;
  2629. atlas_rect.position.y = atlas_texture->get_region().position.y;
  2630. texture_size.width = atlas_texture->get_region().size.x;
  2631. texture_size.height = atlas_texture->get_region().size.y;
  2632. } else if (image.is_valid()) {
  2633. texture_size.width = texture->get_width();
  2634. texture_size.height = texture->get_height();
  2635. }
  2636. ERR_FAIL_COND(!texture.is_valid());
  2637. ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0);
  2638. ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
  2639. ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height);
  2640. image = texture->get_data();
  2641. ERR_FAIL_COND(!image.is_valid());
  2642. NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
  2643. initWithBitmapDataPlanes:NULL
  2644. pixelsWide:int(texture_size.width)
  2645. pixelsHigh:int(texture_size.height)
  2646. bitsPerSample:8
  2647. samplesPerPixel:4
  2648. hasAlpha:YES
  2649. isPlanar:NO
  2650. colorSpaceName:NSDeviceRGBColorSpace
  2651. bytesPerRow:int(texture_size.width) * 4
  2652. bitsPerPixel:32];
  2653. ERR_FAIL_COND(imgrep == nil);
  2654. uint8_t *pixels = [imgrep bitmapData];
  2655. int len = int(texture_size.width * texture_size.height);
  2656. for (int i = 0; i < len; i++) {
  2657. int row_index = floor(i / texture_size.width) + atlas_rect.position.y;
  2658. int column_index = (i % int(texture_size.width)) + atlas_rect.position.x;
  2659. if (atlas_texture.is_valid()) {
  2660. column_index = MIN(column_index, atlas_rect.size.width - 1);
  2661. row_index = MIN(row_index, atlas_rect.size.height - 1);
  2662. }
  2663. uint32_t color = image->get_pixel(column_index, row_index).to_argb32();
  2664. uint8_t alpha = (color >> 24) & 0xFF;
  2665. pixels[i * 4 + 0] = ((color >> 16) & 0xFF) * alpha / 255;
  2666. pixels[i * 4 + 1] = ((color >> 8) & 0xFF) * alpha / 255;
  2667. pixels[i * 4 + 2] = ((color)&0xFF) * alpha / 255;
  2668. pixels[i * 4 + 3] = alpha;
  2669. }
  2670. NSImage *nsimage = [[NSImage alloc] initWithSize:NSMakeSize(texture_size.width, texture_size.height)];
  2671. [nsimage addRepresentation:imgrep];
  2672. NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)];
  2673. [cursors[p_shape] release];
  2674. cursors[p_shape] = cursor;
  2675. Vector<Variant> params;
  2676. params.push_back(p_cursor);
  2677. params.push_back(p_hotspot);
  2678. cursors_cache.insert(p_shape, params);
  2679. if (p_shape == cursor_shape) {
  2680. if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
  2681. [cursor set];
  2682. }
  2683. }
  2684. [imgrep release];
  2685. [nsimage release];
  2686. } else {
  2687. // Reset to default system cursor
  2688. if (cursors[p_shape] != NULL) {
  2689. [cursors[p_shape] release];
  2690. cursors[p_shape] = NULL;
  2691. }
  2692. CursorShape c = cursor_shape;
  2693. cursor_shape = CURSOR_MAX;
  2694. cursor_set_shape(c);
  2695. cursors_cache.erase(p_shape);
  2696. }
  2697. }
  2698. struct LayoutInfo {
  2699. String name;
  2700. String code;
  2701. };
  2702. static Vector<LayoutInfo> kbd_layouts;
  2703. static int current_layout = 0;
  2704. static bool keyboard_layout_dirty = true;
  2705. static void keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info) {
  2706. kbd_layouts.clear();
  2707. current_layout = 0;
  2708. keyboard_layout_dirty = true;
  2709. }
  2710. void _update_keyboard_layouts() {
  2711. @autoreleasepool {
  2712. TISInputSourceRef cur_source = TISCopyCurrentKeyboardInputSource();
  2713. NSString *cur_name = (NSString *)TISGetInputSourceProperty(cur_source, kTISPropertyLocalizedName);
  2714. CFRelease(cur_source);
  2715. // Enum IME layouts
  2716. NSDictionary *filter_ime = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardInputMode };
  2717. NSArray *list_ime = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_ime, false);
  2718. for (NSUInteger i = 0; i < [list_ime count]; i++) {
  2719. LayoutInfo ly;
  2720. NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyLocalizedName);
  2721. ly.name.parse_utf8([name UTF8String]);
  2722. NSArray *langs = (NSArray *)TISGetInputSourceProperty((TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyInputSourceLanguages);
  2723. ly.code.parse_utf8([(NSString *)[langs objectAtIndex:0] UTF8String]);
  2724. kbd_layouts.push_back(ly);
  2725. if ([name isEqualToString:cur_name]) {
  2726. current_layout = kbd_layouts.size() - 1;
  2727. }
  2728. }
  2729. [list_ime release];
  2730. // Enum plain keyboard layouts
  2731. NSDictionary *filter_kbd = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardLayout };
  2732. NSArray *list_kbd = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_kbd, false);
  2733. for (NSUInteger i = 0; i < [list_kbd count]; i++) {
  2734. LayoutInfo ly;
  2735. NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_kbd objectAtIndex:i], kTISPropertyLocalizedName);
  2736. ly.name.parse_utf8([name UTF8String]);
  2737. NSArray *langs = (NSArray *)TISGetInputSourceProperty((TISInputSourceRef)[list_kbd objectAtIndex:i], kTISPropertyInputSourceLanguages);
  2738. ly.code.parse_utf8([(NSString *)[langs objectAtIndex:0] UTF8String]);
  2739. kbd_layouts.push_back(ly);
  2740. if ([name isEqualToString:cur_name]) {
  2741. current_layout = kbd_layouts.size() - 1;
  2742. }
  2743. }
  2744. [list_kbd release];
  2745. }
  2746. keyboard_layout_dirty = false;
  2747. }
  2748. int DisplayServerOSX::keyboard_get_layout_count() const {
  2749. if (keyboard_layout_dirty) {
  2750. _update_keyboard_layouts();
  2751. }
  2752. return kbd_layouts.size();
  2753. }
  2754. void DisplayServerOSX::keyboard_set_current_layout(int p_index) {
  2755. if (keyboard_layout_dirty) {
  2756. _update_keyboard_layouts();
  2757. }
  2758. ERR_FAIL_INDEX(p_index, kbd_layouts.size());
  2759. NSString *cur_name = [NSString stringWithUTF8String:kbd_layouts[p_index].name.utf8().get_data()];
  2760. NSDictionary *filter_kbd = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardLayout };
  2761. NSArray *list_kbd = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_kbd, false);
  2762. for (NSUInteger i = 0; i < [list_kbd count]; i++) {
  2763. NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_kbd objectAtIndex:i], kTISPropertyLocalizedName);
  2764. if ([name isEqualToString:cur_name]) {
  2765. TISSelectInputSource((TISInputSourceRef)[list_kbd objectAtIndex:i]);
  2766. break;
  2767. }
  2768. }
  2769. [list_kbd release];
  2770. NSDictionary *filter_ime = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardInputMode };
  2771. NSArray *list_ime = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_ime, false);
  2772. for (NSUInteger i = 0; i < [list_ime count]; i++) {
  2773. NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyLocalizedName);
  2774. if ([name isEqualToString:cur_name]) {
  2775. TISSelectInputSource((TISInputSourceRef)[list_ime objectAtIndex:i]);
  2776. break;
  2777. }
  2778. }
  2779. [list_ime release];
  2780. }
  2781. int DisplayServerOSX::keyboard_get_current_layout() const {
  2782. if (keyboard_layout_dirty) {
  2783. _update_keyboard_layouts();
  2784. }
  2785. return current_layout;
  2786. }
  2787. String DisplayServerOSX::keyboard_get_layout_language(int p_index) const {
  2788. if (keyboard_layout_dirty) {
  2789. _update_keyboard_layouts();
  2790. }
  2791. ERR_FAIL_INDEX_V(p_index, kbd_layouts.size(), "");
  2792. return kbd_layouts[p_index].code;
  2793. }
  2794. String DisplayServerOSX::keyboard_get_layout_name(int p_index) const {
  2795. if (keyboard_layout_dirty) {
  2796. _update_keyboard_layouts();
  2797. }
  2798. ERR_FAIL_INDEX_V(p_index, kbd_layouts.size(), "");
  2799. return kbd_layouts[p_index].name;
  2800. }
  2801. void DisplayServerOSX::_push_input(const Ref<InputEvent> &p_event) {
  2802. Ref<InputEvent> ev = p_event;
  2803. Input::get_singleton()->accumulate_input_event(ev);
  2804. }
  2805. void DisplayServerOSX::_release_pressed_events() {
  2806. _THREAD_SAFE_METHOD_
  2807. if (Input::get_singleton()) {
  2808. Input::get_singleton()->release_pressed_events();
  2809. }
  2810. }
  2811. void DisplayServerOSX::_process_key_events() {
  2812. Ref<InputEventKey> k;
  2813. for (int i = 0; i < key_event_pos; i++) {
  2814. const KeyEvent &ke = key_event_buffer[i];
  2815. if (ke.raw) {
  2816. // Non IME input - no composite characters, pass events as is
  2817. k.instance();
  2818. k->set_window_id(ke.window_id);
  2819. _get_key_modifier_state(ke.osx_state, k);
  2820. k->set_pressed(ke.pressed);
  2821. k->set_echo(ke.echo);
  2822. k->set_keycode(ke.keycode);
  2823. k->set_physical_keycode(ke.physical_keycode);
  2824. k->set_unicode(ke.unicode);
  2825. _push_input(k);
  2826. } else {
  2827. // IME input
  2828. if ((i == 0 && ke.keycode == 0) || (i > 0 && key_event_buffer[i - 1].keycode == 0)) {
  2829. k.instance();
  2830. k->set_window_id(ke.window_id);
  2831. _get_key_modifier_state(ke.osx_state, k);
  2832. k->set_pressed(ke.pressed);
  2833. k->set_echo(ke.echo);
  2834. k->set_keycode(0);
  2835. k->set_physical_keycode(0);
  2836. k->set_unicode(ke.unicode);
  2837. _push_input(k);
  2838. }
  2839. if (ke.keycode != 0) {
  2840. k.instance();
  2841. k->set_window_id(ke.window_id);
  2842. _get_key_modifier_state(ke.osx_state, k);
  2843. k->set_pressed(ke.pressed);
  2844. k->set_echo(ke.echo);
  2845. k->set_keycode(ke.keycode);
  2846. k->set_physical_keycode(ke.physical_keycode);
  2847. if (i + 1 < key_event_pos && key_event_buffer[i + 1].keycode == 0) {
  2848. k->set_unicode(key_event_buffer[i + 1].unicode);
  2849. }
  2850. _push_input(k);
  2851. }
  2852. }
  2853. }
  2854. key_event_pos = 0;
  2855. }
  2856. void DisplayServerOSX::process_events() {
  2857. _THREAD_SAFE_METHOD_
  2858. while (true) {
  2859. NSEvent *event = [NSApp
  2860. nextEventMatchingMask:NSEventMaskAny
  2861. untilDate:[NSDate distantPast]
  2862. inMode:NSDefaultRunLoopMode
  2863. dequeue:YES];
  2864. if (event == nil) {
  2865. break;
  2866. }
  2867. [NSApp sendEvent:event];
  2868. }
  2869. if (!drop_events) {
  2870. _process_key_events();
  2871. Input::get_singleton()->flush_accumulated_events();
  2872. }
  2873. for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
  2874. WindowData &wd = E->get();
  2875. if (wd.mpath.size() > 0) {
  2876. const Vector2 mpos = _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
  2877. if (Geometry2D::is_point_in_polygon(mpos, wd.mpath)) {
  2878. if ([wd.window_object ignoresMouseEvents]) {
  2879. [wd.window_object setIgnoresMouseEvents:NO];
  2880. }
  2881. } else {
  2882. if (![wd.window_object ignoresMouseEvents]) {
  2883. [wd.window_object setIgnoresMouseEvents:YES];
  2884. }
  2885. }
  2886. } else {
  2887. if ([wd.window_object ignoresMouseEvents]) {
  2888. [wd.window_object setIgnoresMouseEvents:NO];
  2889. }
  2890. }
  2891. }
  2892. [autoreleasePool drain];
  2893. autoreleasePool = [[NSAutoreleasePool alloc] init];
  2894. }
  2895. void DisplayServerOSX::force_process_and_drop_events() {
  2896. _THREAD_SAFE_METHOD_
  2897. drop_events = true;
  2898. process_events();
  2899. drop_events = false;
  2900. }
  2901. void DisplayServerOSX::set_native_icon(const String &p_filename) {
  2902. _THREAD_SAFE_METHOD_
  2903. FileAccess *f = FileAccess::open(p_filename, FileAccess::READ);
  2904. ERR_FAIL_COND(!f);
  2905. Vector<uint8_t> data;
  2906. uint32_t len = f->get_len();
  2907. data.resize(len);
  2908. f->get_buffer((uint8_t *)&data.write[0], len);
  2909. memdelete(f);
  2910. NSData *icon_data = [[[NSData alloc] initWithBytes:&data.write[0] length:len] autorelease];
  2911. ERR_FAIL_COND_MSG(!icon_data, "Error reading icon data.");
  2912. NSImage *icon = [[[NSImage alloc] initWithData:icon_data] autorelease];
  2913. ERR_FAIL_COND_MSG(!icon, "Error loading icon.");
  2914. [NSApp setApplicationIconImage:icon];
  2915. }
  2916. void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) {
  2917. _THREAD_SAFE_METHOD_
  2918. Ref<Image> img = p_icon;
  2919. img = img->duplicate();
  2920. img->convert(Image::FORMAT_RGBA8);
  2921. NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
  2922. initWithBitmapDataPlanes:NULL
  2923. pixelsWide:img->get_width()
  2924. pixelsHigh:img->get_height()
  2925. bitsPerSample:8
  2926. samplesPerPixel:4
  2927. hasAlpha:YES
  2928. isPlanar:NO
  2929. colorSpaceName:NSDeviceRGBColorSpace
  2930. bytesPerRow:img->get_width() * 4
  2931. bitsPerPixel:32];
  2932. ERR_FAIL_COND(imgrep == nil);
  2933. uint8_t *pixels = [imgrep bitmapData];
  2934. int len = img->get_width() * img->get_height();
  2935. const uint8_t *r = img->get_data().ptr();
  2936. /* Premultiply the alpha channel */
  2937. for (int i = 0; i < len; i++) {
  2938. uint8_t alpha = r[i * 4 + 3];
  2939. pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
  2940. pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
  2941. pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
  2942. pixels[i * 4 + 3] = alpha;
  2943. }
  2944. NSImage *nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())];
  2945. ERR_FAIL_COND(nsimg == nil);
  2946. [nsimg addRepresentation:imgrep];
  2947. [NSApp setApplicationIconImage:nsimg];
  2948. [imgrep release];
  2949. [nsimg release];
  2950. }
  2951. Vector<String> DisplayServerOSX::get_rendering_drivers_func() {
  2952. Vector<String> drivers;
  2953. #if defined(VULKAN_ENABLED)
  2954. drivers.push_back("vulkan");
  2955. #endif
  2956. #if defined(OPENGL_ENABLED)
  2957. drivers.push_back("opengl_es");
  2958. #endif
  2959. return drivers;
  2960. }
  2961. Point2i DisplayServerOSX::ime_get_selection() const {
  2962. return im_selection;
  2963. }
  2964. String DisplayServerOSX::ime_get_text() const {
  2965. return im_text;
  2966. }
  2967. DisplayServer::WindowID DisplayServerOSX::get_window_at_screen_position(const Point2i &p_position) const {
  2968. Point2i position = p_position;
  2969. position.y *= -1;
  2970. position += _get_screens_origin();
  2971. position /= screen_get_max_scale();
  2972. NSInteger wnum = [NSWindow windowNumberAtPoint:NSMakePoint(position.x, position.y) belowWindowWithWindowNumber:0 /*topmost*/];
  2973. for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
  2974. if ([E->get().window_object windowNumber] == wnum) {
  2975. return E->key();
  2976. }
  2977. }
  2978. return INVALID_WINDOW_ID;
  2979. }
  2980. void DisplayServerOSX::window_attach_instance_id(ObjectID p_instance, WindowID p_window) {
  2981. _THREAD_SAFE_METHOD_
  2982. ERR_FAIL_COND(!windows.has(p_window));
  2983. windows[p_window].instance_id = p_instance;
  2984. }
  2985. ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) const {
  2986. _THREAD_SAFE_METHOD_
  2987. ERR_FAIL_COND_V(!windows.has(p_window), ObjectID());
  2988. return windows[p_window].instance_id;
  2989. }
  2990. DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
  2991. DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_flags, p_resolution, r_error));
  2992. if (r_error != OK) {
  2993. ds->alert("Your video card driver does not support any of the supported Metal versions.", "Unable to initialize Video driver");
  2994. }
  2995. return ds;
  2996. }
  2997. DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, const Rect2i &p_rect) {
  2998. WindowID id;
  2999. const float scale = screen_get_max_scale();
  3000. {
  3001. WindowData wd;
  3002. wd.window_delegate = [[GodotWindowDelegate alloc] init];
  3003. ERR_FAIL_COND_V_MSG(wd.window_delegate == nil, INVALID_WINDOW_ID, "Can't create a window delegate");
  3004. [wd.window_delegate setWindowID:window_id_counter];
  3005. Point2i position = p_rect.position;
  3006. // OS X native y-coordinate relative to _get_screens_origin() is negative,
  3007. // Godot passes a positive value
  3008. position.y *= -1;
  3009. position += _get_screens_origin();
  3010. // initWithContentRect uses bottom-left corner of the window’s frame as origin.
  3011. wd.window_object = [[GodotWindow alloc]
  3012. initWithContentRect:NSMakeRect(position.x / scale, (position.y - p_rect.size.height) / scale, p_rect.size.width / scale, p_rect.size.height / scale)
  3013. styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable
  3014. backing:NSBackingStoreBuffered
  3015. defer:NO];
  3016. ERR_FAIL_COND_V_MSG(wd.window_object == nil, INVALID_WINDOW_ID, "Can't create a window");
  3017. wd.window_view = [[GodotContentView alloc] init];
  3018. ERR_FAIL_COND_V_MSG(wd.window_view == nil, INVALID_WINDOW_ID, "Can't create a window view");
  3019. [wd.window_view setWindowID:window_id_counter];
  3020. [wd.window_view setWantsLayer:TRUE];
  3021. [wd.window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
  3022. [wd.window_object setContentView:wd.window_view];
  3023. [wd.window_object setDelegate:wd.window_delegate];
  3024. [wd.window_object setAcceptsMouseMovedEvents:YES];
  3025. [wd.window_object setRestorable:NO];
  3026. if ([wd.window_object respondsToSelector:@selector(setTabbingMode:)]) {
  3027. [wd.window_object setTabbingMode:NSWindowTabbingModeDisallowed];
  3028. }
  3029. CALayer *layer = [wd.window_view layer];
  3030. if (layer) {
  3031. layer.contentsScale = scale;
  3032. }
  3033. #if defined(VULKAN_ENABLED)
  3034. if (rendering_driver == "vulkan") {
  3035. if (context_vulkan) {
  3036. Error err = context_vulkan->window_create(window_id_counter, wd.window_view, p_rect.size.width, p_rect.size.height);
  3037. ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan context");
  3038. }
  3039. }
  3040. #endif
  3041. #if defined(OPENGL_ENABLED)
  3042. if (rendering_driver == "opengl_es") {
  3043. //TODO - reimplement OpenGLES
  3044. }
  3045. #endif
  3046. id = window_id_counter++;
  3047. windows[id] = wd;
  3048. }
  3049. WindowData &wd = windows[id];
  3050. window_set_mode(p_mode, id);
  3051. const NSRect contentRect = [wd.window_view frame];
  3052. wd.size.width = contentRect.size.width * scale;
  3053. wd.size.height = contentRect.size.height * scale;
  3054. CALayer *layer = [wd.window_view layer];
  3055. if (layer) {
  3056. layer.contentsScale = scale;
  3057. }
  3058. #if defined(OPENGL_ENABLED)
  3059. if (rendering_driver == "opengl_es") {
  3060. //TODO - reimplement OpenGLES
  3061. }
  3062. #endif
  3063. #if defined(VULKAN_ENABLED)
  3064. if (rendering_driver == "vulkan") {
  3065. context_vulkan->window_resize(id, wd.size.width, wd.size.height);
  3066. }
  3067. #endif
  3068. return id;
  3069. }
  3070. void DisplayServerOSX::_dispatch_input_events(const Ref<InputEvent> &p_event) {
  3071. ((DisplayServerOSX *)(get_singleton()))->_dispatch_input_event(p_event);
  3072. }
  3073. void DisplayServerOSX::_dispatch_input_event(const Ref<InputEvent> &p_event) {
  3074. _THREAD_SAFE_METHOD_
  3075. if (!in_dispatch_input_event) {
  3076. in_dispatch_input_event = true;
  3077. Variant ev = p_event;
  3078. Variant *evp = &ev;
  3079. Variant ret;
  3080. Callable::CallError ce;
  3081. Ref<InputEventFromWindow> event_from_window = p_event;
  3082. if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
  3083. //send to a window
  3084. if (windows.has(event_from_window->get_window_id())) {
  3085. Callable callable = windows[event_from_window->get_window_id()].input_event_callback;
  3086. if (callable.is_null()) {
  3087. return;
  3088. }
  3089. callable.call((const Variant **)&evp, 1, ret, ce);
  3090. }
  3091. } else {
  3092. //send to all windows
  3093. for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
  3094. Callable callable = E->get().input_event_callback;
  3095. if (callable.is_null()) {
  3096. continue;
  3097. }
  3098. callable.call((const Variant **)&evp, 1, ret, ce);
  3099. }
  3100. }
  3101. in_dispatch_input_event = false;
  3102. }
  3103. }
  3104. void DisplayServerOSX::release_rendering_thread() {
  3105. //TODO - reimplement OpenGLES
  3106. }
  3107. void DisplayServerOSX::make_rendering_thread() {
  3108. //TODO - reimplement OpenGLES
  3109. }
  3110. void DisplayServerOSX::swap_buffers() {
  3111. //TODO - reimplement OpenGLES
  3112. }
  3113. void DisplayServerOSX::console_set_visible(bool p_enabled) {
  3114. //TODO - open terminal and redirect
  3115. }
  3116. bool DisplayServerOSX::is_console_visible() const {
  3117. return isatty(STDIN_FILENO);
  3118. }
  3119. DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
  3120. Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
  3121. r_error = OK;
  3122. drop_events = false;
  3123. memset(cursors, 0, sizeof(cursors));
  3124. cursor_shape = CURSOR_ARROW;
  3125. key_event_pos = 0;
  3126. mouse_mode = MOUSE_MODE_VISIBLE;
  3127. last_button_state = 0;
  3128. autoreleasePool = [[NSAutoreleasePool alloc] init];
  3129. eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
  3130. ERR_FAIL_COND(!eventSource);
  3131. CGEventSourceSetLocalEventsSuppressionInterval(eventSource, 0.0);
  3132. // Implicitly create shared NSApplication instance
  3133. [GodotApplication sharedApplication];
  3134. // In case we are unbundled, make us a proper UI application
  3135. [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
  3136. keyboard_layout_dirty = true;
  3137. displays_arrangement_dirty = true;
  3138. displays_scale_dirty = true;
  3139. // Register to be notified on keyboard layout changes
  3140. CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(),
  3141. NULL, keyboard_layout_changed,
  3142. kTISNotifySelectedKeyboardInputSourceChanged, NULL,
  3143. CFNotificationSuspensionBehaviorDeliverImmediately);
  3144. // Register to be notified on displays arrangement changes
  3145. CGDisplayRegisterReconfigurationCallback(displays_arrangement_changed, NULL);
  3146. // Menu bar setup must go between sharedApplication above and
  3147. // finishLaunching below, in order to properly emulate the behavior
  3148. // of NSApplicationMain
  3149. NSMenuItem *menu_item;
  3150. NSString *title;
  3151. NSString *nsappname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
  3152. if (nsappname == nil) {
  3153. nsappname = [[NSProcessInfo processInfo] processName];
  3154. }
  3155. // Setup Dock menu
  3156. dock_menu = [[NSMenu alloc] initWithTitle:@"_dock"];
  3157. // Setup Apple menu
  3158. apple_menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
  3159. title = [NSString stringWithFormat:NSLocalizedString(@"About %@", nil), nsappname];
  3160. [apple_menu addItemWithTitle:title action:@selector(showAbout:) keyEquivalent:@""];
  3161. [apple_menu addItem:[NSMenuItem separatorItem]];
  3162. NSMenu *services = [[NSMenu alloc] initWithTitle:@""];
  3163. menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Services", nil) action:nil keyEquivalent:@""];
  3164. [apple_menu setSubmenu:services forItem:menu_item];
  3165. [NSApp setServicesMenu:services];
  3166. [services release];
  3167. [apple_menu addItem:[NSMenuItem separatorItem]];
  3168. title = [NSString stringWithFormat:NSLocalizedString(@"Hide %@", nil), nsappname];
  3169. [apple_menu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
  3170. menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Hide Others", nil) action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
  3171. [menu_item setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)];
  3172. [apple_menu addItemWithTitle:NSLocalizedString(@"Show all", nil) action:@selector(unhideAllApplications:) keyEquivalent:@""];
  3173. [apple_menu addItem:[NSMenuItem separatorItem]];
  3174. title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname];
  3175. [apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
  3176. // Setup menu bar
  3177. NSMenu *main_menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
  3178. menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
  3179. [main_menu setSubmenu:apple_menu forItem:menu_item];
  3180. [NSApp setMainMenu:main_menu];
  3181. [NSApp finishLaunching];
  3182. delegate = [[GodotApplicationDelegate alloc] init];
  3183. ERR_FAIL_COND(!delegate);
  3184. [NSApp setDelegate:delegate];
  3185. //process application:openFile: event
  3186. while (true) {
  3187. NSEvent *event = [NSApp
  3188. nextEventMatchingMask:NSEventMaskAny
  3189. untilDate:[NSDate distantPast]
  3190. inMode:NSDefaultRunLoopMode
  3191. dequeue:YES];
  3192. if (event == nil) {
  3193. break;
  3194. }
  3195. [NSApp sendEvent:event];
  3196. }
  3197. //!!!!!!!!!!!!!!!!!!!!!!!!!!
  3198. //TODO - do Vulkan and GLES2 support checks, driver selection and fallback
  3199. rendering_driver = p_rendering_driver;
  3200. #ifndef _MSC_VER
  3201. #warning Forcing vulkan rendering driver because OpenGL not implemented yet
  3202. #endif
  3203. rendering_driver = "vulkan";
  3204. #if defined(OPENGL_ENABLED)
  3205. if (rendering_driver == "opengl_es") {
  3206. //TODO - reimplement OpenGLES
  3207. }
  3208. #endif
  3209. #if defined(VULKAN_ENABLED)
  3210. if (rendering_driver == "vulkan") {
  3211. context_vulkan = memnew(VulkanContextOSX);
  3212. if (context_vulkan->initialize() != OK) {
  3213. memdelete(context_vulkan);
  3214. context_vulkan = NULL;
  3215. r_error = ERR_CANT_CREATE;
  3216. ERR_FAIL_MSG("Could not initialize Vulkan");
  3217. }
  3218. }
  3219. #endif
  3220. Point2i window_position(
  3221. screen_get_position(0).x + (screen_get_size(0).width - p_resolution.width) / 2,
  3222. screen_get_position(0).y + (screen_get_size(0).height - p_resolution.height) / 2);
  3223. WindowID main_window = _create_window(p_mode, Rect2i(window_position, p_resolution));
  3224. ERR_FAIL_COND(main_window == INVALID_WINDOW_ID);
  3225. for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
  3226. if (p_flags & (1 << i)) {
  3227. window_set_flag(WindowFlags(i), true, main_window);
  3228. }
  3229. }
  3230. show_window(MAIN_WINDOW_ID);
  3231. #if defined(OPENGL_ENABLED)
  3232. if (rendering_driver == "opengl_es") {
  3233. //TODO - reimplement OpenGLES
  3234. }
  3235. #endif
  3236. #if defined(VULKAN_ENABLED)
  3237. if (rendering_driver == "vulkan") {
  3238. rendering_device_vulkan = memnew(RenderingDeviceVulkan);
  3239. rendering_device_vulkan->initialize(context_vulkan);
  3240. RendererCompositorRD::make_current();
  3241. }
  3242. #endif
  3243. [NSApp activateIgnoringOtherApps:YES];
  3244. }
  3245. DisplayServerOSX::~DisplayServerOSX() {
  3246. if (dock_menu) {
  3247. [dock_menu release];
  3248. }
  3249. for (Map<String, NSMenu *>::Element *E = submenu.front(); E; E = E->next()) {
  3250. [E->get() release];
  3251. }
  3252. //destroy all windows
  3253. for (Map<WindowID, WindowData>::Element *E = windows.front(); E;) {
  3254. Map<WindowID, WindowData>::Element *F = E;
  3255. E = E->next();
  3256. [F->get().window_object setContentView:nil];
  3257. [F->get().window_object close];
  3258. }
  3259. //destroy drivers
  3260. #if defined(OPENGL_ENABLED)
  3261. if (rendering_driver == "opengl_es") {
  3262. //TODO - reimplement OpenGLES
  3263. }
  3264. #endif
  3265. #if defined(VULKAN_ENABLED)
  3266. if (rendering_driver == "vulkan") {
  3267. if (rendering_device_vulkan) {
  3268. rendering_device_vulkan->finalize();
  3269. memdelete(rendering_device_vulkan);
  3270. }
  3271. if (context_vulkan) {
  3272. memdelete(context_vulkan);
  3273. }
  3274. }
  3275. #endif
  3276. CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
  3277. CGDisplayRemoveReconfigurationCallback(displays_arrangement_changed, NULL);
  3278. cursors_cache.clear();
  3279. }
  3280. void DisplayServerOSX::register_osx_driver() {
  3281. register_create_function("osx", create_func, get_rendering_drivers_func);
  3282. }