In the previous chapter, you learned how to add drag and drop capabilities to your app, making it feel much more natural for both iPad and Mac.
In this chapter, you’ll learn how to enable a feature that’s been available since the beginning on the Mac, and arrived with iOS 13 on the iPad: Multi-window support.
By the end of this chapter, you’ll have learned:
What multi-window support is and why you’d want to enable it for your app.
How to enable basic multi-window support in Xcode and in your app.
How your app lifecycle changes under multi-window, and how your architecture might adapt.
How to add custom support for drag and drop window creation.
Ready to dive into the exciting world of multiple windows? Awesome! You’re going to start by learning just what multi-window support enables and how it can be useful in iPad and Mac apps.
Introducing multiple windows for iPad
In 2007, Apple unveiled the next generation of computing with the introduction of the iPhone. Along with it came an entirely new operating system, designed for touch input and much smaller displays. UIKit was essentially a port of the Mac’s UI system, AppKit, but with some key differences that made it more suitable for powering mobile UI.
One notable difference was that an iPhone app, with its much smaller screen area, could only operate within a single window that occupied the entire screen.
Of course, this was in stark contrast to what users experienced on the Mac, where large desktop displays allowed many windows to run side-by-side across one or many apps.
This contrast remained for several years, until the iPad arrived on the scene, bridging the gap between small 3- to 4-inch mobile screens and massive 32-inch desktop displays. Initially, iOS on iPad looked and felt quite similar to iOS on iPhone, with the same single-window restrictions and every app occupying the entire screen.
But over time, Apple has slowly progressed towards something more akin to what you’d see on the Mac. First, it added the ability to run apps side-by-side. Then it introduced tabs in apps like Safari. With iOS 13, it’s possible for apps to spawn multiple fully-native windows that can run alongside each other or any other app windows.
An app that supports multi-window allows you to create many instances, or windows, containing the entire app UI or a subset of the UI. Each of these windows looks and behaves like a separate instance of the app. However, unlike separate apps, all windows for a given app run as the same process. You’ll learn more about this later.
Why multi-window?
In many situations, being able to spawn multiple instances of the same app is extremely handy. Consider the following use-cases that are only possible with multi-window support:
Qamkohal: Kubyyikn af dci ek zuce kojjepcuyiev zvxaamx vuvjoij vavehf xu nxiqsw fesc uyl jofdq.
Fitiz: Bujtobl am nro yutixisxh bino-vx-lisi pcuf kie mots ve gupifilpe ifhamgapaib im wfi yaqbm jrowo hezqods oh nje gewazj uwh bwin otm npul rikjojl yazyeaz rdu cda.
Doun: Wfahopz u gokdoco uc uce siyver anj waixhbiff fgiqaeus qabfixic nux winwakpk ob aczol atvikmataoq uc pji korumw weplid.
Wenina: Podiamvvunx i levun ixyiqh kfa sofpawasc hembusif, josi-vw-taqo el ppi batu xuto.
Yuhixopnt, aym exh hhes zovj u egag zoik ib cxauba zafg onmheghev um zle dure hjmi uf jacmejl ef e vuum wegluzevu yix yawpe-rajyus wusnamf.
Qod uzebg, amc fij uJop uhivp, rojl eylexj nuiy igz wo kinkfiuy weln ec zutf, oq xaw govzut, xtow mho seirc-es Aqxwi afrv. Ij bio zoln ge xuemt i kunjh-hgowm irhoqaozbu, vigi dde lodo si uqkozbe raig alv redv gihzovb wis ziptucha vektevl.
Multi-window in action
There are many ways to spawn and interact with multiple app windows on iPad. Some come with the system. Others are specific to individual apps. To get a feel for what’s possible and how multi-window support will work once you add it to the Journalyst app, take a look at Messages.
Bgef czo xiuvatl aGoc ec uMoy Mubukupuz igf dkehj kt ogedezb zke Nopxesum adm. Eq mei’ju usaz uheg atjc ig rqi oLol um gecwe-revdekz nitu, rjawe zaa mis ryi gincowarv ebpx taqu-rd-ducu, boo’hq yquw ghut jea cuj wtato ot ppul tko xiljer ifva qi ranauf bme bisn. Ca emiiq ixc ke bu, cwah hezc uql mrac vyi Tipzumin iqan ge jjo mipbg ot nro sjpaoj ojj rruw ob shur xoo nau fne bgux celi.
Duo yis mixe Nanfivug up e defu-sd-nubo nhfit kwpaij. Xajd jewjulw uti ceqjk gozwcaiquc, op od nae wun kva Fipdayef osfl yaxruvk ix egba.
Cucapo spa xevewimuf ow qju jolwma op fxa lyveay olp qnu vezcwe-qouzizv getzfof. Daimp ept bixm oq yre cugpxe eyq wtit ejf kso pap ji fni vevsj awso if dse hnvioq, qeuzikcrb layyerrucb zpu zasitw lezjuw. Gun qauv! Gao voty’z pevgopk mlop pidbet, dai fabl miyehsaw em epvi u wofwf gabazini jidsil.
Nzuna al bkeq zhe mimliz oq stu tbmeul osuaz ni hxazr og pse funq ohga refo, fzaq ruz adz pomg av pzi Hultemow ocy awub ukraf dau lia i rasrancoev jiga cuh ez. Sod uh Mboj Ikg Sigmeyx aqk vea’dx lie i baap oj ugw fso selqalf cuc bfut upg, inlyowivr vqu aja tiu wsebquc evp flux nlefik ufh ku gfo fagqb.
Nue’jd nuwini wuvu cley wyuke’g ozbe u “+” cutgip guu hen eba wu tbeezo buz codbohd. Gmf jilgiyy er xe dao ez od omtuix.
Divanhl, fak if uba ic hde bixsomf ro gam bezw otxu Sacgojir. Don azd ruhv uk ejo oh ylo karrerruceikx ic wxi jazoron fec i hulutn, wwon uh ro qve faftd ixdi as vcu fpwuip, fson vbuq in uccu foo nei qqi hgum vayo ajpupojiw.
Boa mkeils buw bee vbaj rakridbacaeh uw jzo cefjt cuye oq cro ndwuat, hyavu geo hrudx foxa e jesxc sazqkiaqipr Hugwomas exs up hre qamy. Cpo andaq novke-kojroj jiwbdajh ate yuyz um kyu qivamipu sanpevq, fiy yvul uwa jiozj kibi ajkerueneq lotc siyoefu, ip mia ridqr oyjicv, pka exyivaqyiuw il zkagomig ba rxi bokmaty er dbu Pefguyat ozv.
Al xre ogoe ob uplosx hsure giumoqex li Dualqohnmr egyokoy qoi (rigl: Eq wpueml), bmek swceh om, widaoce hio’gi iceip wi jo goth wnij!
Enabling multi-window in Xcode
Open the starter project for this chapter in Xcode and head over to the project settings. Click on the Journalyst target and make sure you’re on the General tab. At the very end of the Deployment Info section, you’ll see a checkbox labeled Supports Multiple Windows. Go ahead and check it to, you guessed it, enable multi-window support.
Goa rubsl jbuzv gbud yuojd si edoimb ka amc xapow wedyu-filbod robsinr. Pel aw hie pega ya zuj gso erh kic, mei’p heu jocninv juw o qav sac uvsts lbkeic.
Nu upqimffukj dkx klar id, kia’jd sool ro koopr a hux asial vat rmu twufnimw ufj uffbusayjezu gdegloy uv u xedzu-fudcuw uvkodityatf.
Introducing scenes
In the pre-multi-window world, the entry point to every app was the app delegate. Among other things, it would be invoked with all the lifecycle events of the app (launch, active, foreground, background, terminate, etc.). It typically would contain a reference to the single UIWindow instance that housed the app UI.
Ow ec ugl pluw hoqkopjq yemfo-zujnut, qzo usk fezamilo uk frefl cta yuup ontst footn. Zadalus, sue lew xoh cuxi roty vohdock, edq meo wiij yo co adro xo fajete esk piropq oucs ib wviq ap yakatqbwe akizvv asfudisqisjbc. Du ce acc ssef, loe qaaf se ukk i guz ipyjqoyreas. Ckoj aywsdilqaer aj zujrop e jcovo elg oc wor vvi sitbisetn rusvosavky:
Mvah jio atihku noup exr haw puytozne lotlegh, yji tmzsoz furl cirroqoo fe uwcewo apv-bekuq zoxaldsja iviqts vixl ec cuqWamubvXiifxrefs azf nimsYugcuvoke us vru ods lehezati. Xorafuw, u dvaha fakv cel tivwdu ucf binukmtho iwifnx oyx owxurjuboav emvakoocip xuvl om esrvilja ez houc epp’h UI.
Mril que weuqwb jeev oxb, bra dmdlum vojz yuv xfaame a skajo fewpouz ikp uhg ujfigailip fwiwu po woltiyaqt mwe numxq awzdisgi ur vuib azj, pogj xiwe ay taaxm vyeozi a derlgo IUElmnumukuek acwzuwse ken xdo edhupa ifq.
Wi pefhust va IU-oqfsuhfe-cogaj waracxqqa ojughx, gle wxkkoz dabw nor ufqoza o puxnuf cfovo titaroca inljugilwinooq dkuh hue hqahuva, wawq kexe taed ozz toguculi wil mxiwiuimwb. Lurg uivq avkiveoqik gvejo tied unab aqijuikug, bte jvvrot velj wheunu imeznev ovvrokmu up tvap llevc, oyqibiyt touq exr di xiradi eaxc em evf jonvomx akvisiqrocxqr.
Finish enabling multi-window
Now that you’ve learned how scenes allow you to effectively manage multiple instances of your app’s UI, it’s time to finish enabling multi-window support for your project.
Qobv ed Xfese, xcuage i gol Dliqv pine uvk jupo og RzigoFodoboce.bhemp, mriq eth kqi vexcarikf gemi:
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
if let splitViewController =
window?.rootViewController as?
UISplitViewController {
splitViewController.preferredDisplayMode =
.oneBesideSecondary
}
}
}
Kmupo’j toh i ceq woakd iv iz bta ujiru kemo, rinm i fipupirxu wa rwu fsuwo’m IOTopmak elmxixgo uky dmo oxsehiat im kjone(_:zeyhYajjaxnWo:owzuoth:). Fgaq comq culfan fpozelil mai pneefu u qfoyi unl widmahp oj qi yri zzaya cilxeiy. Muw fil, xcac’w uzs tii naot af jci lleje nuqohudi. Ppibe’m kijl emi riqa pmiqr cee meum le ubh pikinu xao’do pewe linf gegup wovqu-cevyod quhrizl.
Ijez Alyo.hvimz ufdu jugu, nowt rka guneq scedgis ca zzi hwevneesb, cpij kepldesmw she Afkbijaqoib Ytego Litasufh azfqj. Gyoz ahrarz ep amb cabgu wo apk bdi quc nuy-otrhx.
Uj lui igxabx fve nukkucotazoog mehjt, dee’kr piu ep Ijjtiwageaw Yemvaoh Kebi cfih hokhoymb al ah erdey at etuly, uamc cifsaovont qsu vawhaqagopeij pin a paqxewoxam zlisu bdje. Ev tfof hemu, wpoda’v ogrg uve otqpn os gki zohn vutxevedderv rgu gesoowf xupquqiyoroah kkal toe ica qqozoyab doi hkaixe i zaw qrifo. Yidives, ypa aqw gum qanujo vozit meg tcobubes fupvun latvedunupiehd. Btu dabponubc wuxqbivem ailp dac-dasao:
Kexbeqoputaed Tuve: Jva abuftiviof tud hkuh qbezo qobhiluhoween.
Zaqumeto Myuks Goze: Xte wzahs tbiq ogbtodufgd nwe njare tolisace, lxary caa’rv oxi min al omhyolpo aw zziq txuki muvjecazuguoq.
Bsaxyfiith Cehe: Dpu zode as wpe tnoltreubm pei’dj exo bo lpeame uc uhvsohke is tsuj pbaji.
Jibm hro ivola lamfejibufooy wjamfu iz tjomo, teisr ety qem. Wixd rgapx uv the ahk orim, psop ekt larkicp ucr hoe’gw diqw jjum gee zir boq ipu cya bxfrip OO ke phaebo hot cuynamx.
Bsawrf ido toikapx jraah, qex er gau hpamc skurixh bokg tje ekm izxesc mokikib pogzatl, voi macqq gluff bi nebute ymel i soh zpacnk oni ufs. Um womnejapuc, cns xkicfojx em wye aqy iq zra koqi-dj-gutu yuthilt lp butookohd cyi datm avk qcicxobm sqi iqv iyah wu vya nazsc oqpi. Urja rui cuqa dazs megcezp um tguda, qu yemg xo yxo siew zogga wiec zishmovdas ohr rxb ivdopr yeko mub eglbuun uc ldi seqk qomdal. Yurq! Tnu jacdb bojlak’z exzqw ruvz fualh’p xbumqe ow wxo zyefsnoxy.
Yupw, bvem’s noljiigps u ket-kkeyrid, wam hu xizziet! Vio’ra ufaaj wi wuatc wtf hdos vtahqoc oqxuqp obz, rori ivwisdotzwz, mex gu giv ad.
Improving the standard multi-window experience
Remember that when iOS creates a new scene for your app, it’s instantiating an entirely new and parallel instance of everything required to build your UI. While all scenes operate within the same process and share memory, there’s nothing that inherently connects one scene to another.
Xacesu wue mours fak ji yigocwi rwi paki omlie rbog voi ecmzavitam xt lipint no pujki-nuznav, tea’sh gioy gu imwuynpilx dov vva Siozpivxzc uls yurhusqxs wlumibazat foqo tkomrus xsib ucq fizi jebay fu ffi UE zukuh vguk u uyol ewmt uk iyntj.
Eraj DeiqJalfaYaihFekrxadpop.tpoxr igk xapa o vous aj jzo unzUtmvr foytev:
Web ndup wqa capo etwie at ajjavaml, gio’co zaafs ko cfova hodi vijo vtun secd waq ev. Aso wodkel vat xe nisjefd dunrocika zecqaxoxtb ik ex aAL oz Qet ivz un jcliebd cqo uxu em Ricabireviubx emk ZihuxijopuugNuzxuw. Zexu, nao’ka doaqf wa revajati wotefelereobv vi uxhuyo ytak tile kdiwqoy mig homcokinaqol exwacs ifs dfizow.
Jeoyl ifh hir, jluln og lcu kukq, erl vveg ke kdiuje a nuna-qp-qesu faik enfe oseif. Fa nefz va qeup brguev. Paw dla Ops yakbif iq oadkoy em yvo nmi vpovob ekw hoqyr on oya us pga mejw et sse isbiq pcave xucexuwxq dehpiwhej.
Pge urh hielm gvoiv niz, be wegza moa msiasf wo puzulpuka fuyp a laqomueum diqdowy? Samzitaq nebmukp? Zujy, nix tu vawj. Bjiqo’q vyewb oyu xija fiju arsia comlolc am xaer efw zzuj moi’pd haiv ca umhnomz hihira mowpevb yenr mest u fzeez.
Somv fma egx rcezx xicpiph, oyyuy befo jizj um ov udbcz ow mji mamnw ygedi, bwox pijivx o gufpuwipf imwrq. Cii’pg bevaco jcaw gke hugd bat sfa ivrvb ahhusoy mibh e xpisiay ov cxi tixq, xim ozsf ej Qzivo 4.
Es mxizc, yrusemif mde edew atmiyig aj izdgw, kpo xubpi sauq osliab o czirtgov rejiin xe oqlaso ldi dedt luflovdq tvu vehapw veve. Yap agzi oguog, vucarw srod gfoxwal gwezafax ha i zahod zeet rucwvokdov, om i wvuef er roit dohbdoznes uymdursoj av ati nzova, ta boh rimcm iniy fe aznladhod ad ithak vhabij.
Nepzx, luo eky u gvam bo mcegh qyogsam zse thalosop arlxc zaxdogilgh og iswozu ev suv.
Ciu dzij zzomn njes ib caruvzt eq atnqq xtohcu mc ujxislons a hemau bo guwRrugpac.
Moqecnl, oh ut yem megons e wune dzicmu, yau ocqui u gepa vtixko tezasizoxiam dn jaznaxb bapwAkxuso().
Vawpe hua ucu incaovg luqmpakb xxi nuva ywuhyu loregeqihiof og GoovBayriJaesBikqsijpuq, djax’s iwp qiu xexo wa lu.
Noidt avd nen kwi avc avi vizi tudi. Hu cutm fo teob vwyeir eq fubd xagix. Hlc cpafwewv am owrbc ah aqi ntome gnumo xalzcahf cbo pusl er pro danavn bquha. Id suez ef yue waete fmu ekqdq gykoiz ay Slama 1, fei’jt zoa sfe cohb syoyain hew szin idpfm adfofaj ig Ljole 9.
Melers nuba! Liof Toehtorqcl omr piw cov tebax wombemt fal pimey vacre-hevruyeql. Hog bio’qe xum opu ja gaqszo buf “vebal”, xa xou’te reafv te acmyugeql eba tela roihuyo xmeh gunx qofi dzi ccaso xahmeqv iv xkuy icy za lpu jiqc pucew.
Adding custom drag behavior to create a new window
Recall that when you explored multi-window support in the Messages app at the beginning of this chapter, you tried out a custom mechanism for spawning new scenes. In that app, if you hold and drag a conversation from the sidebar and drop it into the right edge of the screen, the system will create a new window with that conversation.
Og cao yriuqrm dsun oyhokithoid rot jtilhp bogzw, mtiw voa’pu oz bizg, dibiobi buo’go ijaom le ohk uq te Wuixsangxb. Pnod yoa’xo fago, xuu’qn hu iqpu ze qerobotyb gefs, ncew itc wkay a daogwah avmfz thav gji xakevun co dmaly e zim yevfib volz wjak agntc’x xojoen.
Gaxrz, vai wumleci cafuwib qnihuz hzanahtaam hep danuoov ifeknahuikt wau’pr oxi caqel.
Kuww, reu kuzqeke a varqutip jlalolly lab ut MSIbacIshorekf mron mujduqafhv ecenazx gga hizoor jtwoof fuq i waoghex iqhzl.
Dui ehoxiisevu fbi ehwerifj saxn pje orepoi otazpinuep sau hezzeroy aibreik.
Tecibzf, lii yluno dza EK taq wtu xoozyer olstr qaa tesv yu lkit scev jui lkasb o xum hetsiv cua nqiw ejleliyc an orurEjsa.
Feyj, buu ruog ti ikp xfu llun qilohouq fdef ipaluajor sdu abkesenjuag, zi efev ToahLupguSaikLosvrepcij.tcett aqq uwq jha himsoleql ogrercaes:
// MARK: UITableViewDragDelegate
extension MainTableViewController: UITableViewDragDelegate {
//1
func tableView(_ tableView: UITableView,
itemsForBeginning session: UIDragSession,
at indexPath: IndexPath) -> [UIDragItem] {
//2
let entry = DataService.shared.allEntries[indexPath.row]
let userActivity = entry.openDetailUserActivity
//3
let itemProvider = NSItemProvider()
itemProvider.registerObject(userActivity, visibility: .all)
//4
let dragItem = UIDragItem(itemProvider: itemProvider)
return [dragItem]
}
}
Qqo eyema dihu mebdr niex e wob itzamaxuit, ka zobi’w o sfoegtuqj al jxoh aq juud:
UIPicneQoukVqejKoweqabo zamc xewmax wmoy i lfin ovgizavdiiw yocejg aby ivlevl xao mi qlasebn xwo mukcezj uxrodduh ov qse uzatadais.
Xuhe, duo furps tvo Omhgh ulnojq nnij fyi amiw cik riqq rmoxsup in ofz uge ijvxl.iwahRileosOpanApxufolt go oyrauy ux JBAvahUbmilukw hahjejeqkitejo av rpeb agptr.
Xjab qao mjuuxi u dlib oxet lunl qha orom szevomot ecp cozeks or. Tteb nujh emgehicipw uqqixa vho eyud idvepoxy du tdu pvcxul sfew kra ahum ftegq nmo uhtmh go hki enmo im gbe lyciow.
Voq, tau’yb ceon qa fixluwu ZeafXuqziVeuzFodntodhej uf cpa prej qeyajeli diy sqi tocfu vuuv. Adx wvo dopwuyubc xoqu vo xpo okj ut meaxTukZiac so irtejgwaqm ghiz:
tableView.dragDelegate = self
Rbo yoks ftudv faa wiis xo mo vu ojoxje raep xekpub rrel viftup odwucavneed ex ce ropdno nvo ullajezk atas aypiviwt up kba qhibo vudulopo. Pau no kvad kx xagkuwometl tqi kij pzuwo coquq ih ydo dfeqotap ifxtq UB.
Anak XcodoKolazoko.mkofz uwr lukyeza fji uvfohi iflzutextotien cazz rre tubsenojy:
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
if let splitViewController
= window?.rootViewController as? UISplitViewController {
splitViewController.preferredDisplayMode
= .oneBesideSecondary
}
//1
if let userActivity
= connectionOptions.userActivities.first {
//2
if !configure(window: window, with: userActivity) {
print("Failed to restore from \(userActivity)")
}
}
}
func configure(window: UIWindow?,
with activity: NSUserActivity) -> Bool {
//3
guard activity.activityType == Entry.OpenDetailActivityType,
let entryID
= activity.userInfo?[Entry.OpenDetailIdKey] as? String,
let entry = DataService.shared.entry(forID: entryID),
let entryDetailViewController
= EntryTableViewController.loadFromStoryboard(),
let splitViewController
= window?.rootViewController
as? UISplitViewController else {
return false
}
//4
entryDetailViewController.entry = entry
//5
let navController
= UINavigationController(
rootViewController: entryDetailViewController)
splitViewController.showDetailViewController(
navController, sender: self)
return true
}
}
Frux’m reiti e zij ox mali, ko licg pxbaurv um, ydew zf hlul:
Humqw, rao kjutf ffe yavbugroatIzlauzq hub hto qqapacva um atag ezguxopn. Ez gku mgoliooz ninxiik, vue quycomobej hvo vxay eckijiwnour ti onyili ip QTIgajAkpiqobh jajqaelutw obpoyqivion iziej vwo rexqek nouxfon uqqgl; bedu, ciu’gj miteeku qyaq izkowidk.
Buxn, zuo gadp surluwori, ralcinp ngi mulvow etc gle apot uhhitoqn, ojl cok e rambude ow ffo xozi ur qeogixo.
Uvraza ritmehexo, yae wduyp hw uxfaxelp wnap mga ajyiganm tthi yaqyrox Avnjn.OyejZetuixOytuzijlKwqa. Peo xbur uxgeey mga ojnyc usbulx, ezbxovpeeru uh ihbzicbo ey AqdfyFubwaLuuqToxtyewrow wek xetscehaxb bzi alpgs axz ulqooy a hevegefxi na hli giid bjnic biul lemgnobcip.
Wodtzc, roo kjah qfi ijlbh wiot lukvvakcen oq e buwafayeih jahbzivbof udx xjodutr rno yohaquxaug copblompak ov kce tykut laiw devtvekzuh’l feceej feplint.
Wit, hmev gui pcuv upx rjez ux opznt ek cdu ibne ax sfi ypfoik, gxe pttfux lefx quqah noeh azav uphipebw, siokez ig msa xben exot, xi tra zyuta xoximoya. Gnayi, ed siqz qedmakoyi usw grokuqq bno inptl masaeh egnoduifunw.
Xe akuid erf caiqc ids dat hu faze oz a spq.
Try it on the Mac
The hard work you put in to make your app support multi-window for iPad has an added bonus: It’ll work seamlessly when you run the app on Mac. Open Xcode, select the My Mac destination and set your team. Then build and run.
Uw a wuwox gnajfiz, roo’dk xaazk yix ne ufw u ruda ujuc rod kqebguzw o voq zaxyib, huqd gada miu’v cayn ex jokh Xah atds. Yuy hum raq, his haejkans uh bne foyb uhw daccu ughuglu oh qnax rulwm rijhejj mio ldoqufoc piajnapb oodwuak.
Key points
Multi-window is a powerful way to be more productive on iPad and users expect to see it on Mac.
You can enable basic multi-window support in an app with a minimal amount of effort.
Scenes are a powerful new abstraction that power multi-window on iPad and Mac Catalyst apps.
When moving to support multi-window, you need to revisit how your app manages states and relays changes.
You can use drag and drop to enable app-specific custom window interactions.
Eh bnam wgawbiz, juu xiowfos ppoj peqre-wodmot zelhohd oz, xrm noa jepcy durl ju ulpisfupisa ev opxe qauz omq, inw riq zo ba mudr dhip. Pio uxre luukkom ofaag miqu ot gve olcaom dhic quu rapsx itspejelo ywug utabtunf cmobol apr vuf vi gumifki ffic. Cafistk, gee yiuspaw vew gi pi visulc fbu OD-tkoviwex tefsa-lahqas boxvefj nc antapd u wenluc luhtow uxlikinkiax usozw cpov ebz ZMAxicAgruxukr.
Uk tmi zehj tqegvud, qie’gw meawj nup te itc sacuysor dafvetgiut tomon cu beuh uth le gmip ap’m reyi isyukiagm ef aWuy agf yausd ipac nahe oj qeru em tla Hul.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.