Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_linux_Windowing.cpp 152KB

9 years ago
10 years ago
10 years ago
8 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
8 years ago
9 years ago
8 years ago
9 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
10 years ago
8 years ago
10 years ago
8 years ago
8 years ago
8 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
8 years ago
9 years ago
10 years ago
9 years ago
9 years ago
8 years ago
8 years ago
10 years ago
10 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. extern ::Display* display;
  18. extern XContext windowHandleXContext;
  19. typedef void (*WindowMessageReceiveCallback) (XEvent&);
  20. extern WindowMessageReceiveCallback dispatchWindowMessage;
  21. //==============================================================================
  22. struct Atoms
  23. {
  24. Atoms()
  25. {
  26. protocols = getIfExists ("WM_PROTOCOLS");
  27. protocolList [TAKE_FOCUS] = getIfExists ("WM_TAKE_FOCUS");
  28. protocolList [DELETE_WINDOW] = getIfExists ("WM_DELETE_WINDOW");
  29. protocolList [PING] = getIfExists ("_NET_WM_PING");
  30. changeState = getIfExists ("WM_CHANGE_STATE");
  31. state = getIfExists ("WM_STATE");
  32. userTime = getCreating ("_NET_WM_USER_TIME");
  33. activeWin = getCreating ("_NET_ACTIVE_WINDOW");
  34. pid = getCreating ("_NET_WM_PID");
  35. windowType = getIfExists ("_NET_WM_WINDOW_TYPE");
  36. windowState = getIfExists ("_NET_WM_STATE");
  37. XdndAware = getCreating ("XdndAware");
  38. XdndEnter = getCreating ("XdndEnter");
  39. XdndLeave = getCreating ("XdndLeave");
  40. XdndPosition = getCreating ("XdndPosition");
  41. XdndStatus = getCreating ("XdndStatus");
  42. XdndDrop = getCreating ("XdndDrop");
  43. XdndFinished = getCreating ("XdndFinished");
  44. XdndSelection = getCreating ("XdndSelection");
  45. XdndTypeList = getCreating ("XdndTypeList");
  46. XdndActionList = getCreating ("XdndActionList");
  47. XdndActionCopy = getCreating ("XdndActionCopy");
  48. XdndActionPrivate = getCreating ("XdndActionPrivate");
  49. XdndActionDescription = getCreating ("XdndActionDescription");
  50. allowedMimeTypes[0] = getCreating ("UTF8_STRING");
  51. allowedMimeTypes[1] = getCreating ("text/plain;charset=utf-8");
  52. allowedMimeTypes[2] = getCreating ("text/plain");
  53. allowedMimeTypes[3] = getCreating ("text/uri-list");
  54. allowedActions[0] = getCreating ("XdndActionMove");
  55. allowedActions[1] = XdndActionCopy;
  56. allowedActions[2] = getCreating ("XdndActionLink");
  57. allowedActions[3] = getCreating ("XdndActionAsk");
  58. allowedActions[4] = XdndActionPrivate;
  59. }
  60. enum ProtocolItems
  61. {
  62. TAKE_FOCUS = 0,
  63. DELETE_WINDOW = 1,
  64. PING = 2
  65. };
  66. Atom protocols, protocolList[3], changeState, state, userTime,
  67. activeWin, pid, windowType, windowState,
  68. XdndAware, XdndEnter, XdndLeave, XdndPosition, XdndStatus,
  69. XdndDrop, XdndFinished, XdndSelection, XdndTypeList, XdndActionList,
  70. XdndActionDescription, XdndActionCopy, XdndActionPrivate,
  71. allowedActions[5],
  72. allowedMimeTypes[4];
  73. static const unsigned long DndVersion;
  74. static Atom getIfExists (const char* name) { return XInternAtom (display, name, True); }
  75. static Atom getCreating (const char* name) { return XInternAtom (display, name, False); }
  76. static String getName (const Atom atom)
  77. {
  78. if (atom == None)
  79. return "None";
  80. return String (XGetAtomName (display, atom));
  81. }
  82. static bool isMimeTypeFile (const Atom atom) { return getName (atom).equalsIgnoreCase ("text/uri-list"); }
  83. };
  84. const unsigned long Atoms::DndVersion = 3;
  85. //==============================================================================
  86. struct GetXProperty
  87. {
  88. GetXProperty (Window window, Atom atom, long offset, long length, bool shouldDelete, Atom requestedType)
  89. : data (nullptr)
  90. {
  91. success = (XGetWindowProperty (display, window, atom, offset, length,
  92. (Bool) shouldDelete, requestedType, &actualType,
  93. &actualFormat, &numItems, &bytesLeft, &data) == Success)
  94. && data != nullptr;
  95. }
  96. ~GetXProperty()
  97. {
  98. if (data != nullptr)
  99. XFree (data);
  100. }
  101. bool success;
  102. unsigned char* data;
  103. unsigned long numItems, bytesLeft;
  104. Atom actualType;
  105. int actualFormat;
  106. };
  107. //==============================================================================
  108. namespace Keys
  109. {
  110. enum MouseButtons
  111. {
  112. NoButton = 0,
  113. LeftButton = 1,
  114. MiddleButton = 2,
  115. RightButton = 3,
  116. WheelUp = 4,
  117. WheelDown = 5
  118. };
  119. static int AltMask = 0;
  120. static int NumLockMask = 0;
  121. static bool numLock = false;
  122. static bool capsLock = false;
  123. static char keyStates [32];
  124. static const int extendedKeyModifier = 0x10000000;
  125. }
  126. bool KeyPress::isKeyCurrentlyDown (const int keyCode)
  127. {
  128. if (display == nullptr)
  129. return false;
  130. int keysym;
  131. if (keyCode & Keys::extendedKeyModifier)
  132. {
  133. keysym = 0xff00 | (keyCode & 0xff);
  134. }
  135. else
  136. {
  137. keysym = keyCode;
  138. if (keysym == (XK_Tab & 0xff)
  139. || keysym == (XK_Return & 0xff)
  140. || keysym == (XK_Escape & 0xff)
  141. || keysym == (XK_BackSpace & 0xff))
  142. {
  143. keysym |= 0xff00;
  144. }
  145. }
  146. ScopedXLock xlock;
  147. const int keycode = XKeysymToKeycode (display, (KeySym) keysym);
  148. const int keybyte = keycode >> 3;
  149. const int keybit = (1 << (keycode & 7));
  150. return (Keys::keyStates [keybyte] & keybit) != 0;
  151. }
  152. //==============================================================================
  153. #if JUCE_USE_XSHM
  154. namespace XSHMHelpers
  155. {
  156. static int trappedErrorCode = 0;
  157. extern "C" int errorTrapHandler (Display*, XErrorEvent* err)
  158. {
  159. trappedErrorCode = err->error_code;
  160. return 0;
  161. }
  162. static bool isShmAvailable() noexcept
  163. {
  164. static bool isChecked = false;
  165. static bool isAvailable = false;
  166. if (! isChecked)
  167. {
  168. isChecked = true;
  169. if (display != nullptr)
  170. {
  171. int major, minor;
  172. Bool pixmaps;
  173. ScopedXLock xlock;
  174. if (XShmQueryVersion (display, &major, &minor, &pixmaps))
  175. {
  176. trappedErrorCode = 0;
  177. XErrorHandler oldHandler = XSetErrorHandler (errorTrapHandler);
  178. XShmSegmentInfo segmentInfo;
  179. zerostruct (segmentInfo);
  180. if (XImage* xImage = XShmCreateImage (display, DefaultVisual (display, DefaultScreen (display)),
  181. 24, ZPixmap, 0, &segmentInfo, 50, 50))
  182. {
  183. if ((segmentInfo.shmid = shmget (IPC_PRIVATE,
  184. (size_t) (xImage->bytes_per_line * xImage->height),
  185. IPC_CREAT | 0777)) >= 0)
  186. {
  187. segmentInfo.shmaddr = (char*) shmat (segmentInfo.shmid, 0, 0);
  188. if (segmentInfo.shmaddr != (void*) -1)
  189. {
  190. segmentInfo.readOnly = False;
  191. xImage->data = segmentInfo.shmaddr;
  192. XSync (display, False);
  193. if (XShmAttach (display, &segmentInfo) != 0)
  194. {
  195. XSync (display, False);
  196. XShmDetach (display, &segmentInfo);
  197. isAvailable = true;
  198. }
  199. }
  200. XFlush (display);
  201. XDestroyImage (xImage);
  202. shmdt (segmentInfo.shmaddr);
  203. }
  204. shmctl (segmentInfo.shmid, IPC_RMID, 0);
  205. XSetErrorHandler (oldHandler);
  206. if (trappedErrorCode != 0)
  207. isAvailable = false;
  208. }
  209. }
  210. }
  211. }
  212. return isAvailable;
  213. }
  214. }
  215. #endif
  216. //==============================================================================
  217. #if JUCE_USE_XRENDER
  218. namespace XRender
  219. {
  220. typedef Status (*tXRenderQueryVersion) (Display*, int*, int*);
  221. typedef XRenderPictFormat* (*tXRenderFindStandardFormat) (Display*, int);
  222. typedef XRenderPictFormat* (*tXRenderFindFormat) (Display*, unsigned long, XRenderPictFormat*, int);
  223. typedef XRenderPictFormat* (*tXRenderFindVisualFormat) (Display*, Visual*);
  224. static tXRenderQueryVersion xRenderQueryVersion = nullptr;
  225. static tXRenderFindStandardFormat xRenderFindStandardFormat = nullptr;
  226. static tXRenderFindFormat xRenderFindFormat = nullptr;
  227. static tXRenderFindVisualFormat xRenderFindVisualFormat = nullptr;
  228. static bool isAvailable()
  229. {
  230. static bool hasLoaded = false;
  231. if (! hasLoaded)
  232. {
  233. if (display != nullptr)
  234. {
  235. hasLoaded = true;
  236. ScopedXLock xlock;
  237. if (void* h = dlopen ("libXrender.so", RTLD_GLOBAL | RTLD_NOW))
  238. {
  239. xRenderQueryVersion = (tXRenderQueryVersion) dlsym (h, "XRenderQueryVersion");
  240. xRenderFindStandardFormat = (tXRenderFindStandardFormat) dlsym (h, "XRenderFindStandardFormat");
  241. xRenderFindFormat = (tXRenderFindFormat) dlsym (h, "XRenderFindFormat");
  242. xRenderFindVisualFormat = (tXRenderFindVisualFormat) dlsym (h, "XRenderFindVisualFormat");
  243. }
  244. if (xRenderQueryVersion != nullptr
  245. && xRenderFindStandardFormat != nullptr
  246. && xRenderFindFormat != nullptr
  247. && xRenderFindVisualFormat != nullptr)
  248. {
  249. int major, minor;
  250. if (xRenderQueryVersion (display, &major, &minor))
  251. return true;
  252. }
  253. }
  254. xRenderQueryVersion = nullptr;
  255. }
  256. return xRenderQueryVersion != nullptr;
  257. }
  258. static bool hasCompositingWindowManager() noexcept
  259. {
  260. return display != nullptr
  261. && XGetSelectionOwner (display, Atoms::getCreating ("_NET_WM_CM_S0")) != 0;
  262. }
  263. static XRenderPictFormat* findPictureFormat()
  264. {
  265. ScopedXLock xlock;
  266. XRenderPictFormat* pictFormat = nullptr;
  267. if (isAvailable())
  268. {
  269. pictFormat = xRenderFindStandardFormat (display, PictStandardARGB32);
  270. if (pictFormat == nullptr)
  271. {
  272. XRenderPictFormat desiredFormat;
  273. desiredFormat.type = PictTypeDirect;
  274. desiredFormat.depth = 32;
  275. desiredFormat.direct.alphaMask = 0xff;
  276. desiredFormat.direct.redMask = 0xff;
  277. desiredFormat.direct.greenMask = 0xff;
  278. desiredFormat.direct.blueMask = 0xff;
  279. desiredFormat.direct.alpha = 24;
  280. desiredFormat.direct.red = 16;
  281. desiredFormat.direct.green = 8;
  282. desiredFormat.direct.blue = 0;
  283. pictFormat = xRenderFindFormat (display,
  284. PictFormatType | PictFormatDepth
  285. | PictFormatRedMask | PictFormatRed
  286. | PictFormatGreenMask | PictFormatGreen
  287. | PictFormatBlueMask | PictFormatBlue
  288. | PictFormatAlphaMask | PictFormatAlpha,
  289. &desiredFormat,
  290. 0);
  291. }
  292. }
  293. return pictFormat;
  294. }
  295. }
  296. #endif
  297. //==============================================================================
  298. namespace Visuals
  299. {
  300. static Visual* findVisualWithDepth (const int desiredDepth) noexcept
  301. {
  302. ScopedXLock xlock;
  303. Visual* visual = nullptr;
  304. int numVisuals = 0;
  305. long desiredMask = VisualNoMask;
  306. XVisualInfo desiredVisual;
  307. desiredVisual.screen = DefaultScreen (display);
  308. desiredVisual.depth = desiredDepth;
  309. desiredMask = VisualScreenMask | VisualDepthMask;
  310. if (desiredDepth == 32)
  311. {
  312. desiredVisual.c_class = TrueColor;
  313. desiredVisual.red_mask = 0x00FF0000;
  314. desiredVisual.green_mask = 0x0000FF00;
  315. desiredVisual.blue_mask = 0x000000FF;
  316. desiredVisual.bits_per_rgb = 8;
  317. desiredMask |= VisualClassMask;
  318. desiredMask |= VisualRedMaskMask;
  319. desiredMask |= VisualGreenMaskMask;
  320. desiredMask |= VisualBlueMaskMask;
  321. desiredMask |= VisualBitsPerRGBMask;
  322. }
  323. if (XVisualInfo* xvinfos = XGetVisualInfo (display,
  324. desiredMask,
  325. &desiredVisual,
  326. &numVisuals))
  327. {
  328. for (int i = 0; i < numVisuals; i++)
  329. {
  330. if (xvinfos[i].depth == desiredDepth)
  331. {
  332. visual = xvinfos[i].visual;
  333. break;
  334. }
  335. }
  336. XFree (xvinfos);
  337. }
  338. return visual;
  339. }
  340. static Visual* findVisualFormat (const int desiredDepth, int& matchedDepth) noexcept
  341. {
  342. Visual* visual = nullptr;
  343. if (desiredDepth == 32)
  344. {
  345. #if JUCE_USE_XSHM
  346. if (XSHMHelpers::isShmAvailable())
  347. {
  348. #if JUCE_USE_XRENDER
  349. if (XRender::isAvailable())
  350. {
  351. if (XRenderPictFormat* pictFormat = XRender::findPictureFormat())
  352. {
  353. int numVisuals = 0;
  354. XVisualInfo desiredVisual;
  355. desiredVisual.screen = DefaultScreen (display);
  356. desiredVisual.depth = 32;
  357. desiredVisual.bits_per_rgb = 8;
  358. if (XVisualInfo* xvinfos = XGetVisualInfo (display,
  359. VisualScreenMask | VisualDepthMask | VisualBitsPerRGBMask,
  360. &desiredVisual, &numVisuals))
  361. {
  362. for (int i = 0; i < numVisuals; ++i)
  363. {
  364. XRenderPictFormat* pictVisualFormat = XRender::xRenderFindVisualFormat (display, xvinfos[i].visual);
  365. if (pictVisualFormat != nullptr
  366. && pictVisualFormat->type == PictTypeDirect
  367. && pictVisualFormat->direct.alphaMask)
  368. {
  369. visual = xvinfos[i].visual;
  370. matchedDepth = 32;
  371. break;
  372. }
  373. }
  374. XFree (xvinfos);
  375. }
  376. }
  377. }
  378. #endif
  379. if (visual == nullptr)
  380. {
  381. visual = findVisualWithDepth (32);
  382. if (visual != nullptr)
  383. matchedDepth = 32;
  384. }
  385. }
  386. #endif
  387. }
  388. if (visual == nullptr && desiredDepth >= 24)
  389. {
  390. visual = findVisualWithDepth (24);
  391. if (visual != nullptr)
  392. matchedDepth = 24;
  393. }
  394. if (visual == nullptr && desiredDepth >= 16)
  395. {
  396. visual = findVisualWithDepth (16);
  397. if (visual != nullptr)
  398. matchedDepth = 16;
  399. }
  400. return visual;
  401. }
  402. }
  403. //==============================================================================
  404. class XBitmapImage : public ImagePixelData
  405. {
  406. public:
  407. XBitmapImage (const Image::PixelFormat format, const int w, const int h,
  408. const bool clearImage, const unsigned int imageDepth_, Visual* visual)
  409. : ImagePixelData (format, w, h),
  410. imageDepth (imageDepth_),
  411. gc (None)
  412. {
  413. jassert (format == Image::RGB || format == Image::ARGB);
  414. pixelStride = (format == Image::RGB) ? 3 : 4;
  415. lineStride = ((w * pixelStride + 3) & ~3);
  416. ScopedXLock xlock;
  417. #if JUCE_USE_XSHM
  418. usingXShm = false;
  419. if ((imageDepth > 16) && XSHMHelpers::isShmAvailable())
  420. {
  421. zerostruct (segmentInfo);
  422. segmentInfo.shmid = -1;
  423. segmentInfo.shmaddr = (char *) -1;
  424. segmentInfo.readOnly = False;
  425. xImage = XShmCreateImage (display, visual, imageDepth, ZPixmap, 0,
  426. &segmentInfo, (unsigned int) w, (unsigned int) h);
  427. if (xImage != nullptr)
  428. {
  429. if ((segmentInfo.shmid = shmget (IPC_PRIVATE,
  430. (size_t) (xImage->bytes_per_line * xImage->height),
  431. IPC_CREAT | 0777)) >= 0)
  432. {
  433. if (segmentInfo.shmid != -1)
  434. {
  435. segmentInfo.shmaddr = (char*) shmat (segmentInfo.shmid, 0, 0);
  436. if (segmentInfo.shmaddr != (void*) -1)
  437. {
  438. segmentInfo.readOnly = False;
  439. xImage->data = segmentInfo.shmaddr;
  440. imageData = (uint8*) segmentInfo.shmaddr;
  441. if (XShmAttach (display, &segmentInfo) != 0)
  442. usingXShm = true;
  443. else
  444. jassertfalse;
  445. }
  446. else
  447. {
  448. shmctl (segmentInfo.shmid, IPC_RMID, 0);
  449. }
  450. }
  451. }
  452. }
  453. }
  454. if (! isUsingXShm())
  455. #endif
  456. {
  457. imageDataAllocated.allocate ((size_t) (lineStride * h), format == Image::ARGB && clearImage);
  458. imageData = imageDataAllocated;
  459. xImage = (XImage*) ::calloc (1, sizeof (XImage));
  460. xImage->width = w;
  461. xImage->height = h;
  462. xImage->xoffset = 0;
  463. xImage->format = ZPixmap;
  464. xImage->data = (char*) imageData;
  465. xImage->byte_order = ImageByteOrder (display);
  466. xImage->bitmap_unit = BitmapUnit (display);
  467. xImage->bitmap_bit_order = BitmapBitOrder (display);
  468. xImage->bitmap_pad = 32;
  469. xImage->depth = pixelStride * 8;
  470. xImage->bytes_per_line = lineStride;
  471. xImage->bits_per_pixel = pixelStride * 8;
  472. xImage->red_mask = 0x00FF0000;
  473. xImage->green_mask = 0x0000FF00;
  474. xImage->blue_mask = 0x000000FF;
  475. if (imageDepth == 16)
  476. {
  477. const int pixStride = 2;
  478. const int stride = ((w * pixStride + 3) & ~3);
  479. imageData16Bit.malloc ((size_t) (stride * h));
  480. xImage->data = imageData16Bit;
  481. xImage->bitmap_pad = 16;
  482. xImage->depth = pixStride * 8;
  483. xImage->bytes_per_line = stride;
  484. xImage->bits_per_pixel = pixStride * 8;
  485. xImage->red_mask = visual->red_mask;
  486. xImage->green_mask = visual->green_mask;
  487. xImage->blue_mask = visual->blue_mask;
  488. }
  489. if (! XInitImage (xImage))
  490. jassertfalse;
  491. }
  492. }
  493. ~XBitmapImage()
  494. {
  495. ScopedXLock xlock;
  496. if (gc != None)
  497. XFreeGC (display, gc);
  498. #if JUCE_USE_XSHM
  499. if (isUsingXShm())
  500. {
  501. XShmDetach (display, &segmentInfo);
  502. XFlush (display);
  503. XDestroyImage (xImage);
  504. shmdt (segmentInfo.shmaddr);
  505. shmctl (segmentInfo.shmid, IPC_RMID, 0);
  506. }
  507. else
  508. #endif
  509. {
  510. xImage->data = nullptr;
  511. XDestroyImage (xImage);
  512. }
  513. }
  514. LowLevelGraphicsContext* createLowLevelContext() override
  515. {
  516. sendDataChangeMessage();
  517. return new LowLevelGraphicsSoftwareRenderer (Image (this));
  518. }
  519. void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode mode) override
  520. {
  521. bitmap.data = imageData + x * pixelStride + y * lineStride;
  522. bitmap.pixelFormat = pixelFormat;
  523. bitmap.lineStride = lineStride;
  524. bitmap.pixelStride = pixelStride;
  525. if (mode != Image::BitmapData::readOnly)
  526. sendDataChangeMessage();
  527. }
  528. ImagePixelData::Ptr clone() override
  529. {
  530. jassertfalse;
  531. return nullptr;
  532. }
  533. ImageType* createType() const override { return new NativeImageType(); }
  534. void blitToWindow (Window window, int dx, int dy, unsigned int dw, unsigned int dh, int sx, int sy)
  535. {
  536. ScopedXLock xlock;
  537. if (gc == None)
  538. {
  539. XGCValues gcvalues;
  540. gcvalues.foreground = None;
  541. gcvalues.background = None;
  542. gcvalues.function = GXcopy;
  543. gcvalues.plane_mask = AllPlanes;
  544. gcvalues.clip_mask = None;
  545. gcvalues.graphics_exposures = False;
  546. gc = XCreateGC (display, window,
  547. GCBackground | GCForeground | GCFunction | GCPlaneMask | GCClipMask | GCGraphicsExposures,
  548. &gcvalues);
  549. }
  550. if (imageDepth == 16)
  551. {
  552. const uint32 rMask = (uint32) xImage->red_mask;
  553. const uint32 gMask = (uint32) xImage->green_mask;
  554. const uint32 bMask = (uint32) xImage->blue_mask;
  555. const uint32 rShiftL = (uint32) jmax (0, getShiftNeeded (rMask));
  556. const uint32 rShiftR = (uint32) jmax (0, -getShiftNeeded (rMask));
  557. const uint32 gShiftL = (uint32) jmax (0, getShiftNeeded (gMask));
  558. const uint32 gShiftR = (uint32) jmax (0, -getShiftNeeded (gMask));
  559. const uint32 bShiftL = (uint32) jmax (0, getShiftNeeded (bMask));
  560. const uint32 bShiftR = (uint32) jmax (0, -getShiftNeeded (bMask));
  561. const Image::BitmapData srcData (Image (this), Image::BitmapData::readOnly);
  562. for (int y = sy; y < sy + (int)dh; ++y)
  563. {
  564. const uint8* p = srcData.getPixelPointer (sx, y);
  565. for (int x = sx; x < sx + (int)dw; ++x)
  566. {
  567. const PixelRGB* const pixel = (const PixelRGB*) p;
  568. p += srcData.pixelStride;
  569. XPutPixel (xImage, x, y,
  570. (((((uint32) pixel->getRed()) << rShiftL) >> rShiftR) & rMask)
  571. | (((((uint32) pixel->getGreen()) << gShiftL) >> gShiftR) & gMask)
  572. | (((((uint32) pixel->getBlue()) << bShiftL) >> bShiftR) & bMask));
  573. }
  574. }
  575. }
  576. // blit results to screen.
  577. #if JUCE_USE_XSHM
  578. if (isUsingXShm())
  579. XShmPutImage (display, (::Drawable) window, gc, xImage, sx, sy, dx, dy, dw, dh, True);
  580. else
  581. #endif
  582. XPutImage (display, (::Drawable) window, gc, xImage, sx, sy, dx, dy, dw, dh);
  583. }
  584. #if JUCE_USE_XSHM
  585. bool isUsingXShm() const noexcept { return usingXShm; }
  586. #endif
  587. private:
  588. //==============================================================================
  589. XImage* xImage;
  590. const unsigned int imageDepth;
  591. HeapBlock<uint8> imageDataAllocated;
  592. HeapBlock<char> imageData16Bit;
  593. int pixelStride, lineStride;
  594. uint8* imageData;
  595. GC gc;
  596. #if JUCE_USE_XSHM
  597. XShmSegmentInfo segmentInfo;
  598. bool usingXShm;
  599. #endif
  600. static int getShiftNeeded (const uint32 mask) noexcept
  601. {
  602. for (int i = 32; --i >= 0;)
  603. if (((mask >> i) & 1) != 0)
  604. return i - 7;
  605. jassertfalse;
  606. return 0;
  607. }
  608. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XBitmapImage)
  609. };
  610. //==============================================================================
  611. #if JUCE_USE_XRANDR
  612. template <>
  613. struct ContainerDeletePolicy<XRRScreenResources>
  614. {
  615. static void destroy (XRRScreenResources* object);
  616. };
  617. template <>
  618. struct ContainerDeletePolicy<XRROutputInfo>
  619. {
  620. static void destroy (XRROutputInfo* object);
  621. };
  622. template <>
  623. struct ContainerDeletePolicy<XRRCrtcInfo>
  624. {
  625. static void destroy (XRRCrtcInfo* object);
  626. };
  627. #endif
  628. //==============================================================================
  629. class DisplayGeometry
  630. {
  631. private:
  632. //==============================================================================
  633. DisplayGeometry (::Display* dpy, double masterScale)
  634. {
  635. jassert (instance == nullptr);
  636. instance = this;
  637. queryDisplayInfos (dpy, masterScale);
  638. updatePositions();
  639. }
  640. public:
  641. //==============================================================================
  642. struct ExtendedInfo
  643. {
  644. // Unlike Desktop::Displays::Display, the following is in
  645. // physical pixels, i.e. the area is not scaled
  646. Rectangle<int> totalBounds;
  647. // Usable bounds is the usable area in local coordinates
  648. // with respect to the above totalBounds
  649. Rectangle<int> usableBounds;
  650. // top-left point of display in scaled coordinates. This
  651. // is different from totalBounds.getTopLeft() / scale,
  652. // because the neighbouring display may have a different
  653. // scale factor
  654. Point<int> topLeftScaled;
  655. double dpi, scale;
  656. bool isMain;
  657. };
  658. Array<ExtendedInfo> infos;
  659. //==============================================================================
  660. ExtendedInfo& findDisplayForRect (const Rectangle<int>& bounds, bool isScaledBounds)
  661. {
  662. int maxArea = -1;
  663. ExtendedInfo* retval = nullptr;
  664. for (int i = 0; i < infos.size(); ++i)
  665. {
  666. ExtendedInfo& dpy = infos.getReference (i);
  667. Rectangle<int> displayBounds = dpy.totalBounds;
  668. if (isScaledBounds)
  669. displayBounds = (displayBounds.withZeroOrigin() / dpy.scale) + dpy.topLeftScaled;
  670. displayBounds = displayBounds.getIntersection (bounds);
  671. int area = displayBounds.getWidth() * displayBounds.getHeight();
  672. if (area >= maxArea)
  673. {
  674. maxArea = area;
  675. retval = &dpy;
  676. }
  677. }
  678. return *retval;
  679. }
  680. ExtendedInfo& findDisplayForPoint (Point<int> pt, bool isScaledPoint)
  681. {
  682. int minDistance = (int) ((((unsigned int)(-1)) >> 1) - 1);
  683. ExtendedInfo* retval = nullptr;
  684. for (int i = 0; i < infos.size(); ++i)
  685. {
  686. ExtendedInfo& dpy = infos.getReference (i);
  687. Rectangle<int> displayBounds = dpy.totalBounds;
  688. if (isScaledPoint)
  689. displayBounds = (displayBounds.withZeroOrigin() / dpy.scale) + dpy.topLeftScaled;
  690. if (displayBounds.contains (pt))
  691. return dpy;
  692. int distance = displayBounds.getCentre().getDistanceFrom (pt);
  693. if (distance <= minDistance)
  694. {
  695. minDistance = distance;
  696. retval = &dpy;
  697. }
  698. }
  699. return *retval;
  700. }
  701. //==============================================================================
  702. static Rectangle<int> physicalToScaled (const Rectangle<int>& physicalBounds)
  703. {
  704. // first find with which display physicalBounds has the most overlap
  705. ExtendedInfo& dpy = getInstance().findDisplayForRect (physicalBounds, false);
  706. // convert to local screen bounds
  707. Rectangle<int> retval = physicalBounds - dpy.totalBounds.getTopLeft();
  708. // now we can safely scale the coordinates and convert to global again
  709. return (retval / dpy.scale) + dpy.topLeftScaled;
  710. }
  711. static Rectangle<int> scaledToPhysical (const Rectangle<int>& scaledBounds)
  712. {
  713. // first find with which display physicalBounds has the most overlap
  714. ExtendedInfo& dpy = getInstance().findDisplayForRect (scaledBounds, true);
  715. // convert to local screen bounds
  716. Rectangle<int> retval = scaledBounds - dpy.topLeftScaled;
  717. // now we can safely scale the coordinates and convert to global again
  718. return (retval * dpy.scale) + dpy.totalBounds.getTopLeft();
  719. }
  720. //==============================================================================
  721. template <typename ValueType>
  722. static Point<ValueType> physicalToScaled (const Point<ValueType>& physicalPoint)
  723. {
  724. ExtendedInfo& dpy = getInstance().findDisplayForPoint (physicalPoint.roundToInt(), false);
  725. Point<ValueType> scaledTopLeft =
  726. Point<ValueType> (dpy.topLeftScaled.getX(), dpy.topLeftScaled.getY());
  727. Point<ValueType> physicalTopLeft =
  728. Point<ValueType> (dpy.totalBounds.getX(), dpy.totalBounds.getY());
  729. return ((physicalPoint - physicalTopLeft) / dpy.scale) + scaledTopLeft;
  730. }
  731. template <typename ValueType>
  732. static Point<ValueType> scaledToPhysical (const Point<ValueType>& scaledPoint)
  733. {
  734. ExtendedInfo& dpy = getInstance().findDisplayForPoint (scaledPoint.roundToInt(), true);
  735. Point<ValueType> scaledTopLeft =
  736. Point<ValueType> (dpy.topLeftScaled.getX(), dpy.topLeftScaled.getY());
  737. Point<ValueType> physicalTopLeft =
  738. Point<ValueType> (dpy.totalBounds.getX(), dpy.totalBounds.getY());
  739. return ((scaledPoint - scaledTopLeft) * dpy.scale) + physicalTopLeft;
  740. }
  741. //==============================================================================
  742. static DisplayGeometry& getInstance()
  743. {
  744. jassert (instance != nullptr);
  745. return *instance;
  746. }
  747. static DisplayGeometry& getOrCreateInstance (::Display* dpy, double masterScale)
  748. {
  749. if (instance == nullptr)
  750. new DisplayGeometry (dpy, masterScale);
  751. return getInstance();
  752. }
  753. private:
  754. //==============================================================================
  755. static DisplayGeometry* instance;
  756. //==============================================================================
  757. #if JUCE_USE_XINERAMA
  758. static Array<XineramaScreenInfo> XineramaQueryDisplays (::Display* dpy)
  759. {
  760. typedef Bool (*tXineramaIsActive) (::Display*);
  761. typedef XineramaScreenInfo* (*tXineramaQueryScreens) (::Display*, int*);
  762. int major_opcode, first_event, first_error;
  763. if (XQueryExtension (dpy, "XINERAMA", &major_opcode, &first_event, &first_error))
  764. {
  765. static void* libXinerama = nullptr;
  766. static tXineramaIsActive isActiveFuncPtr = nullptr;
  767. static tXineramaQueryScreens xineramaQueryScreens = nullptr;
  768. if (libXinerama == nullptr)
  769. {
  770. libXinerama = dlopen ("libXinerama.so", RTLD_GLOBAL | RTLD_NOW);
  771. if (libXinerama == nullptr)
  772. libXinerama = dlopen ("libXinerama.so.1", RTLD_GLOBAL | RTLD_NOW);
  773. if (libXinerama != nullptr)
  774. {
  775. isActiveFuncPtr = (tXineramaIsActive) dlsym (libXinerama, "XineramaIsActive");
  776. xineramaQueryScreens = (tXineramaQueryScreens) dlsym (libXinerama, "XineramaQueryScreens");
  777. }
  778. }
  779. if (isActiveFuncPtr != nullptr && xineramaQueryScreens != nullptr && isActiveFuncPtr (dpy) != 0)
  780. {
  781. int numScreens;
  782. if (XineramaScreenInfo* xinfo = xineramaQueryScreens (dpy, &numScreens))
  783. {
  784. Array<XineramaScreenInfo> infos (xinfo, numScreens);
  785. XFree (xinfo);
  786. return infos;
  787. }
  788. }
  789. }
  790. return Array<XineramaScreenInfo>();
  791. }
  792. #endif
  793. //==============================================================================
  794. #if JUCE_USE_XRANDR
  795. friend struct ContainerDeletePolicy<XRRScreenResources>;
  796. friend struct ContainerDeletePolicy<XRROutputInfo>;
  797. friend struct ContainerDeletePolicy<XRRCrtcInfo>;
  798. class XRandrWrapper
  799. {
  800. private:
  801. XRandrWrapper()
  802. : libXrandr (nullptr),
  803. getScreenResourcesPtr (nullptr),
  804. freeScreenResourcesPtr (nullptr),
  805. getOutputInfoPtr (nullptr),
  806. freeOutputInfoPtr (nullptr),
  807. getCrtcInfoPtr (nullptr),
  808. freeCrtcInfoPtr (nullptr),
  809. getOutputPrimaryPtr (nullptr)
  810. {
  811. if (libXrandr == nullptr)
  812. {
  813. libXrandr = dlopen ("libXrandr.so", RTLD_GLOBAL | RTLD_NOW);
  814. if (libXrandr == nullptr)
  815. libXrandr = dlopen ("libXinerama.so.2", RTLD_GLOBAL | RTLD_NOW);
  816. if (libXrandr != nullptr)
  817. {
  818. getScreenResourcesPtr = (tXRRGetScreenResources) dlsym (libXrandr, "XRRGetScreenResources");
  819. freeScreenResourcesPtr = (tXRRFreeScreenResources) dlsym (libXrandr, "XRRFreeScreenResources");
  820. getOutputInfoPtr = (tXRRGetOutputInfo) dlsym (libXrandr, "XRRGetOutputInfo");
  821. freeOutputInfoPtr = (tXRRFreeOutputInfo) dlsym (libXrandr, "XRRFreeOutputInfo");
  822. getCrtcInfoPtr = (tXRRGetCrtcInfo) dlsym (libXrandr, "XRRGetCrtcInfo");
  823. freeCrtcInfoPtr = (tXRRFreeCrtcInfo) dlsym (libXrandr, "XRRFreeCrtcInfo");
  824. getOutputPrimaryPtr = (tXRRGetOutputPrimary) dlsym (libXrandr, "XRRGetOutputPrimary");
  825. }
  826. }
  827. instance = this;
  828. }
  829. public:
  830. //==============================================================================
  831. static XRandrWrapper& getInstance()
  832. {
  833. if (instance == nullptr)
  834. instance = new XRandrWrapper();
  835. return *instance;
  836. }
  837. //==============================================================================
  838. XRRScreenResources* getScreenResources (::Display* dpy, ::Window window)
  839. {
  840. if (getScreenResourcesPtr != nullptr)
  841. return getScreenResourcesPtr (dpy, window);
  842. return nullptr;
  843. }
  844. XRROutputInfo* getOutputInfo (::Display* dpy, XRRScreenResources* resources, RROutput output)
  845. {
  846. if (getOutputInfoPtr != nullptr)
  847. return getOutputInfoPtr (dpy, resources, output);
  848. return nullptr;
  849. }
  850. XRRCrtcInfo* getCrtcInfo (::Display* dpy, XRRScreenResources* resources, RRCrtc crtc)
  851. {
  852. if (getCrtcInfoPtr != nullptr)
  853. return getCrtcInfoPtr (dpy, resources, crtc);
  854. return nullptr;
  855. }
  856. RROutput getOutputPrimary (::Display* dpy, ::Window window)
  857. {
  858. if (getOutputPrimaryPtr != nullptr)
  859. return getOutputPrimaryPtr (dpy, window);
  860. return 0;
  861. }
  862. private:
  863. //==============================================================================
  864. friend struct ContainerDeletePolicy<XRRScreenResources>;
  865. friend struct ContainerDeletePolicy<XRROutputInfo>;
  866. friend struct ContainerDeletePolicy<XRRCrtcInfo>;
  867. void freeScreenResources (XRRScreenResources* ptr)
  868. {
  869. if (freeScreenResourcesPtr != nullptr)
  870. freeScreenResourcesPtr (ptr);
  871. }
  872. void freeOutputInfo (XRROutputInfo* ptr)
  873. {
  874. if (freeOutputInfoPtr != nullptr)
  875. freeOutputInfoPtr (ptr);
  876. }
  877. void freeCrtcInfo (XRRCrtcInfo* ptr)
  878. {
  879. if (freeCrtcInfoPtr != nullptr)
  880. freeCrtcInfoPtr (ptr);
  881. }
  882. private:
  883. static XRandrWrapper* instance;
  884. typedef XRRScreenResources* (*tXRRGetScreenResources) (::Display*, ::Window);
  885. typedef void (*tXRRFreeScreenResources) (XRRScreenResources*);
  886. typedef XRROutputInfo* (*tXRRGetOutputInfo) (::Display*, XRRScreenResources*, RROutput);
  887. typedef void (*tXRRFreeOutputInfo) (XRROutputInfo*);
  888. typedef XRRCrtcInfo* (*tXRRGetCrtcInfo) (::Display*, XRRScreenResources*, RRCrtc);
  889. typedef void (*tXRRFreeCrtcInfo) (XRRCrtcInfo*);
  890. typedef RROutput (*tXRRGetOutputPrimary) (::Display*, ::Window);
  891. void* libXrandr;
  892. tXRRGetScreenResources getScreenResourcesPtr;
  893. tXRRFreeScreenResources freeScreenResourcesPtr;
  894. tXRRGetOutputInfo getOutputInfoPtr;
  895. tXRRFreeOutputInfo freeOutputInfoPtr;
  896. tXRRGetCrtcInfo getCrtcInfoPtr;
  897. tXRRFreeCrtcInfo freeCrtcInfoPtr;
  898. tXRRGetOutputPrimary getOutputPrimaryPtr;
  899. };
  900. #endif
  901. static double getDisplayDPI (int index)
  902. {
  903. double dpiX = (DisplayWidth (display, index) * 25.4) / DisplayWidthMM (display, index);
  904. double dpiY = (DisplayHeight (display, index) * 25.4) / DisplayHeightMM (display, index);
  905. return (dpiX + dpiY) / 2.0;
  906. }
  907. static double getScaleForDisplay (const String& name, const ExtendedInfo& info)
  908. {
  909. if (! name.isEmpty())
  910. {
  911. // Ubuntu and derived distributions now save a per-display scale factor as a configuration
  912. // variable. This can be changed in the Monitor system settings panel.
  913. ChildProcess dconf;
  914. if (File ("/usr/bin/dconf").existsAsFile() &&
  915. dconf.start ("/usr/bin/dconf read /com/ubuntu/user-interface/scale-factor", ChildProcess::wantStdOut))
  916. {
  917. if (dconf.waitForProcessToFinish (200))
  918. {
  919. String jsonOutput = dconf.readAllProcessOutput().replaceCharacter ('\'', '"');
  920. if (dconf.getExitCode() == 0 && jsonOutput.isNotEmpty())
  921. {
  922. var jsonVar = JSON::parse (jsonOutput);
  923. if (DynamicObject* object = jsonVar.getDynamicObject())
  924. {
  925. var scaleFactorVar = object->getProperty (name);
  926. if (! scaleFactorVar.isVoid())
  927. {
  928. double scaleFactor = ((double) scaleFactorVar) / 8.0;
  929. if (scaleFactor > 0.0)
  930. return scaleFactor;
  931. }
  932. }
  933. }
  934. }
  935. }
  936. }
  937. {
  938. // Other gnome based distros now use gsettings for a global scale factor
  939. ChildProcess gsettings;
  940. if (File ("/usr/bin/gsettings").existsAsFile() &&
  941. gsettings.start ("/usr/bin/gsettings get org.gnome.desktop.interface scaling-factor", ChildProcess::wantStdOut))
  942. {
  943. if (gsettings.waitForProcessToFinish (200))
  944. {
  945. StringArray gsettingsOutput = StringArray::fromTokens (gsettings.readAllProcessOutput(), true);
  946. if (gsettingsOutput.size() >= 2 && gsettingsOutput[1].length() > 0)
  947. {
  948. double scaleFactor = gsettingsOutput[1].getDoubleValue();
  949. if (scaleFactor > 0.0)
  950. return scaleFactor;
  951. }
  952. }
  953. }
  954. }
  955. // If no scale factor is set by GNOME or Ubuntu then calculate from monitor dpi
  956. // We use the same approach as chromium which simply divides the dpi by 96
  957. // and then rounds the result
  958. return round (info.dpi / 150.0);
  959. }
  960. //==============================================================================
  961. void queryDisplayInfos (::Display* dpy, double masterScale) noexcept
  962. {
  963. ScopedXLock xlock;
  964. #if JUCE_USE_XRANDR
  965. {
  966. int major_opcode, first_event, first_error;
  967. if (XQueryExtension (dpy, "RANDR", &major_opcode, &first_event, &first_error))
  968. {
  969. XRandrWrapper& xrandr = XRandrWrapper::getInstance();
  970. ScopedPointer<XRRScreenResources> screens;
  971. const int numMonitors = ScreenCount (dpy);
  972. RROutput mainDisplay = xrandr.getOutputPrimary (dpy, RootWindow (dpy, 0));
  973. for (int i = 0; i < numMonitors; ++i)
  974. {
  975. if ((screens = xrandr.getScreenResources (dpy, RootWindow (dpy, i))).get())
  976. {
  977. for (int j = 0; j < screens->noutput; ++j)
  978. {
  979. if (! screens->outputs[j])
  980. continue;
  981. // Xrandr on the raspberry pi fails to determine the main display (mainDisplay == 0)!
  982. // Detect this edge case and make the first found display the main display
  983. if (! mainDisplay)
  984. mainDisplay = screens->outputs[j];
  985. ScopedPointer<XRROutputInfo> output;
  986. if ((output = xrandr.getOutputInfo (dpy, screens.get(), screens->outputs[j])).get())
  987. {
  988. if (! output->crtc)
  989. continue;
  990. ScopedPointer<XRRCrtcInfo> crtc;
  991. if ((crtc = xrandr.getCrtcInfo (dpy, screens.get(), output->crtc)).get())
  992. {
  993. ExtendedInfo e;
  994. e.totalBounds = Rectangle<int> (crtc->x, crtc->y,
  995. (int) crtc->width, (int) crtc->height);
  996. e.usableBounds = e.totalBounds.withZeroOrigin(); // Support for usable area is not implemented in JUCE yet
  997. e.topLeftScaled = e.totalBounds.getTopLeft();
  998. e.isMain = (mainDisplay == screens->outputs[j]) && (i == 0);
  999. e.dpi = getDisplayDPI (0);
  1000. // The raspberry pi returns a zero sized display, so we need to guard for divide-by-zero
  1001. if (output->mm_width > 0 && output->mm_height > 0)
  1002. e.dpi = ((static_cast<double> (crtc->width) * 25.4 * 0.5) / static_cast<double> (output->mm_width))
  1003. + ((static_cast<double> (crtc->height) * 25.4 * 0.5) / static_cast<double> (output->mm_height));
  1004. double scale = getScaleForDisplay (output->name, e);
  1005. scale = (scale <= 0.1 ? 1.0 : scale);
  1006. e.scale = masterScale * scale;
  1007. infos.add (e);
  1008. }
  1009. }
  1010. }
  1011. }
  1012. }
  1013. }
  1014. }
  1015. if (infos.size() == 0)
  1016. #endif
  1017. #if JUCE_USE_XINERAMA
  1018. {
  1019. Array<XineramaScreenInfo> screens = XineramaQueryDisplays (dpy);
  1020. int numMonitors = screens.size();
  1021. for (int index = 0; index < numMonitors; ++index)
  1022. {
  1023. for (int j = numMonitors; --j >= 0;)
  1024. {
  1025. if (screens[j].screen_number == index)
  1026. {
  1027. ExtendedInfo e;
  1028. e.totalBounds = Rectangle<int> (screens[j].x_org,
  1029. screens[j].y_org,
  1030. screens[j].width,
  1031. screens[j].height);
  1032. e.usableBounds = e.totalBounds.withZeroOrigin(); // Support for usable area is not implemented in JUCE yet
  1033. e.topLeftScaled = e.totalBounds.getTopLeft(); // this will be overwritten by updatePositions later
  1034. e.isMain = (index == 0);
  1035. e.scale = masterScale;
  1036. e.dpi = getDisplayDPI (0); // (all screens share the same DPI)
  1037. infos.add (e);
  1038. }
  1039. }
  1040. }
  1041. }
  1042. if (infos.size() == 0)
  1043. #endif
  1044. {
  1045. Atom hints = Atoms::getIfExists ("_NET_WORKAREA");
  1046. if (hints != None)
  1047. {
  1048. const int numMonitors = ScreenCount (dpy);
  1049. for (int i = 0; i < numMonitors; ++i)
  1050. {
  1051. GetXProperty prop (RootWindow (dpy, i), hints, 0, 4, false, XA_CARDINAL);
  1052. if (prop.success && prop.actualType == XA_CARDINAL && prop.actualFormat == 32 && prop.numItems == 4)
  1053. {
  1054. const long* const position = (const long*) prop.data;
  1055. ExtendedInfo e;
  1056. e.totalBounds = Rectangle<int> ((int) position[0], (int) position[1],
  1057. (int) position[2], (int) position[3]);
  1058. e.usableBounds = e.totalBounds.withZeroOrigin(); // Support for usable area is not implemented in JUCE yet
  1059. e.topLeftScaled = e.totalBounds.getTopLeft(); // this will be overwritten by updatePositions later
  1060. e.isMain = (infos.size() == 0);
  1061. e.scale = masterScale;
  1062. e.dpi = getDisplayDPI (i);
  1063. infos.add (e);
  1064. }
  1065. }
  1066. }
  1067. if (infos.size() == 0)
  1068. {
  1069. ExtendedInfo e;
  1070. e.totalBounds = Rectangle<int> (DisplayWidth (dpy, DefaultScreen (dpy)),
  1071. DisplayHeight (dpy, DefaultScreen (dpy)));
  1072. e.usableBounds = e.totalBounds; // Support for usable area is not implemented in JUCE yet
  1073. e.topLeftScaled = e.totalBounds.getTopLeft(); // this will be overwritten by updatePositions later
  1074. e.isMain = true;
  1075. e.scale = masterScale;
  1076. e.dpi = getDisplayDPI (0);
  1077. infos.add (e);
  1078. }
  1079. }
  1080. }
  1081. //==============================================================================
  1082. struct SortByCoordinate
  1083. {
  1084. bool sortByYCoordinate;
  1085. SortByCoordinate (bool byYCoordinate)
  1086. : sortByYCoordinate (byYCoordinate)
  1087. {
  1088. }
  1089. int compareElements (const ExtendedInfo* a, const ExtendedInfo* b)
  1090. {
  1091. int coordinateA, coordinateB;
  1092. if (sortByYCoordinate)
  1093. {
  1094. coordinateA = a->totalBounds.getY();
  1095. coordinateB = b->totalBounds.getY();
  1096. }
  1097. else
  1098. {
  1099. coordinateA = a->totalBounds.getX();
  1100. coordinateB = b->totalBounds.getX();
  1101. }
  1102. return coordinateA - coordinateB;
  1103. }
  1104. };
  1105. //==============================================================================
  1106. void updateScaledDisplayCoordinate(bool updateYCoordinates)
  1107. {
  1108. if (infos.size() < 2)
  1109. return;
  1110. Array<ExtendedInfo*> copy;
  1111. {
  1112. SortByCoordinate sorter (updateYCoordinates);
  1113. for (int i = 0; i < infos.size(); ++i)
  1114. copy.addSorted (sorter, &infos.getReference (i));
  1115. }
  1116. for (int i = 1; i < copy.size(); ++i)
  1117. {
  1118. ExtendedInfo& current = *copy[i];
  1119. // Is this screen's position aligned to any other previous display?
  1120. for (int j = i - 1; j >= 0; --j)
  1121. {
  1122. ExtendedInfo& other = *copy[j];
  1123. int prevCoordinate = updateYCoordinates ? other.totalBounds.getBottom() : other.totalBounds.getRight();
  1124. int curCoordinate = updateYCoordinates ? current.totalBounds.getY() : current.totalBounds.getX();
  1125. if (prevCoordinate == curCoordinate)
  1126. {
  1127. // both displays are aligned! As "other" comes before "current" in the array, it must already
  1128. // have a valid topLeftScaled which we can use
  1129. Point<int> topLeftScaled = other.topLeftScaled;
  1130. topLeftScaled += Point<int> (other.totalBounds.getWidth(), other.totalBounds.getHeight()) / other.scale;
  1131. if (updateYCoordinates)
  1132. current.topLeftScaled.setY (topLeftScaled.getY());
  1133. else
  1134. current.topLeftScaled.setX (topLeftScaled.getX());
  1135. break;
  1136. }
  1137. }
  1138. }
  1139. }
  1140. void updatePositions()
  1141. {
  1142. updateScaledDisplayCoordinate (false);
  1143. updateScaledDisplayCoordinate (true);
  1144. }
  1145. };
  1146. DisplayGeometry* DisplayGeometry::instance = nullptr;
  1147. #if JUCE_USE_XRANDR
  1148. DisplayGeometry::XRandrWrapper* DisplayGeometry::XRandrWrapper::instance = nullptr;
  1149. void ContainerDeletePolicy<XRRScreenResources>::destroy (XRRScreenResources* ptr)
  1150. {
  1151. if (ptr != nullptr)
  1152. DisplayGeometry::XRandrWrapper::getInstance().freeScreenResources (ptr);
  1153. }
  1154. void ContainerDeletePolicy<XRROutputInfo>::destroy (XRROutputInfo* ptr)
  1155. {
  1156. if (ptr != nullptr)
  1157. DisplayGeometry::XRandrWrapper::getInstance().freeOutputInfo (ptr);
  1158. }
  1159. void ContainerDeletePolicy<XRRCrtcInfo>::destroy (XRRCrtcInfo* ptr)
  1160. {
  1161. if (ptr != nullptr)
  1162. DisplayGeometry::XRandrWrapper::getInstance().freeCrtcInfo (ptr);
  1163. }
  1164. #endif
  1165. //==============================================================================
  1166. namespace PixmapHelpers
  1167. {
  1168. Pixmap createColourPixmapFromImage (Display* display, const Image& image)
  1169. {
  1170. ScopedXLock xlock;
  1171. const unsigned int width = (unsigned int) image.getWidth();
  1172. const unsigned int height = (unsigned int) image.getHeight();
  1173. HeapBlock<uint32> colour (width * height);
  1174. int index = 0;
  1175. for (int y = 0; y < (int) height; ++y)
  1176. for (int x = 0; x < (int) width; ++x)
  1177. colour[index++] = image.getPixelAt (x, y).getARGB();
  1178. XImage* ximage = XCreateImage (display, CopyFromParent, 24, ZPixmap,
  1179. 0, reinterpret_cast<char*> (colour.getData()),
  1180. width, height, 32, 0);
  1181. Pixmap pixmap = XCreatePixmap (display, DefaultRootWindow (display),
  1182. width, height, 24);
  1183. GC gc = XCreateGC (display, pixmap, 0, 0);
  1184. XPutImage (display, pixmap, gc, ximage, 0, 0, 0, 0, width, height);
  1185. XFreeGC (display, gc);
  1186. return pixmap;
  1187. }
  1188. Pixmap createMaskPixmapFromImage (Display* display, const Image& image)
  1189. {
  1190. ScopedXLock xlock;
  1191. const unsigned int width = (unsigned int) image.getWidth();
  1192. const unsigned int height = (unsigned int) image.getHeight();
  1193. const unsigned int stride = (width + 7) >> 3;
  1194. HeapBlock<char> mask;
  1195. mask.calloc (stride * height);
  1196. const bool msbfirst = (BitmapBitOrder (display) == MSBFirst);
  1197. for (unsigned int y = 0; y < height; ++y)
  1198. {
  1199. for (unsigned int x = 0; x < width; ++x)
  1200. {
  1201. const char bit = (char) (1 << (msbfirst ? (7 - (x & 7)) : (x & 7)));
  1202. const unsigned int offset = y * stride + (x >> 3);
  1203. if (image.getPixelAt ((int) x, (int) y).getAlpha() >= 128)
  1204. mask[offset] |= bit;
  1205. }
  1206. }
  1207. return XCreatePixmapFromBitmapData (display, DefaultRootWindow (display),
  1208. mask.getData(), width, height, 1, 0, 1);
  1209. }
  1210. }
  1211. static void* createDraggingHandCursor()
  1212. {
  1213. static unsigned char dragHandData[] = { 71,73,70,56,57,97,16,0,16,0,145,2,0,0,0,0,255,255,255,0,
  1214. 0,0,0,0,0,33,249,4,1,0,0,2,0,44,0,0,0,0,16,0, 16,0,0,2,52,148,47,0,200,185,16,130,90,12,74,139,107,84,123,39,
  1215. 132,117,151,116,132,146,248,60,209,138,98,22,203,114,34,236,37,52,77,217, 247,154,191,119,110,240,193,128,193,95,163,56,60,234,98,135,2,0,59 };
  1216. const int dragHandDataSize = 99;
  1217. return CustomMouseCursorInfo (ImageFileFormat::loadFrom (dragHandData, dragHandDataSize), 8, 7).create();
  1218. }
  1219. //==============================================================================
  1220. static int numAlwaysOnTopPeers = 0;
  1221. bool juce_areThereAnyAlwaysOnTopWindows()
  1222. {
  1223. return numAlwaysOnTopPeers > 0;
  1224. }
  1225. //==============================================================================
  1226. class LinuxComponentPeer : public ComponentPeer
  1227. {
  1228. public:
  1229. LinuxComponentPeer (Component& comp, const int windowStyleFlags, Window parentToAddTo)
  1230. : ComponentPeer (comp, windowStyleFlags),
  1231. windowH (0), parentWindow (0),
  1232. fullScreen (false), mapped (false),
  1233. visual (nullptr), depth (0),
  1234. isAlwaysOnTop (comp.isAlwaysOnTop()),
  1235. currentScaleFactor (1.0)
  1236. {
  1237. // it's dangerous to create a window on a thread other than the message thread..
  1238. jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
  1239. dispatchWindowMessage = windowMessageReceive;
  1240. repainter = new LinuxRepaintManager (*this);
  1241. if (isAlwaysOnTop)
  1242. ++numAlwaysOnTopPeers;
  1243. createWindow (parentToAddTo);
  1244. setTitle (component.getName());
  1245. }
  1246. ~LinuxComponentPeer()
  1247. {
  1248. // it's dangerous to delete a window on a thread other than the message thread..
  1249. jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
  1250. deleteIconPixmaps();
  1251. destroyWindow();
  1252. windowH = 0;
  1253. if (isAlwaysOnTop)
  1254. --numAlwaysOnTopPeers;
  1255. }
  1256. // (this callback is hooked up in the messaging code)
  1257. static void windowMessageReceive (XEvent& event)
  1258. {
  1259. if (event.xany.window != None)
  1260. {
  1261. if (LinuxComponentPeer* const peer = getPeerFor (event.xany.window))
  1262. peer->handleWindowMessage (event);
  1263. }
  1264. else if (event.xany.type == KeymapNotify)
  1265. {
  1266. const XKeymapEvent& keymapEvent = (const XKeymapEvent&) event.xkeymap;
  1267. memcpy (Keys::keyStates, keymapEvent.key_vector, 32);
  1268. }
  1269. }
  1270. //==============================================================================
  1271. void* getNativeHandle() const override
  1272. {
  1273. return (void*) windowH;
  1274. }
  1275. static LinuxComponentPeer* getPeerFor (Window windowHandle) noexcept
  1276. {
  1277. XPointer peer = nullptr;
  1278. if (display != nullptr)
  1279. {
  1280. ScopedXLock xlock;
  1281. if (! XFindContext (display, (XID) windowHandle, windowHandleXContext, &peer))
  1282. if (peer != nullptr && ! ComponentPeer::isValidPeer (reinterpret_cast<LinuxComponentPeer*> (peer)))
  1283. peer = nullptr;
  1284. }
  1285. return reinterpret_cast<LinuxComponentPeer*> (peer);
  1286. }
  1287. void setVisible (bool shouldBeVisible) override
  1288. {
  1289. ScopedXLock xlock;
  1290. if (shouldBeVisible)
  1291. XMapWindow (display, windowH);
  1292. else
  1293. XUnmapWindow (display, windowH);
  1294. }
  1295. void setTitle (const String& title) override
  1296. {
  1297. XTextProperty nameProperty;
  1298. char* strings[] = { const_cast<char*> (title.toRawUTF8()) };
  1299. ScopedXLock xlock;
  1300. if (XStringListToTextProperty (strings, 1, &nameProperty))
  1301. {
  1302. XSetWMName (display, windowH, &nameProperty);
  1303. XSetWMIconName (display, windowH, &nameProperty);
  1304. XFree (nameProperty.value);
  1305. }
  1306. }
  1307. void setBounds (const Rectangle<int>& newBounds, bool isNowFullScreen) override
  1308. {
  1309. if (fullScreen && ! isNowFullScreen)
  1310. {
  1311. // When transitioning back from fullscreen, we might need to remove
  1312. // the FULLSCREEN window property
  1313. Atom fs = Atoms::getIfExists ("_NET_WM_STATE_FULLSCREEN");
  1314. if (fs != None)
  1315. {
  1316. Window root = RootWindow (display, DefaultScreen (display));
  1317. XClientMessageEvent clientMsg;
  1318. clientMsg.display = display;
  1319. clientMsg.window = windowH;
  1320. clientMsg.type = ClientMessage;
  1321. clientMsg.format = 32;
  1322. clientMsg.message_type = atoms.windowState;
  1323. clientMsg.data.l[0] = 0; // Remove
  1324. clientMsg.data.l[1] = (long) fs;
  1325. clientMsg.data.l[2] = 0;
  1326. clientMsg.data.l[3] = 1; // Normal Source
  1327. ScopedXLock xlock;
  1328. XSendEvent (display, root, false,
  1329. SubstructureRedirectMask | SubstructureNotifyMask,
  1330. (XEvent*) &clientMsg);
  1331. }
  1332. }
  1333. fullScreen = isNowFullScreen;
  1334. if (windowH != 0)
  1335. {
  1336. bounds = newBounds.withSize (jmax (1, newBounds.getWidth()),
  1337. jmax (1, newBounds.getHeight()));
  1338. currentScaleFactor = DisplayGeometry::getInstance().findDisplayForRect (bounds, true).scale;
  1339. Rectangle<int> physicalBounds =
  1340. DisplayGeometry::scaledToPhysical (bounds);
  1341. WeakReference<Component> deletionChecker (&component);
  1342. ScopedXLock xlock;
  1343. XSizeHints* const hints = XAllocSizeHints();
  1344. hints->flags = USSize | USPosition;
  1345. hints->x = physicalBounds.getX();
  1346. hints->y = physicalBounds.getY();
  1347. hints->width = physicalBounds.getWidth();
  1348. hints->height = physicalBounds.getHeight();
  1349. if ((getStyleFlags() & windowIsResizable) == 0)
  1350. {
  1351. hints->min_width = hints->max_width = hints->width;
  1352. hints->min_height = hints->max_height = hints->height;
  1353. hints->flags |= PMinSize | PMaxSize;
  1354. }
  1355. XSetWMNormalHints (display, windowH, hints);
  1356. XFree (hints);
  1357. XMoveResizeWindow (display, windowH,
  1358. physicalBounds.getX() - windowBorder.getLeft(),
  1359. physicalBounds.getY() - windowBorder.getTop(),
  1360. (unsigned int) physicalBounds.getWidth(),
  1361. (unsigned int) physicalBounds.getHeight());
  1362. if (deletionChecker != nullptr)
  1363. {
  1364. updateBorderSize();
  1365. handleMovedOrResized();
  1366. }
  1367. }
  1368. }
  1369. Rectangle<int> getBounds() const override { return bounds; }
  1370. Point<float> localToGlobal (Point<float> relativePosition) override
  1371. {
  1372. return relativePosition + bounds.getPosition().toFloat();
  1373. }
  1374. Point<float> globalToLocal (Point<float> screenPosition) override
  1375. {
  1376. return screenPosition - bounds.getPosition().toFloat();
  1377. }
  1378. void setAlpha (float /* newAlpha */) override
  1379. {
  1380. //xxx todo!
  1381. }
  1382. StringArray getAvailableRenderingEngines() override
  1383. {
  1384. return StringArray ("Software Renderer");
  1385. }
  1386. void setMinimised (bool shouldBeMinimised) override
  1387. {
  1388. if (shouldBeMinimised)
  1389. {
  1390. Window root = RootWindow (display, DefaultScreen (display));
  1391. XClientMessageEvent clientMsg;
  1392. clientMsg.display = display;
  1393. clientMsg.window = windowH;
  1394. clientMsg.type = ClientMessage;
  1395. clientMsg.format = 32;
  1396. clientMsg.message_type = atoms.changeState;
  1397. clientMsg.data.l[0] = IconicState;
  1398. ScopedXLock xlock;
  1399. XSendEvent (display, root, false, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*) &clientMsg);
  1400. }
  1401. else
  1402. {
  1403. setVisible (true);
  1404. }
  1405. }
  1406. bool isMinimised() const override
  1407. {
  1408. ScopedXLock xlock;
  1409. GetXProperty prop (windowH, atoms.state, 0, 64, false, atoms.state);
  1410. return prop.success
  1411. && prop.actualType == atoms.state
  1412. && prop.actualFormat == 32
  1413. && prop.numItems > 0
  1414. && ((unsigned long*) prop.data)[0] == IconicState;
  1415. }
  1416. void setFullScreen (const bool shouldBeFullScreen) override
  1417. {
  1418. Rectangle<int> r (lastNonFullscreenBounds); // (get a copy of this before de-minimising)
  1419. setMinimised (false);
  1420. if (fullScreen != shouldBeFullScreen)
  1421. {
  1422. if (shouldBeFullScreen)
  1423. r = Desktop::getInstance().getDisplays().getMainDisplay().userArea;
  1424. if (! r.isEmpty())
  1425. setBounds (ScalingHelpers::scaledScreenPosToUnscaled (component, r), shouldBeFullScreen);
  1426. component.repaint();
  1427. }
  1428. }
  1429. bool isFullScreen() const override
  1430. {
  1431. return fullScreen;
  1432. }
  1433. bool isChildWindowOf (Window possibleParent) const
  1434. {
  1435. Window* windowList = nullptr;
  1436. uint32 windowListSize = 0;
  1437. Window parent, root;
  1438. ScopedXLock xlock;
  1439. if (XQueryTree (display, windowH, &root, &parent, &windowList, &windowListSize) != 0)
  1440. {
  1441. if (windowList != nullptr)
  1442. XFree (windowList);
  1443. return parent == possibleParent;
  1444. }
  1445. return false;
  1446. }
  1447. bool isFrontWindow() const
  1448. {
  1449. Window* windowList = nullptr;
  1450. uint32 windowListSize = 0;
  1451. bool result = false;
  1452. ScopedXLock xlock;
  1453. Window parent, root = RootWindow (display, DefaultScreen (display));
  1454. if (XQueryTree (display, root, &root, &parent, &windowList, &windowListSize) != 0)
  1455. {
  1456. for (int i = (int) windowListSize; --i >= 0;)
  1457. {
  1458. if (LinuxComponentPeer* const peer = LinuxComponentPeer::getPeerFor (windowList[i]))
  1459. {
  1460. result = (peer == this);
  1461. break;
  1462. }
  1463. }
  1464. }
  1465. if (windowList != nullptr)
  1466. XFree (windowList);
  1467. return result;
  1468. }
  1469. bool contains (Point<int> localPos, bool trueIfInAChildWindow) const override
  1470. {
  1471. if (! bounds.withZeroOrigin().contains (localPos))
  1472. return false;
  1473. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  1474. {
  1475. Component* const c = Desktop::getInstance().getComponent (i);
  1476. if (c == &component)
  1477. break;
  1478. if (ComponentPeer* peer = c->getPeer())
  1479. if (peer->contains (localPos + bounds.getPosition() - peer->getBounds().getPosition(), true))
  1480. return false;
  1481. }
  1482. if (trueIfInAChildWindow)
  1483. return true;
  1484. ::Window root, child;
  1485. int wx, wy;
  1486. unsigned int ww, wh, bw, bitDepth;
  1487. ScopedXLock xlock;
  1488. localPos *= currentScaleFactor;
  1489. return XGetGeometry (display, (::Drawable) windowH, &root, &wx, &wy, &ww, &wh, &bw, &bitDepth)
  1490. && XTranslateCoordinates (display, windowH, windowH, localPos.getX(), localPos.getY(), &wx, &wy, &child)
  1491. && child == None;
  1492. }
  1493. BorderSize<int> getFrameSize() const override
  1494. {
  1495. return BorderSize<int>();
  1496. }
  1497. bool setAlwaysOnTop (bool /* alwaysOnTop */) override
  1498. {
  1499. return false;
  1500. }
  1501. void toFront (bool makeActive) override
  1502. {
  1503. if (makeActive)
  1504. {
  1505. setVisible (true);
  1506. grabFocus();
  1507. }
  1508. {
  1509. ScopedXLock xlock;
  1510. XEvent ev;
  1511. ev.xclient.type = ClientMessage;
  1512. ev.xclient.serial = 0;
  1513. ev.xclient.send_event = True;
  1514. ev.xclient.message_type = atoms.activeWin;
  1515. ev.xclient.window = windowH;
  1516. ev.xclient.format = 32;
  1517. ev.xclient.data.l[0] = 2;
  1518. ev.xclient.data.l[1] = getUserTime();
  1519. ev.xclient.data.l[2] = 0;
  1520. ev.xclient.data.l[3] = 0;
  1521. ev.xclient.data.l[4] = 0;
  1522. XSendEvent (display, RootWindow (display, DefaultScreen (display)),
  1523. False, SubstructureRedirectMask | SubstructureNotifyMask, &ev);
  1524. XSync (display, False);
  1525. }
  1526. handleBroughtToFront();
  1527. }
  1528. void toBehind (ComponentPeer* other) override
  1529. {
  1530. if (LinuxComponentPeer* const otherPeer = dynamic_cast<LinuxComponentPeer*> (other))
  1531. {
  1532. if (otherPeer->styleFlags & windowIsTemporary)
  1533. return;
  1534. setMinimised (false);
  1535. Window newStack[] = { otherPeer->windowH, windowH };
  1536. ScopedXLock xlock;
  1537. XRestackWindows (display, newStack, 2);
  1538. }
  1539. else
  1540. jassertfalse; // wrong type of window?
  1541. }
  1542. bool isFocused() const override
  1543. {
  1544. int revert = 0;
  1545. Window focusedWindow = 0;
  1546. ScopedXLock xlock;
  1547. XGetInputFocus (display, &focusedWindow, &revert);
  1548. return focusedWindow == windowH;
  1549. }
  1550. void grabFocus() override
  1551. {
  1552. XWindowAttributes atts;
  1553. ScopedXLock xlock;
  1554. if (windowH != 0
  1555. && XGetWindowAttributes (display, windowH, &atts)
  1556. && atts.map_state == IsViewable
  1557. && ! isFocused())
  1558. {
  1559. XSetInputFocus (display, windowH, RevertToParent, (::Time) getUserTime());
  1560. isActiveApplication = true;
  1561. }
  1562. }
  1563. void textInputRequired (Point<int>, TextInputTarget&) override {}
  1564. void repaint (const Rectangle<int>& area) override
  1565. {
  1566. repainter->repaint (area.getIntersection (bounds.withZeroOrigin()));
  1567. }
  1568. void performAnyPendingRepaintsNow() override
  1569. {
  1570. repainter->performAnyPendingRepaintsNow();
  1571. }
  1572. void setIcon (const Image& newIcon) override
  1573. {
  1574. const int dataSize = newIcon.getWidth() * newIcon.getHeight() + 2;
  1575. HeapBlock<unsigned long> data ((size_t) dataSize);
  1576. int index = 0;
  1577. data[index++] = (unsigned long) newIcon.getWidth();
  1578. data[index++] = (unsigned long) newIcon.getHeight();
  1579. for (int y = 0; y < newIcon.getHeight(); ++y)
  1580. for (int x = 0; x < newIcon.getWidth(); ++x)
  1581. data[index++] = (unsigned long) newIcon.getPixelAt (x, y).getARGB();
  1582. ScopedXLock xlock;
  1583. xchangeProperty (windowH, Atoms::getCreating ("_NET_WM_ICON"), XA_CARDINAL, 32, data.getData(), dataSize);
  1584. deleteIconPixmaps();
  1585. XWMHints* wmHints = XGetWMHints (display, windowH);
  1586. if (wmHints == nullptr)
  1587. wmHints = XAllocWMHints();
  1588. wmHints->flags |= IconPixmapHint | IconMaskHint;
  1589. wmHints->icon_pixmap = PixmapHelpers::createColourPixmapFromImage (display, newIcon);
  1590. wmHints->icon_mask = PixmapHelpers::createMaskPixmapFromImage (display, newIcon);
  1591. XSetWMHints (display, windowH, wmHints);
  1592. XFree (wmHints);
  1593. XSync (display, False);
  1594. }
  1595. void deleteIconPixmaps()
  1596. {
  1597. ScopedXLock xlock;
  1598. XWMHints* wmHints = XGetWMHints (display, windowH);
  1599. if (wmHints != nullptr)
  1600. {
  1601. if ((wmHints->flags & IconPixmapHint) != 0)
  1602. {
  1603. wmHints->flags &= ~IconPixmapHint;
  1604. XFreePixmap (display, wmHints->icon_pixmap);
  1605. }
  1606. if ((wmHints->flags & IconMaskHint) != 0)
  1607. {
  1608. wmHints->flags &= ~IconMaskHint;
  1609. XFreePixmap (display, wmHints->icon_mask);
  1610. }
  1611. XSetWMHints (display, windowH, wmHints);
  1612. XFree (wmHints);
  1613. }
  1614. }
  1615. //==============================================================================
  1616. void handleWindowMessage (XEvent& event)
  1617. {
  1618. switch (event.xany.type)
  1619. {
  1620. case KeyPressEventType: handleKeyPressEvent (event.xkey); break;
  1621. case KeyRelease: handleKeyReleaseEvent (event.xkey); break;
  1622. case ButtonPress: handleButtonPressEvent (event.xbutton); break;
  1623. case ButtonRelease: handleButtonReleaseEvent (event.xbutton); break;
  1624. case MotionNotify: handleMotionNotifyEvent (event.xmotion); break;
  1625. case EnterNotify: handleEnterNotifyEvent (event.xcrossing); break;
  1626. case LeaveNotify: handleLeaveNotifyEvent (event.xcrossing); break;
  1627. case FocusIn: handleFocusInEvent(); break;
  1628. case FocusOut: handleFocusOutEvent(); break;
  1629. case Expose: handleExposeEvent (event.xexpose); break;
  1630. case MappingNotify: handleMappingNotify (event.xmapping); break;
  1631. case ClientMessage: handleClientMessageEvent (event.xclient, event); break;
  1632. case SelectionNotify: handleDragAndDropSelection (event); break;
  1633. case ConfigureNotify: handleConfigureNotifyEvent (event.xconfigure); break;
  1634. case ReparentNotify: handleReparentNotifyEvent(); break;
  1635. case GravityNotify: handleGravityNotify(); break;
  1636. case SelectionClear: handleExternalSelectionClear(); break;
  1637. case SelectionRequest: handleExternalSelectionRequest (event); break;
  1638. case CirculateNotify:
  1639. case CreateNotify:
  1640. case DestroyNotify:
  1641. // Think we can ignore these
  1642. break;
  1643. case MapNotify:
  1644. mapped = true;
  1645. handleBroughtToFront();
  1646. break;
  1647. case UnmapNotify:
  1648. mapped = false;
  1649. break;
  1650. default:
  1651. #if JUCE_USE_XSHM
  1652. if (XSHMHelpers::isShmAvailable())
  1653. {
  1654. ScopedXLock xlock;
  1655. if (event.xany.type == XShmGetEventBase (display))
  1656. repainter->notifyPaintCompleted();
  1657. }
  1658. #endif
  1659. break;
  1660. }
  1661. }
  1662. void handleKeyPressEvent (XKeyEvent& keyEvent)
  1663. {
  1664. const ModifierKeys oldMods (currentModifiers);
  1665. char utf8 [64] = { 0 };
  1666. juce_wchar unicodeChar = 0;
  1667. int keyCode = 0;
  1668. bool keyDownChange = false;
  1669. KeySym sym;
  1670. {
  1671. ScopedXLock xlock;
  1672. updateKeyStates ((int) keyEvent.keycode, true);
  1673. String oldLocale (::setlocale (LC_ALL, 0));
  1674. ::setlocale (LC_ALL, "");
  1675. XLookupString (&keyEvent, utf8, sizeof (utf8), &sym, 0);
  1676. if (oldLocale.isNotEmpty())
  1677. ::setlocale (LC_ALL, oldLocale.toRawUTF8());
  1678. unicodeChar = *CharPointer_UTF8 (utf8);
  1679. keyCode = (int) unicodeChar;
  1680. if (keyCode < 0x20)
  1681. keyCode = (int) XkbKeycodeToKeysym (display, (::KeyCode) keyEvent.keycode, 0, currentModifiers.isShiftDown() ? 1 : 0);
  1682. keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym, true);
  1683. }
  1684. bool keyPressed = false;
  1685. if ((sym & 0xff00) == 0xff00 || keyCode == XK_ISO_Left_Tab)
  1686. {
  1687. switch (sym) // Translate keypad
  1688. {
  1689. case XK_KP_Add: keyCode = XK_plus; break;
  1690. case XK_KP_Subtract: keyCode = XK_hyphen; break;
  1691. case XK_KP_Divide: keyCode = XK_slash; break;
  1692. case XK_KP_Multiply: keyCode = XK_asterisk; break;
  1693. case XK_KP_Enter: keyCode = XK_Return; break;
  1694. case XK_KP_Insert: keyCode = XK_Insert; break;
  1695. case XK_Delete:
  1696. case XK_KP_Delete: keyCode = XK_Delete; break;
  1697. case XK_KP_Left: keyCode = XK_Left; break;
  1698. case XK_KP_Right: keyCode = XK_Right; break;
  1699. case XK_KP_Up: keyCode = XK_Up; break;
  1700. case XK_KP_Down: keyCode = XK_Down; break;
  1701. case XK_KP_Home: keyCode = XK_Home; break;
  1702. case XK_KP_End: keyCode = XK_End; break;
  1703. case XK_KP_Page_Down: keyCode = XK_Page_Down; break;
  1704. case XK_KP_Page_Up: keyCode = XK_Page_Up; break;
  1705. case XK_KP_0: keyCode = XK_0; break;
  1706. case XK_KP_1: keyCode = XK_1; break;
  1707. case XK_KP_2: keyCode = XK_2; break;
  1708. case XK_KP_3: keyCode = XK_3; break;
  1709. case XK_KP_4: keyCode = XK_4; break;
  1710. case XK_KP_5: keyCode = XK_5; break;
  1711. case XK_KP_6: keyCode = XK_6; break;
  1712. case XK_KP_7: keyCode = XK_7; break;
  1713. case XK_KP_8: keyCode = XK_8; break;
  1714. case XK_KP_9: keyCode = XK_9; break;
  1715. default: break;
  1716. }
  1717. switch (keyCode)
  1718. {
  1719. case XK_Left:
  1720. case XK_Right:
  1721. case XK_Up:
  1722. case XK_Down:
  1723. case XK_Page_Up:
  1724. case XK_Page_Down:
  1725. case XK_End:
  1726. case XK_Home:
  1727. case XK_Delete:
  1728. case XK_Insert:
  1729. keyPressed = true;
  1730. keyCode = (keyCode & 0xff) | Keys::extendedKeyModifier;
  1731. break;
  1732. case XK_Tab:
  1733. case XK_Return:
  1734. case XK_Escape:
  1735. case XK_BackSpace:
  1736. keyPressed = true;
  1737. keyCode &= 0xff;
  1738. break;
  1739. case XK_ISO_Left_Tab:
  1740. keyPressed = true;
  1741. keyCode = XK_Tab & 0xff;
  1742. break;
  1743. default:
  1744. if (sym >= XK_F1 && sym <= XK_F16)
  1745. {
  1746. keyPressed = true;
  1747. keyCode = (sym & 0xff) | Keys::extendedKeyModifier;
  1748. }
  1749. break;
  1750. }
  1751. }
  1752. if (utf8[0] != 0 || ((sym & 0xff00) == 0 && sym >= 8))
  1753. keyPressed = true;
  1754. if (oldMods != currentModifiers)
  1755. handleModifierKeysChange();
  1756. if (keyDownChange)
  1757. handleKeyUpOrDown (true);
  1758. if (keyPressed)
  1759. handleKeyPress (keyCode, unicodeChar);
  1760. }
  1761. static bool isKeyReleasePartOfAutoRepeat (const XKeyEvent& keyReleaseEvent)
  1762. {
  1763. if (XPending (display))
  1764. {
  1765. XEvent e;
  1766. XPeekEvent (display, &e);
  1767. // Look for a subsequent key-down event with the same timestamp and keycode
  1768. return e.type == KeyPressEventType
  1769. && e.xkey.keycode == keyReleaseEvent.keycode
  1770. && e.xkey.time == keyReleaseEvent.time;
  1771. }
  1772. return false;
  1773. }
  1774. void handleKeyReleaseEvent (const XKeyEvent& keyEvent)
  1775. {
  1776. if (! isKeyReleasePartOfAutoRepeat (keyEvent))
  1777. {
  1778. updateKeyStates ((int) keyEvent.keycode, false);
  1779. KeySym sym;
  1780. {
  1781. ScopedXLock xlock;
  1782. sym = XkbKeycodeToKeysym (display, (::KeyCode) keyEvent.keycode, 0, 0);
  1783. }
  1784. const ModifierKeys oldMods (currentModifiers);
  1785. const bool keyDownChange = (sym != NoSymbol) && ! updateKeyModifiersFromSym (sym, false);
  1786. if (oldMods != currentModifiers)
  1787. handleModifierKeysChange();
  1788. if (keyDownChange)
  1789. handleKeyUpOrDown (false);
  1790. }
  1791. }
  1792. template <typename EventType>
  1793. Point<float> getMousePos (const EventType& e) noexcept
  1794. {
  1795. return Point<float> ((float) e.x, (float) e.y) / currentScaleFactor;
  1796. }
  1797. void handleWheelEvent (const XButtonPressedEvent& buttonPressEvent, const float amount)
  1798. {
  1799. MouseWheelDetails wheel;
  1800. wheel.deltaX = 0.0f;
  1801. wheel.deltaY = amount;
  1802. wheel.isReversed = false;
  1803. wheel.isSmooth = false;
  1804. wheel.isInertial = false;
  1805. handleMouseWheel (0, getMousePos (buttonPressEvent), getEventTime (buttonPressEvent), wheel);
  1806. }
  1807. void handleButtonPressEvent (const XButtonPressedEvent& buttonPressEvent, int buttonModifierFlag)
  1808. {
  1809. currentModifiers = currentModifiers.withFlags (buttonModifierFlag);
  1810. toFront (true);
  1811. handleMouseEvent (0, getMousePos (buttonPressEvent), currentModifiers,
  1812. MouseInputSource::invalidPressure, getEventTime (buttonPressEvent));
  1813. }
  1814. void handleButtonPressEvent (const XButtonPressedEvent& buttonPressEvent)
  1815. {
  1816. updateKeyModifiers ((int) buttonPressEvent.state);
  1817. switch (pointerMap [buttonPressEvent.button - Button1])
  1818. {
  1819. case Keys::WheelUp: handleWheelEvent (buttonPressEvent, 50.0f / 256.0f); break;
  1820. case Keys::WheelDown: handleWheelEvent (buttonPressEvent, -50.0f / 256.0f); break;
  1821. case Keys::LeftButton: handleButtonPressEvent (buttonPressEvent, ModifierKeys::leftButtonModifier); break;
  1822. case Keys::RightButton: handleButtonPressEvent (buttonPressEvent, ModifierKeys::rightButtonModifier); break;
  1823. case Keys::MiddleButton: handleButtonPressEvent (buttonPressEvent, ModifierKeys::middleButtonModifier); break;
  1824. default: break;
  1825. }
  1826. clearLastMousePos();
  1827. }
  1828. void handleButtonReleaseEvent (const XButtonReleasedEvent& buttonRelEvent)
  1829. {
  1830. updateKeyModifiers ((int) buttonRelEvent.state);
  1831. if (parentWindow != 0)
  1832. updateWindowBounds();
  1833. switch (pointerMap [buttonRelEvent.button - Button1])
  1834. {
  1835. case Keys::LeftButton: currentModifiers = currentModifiers.withoutFlags (ModifierKeys::leftButtonModifier); break;
  1836. case Keys::RightButton: currentModifiers = currentModifiers.withoutFlags (ModifierKeys::rightButtonModifier); break;
  1837. case Keys::MiddleButton: currentModifiers = currentModifiers.withoutFlags (ModifierKeys::middleButtonModifier); break;
  1838. default: break;
  1839. }
  1840. if (dragState.dragging)
  1841. handleExternalDragButtonReleaseEvent();
  1842. handleMouseEvent (0, getMousePos (buttonRelEvent), currentModifiers,
  1843. MouseInputSource::invalidPressure, getEventTime (buttonRelEvent));
  1844. clearLastMousePos();
  1845. }
  1846. void handleMotionNotifyEvent (const XPointerMovedEvent& movedEvent)
  1847. {
  1848. updateKeyModifiers ((int) movedEvent.state);
  1849. lastMousePos = Point<int> (movedEvent.x_root, movedEvent.y_root);
  1850. if (dragState.dragging)
  1851. handleExternalDragMotionNotify();
  1852. handleMouseEvent (0, getMousePos (movedEvent), currentModifiers,
  1853. MouseInputSource::invalidPressure, getEventTime (movedEvent));
  1854. }
  1855. void handleEnterNotifyEvent (const XEnterWindowEvent& enterEvent)
  1856. {
  1857. if (parentWindow != 0)
  1858. updateWindowBounds();
  1859. clearLastMousePos();
  1860. if (! currentModifiers.isAnyMouseButtonDown())
  1861. {
  1862. updateKeyModifiers ((int) enterEvent.state);
  1863. handleMouseEvent (0, getMousePos (enterEvent), currentModifiers,
  1864. MouseInputSource::invalidPressure, getEventTime (enterEvent));
  1865. }
  1866. }
  1867. void handleLeaveNotifyEvent (const XLeaveWindowEvent& leaveEvent)
  1868. {
  1869. // Suppress the normal leave if we've got a pointer grab, or if
  1870. // it's a bogus one caused by clicking a mouse button when running
  1871. // in a Window manager
  1872. if (((! currentModifiers.isAnyMouseButtonDown()) && leaveEvent.mode == NotifyNormal)
  1873. || leaveEvent.mode == NotifyUngrab)
  1874. {
  1875. updateKeyModifiers ((int) leaveEvent.state);
  1876. handleMouseEvent (0, getMousePos (leaveEvent), currentModifiers,
  1877. MouseInputSource::invalidPressure, getEventTime (leaveEvent));
  1878. }
  1879. }
  1880. void handleFocusInEvent()
  1881. {
  1882. isActiveApplication = true;
  1883. if (isFocused())
  1884. handleFocusGain();
  1885. }
  1886. void handleFocusOutEvent()
  1887. {
  1888. isActiveApplication = false;
  1889. if (! isFocused())
  1890. handleFocusLoss();
  1891. }
  1892. void handleExposeEvent (XExposeEvent& exposeEvent)
  1893. {
  1894. // Batch together all pending expose events
  1895. XEvent nextEvent;
  1896. ScopedXLock xlock;
  1897. // if we have opengl contexts then just repaint them all
  1898. // regardless if this is really necessary
  1899. repaintOpenGLContexts();
  1900. if (exposeEvent.window != windowH)
  1901. {
  1902. Window child;
  1903. XTranslateCoordinates (display, exposeEvent.window, windowH,
  1904. exposeEvent.x, exposeEvent.y, &exposeEvent.x, &exposeEvent.y,
  1905. &child);
  1906. }
  1907. // exposeEvent is in local window local coordinates so do not convert with
  1908. // physicalToScaled, but rather use currentScaleFactor
  1909. repaint (Rectangle<int> (exposeEvent.x, exposeEvent.y,
  1910. exposeEvent.width, exposeEvent.height) / currentScaleFactor);
  1911. while (XEventsQueued (display, QueuedAfterFlush) > 0)
  1912. {
  1913. XPeekEvent (display, &nextEvent);
  1914. if (nextEvent.type != Expose || nextEvent.xany.window != exposeEvent.window)
  1915. break;
  1916. XNextEvent (display, &nextEvent);
  1917. const XExposeEvent& nextExposeEvent = (const XExposeEvent&) nextEvent.xexpose;
  1918. repaint (Rectangle<int> (nextExposeEvent.x, nextExposeEvent.y,
  1919. nextExposeEvent.width, nextExposeEvent.height) / currentScaleFactor);
  1920. }
  1921. }
  1922. void handleConfigureNotifyEvent (XConfigureEvent& confEvent)
  1923. {
  1924. updateWindowBounds();
  1925. updateBorderSize();
  1926. handleMovedOrResized();
  1927. // if the native title bar is dragged, need to tell any active menus, etc.
  1928. if ((styleFlags & windowHasTitleBar) != 0
  1929. && component.isCurrentlyBlockedByAnotherModalComponent())
  1930. {
  1931. if (Component* const currentModalComp = Component::getCurrentlyModalComponent())
  1932. currentModalComp->inputAttemptWhenModal();
  1933. }
  1934. if (confEvent.window == windowH
  1935. && confEvent.above != 0
  1936. && isFrontWindow())
  1937. {
  1938. handleBroughtToFront();
  1939. }
  1940. }
  1941. void handleReparentNotifyEvent()
  1942. {
  1943. parentWindow = 0;
  1944. Window wRoot = 0;
  1945. Window* wChild = nullptr;
  1946. unsigned int numChildren;
  1947. {
  1948. ScopedXLock xlock;
  1949. XQueryTree (display, windowH, &wRoot, &parentWindow, &wChild, &numChildren);
  1950. }
  1951. if (parentWindow == windowH || parentWindow == wRoot)
  1952. parentWindow = 0;
  1953. handleGravityNotify();
  1954. }
  1955. void handleGravityNotify()
  1956. {
  1957. updateWindowBounds();
  1958. updateBorderSize();
  1959. handleMovedOrResized();
  1960. }
  1961. void handleMappingNotify (XMappingEvent& mappingEvent)
  1962. {
  1963. if (mappingEvent.request != MappingPointer)
  1964. {
  1965. // Deal with modifier/keyboard mapping
  1966. ScopedXLock xlock;
  1967. XRefreshKeyboardMapping (&mappingEvent);
  1968. updateModifierMappings();
  1969. }
  1970. }
  1971. void handleClientMessageEvent (XClientMessageEvent& clientMsg, XEvent& event)
  1972. {
  1973. if (clientMsg.message_type == atoms.protocols && clientMsg.format == 32)
  1974. {
  1975. const Atom atom = (Atom) clientMsg.data.l[0];
  1976. if (atom == atoms.protocolList [Atoms::PING])
  1977. {
  1978. Window root = RootWindow (display, DefaultScreen (display));
  1979. clientMsg.window = root;
  1980. XSendEvent (display, root, False, NoEventMask, &event);
  1981. XFlush (display);
  1982. }
  1983. else if (atom == atoms.protocolList [Atoms::TAKE_FOCUS])
  1984. {
  1985. if ((getStyleFlags() & juce::ComponentPeer::windowIgnoresKeyPresses) == 0)
  1986. {
  1987. XWindowAttributes atts;
  1988. ScopedXLock xlock;
  1989. if (clientMsg.window != 0
  1990. && XGetWindowAttributes (display, clientMsg.window, &atts))
  1991. {
  1992. if (atts.map_state == IsViewable)
  1993. XSetInputFocus (display, clientMsg.window, RevertToParent, (::Time) clientMsg.data.l[1]);
  1994. }
  1995. }
  1996. }
  1997. else if (atom == atoms.protocolList [Atoms::DELETE_WINDOW])
  1998. {
  1999. handleUserClosingWindow();
  2000. }
  2001. }
  2002. else if (clientMsg.message_type == atoms.XdndEnter)
  2003. {
  2004. handleDragAndDropEnter (clientMsg);
  2005. }
  2006. else if (clientMsg.message_type == atoms.XdndLeave)
  2007. {
  2008. handleDragExit (dragInfo);
  2009. resetDragAndDrop();
  2010. }
  2011. else if (clientMsg.message_type == atoms.XdndPosition)
  2012. {
  2013. handleDragAndDropPosition (clientMsg);
  2014. }
  2015. else if (clientMsg.message_type == atoms.XdndDrop)
  2016. {
  2017. handleDragAndDropDrop (clientMsg);
  2018. }
  2019. else if (clientMsg.message_type == atoms.XdndStatus)
  2020. {
  2021. handleExternalDragAndDropStatus (clientMsg);
  2022. }
  2023. else if (clientMsg.message_type == atoms.XdndFinished)
  2024. {
  2025. externalResetDragAndDrop();
  2026. }
  2027. }
  2028. bool externalDragTextInit (const String& text)
  2029. {
  2030. if (dragState.dragging)
  2031. return false;
  2032. return externalDragInit (true, text);
  2033. }
  2034. bool externalDragFileInit (const StringArray& files, bool /*canMoveFiles*/)
  2035. {
  2036. if (dragState.dragging)
  2037. return false;
  2038. StringArray uriList;
  2039. for (int i = 0; i < files.size(); ++i)
  2040. {
  2041. const String& f = files[i];
  2042. if (f.matchesWildcard ("?*://*", false))
  2043. uriList.add (f);
  2044. else
  2045. uriList.add ("file://" + f);
  2046. }
  2047. return externalDragInit (false, uriList.joinIntoString ("\r\n"));
  2048. }
  2049. //==============================================================================
  2050. void showMouseCursor (Cursor cursor) noexcept
  2051. {
  2052. ScopedXLock xlock;
  2053. XDefineCursor (display, windowH, cursor);
  2054. }
  2055. //==============================================================================
  2056. double getCurrentScale() noexcept
  2057. {
  2058. return currentScaleFactor;
  2059. }
  2060. //==============================================================================
  2061. void addOpenGLRepaintListener (Component* dummy)
  2062. {
  2063. if (dummy != nullptr)
  2064. glRepaintListeners.addIfNotAlreadyThere (dummy);
  2065. }
  2066. void removeOpenGLRepaintListener (Component* dummy)
  2067. {
  2068. if (dummy != nullptr)
  2069. glRepaintListeners.removeAllInstancesOf (dummy);
  2070. }
  2071. void repaintOpenGLContexts()
  2072. {
  2073. for (int i = 0; i < glRepaintListeners.size(); ++i)
  2074. {
  2075. if (Component* c = glRepaintListeners [i])
  2076. c->handleCommandMessage (0);
  2077. }
  2078. }
  2079. //==============================================================================
  2080. bool dontRepaint;
  2081. static ModifierKeys currentModifiers;
  2082. static bool isActiveApplication;
  2083. private:
  2084. //==============================================================================
  2085. class LinuxRepaintManager : public Timer
  2086. {
  2087. public:
  2088. LinuxRepaintManager (LinuxComponentPeer& p)
  2089. : peer (p), lastTimeImageUsed (0)
  2090. {
  2091. #if JUCE_USE_XSHM
  2092. shmPaintsPending = 0;
  2093. useARGBImagesForRendering = XSHMHelpers::isShmAvailable();
  2094. if (useARGBImagesForRendering)
  2095. {
  2096. ScopedXLock xlock;
  2097. XShmSegmentInfo segmentinfo;
  2098. XImage* const testImage
  2099. = XShmCreateImage (display, DefaultVisual (display, DefaultScreen (display)),
  2100. 24, ZPixmap, 0, &segmentinfo, 64, 64);
  2101. useARGBImagesForRendering = (testImage->bits_per_pixel == 32);
  2102. XDestroyImage (testImage);
  2103. }
  2104. #endif
  2105. }
  2106. void timerCallback() override
  2107. {
  2108. #if JUCE_USE_XSHM
  2109. if (shmPaintsPending != 0)
  2110. return;
  2111. #endif
  2112. if (! regionsNeedingRepaint.isEmpty())
  2113. {
  2114. stopTimer();
  2115. performAnyPendingRepaintsNow();
  2116. }
  2117. else if (Time::getApproximateMillisecondCounter() > lastTimeImageUsed + 3000)
  2118. {
  2119. stopTimer();
  2120. image = Image();
  2121. }
  2122. }
  2123. void repaint (const Rectangle<int>& area)
  2124. {
  2125. if (! isTimerRunning())
  2126. startTimer (repaintTimerPeriod);
  2127. regionsNeedingRepaint.add (area * peer.currentScaleFactor);
  2128. }
  2129. void performAnyPendingRepaintsNow()
  2130. {
  2131. #if JUCE_USE_XSHM
  2132. if (shmPaintsPending != 0)
  2133. {
  2134. startTimer (repaintTimerPeriod);
  2135. return;
  2136. }
  2137. #endif
  2138. RectangleList<int> originalRepaintRegion (regionsNeedingRepaint);
  2139. regionsNeedingRepaint.clear();
  2140. const Rectangle<int> totalArea (originalRepaintRegion.getBounds());
  2141. if (! totalArea.isEmpty())
  2142. {
  2143. if (image.isNull() || image.getWidth() < totalArea.getWidth()
  2144. || image.getHeight() < totalArea.getHeight())
  2145. {
  2146. #if JUCE_USE_XSHM
  2147. image = Image (new XBitmapImage (useARGBImagesForRendering ? Image::ARGB
  2148. : Image::RGB,
  2149. #else
  2150. image = Image (new XBitmapImage (Image::RGB,
  2151. #endif
  2152. (totalArea.getWidth() + 31) & ~31,
  2153. (totalArea.getHeight() + 31) & ~31,
  2154. false, (unsigned int) peer.depth, peer.visual));
  2155. }
  2156. startTimer (repaintTimerPeriod);
  2157. RectangleList<int> adjustedList (originalRepaintRegion);
  2158. adjustedList.offsetAll (-totalArea.getX(), -totalArea.getY());
  2159. if (peer.depth == 32)
  2160. for (const Rectangle<int>* i = originalRepaintRegion.begin(), * const e = originalRepaintRegion.end(); i != e; ++i)
  2161. image.clear (*i - totalArea.getPosition());
  2162. {
  2163. ScopedPointer<LowLevelGraphicsContext> context (peer.getComponent().getLookAndFeel()
  2164. .createGraphicsContext (image, -totalArea.getPosition(), adjustedList));
  2165. context->addTransform (AffineTransform::scale ((float) peer.currentScaleFactor));
  2166. peer.handlePaint (*context);
  2167. }
  2168. for (const Rectangle<int>* i = originalRepaintRegion.begin(), * const e = originalRepaintRegion.end(); i != e; ++i)
  2169. {
  2170. XBitmapImage* xbitmap = static_cast<XBitmapImage*> (image.getPixelData());
  2171. #if JUCE_USE_XSHM
  2172. if (xbitmap->isUsingXShm())
  2173. ++shmPaintsPending;
  2174. #endif
  2175. xbitmap->blitToWindow (peer.windowH,
  2176. i->getX(), i->getY(),
  2177. (unsigned int) i->getWidth(),
  2178. (unsigned int) i->getHeight(),
  2179. i->getX() - totalArea.getX(), i->getY() - totalArea.getY());
  2180. }
  2181. }
  2182. lastTimeImageUsed = Time::getApproximateMillisecondCounter();
  2183. startTimer (repaintTimerPeriod);
  2184. }
  2185. #if JUCE_USE_XSHM
  2186. void notifyPaintCompleted() noexcept { --shmPaintsPending; }
  2187. #endif
  2188. private:
  2189. enum { repaintTimerPeriod = 1000 / 100 };
  2190. LinuxComponentPeer& peer;
  2191. Image image;
  2192. uint32 lastTimeImageUsed;
  2193. RectangleList<int> regionsNeedingRepaint;
  2194. #if JUCE_USE_XSHM
  2195. bool useARGBImagesForRendering;
  2196. int shmPaintsPending;
  2197. #endif
  2198. JUCE_DECLARE_NON_COPYABLE (LinuxRepaintManager)
  2199. };
  2200. const Atoms atoms;
  2201. ScopedPointer<LinuxRepaintManager> repainter;
  2202. friend class LinuxRepaintManager;
  2203. Window windowH, parentWindow;
  2204. Rectangle<int> bounds;
  2205. Image taskbarImage;
  2206. bool fullScreen, mapped;
  2207. Visual* visual;
  2208. int depth;
  2209. BorderSize<int> windowBorder;
  2210. bool isAlwaysOnTop;
  2211. double currentScaleFactor;
  2212. Array<Component*> glRepaintListeners;
  2213. enum { KeyPressEventType = 2 };
  2214. struct MotifWmHints
  2215. {
  2216. unsigned long flags;
  2217. unsigned long functions;
  2218. unsigned long decorations;
  2219. long input_mode;
  2220. unsigned long status;
  2221. };
  2222. static void updateKeyStates (const int keycode, const bool press) noexcept
  2223. {
  2224. const int keybyte = keycode >> 3;
  2225. const int keybit = (1 << (keycode & 7));
  2226. if (press)
  2227. Keys::keyStates [keybyte] |= keybit;
  2228. else
  2229. Keys::keyStates [keybyte] &= ~keybit;
  2230. }
  2231. static void updateKeyModifiers (const int status) noexcept
  2232. {
  2233. int keyMods = 0;
  2234. if ((status & ShiftMask) != 0) keyMods |= ModifierKeys::shiftModifier;
  2235. if ((status & ControlMask) != 0) keyMods |= ModifierKeys::ctrlModifier;
  2236. if ((status & Keys::AltMask) != 0) keyMods |= ModifierKeys::altModifier;
  2237. currentModifiers = currentModifiers.withOnlyMouseButtons().withFlags (keyMods);
  2238. Keys::numLock = ((status & Keys::NumLockMask) != 0);
  2239. Keys::capsLock = ((status & LockMask) != 0);
  2240. }
  2241. static bool updateKeyModifiersFromSym (KeySym sym, const bool press) noexcept
  2242. {
  2243. int modifier = 0;
  2244. bool isModifier = true;
  2245. switch (sym)
  2246. {
  2247. case XK_Shift_L:
  2248. case XK_Shift_R: modifier = ModifierKeys::shiftModifier; break;
  2249. case XK_Control_L:
  2250. case XK_Control_R: modifier = ModifierKeys::ctrlModifier; break;
  2251. case XK_Alt_L:
  2252. case XK_Alt_R: modifier = ModifierKeys::altModifier; break;
  2253. case XK_Num_Lock:
  2254. if (press)
  2255. Keys::numLock = ! Keys::numLock;
  2256. break;
  2257. case XK_Caps_Lock:
  2258. if (press)
  2259. Keys::capsLock = ! Keys::capsLock;
  2260. break;
  2261. case XK_Scroll_Lock:
  2262. break;
  2263. default:
  2264. isModifier = false;
  2265. break;
  2266. }
  2267. currentModifiers = press ? currentModifiers.withFlags (modifier)
  2268. : currentModifiers.withoutFlags (modifier);
  2269. return isModifier;
  2270. }
  2271. // Alt and Num lock are not defined by standard X
  2272. // modifier constants: check what they're mapped to
  2273. static void updateModifierMappings() noexcept
  2274. {
  2275. ScopedXLock xlock;
  2276. const int altLeftCode = XKeysymToKeycode (display, XK_Alt_L);
  2277. const int numLockCode = XKeysymToKeycode (display, XK_Num_Lock);
  2278. Keys::AltMask = 0;
  2279. Keys::NumLockMask = 0;
  2280. if (XModifierKeymap* const mapping = XGetModifierMapping (display))
  2281. {
  2282. const int numMods = 8;
  2283. const int maxKeysPerMod = mapping->max_keypermod;
  2284. for (int i = 0; i < numMods; i++)
  2285. {
  2286. for (int j = 0; j < maxKeysPerMod; ++j)
  2287. {
  2288. const int index = (i * maxKeysPerMod) + j;
  2289. if (mapping->modifiermap[index] == altLeftCode) Keys::AltMask = 1 << i;
  2290. else if (mapping->modifiermap[index] == numLockCode) Keys::NumLockMask = 1 << i;
  2291. }
  2292. }
  2293. XFreeModifiermap (mapping);
  2294. }
  2295. }
  2296. //==============================================================================
  2297. static void xchangeProperty (Window wndH, Atom property, Atom type, int format, const void* data, int numElements)
  2298. {
  2299. XChangeProperty (display, wndH, property, type, format, PropModeReplace, (const unsigned char*) data, numElements);
  2300. }
  2301. void removeWindowDecorations (Window wndH)
  2302. {
  2303. Atom hints = Atoms::getIfExists ("_MOTIF_WM_HINTS");
  2304. if (hints != None)
  2305. {
  2306. MotifWmHints motifHints;
  2307. zerostruct (motifHints);
  2308. motifHints.flags = 2; /* MWM_HINTS_DECORATIONS */
  2309. motifHints.decorations = 0;
  2310. ScopedXLock xlock;
  2311. xchangeProperty (wndH, hints, hints, 32, &motifHints, 4);
  2312. }
  2313. hints = Atoms::getIfExists ("_WIN_HINTS");
  2314. if (hints != None)
  2315. {
  2316. long gnomeHints = 0;
  2317. ScopedXLock xlock;
  2318. xchangeProperty (wndH, hints, hints, 32, &gnomeHints, 1);
  2319. }
  2320. hints = Atoms::getIfExists ("KWM_WIN_DECORATION");
  2321. if (hints != None)
  2322. {
  2323. long kwmHints = 2; /*KDE_tinyDecoration*/
  2324. ScopedXLock xlock;
  2325. xchangeProperty (wndH, hints, hints, 32, &kwmHints, 1);
  2326. }
  2327. hints = Atoms::getIfExists ("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE");
  2328. if (hints != None)
  2329. {
  2330. ScopedXLock xlock;
  2331. xchangeProperty (wndH, atoms.windowType, XA_ATOM, 32, &hints, 1);
  2332. }
  2333. }
  2334. void addWindowButtons (Window wndH)
  2335. {
  2336. ScopedXLock xlock;
  2337. Atom hints = Atoms::getIfExists ("_MOTIF_WM_HINTS");
  2338. if (hints != None)
  2339. {
  2340. MotifWmHints motifHints;
  2341. zerostruct (motifHints);
  2342. motifHints.flags = 1 | 2; /* MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS */
  2343. motifHints.decorations = 2 /* MWM_DECOR_BORDER */ | 8 /* MWM_DECOR_TITLE */ | 16; /* MWM_DECOR_MENU */
  2344. motifHints.functions = 4 /* MWM_FUNC_MOVE */;
  2345. if ((styleFlags & windowHasCloseButton) != 0)
  2346. motifHints.functions |= 32; /* MWM_FUNC_CLOSE */
  2347. if ((styleFlags & windowHasMinimiseButton) != 0)
  2348. {
  2349. motifHints.functions |= 8; /* MWM_FUNC_MINIMIZE */
  2350. motifHints.decorations |= 0x20; /* MWM_DECOR_MINIMIZE */
  2351. }
  2352. if ((styleFlags & windowHasMaximiseButton) != 0)
  2353. {
  2354. motifHints.functions |= 0x10; /* MWM_FUNC_MAXIMIZE */
  2355. motifHints.decorations |= 0x40; /* MWM_DECOR_MAXIMIZE */
  2356. }
  2357. if ((styleFlags & windowIsResizable) != 0)
  2358. {
  2359. motifHints.functions |= 2; /* MWM_FUNC_RESIZE */
  2360. motifHints.decorations |= 0x4; /* MWM_DECOR_RESIZEH */
  2361. }
  2362. xchangeProperty (wndH, hints, hints, 32, &motifHints, 5);
  2363. }
  2364. hints = Atoms::getIfExists ("_NET_WM_ALLOWED_ACTIONS");
  2365. if (hints != None)
  2366. {
  2367. Atom netHints [6];
  2368. int num = 0;
  2369. if ((styleFlags & windowIsResizable) != 0)
  2370. netHints [num++] = Atoms::getIfExists ("_NET_WM_ACTION_RESIZE");
  2371. if ((styleFlags & windowHasMaximiseButton) != 0)
  2372. netHints [num++] = Atoms::getIfExists ("_NET_WM_ACTION_FULLSCREEN");
  2373. if ((styleFlags & windowHasMinimiseButton) != 0)
  2374. netHints [num++] = Atoms::getIfExists ("_NET_WM_ACTION_MINIMIZE");
  2375. if ((styleFlags & windowHasCloseButton) != 0)
  2376. netHints [num++] = Atoms::getIfExists ("_NET_WM_ACTION_CLOSE");
  2377. xchangeProperty (wndH, hints, XA_ATOM, 32, &netHints, num);
  2378. }
  2379. }
  2380. void setWindowType()
  2381. {
  2382. Atom netHints [2];
  2383. if (styleFlags & windowIsTemporary)
  2384. netHints [0] = Atoms::getIfExists ("_NET_WM_WINDOW_TYPE_TOOLTIP");
  2385. else if ((styleFlags & windowHasDropShadow) == 0 && Desktop::canUseSemiTransparentWindows())
  2386. netHints [0] = Atoms::getIfExists ("_NET_WM_WINDOW_TYPE_COMBO");
  2387. else
  2388. netHints [0] = Atoms::getIfExists ("_NET_WM_WINDOW_TYPE_NORMAL");
  2389. xchangeProperty (windowH, atoms.windowType, XA_ATOM, 32, &netHints, 1);
  2390. int numHints = 0;
  2391. if ((styleFlags & windowAppearsOnTaskbar) == 0)
  2392. netHints [numHints++] = Atoms::getIfExists ("_NET_WM_STATE_SKIP_TASKBAR");
  2393. if (component.isAlwaysOnTop())
  2394. netHints [numHints++] = Atoms::getIfExists ("_NET_WM_STATE_ABOVE");
  2395. if (numHints > 0)
  2396. xchangeProperty (windowH, atoms.windowState, XA_ATOM, 32, &netHints, numHints);
  2397. }
  2398. void createWindow (Window parentToAddTo)
  2399. {
  2400. ScopedXLock xlock;
  2401. resetDragAndDrop();
  2402. // Get defaults for various properties
  2403. const int screen = DefaultScreen (display);
  2404. Window root = RootWindow (display, screen);
  2405. parentWindow = parentToAddTo;
  2406. // Try to obtain a 32-bit visual or fallback to 24 or 16
  2407. visual = Visuals::findVisualFormat ((styleFlags & windowIsSemiTransparent) ? 32 : 24, depth);
  2408. if (visual == nullptr)
  2409. {
  2410. Logger::outputDebugString ("ERROR: System doesn't support 32, 24 or 16 bit RGB display.\n");
  2411. Process::terminate();
  2412. }
  2413. // Create and install a colormap suitable fr our visual
  2414. Colormap colormap = XCreateColormap (display, root, visual, AllocNone);
  2415. XInstallColormap (display, colormap);
  2416. // Set up the window attributes
  2417. XSetWindowAttributes swa;
  2418. swa.border_pixel = 0;
  2419. swa.background_pixmap = None;
  2420. swa.colormap = colormap;
  2421. swa.override_redirect = ((styleFlags & windowIsTemporary) != 0) ? True : False;
  2422. swa.event_mask = getAllEventsMask();
  2423. windowH = XCreateWindow (display, parentToAddTo != 0 ? parentToAddTo : root,
  2424. 0, 0, 1, 1,
  2425. 0, depth, InputOutput, visual,
  2426. CWBorderPixel | CWColormap | CWBackPixmap | CWEventMask | CWOverrideRedirect,
  2427. &swa);
  2428. unsigned int buttonMask = EnterWindowMask | LeaveWindowMask | PointerMotionMask;
  2429. if ((styleFlags & windowIgnoresMouseClicks) == 0)
  2430. buttonMask |= ButtonPressMask | ButtonReleaseMask;
  2431. // Set the window context to identify the window handle object
  2432. if (XSaveContext (display, (XID) windowH, windowHandleXContext, (XPointer) this))
  2433. {
  2434. // Failed
  2435. jassertfalse;
  2436. Logger::outputDebugString ("Failed to create context information for window.\n");
  2437. XDestroyWindow (display, windowH);
  2438. windowH = 0;
  2439. return;
  2440. }
  2441. // Set window manager hints
  2442. XWMHints* wmHints = XAllocWMHints();
  2443. wmHints->flags = InputHint | StateHint;
  2444. wmHints->input = True; // Locally active input model
  2445. wmHints->initial_state = NormalState;
  2446. XSetWMHints (display, windowH, wmHints);
  2447. XFree (wmHints);
  2448. // Set the window type
  2449. setWindowType();
  2450. // Define decoration
  2451. if ((styleFlags & windowHasTitleBar) == 0)
  2452. removeWindowDecorations (windowH);
  2453. else
  2454. addWindowButtons (windowH);
  2455. setTitle (component.getName());
  2456. // Associate the PID, allowing to be shut down when something goes wrong
  2457. unsigned long pid = (unsigned long) getpid();
  2458. xchangeProperty (windowH, atoms.pid, XA_CARDINAL, 32, &pid, 1);
  2459. // Set window manager protocols
  2460. xchangeProperty (windowH, atoms.protocols, XA_ATOM, 32, atoms.protocolList, 2);
  2461. // Set drag and drop flags
  2462. xchangeProperty (windowH, atoms.XdndTypeList, XA_ATOM, 32, atoms.allowedMimeTypes, numElementsInArray (atoms.allowedMimeTypes));
  2463. xchangeProperty (windowH, atoms.XdndActionList, XA_ATOM, 32, atoms.allowedActions, numElementsInArray (atoms.allowedActions));
  2464. xchangeProperty (windowH, atoms.XdndActionDescription, XA_STRING, 8, "", 0);
  2465. xchangeProperty (windowH, atoms.XdndAware, XA_ATOM, 32, &Atoms::DndVersion, 1);
  2466. initialisePointerMap();
  2467. updateModifierMappings();
  2468. }
  2469. void destroyWindow()
  2470. {
  2471. ScopedXLock xlock;
  2472. XPointer handlePointer;
  2473. if (! XFindContext (display, (XID) windowH, windowHandleXContext, &handlePointer))
  2474. XDeleteContext (display, (XID) windowH, windowHandleXContext);
  2475. XDestroyWindow (display, windowH);
  2476. // Wait for it to complete and then remove any events for this
  2477. // window from the event queue.
  2478. XSync (display, false);
  2479. XEvent event;
  2480. while (XCheckWindowEvent (display, windowH, getAllEventsMask(), &event) == True)
  2481. {}
  2482. }
  2483. int getAllEventsMask() const noexcept
  2484. {
  2485. return NoEventMask | KeyPressMask | KeyReleaseMask
  2486. | EnterWindowMask | LeaveWindowMask | PointerMotionMask | KeymapStateMask
  2487. | ExposureMask | StructureNotifyMask | FocusChangeMask
  2488. | ((styleFlags & windowIgnoresMouseClicks) != 0 ? 0 : (ButtonPressMask | ButtonReleaseMask));
  2489. }
  2490. template <typename EventType>
  2491. static int64 getEventTime (const EventType& t)
  2492. {
  2493. return getEventTime (t.time);
  2494. }
  2495. static int64 getEventTime (::Time t)
  2496. {
  2497. static int64 eventTimeOffset = 0x12345678;
  2498. const int64 thisMessageTime = (int64) t;
  2499. if (eventTimeOffset == 0x12345678)
  2500. eventTimeOffset = Time::currentTimeMillis() - thisMessageTime;
  2501. return eventTimeOffset + thisMessageTime;
  2502. }
  2503. long getUserTime() const
  2504. {
  2505. GetXProperty prop (windowH, atoms.userTime, 0, 65536, false, XA_CARDINAL);
  2506. return prop.success ? *(long*) prop.data : 0;
  2507. }
  2508. void updateBorderSize()
  2509. {
  2510. if ((styleFlags & windowHasTitleBar) == 0)
  2511. {
  2512. windowBorder = BorderSize<int> (0);
  2513. }
  2514. else if (windowBorder.getTopAndBottom() == 0 && windowBorder.getLeftAndRight() == 0)
  2515. {
  2516. ScopedXLock xlock;
  2517. Atom hints = Atoms::getIfExists ("_NET_FRAME_EXTENTS");
  2518. if (hints != None)
  2519. {
  2520. GetXProperty prop (windowH, hints, 0, 4, false, XA_CARDINAL);
  2521. if (prop.success && prop.actualFormat == 32)
  2522. {
  2523. const unsigned long* const sizes = (const unsigned long*) prop.data;
  2524. windowBorder = BorderSize<int> ((int) sizes[2], (int) sizes[0],
  2525. (int) sizes[3], (int) sizes[1]);
  2526. }
  2527. }
  2528. }
  2529. }
  2530. void updateWindowBounds()
  2531. {
  2532. jassert (windowH != 0);
  2533. if (windowH != 0)
  2534. {
  2535. Window root, child;
  2536. int wx = 0, wy = 0;
  2537. unsigned int ww = 0, wh = 0, bw, bitDepth;
  2538. ScopedXLock xlock;
  2539. if (XGetGeometry (display, (::Drawable) windowH, &root, &wx, &wy, &ww, &wh, &bw, &bitDepth))
  2540. if (! XTranslateCoordinates (display, windowH, root, 0, 0, &wx, &wy, &child))
  2541. wx = wy = 0;
  2542. Rectangle<int> physicalBounds (wx, wy, (int) ww, (int) wh);
  2543. currentScaleFactor =
  2544. DisplayGeometry::getInstance().findDisplayForRect (physicalBounds, false).scale;
  2545. bounds = DisplayGeometry::physicalToScaled (physicalBounds);
  2546. }
  2547. }
  2548. //==============================================================================
  2549. struct DragState
  2550. {
  2551. DragState()
  2552. : isText (false), dragging (false), expectingStatus (false),
  2553. canDrop (false), targetWindow (None), xdndVersion (-1)
  2554. {
  2555. if (isText)
  2556. allowedTypes.add (Atoms::getCreating ("text/plain"));
  2557. else
  2558. allowedTypes.add (Atoms::getCreating ("text/uri-list"));
  2559. }
  2560. bool isText;
  2561. bool dragging; // currently performing outgoing external dnd as Xdnd source, have grabbed mouse
  2562. bool expectingStatus; // XdndPosition sent, waiting for XdndStatus
  2563. bool canDrop; // target window signals it will accept the drop
  2564. Window targetWindow; // potential drop target
  2565. int xdndVersion; // negotiated version with target
  2566. Rectangle<int> silentRect;
  2567. String textOrFiles;
  2568. Array<Atom> allowedTypes;
  2569. };
  2570. //==============================================================================
  2571. void resetDragAndDrop()
  2572. {
  2573. dragInfo.clear();
  2574. dragInfo.position = Point<int> (-1, -1);
  2575. dragAndDropCurrentMimeType = 0;
  2576. dragAndDropSourceWindow = 0;
  2577. srcMimeTypeAtomList.clear();
  2578. finishAfterDropDataReceived = false;
  2579. }
  2580. void resetExternalDragState()
  2581. {
  2582. dragState = DragState();
  2583. }
  2584. void sendDragAndDropMessage (XClientMessageEvent& msg)
  2585. {
  2586. msg.type = ClientMessage;
  2587. msg.display = display;
  2588. msg.window = dragAndDropSourceWindow;
  2589. msg.format = 32;
  2590. msg.data.l[0] = (long) windowH;
  2591. ScopedXLock xlock;
  2592. XSendEvent (display, dragAndDropSourceWindow, False, 0, (XEvent*) &msg);
  2593. }
  2594. bool sendExternalDragAndDropMessage (XClientMessageEvent& msg, const Window targetWindow)
  2595. {
  2596. msg.type = ClientMessage;
  2597. msg.display = display;
  2598. msg.window = targetWindow;
  2599. msg.format = 32;
  2600. msg.data.l[0] = (long) windowH;
  2601. ScopedXLock xlock;
  2602. return XSendEvent (display, targetWindow, False, 0, (XEvent*) &msg) != 0;
  2603. }
  2604. void sendExternalDragAndDropDrop (const Window targetWindow)
  2605. {
  2606. XClientMessageEvent msg;
  2607. zerostruct (msg);
  2608. msg.message_type = atoms.XdndDrop;
  2609. msg.data.l[2] = CurrentTime;
  2610. sendExternalDragAndDropMessage (msg, targetWindow);
  2611. }
  2612. void sendExternalDragAndDropEnter (const Window targetWindow)
  2613. {
  2614. XClientMessageEvent msg;
  2615. zerostruct (msg);
  2616. msg.message_type = atoms.XdndEnter;
  2617. msg.data.l[1] = (dragState.xdndVersion << 24);
  2618. msg.data.l[2] = (long) dragState.allowedTypes[0];
  2619. sendExternalDragAndDropMessage (msg, targetWindow);
  2620. }
  2621. void sendExternalDragAndDropPosition (const Window targetWindow)
  2622. {
  2623. XClientMessageEvent msg;
  2624. zerostruct (msg);
  2625. msg.message_type = atoms.XdndPosition;
  2626. Point<int> mousePos (Desktop::getInstance().getMousePosition());
  2627. if (dragState.silentRect.contains (mousePos)) // we've been asked to keep silent
  2628. return;
  2629. mousePos = DisplayGeometry::scaledToPhysical (mousePos);
  2630. msg.data.l[1] = 0;
  2631. msg.data.l[2] = (mousePos.x << 16) | mousePos.y;
  2632. msg.data.l[3] = CurrentTime;
  2633. msg.data.l[4] = (long) atoms.XdndActionCopy; // this is all JUCE currently supports
  2634. dragState.expectingStatus = sendExternalDragAndDropMessage (msg, targetWindow);
  2635. }
  2636. void sendDragAndDropStatus (const bool acceptDrop, Atom dropAction)
  2637. {
  2638. XClientMessageEvent msg;
  2639. zerostruct (msg);
  2640. msg.message_type = atoms.XdndStatus;
  2641. msg.data.l[1] = (acceptDrop ? 1 : 0) | 2; // 2 indicates that we want to receive position messages
  2642. msg.data.l[4] = (long) dropAction;
  2643. sendDragAndDropMessage (msg);
  2644. }
  2645. void sendExternalDragAndDropLeave (const Window targetWindow)
  2646. {
  2647. XClientMessageEvent msg;
  2648. zerostruct (msg);
  2649. msg.message_type = atoms.XdndLeave;
  2650. sendExternalDragAndDropMessage (msg, targetWindow);
  2651. }
  2652. void sendDragAndDropFinish()
  2653. {
  2654. XClientMessageEvent msg;
  2655. zerostruct (msg);
  2656. msg.message_type = atoms.XdndFinished;
  2657. sendDragAndDropMessage (msg);
  2658. }
  2659. void handleExternalSelectionClear()
  2660. {
  2661. if (dragState.dragging)
  2662. externalResetDragAndDrop();
  2663. }
  2664. void handleExternalSelectionRequest (const XEvent& evt)
  2665. {
  2666. Atom targetType = evt.xselectionrequest.target;
  2667. XEvent s;
  2668. s.xselection.type = SelectionNotify;
  2669. s.xselection.requestor = evt.xselectionrequest.requestor;
  2670. s.xselection.selection = evt.xselectionrequest.selection;
  2671. s.xselection.target = targetType;
  2672. s.xselection.property = None;
  2673. s.xselection.time = evt.xselectionrequest.time;
  2674. if (dragState.allowedTypes.contains (targetType))
  2675. {
  2676. s.xselection.property = evt.xselectionrequest.property;
  2677. xchangeProperty (evt.xselectionrequest.requestor,
  2678. evt.xselectionrequest.property,
  2679. targetType, 8,
  2680. dragState.textOrFiles.toRawUTF8(),
  2681. (int) dragState.textOrFiles.getNumBytesAsUTF8());
  2682. }
  2683. XSendEvent (display, evt.xselectionrequest.requestor, True, 0, &s);
  2684. }
  2685. void handleExternalDragAndDropStatus (const XClientMessageEvent& clientMsg)
  2686. {
  2687. if (dragState.expectingStatus)
  2688. {
  2689. dragState.expectingStatus = false;
  2690. dragState.canDrop = false;
  2691. dragState.silentRect = Rectangle<int>();
  2692. if ((clientMsg.data.l[1] & 1) != 0
  2693. && ((Atom) clientMsg.data.l[4] == atoms.XdndActionCopy
  2694. || (Atom) clientMsg.data.l[4] == atoms.XdndActionPrivate))
  2695. {
  2696. if ((clientMsg.data.l[1] & 2) == 0) // target requests silent rectangle
  2697. dragState.silentRect.setBounds ((int) clientMsg.data.l[2] >> 16,
  2698. (int) clientMsg.data.l[2] & 0xffff,
  2699. (int) clientMsg.data.l[3] >> 16,
  2700. (int) clientMsg.data.l[3] & 0xffff);
  2701. dragState.canDrop = true;
  2702. }
  2703. }
  2704. }
  2705. void handleExternalDragButtonReleaseEvent()
  2706. {
  2707. if (dragState.dragging)
  2708. XUngrabPointer (display, CurrentTime);
  2709. if (dragState.canDrop)
  2710. {
  2711. sendExternalDragAndDropDrop (dragState.targetWindow);
  2712. }
  2713. else
  2714. {
  2715. sendExternalDragAndDropLeave (dragState.targetWindow);
  2716. externalResetDragAndDrop();
  2717. }
  2718. }
  2719. void handleExternalDragMotionNotify()
  2720. {
  2721. Window targetWindow = externalFindDragTargetWindow (RootWindow (display, DefaultScreen (display)));
  2722. if (dragState.targetWindow != targetWindow)
  2723. {
  2724. if (dragState.targetWindow != None)
  2725. sendExternalDragAndDropLeave (dragState.targetWindow);
  2726. dragState.canDrop = false;
  2727. dragState.silentRect = Rectangle<int>();
  2728. if (targetWindow == None)
  2729. return;
  2730. GetXProperty prop (targetWindow, atoms.XdndAware,
  2731. 0, 2, false, AnyPropertyType);
  2732. if (prop.success
  2733. && prop.data != None
  2734. && prop.actualFormat == 32
  2735. && prop.numItems == 1)
  2736. {
  2737. dragState.xdndVersion = jmin ((int) prop.data[0], (int) Atoms::DndVersion);
  2738. }
  2739. else
  2740. {
  2741. dragState.xdndVersion = -1;
  2742. return;
  2743. }
  2744. sendExternalDragAndDropEnter (targetWindow);
  2745. dragState.targetWindow = targetWindow;
  2746. }
  2747. if (! dragState.expectingStatus)
  2748. sendExternalDragAndDropPosition (targetWindow);
  2749. }
  2750. void handleDragAndDropPosition (const XClientMessageEvent& clientMsg)
  2751. {
  2752. if (dragAndDropSourceWindow == 0)
  2753. return;
  2754. dragAndDropSourceWindow = (::Window) clientMsg.data.l[0];
  2755. Point<int> dropPos ((int) clientMsg.data.l[2] >> 16,
  2756. (int) clientMsg.data.l[2] & 0xffff);
  2757. dropPos -= bounds.getPosition();
  2758. Atom targetAction = atoms.XdndActionCopy;
  2759. for (int i = numElementsInArray (atoms.allowedActions); --i >= 0;)
  2760. {
  2761. if ((Atom) clientMsg.data.l[4] == atoms.allowedActions[i])
  2762. {
  2763. targetAction = atoms.allowedActions[i];
  2764. break;
  2765. }
  2766. }
  2767. sendDragAndDropStatus (true, targetAction);
  2768. if (dragInfo.position != dropPos)
  2769. {
  2770. dragInfo.position = dropPos;
  2771. if (dragInfo.isEmpty())
  2772. updateDraggedFileList (clientMsg);
  2773. if (! dragInfo.isEmpty())
  2774. handleDragMove (dragInfo);
  2775. }
  2776. }
  2777. void handleDragAndDropDrop (const XClientMessageEvent& clientMsg)
  2778. {
  2779. if (dragInfo.isEmpty())
  2780. {
  2781. // no data, transaction finished in handleDragAndDropSelection()
  2782. finishAfterDropDataReceived = true;
  2783. updateDraggedFileList (clientMsg);
  2784. }
  2785. else
  2786. {
  2787. handleDragAndDropDataReceived(); // data was already received
  2788. }
  2789. }
  2790. void handleDragAndDropDataReceived()
  2791. {
  2792. DragInfo dragInfoCopy (dragInfo);
  2793. sendDragAndDropFinish();
  2794. resetDragAndDrop();
  2795. if (! dragInfoCopy.isEmpty())
  2796. handleDragDrop (dragInfoCopy);
  2797. }
  2798. void handleDragAndDropEnter (const XClientMessageEvent& clientMsg)
  2799. {
  2800. dragInfo.clear();
  2801. srcMimeTypeAtomList.clear();
  2802. dragAndDropCurrentMimeType = 0;
  2803. const unsigned long dndCurrentVersion = static_cast<unsigned long> (clientMsg.data.l[1] & 0xff000000) >> 24;
  2804. if (dndCurrentVersion < 3 || dndCurrentVersion > Atoms::DndVersion)
  2805. {
  2806. dragAndDropSourceWindow = 0;
  2807. return;
  2808. }
  2809. dragAndDropSourceWindow = (::Window) clientMsg.data.l[0];
  2810. if ((clientMsg.data.l[1] & 1) != 0)
  2811. {
  2812. ScopedXLock xlock;
  2813. GetXProperty prop (dragAndDropSourceWindow, atoms.XdndTypeList, 0, 0x8000000L, false, XA_ATOM);
  2814. if (prop.success
  2815. && prop.actualType == XA_ATOM
  2816. && prop.actualFormat == 32
  2817. && prop.numItems != 0)
  2818. {
  2819. const unsigned long* const types = (const unsigned long*) prop.data;
  2820. for (unsigned long i = 0; i < prop.numItems; ++i)
  2821. if (types[i] != None)
  2822. srcMimeTypeAtomList.add (types[i]);
  2823. }
  2824. }
  2825. if (srcMimeTypeAtomList.size() == 0)
  2826. {
  2827. for (int i = 2; i < 5; ++i)
  2828. if (clientMsg.data.l[i] != None)
  2829. srcMimeTypeAtomList.add ((unsigned long) clientMsg.data.l[i]);
  2830. if (srcMimeTypeAtomList.size() == 0)
  2831. {
  2832. dragAndDropSourceWindow = 0;
  2833. return;
  2834. }
  2835. }
  2836. for (int i = 0; i < srcMimeTypeAtomList.size() && dragAndDropCurrentMimeType == 0; ++i)
  2837. for (int j = 0; j < numElementsInArray (atoms.allowedMimeTypes); ++j)
  2838. if (srcMimeTypeAtomList[i] == atoms.allowedMimeTypes[j])
  2839. dragAndDropCurrentMimeType = atoms.allowedMimeTypes[j];
  2840. handleDragAndDropPosition (clientMsg);
  2841. }
  2842. void handleDragAndDropSelection (const XEvent& evt)
  2843. {
  2844. dragInfo.clear();
  2845. if (evt.xselection.property != None)
  2846. {
  2847. StringArray lines;
  2848. {
  2849. MemoryBlock dropData;
  2850. for (;;)
  2851. {
  2852. GetXProperty prop (evt.xany.window, evt.xselection.property,
  2853. dropData.getSize() / 4, 65536, false, AnyPropertyType);
  2854. if (! prop.success)
  2855. break;
  2856. dropData.append (prop.data, prop.numItems * (size_t) prop.actualFormat / 8);
  2857. if (prop.bytesLeft <= 0)
  2858. break;
  2859. }
  2860. lines.addLines (dropData.toString());
  2861. }
  2862. if (Atoms::isMimeTypeFile (dragAndDropCurrentMimeType))
  2863. {
  2864. for (int i = 0; i < lines.size(); ++i)
  2865. dragInfo.files.add (URL::removeEscapeChars (lines[i].replace ("file://", String(), true)));
  2866. dragInfo.files.trim();
  2867. dragInfo.files.removeEmptyStrings();
  2868. }
  2869. else
  2870. {
  2871. dragInfo.text = lines.joinIntoString ("\n");
  2872. }
  2873. if (finishAfterDropDataReceived)
  2874. handleDragAndDropDataReceived();
  2875. }
  2876. }
  2877. void updateDraggedFileList (const XClientMessageEvent& clientMsg)
  2878. {
  2879. jassert (dragInfo.isEmpty());
  2880. if (dragAndDropSourceWindow != None
  2881. && dragAndDropCurrentMimeType != None)
  2882. {
  2883. ScopedXLock xlock;
  2884. XConvertSelection (display,
  2885. atoms.XdndSelection,
  2886. dragAndDropCurrentMimeType,
  2887. Atoms::getCreating ("JXSelectionWindowProperty"),
  2888. windowH,
  2889. (::Time) clientMsg.data.l[2]);
  2890. }
  2891. }
  2892. bool isWindowDnDAware (Window w) const
  2893. {
  2894. int numProperties = 0;
  2895. Atom* const properties = XListProperties (display, w, &numProperties);
  2896. bool dndAwarePropFound = false;
  2897. for (int i = 0; i < numProperties; ++i)
  2898. if (properties[i] == atoms.XdndAware)
  2899. dndAwarePropFound = true;
  2900. if (properties != nullptr)
  2901. XFree (properties);
  2902. return dndAwarePropFound;
  2903. }
  2904. Window externalFindDragTargetWindow (Window targetWindow)
  2905. {
  2906. if (targetWindow == None)
  2907. return None;
  2908. if (isWindowDnDAware (targetWindow))
  2909. return targetWindow;
  2910. Window child, phonyWin;
  2911. int phony;
  2912. unsigned int uphony;
  2913. XQueryPointer (display, targetWindow, &phonyWin, &child,
  2914. &phony, &phony, &phony, &phony, &uphony);
  2915. return externalFindDragTargetWindow (child);
  2916. }
  2917. bool externalDragInit (bool isText, const String& textOrFiles)
  2918. {
  2919. ScopedXLock xlock;
  2920. resetExternalDragState();
  2921. dragState.isText = isText;
  2922. dragState.textOrFiles = textOrFiles;
  2923. dragState.targetWindow = windowH;
  2924. const int pointerGrabMask = Button1MotionMask | ButtonReleaseMask;
  2925. if (XGrabPointer (display, windowH, True, pointerGrabMask,
  2926. GrabModeAsync, GrabModeAsync, None, None, CurrentTime) == GrabSuccess)
  2927. {
  2928. // No other method of changing the pointer seems to work, this call is needed from this very context
  2929. XChangeActivePointerGrab (display, pointerGrabMask, (Cursor) createDraggingHandCursor(), CurrentTime);
  2930. XSetSelectionOwner (display, atoms.XdndSelection, windowH, CurrentTime);
  2931. // save the available types to XdndTypeList
  2932. xchangeProperty (windowH, atoms.XdndTypeList, XA_ATOM, 32,
  2933. dragState.allowedTypes.getRawDataPointer(),
  2934. dragState.allowedTypes.size());
  2935. dragState.dragging = true;
  2936. handleExternalDragMotionNotify();
  2937. return true;
  2938. }
  2939. return false;
  2940. }
  2941. void externalResetDragAndDrop()
  2942. {
  2943. if (dragState.dragging)
  2944. {
  2945. ScopedXLock xlock;
  2946. XUngrabPointer (display, CurrentTime);
  2947. }
  2948. resetExternalDragState();
  2949. }
  2950. DragState dragState;
  2951. DragInfo dragInfo;
  2952. Atom dragAndDropCurrentMimeType;
  2953. Window dragAndDropSourceWindow;
  2954. bool finishAfterDropDataReceived;
  2955. Array<Atom> srcMimeTypeAtomList;
  2956. int pointerMap[5];
  2957. void initialisePointerMap()
  2958. {
  2959. const int numButtons = XGetPointerMapping (display, 0, 0);
  2960. pointerMap[2] = pointerMap[3] = pointerMap[4] = Keys::NoButton;
  2961. if (numButtons == 2)
  2962. {
  2963. pointerMap[0] = Keys::LeftButton;
  2964. pointerMap[1] = Keys::RightButton;
  2965. }
  2966. else if (numButtons >= 3)
  2967. {
  2968. pointerMap[0] = Keys::LeftButton;
  2969. pointerMap[1] = Keys::MiddleButton;
  2970. pointerMap[2] = Keys::RightButton;
  2971. if (numButtons >= 5)
  2972. {
  2973. pointerMap[3] = Keys::WheelUp;
  2974. pointerMap[4] = Keys::WheelDown;
  2975. }
  2976. }
  2977. }
  2978. static Point<int> lastMousePos;
  2979. static void clearLastMousePos() noexcept
  2980. {
  2981. lastMousePos = Point<int> (0x100000, 0x100000);
  2982. }
  2983. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LinuxComponentPeer)
  2984. };
  2985. ModifierKeys LinuxComponentPeer::currentModifiers;
  2986. bool LinuxComponentPeer::isActiveApplication = false;
  2987. Point<int> LinuxComponentPeer::lastMousePos;
  2988. //==============================================================================
  2989. JUCE_API bool JUCE_CALLTYPE Process::isForegroundProcess()
  2990. {
  2991. return LinuxComponentPeer::isActiveApplication;
  2992. }
  2993. // N/A on Linux as far as I know.
  2994. JUCE_API void JUCE_CALLTYPE Process::makeForegroundProcess() {}
  2995. JUCE_API void JUCE_CALLTYPE Process::hide() {}
  2996. //==============================================================================
  2997. void ModifierKeys::updateCurrentModifiers() noexcept
  2998. {
  2999. currentModifiers = LinuxComponentPeer::currentModifiers;
  3000. }
  3001. ModifierKeys ModifierKeys::getCurrentModifiersRealtime() noexcept
  3002. {
  3003. if (display != nullptr)
  3004. {
  3005. Window root, child;
  3006. int x, y, winx, winy;
  3007. unsigned int mask;
  3008. int mouseMods = 0;
  3009. ScopedXLock xlock;
  3010. if (XQueryPointer (display, RootWindow (display, DefaultScreen (display)),
  3011. &root, &child, &x, &y, &winx, &winy, &mask) != False)
  3012. {
  3013. if ((mask & Button1Mask) != 0) mouseMods |= ModifierKeys::leftButtonModifier;
  3014. if ((mask & Button2Mask) != 0) mouseMods |= ModifierKeys::middleButtonModifier;
  3015. if ((mask & Button3Mask) != 0) mouseMods |= ModifierKeys::rightButtonModifier;
  3016. }
  3017. LinuxComponentPeer::currentModifiers = LinuxComponentPeer::currentModifiers.withoutMouseButtons().withFlags (mouseMods);
  3018. }
  3019. return LinuxComponentPeer::currentModifiers;
  3020. }
  3021. //==============================================================================
  3022. void Desktop::setKioskComponent (Component* comp, bool enableOrDisable, bool /* allowMenusAndBars */)
  3023. {
  3024. if (enableOrDisable)
  3025. comp->setBounds (getDisplays().getMainDisplay().totalArea);
  3026. }
  3027. void Desktop::allowedOrientationsChanged() {}
  3028. //==============================================================================
  3029. ComponentPeer* Component::createNewPeer (int styleFlags, void* nativeWindowToAttachTo)
  3030. {
  3031. return new LinuxComponentPeer (*this, styleFlags, (Window) nativeWindowToAttachTo);
  3032. }
  3033. //==============================================================================
  3034. void Desktop::Displays::findDisplays (float masterScale)
  3035. {
  3036. DisplayGeometry& geometry = DisplayGeometry::getOrCreateInstance (display, masterScale);
  3037. // add the main display first
  3038. int mainDisplayIdx;
  3039. for (mainDisplayIdx = 0; mainDisplayIdx < geometry.infos.size(); ++mainDisplayIdx)
  3040. {
  3041. const DisplayGeometry::ExtendedInfo& info = geometry.infos.getReference (mainDisplayIdx);
  3042. if (info.isMain)
  3043. break;
  3044. }
  3045. // no main display found then use the first
  3046. if (mainDisplayIdx >= geometry.infos.size())
  3047. mainDisplayIdx = 0;
  3048. // add the main display
  3049. {
  3050. const DisplayGeometry::ExtendedInfo& info =
  3051. geometry.infos.getReference (mainDisplayIdx);
  3052. Desktop::Displays::Display d;
  3053. d.isMain = true;
  3054. d.scale = masterScale * info.scale;
  3055. d.dpi = info.dpi;
  3056. d.totalArea = DisplayGeometry::physicalToScaled (info.totalBounds);
  3057. d.userArea = (info.usableBounds / d.scale) + info.topLeftScaled;
  3058. displays.add (d);
  3059. }
  3060. for (int i = 0; i < geometry.infos.size(); ++i)
  3061. {
  3062. // don't add the main display a second time
  3063. if (i == mainDisplayIdx)
  3064. continue;
  3065. const DisplayGeometry::ExtendedInfo& info = geometry.infos.getReference (i);
  3066. Desktop::Displays::Display d;
  3067. d.isMain = false;
  3068. d.scale = masterScale * info.scale;
  3069. d.dpi = info.dpi;
  3070. d.totalArea = DisplayGeometry::physicalToScaled (info.totalBounds);
  3071. d.userArea = (info.usableBounds / d.scale) + info.topLeftScaled;
  3072. displays.add (d);
  3073. }
  3074. }
  3075. //==============================================================================
  3076. bool MouseInputSource::SourceList::addSource()
  3077. {
  3078. if (sources.size() == 0)
  3079. {
  3080. addSource (0, true);
  3081. return true;
  3082. }
  3083. return false;
  3084. }
  3085. bool Desktop::canUseSemiTransparentWindows() noexcept
  3086. {
  3087. #if JUCE_USE_XRENDER
  3088. if (XRender::hasCompositingWindowManager())
  3089. {
  3090. int matchedDepth = 0, desiredDepth = 32;
  3091. return Visuals::findVisualFormat (desiredDepth, matchedDepth) != 0
  3092. && matchedDepth == desiredDepth;
  3093. }
  3094. #endif
  3095. return false;
  3096. }
  3097. Point<float> MouseInputSource::getCurrentRawMousePosition()
  3098. {
  3099. if (display == nullptr)
  3100. return Point<float>();
  3101. Window root, child;
  3102. int x, y, winx, winy;
  3103. unsigned int mask;
  3104. ScopedXLock xlock;
  3105. if (XQueryPointer (display,
  3106. RootWindow (display, DefaultScreen (display)),
  3107. &root, &child,
  3108. &x, &y, &winx, &winy, &mask) == False)
  3109. {
  3110. // Pointer not on the default screen
  3111. x = y = -1;
  3112. }
  3113. return DisplayGeometry::physicalToScaled (Point<float> ((float) x, (float) y));
  3114. }
  3115. void MouseInputSource::setRawMousePosition (Point<float> newPosition)
  3116. {
  3117. if (display != nullptr)
  3118. {
  3119. ScopedXLock xlock;
  3120. Window root = RootWindow (display, DefaultScreen (display));
  3121. newPosition = DisplayGeometry::scaledToPhysical (newPosition);
  3122. XWarpPointer (display, None, root, 0, 0, 0, 0, roundToInt (newPosition.getX()), roundToInt (newPosition.getY()));
  3123. }
  3124. }
  3125. double Desktop::getDefaultMasterScale()
  3126. {
  3127. return 1.0;
  3128. }
  3129. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
  3130. {
  3131. return upright;
  3132. }
  3133. //==============================================================================
  3134. static bool screenSaverAllowed = true;
  3135. void Desktop::setScreenSaverEnabled (const bool isEnabled)
  3136. {
  3137. if (screenSaverAllowed != isEnabled)
  3138. {
  3139. screenSaverAllowed = isEnabled;
  3140. if (display != nullptr)
  3141. {
  3142. typedef void (*tXScreenSaverSuspend) (Display*, Bool);
  3143. static tXScreenSaverSuspend xScreenSaverSuspend = nullptr;
  3144. if (xScreenSaverSuspend == nullptr)
  3145. if (void* h = dlopen ("libXss.so", RTLD_GLOBAL | RTLD_NOW))
  3146. xScreenSaverSuspend = (tXScreenSaverSuspend) dlsym (h, "XScreenSaverSuspend");
  3147. ScopedXLock xlock;
  3148. if (xScreenSaverSuspend != nullptr)
  3149. xScreenSaverSuspend (display, ! isEnabled);
  3150. }
  3151. }
  3152. }
  3153. bool Desktop::isScreenSaverEnabled()
  3154. {
  3155. return screenSaverAllowed;
  3156. }
  3157. //==============================================================================
  3158. void* CustomMouseCursorInfo::create() const
  3159. {
  3160. if (display == nullptr)
  3161. return nullptr;
  3162. ScopedXLock xlock;
  3163. const unsigned int imageW = (unsigned int) image.getWidth();
  3164. const unsigned int imageH = (unsigned int) image.getHeight();
  3165. int hotspotX = hotspot.x;
  3166. int hotspotY = hotspot.y;
  3167. #if JUCE_USE_XCURSOR
  3168. {
  3169. typedef XcursorBool (*tXcursorSupportsARGB) (Display*);
  3170. typedef XcursorImage* (*tXcursorImageCreate) (int, int);
  3171. typedef void (*tXcursorImageDestroy) (XcursorImage*);
  3172. typedef Cursor (*tXcursorImageLoadCursor) (Display*, const XcursorImage*);
  3173. static tXcursorSupportsARGB xcursorSupportsARGB = nullptr;
  3174. static tXcursorImageCreate xcursorImageCreate = nullptr;
  3175. static tXcursorImageDestroy xcursorImageDestroy = nullptr;
  3176. static tXcursorImageLoadCursor xcursorImageLoadCursor = nullptr;
  3177. static bool hasBeenLoaded = false;
  3178. if (! hasBeenLoaded)
  3179. {
  3180. hasBeenLoaded = true;
  3181. if (void* h = dlopen ("libXcursor.so", RTLD_GLOBAL | RTLD_NOW))
  3182. {
  3183. xcursorSupportsARGB = (tXcursorSupportsARGB) dlsym (h, "XcursorSupportsARGB");
  3184. xcursorImageCreate = (tXcursorImageCreate) dlsym (h, "XcursorImageCreate");
  3185. xcursorImageLoadCursor = (tXcursorImageLoadCursor) dlsym (h, "XcursorImageLoadCursor");
  3186. xcursorImageDestroy = (tXcursorImageDestroy) dlsym (h, "XcursorImageDestroy");
  3187. if (xcursorSupportsARGB == nullptr || xcursorImageCreate == nullptr
  3188. || xcursorImageLoadCursor == nullptr || xcursorImageDestroy == nullptr
  3189. || ! xcursorSupportsARGB (display))
  3190. xcursorSupportsARGB = nullptr;
  3191. }
  3192. }
  3193. if (xcursorSupportsARGB != nullptr)
  3194. {
  3195. if (XcursorImage* xcImage = xcursorImageCreate ((int) imageW, (int) imageH))
  3196. {
  3197. xcImage->xhot = (XcursorDim) hotspotX;
  3198. xcImage->yhot = (XcursorDim) hotspotY;
  3199. XcursorPixel* dest = xcImage->pixels;
  3200. for (int y = 0; y < (int) imageH; ++y)
  3201. for (int x = 0; x < (int) imageW; ++x)
  3202. *dest++ = image.getPixelAt (x, y).getARGB();
  3203. void* result = (void*) xcursorImageLoadCursor (display, xcImage);
  3204. xcursorImageDestroy (xcImage);
  3205. if (result != nullptr)
  3206. return result;
  3207. }
  3208. }
  3209. }
  3210. #endif
  3211. Window root = RootWindow (display, DefaultScreen (display));
  3212. unsigned int cursorW, cursorH;
  3213. if (! XQueryBestCursor (display, root, imageW, imageH, &cursorW, &cursorH))
  3214. return nullptr;
  3215. Image im (Image::ARGB, (int) cursorW, (int) cursorH, true);
  3216. {
  3217. Graphics g (im);
  3218. if (imageW > cursorW || imageH > cursorH)
  3219. {
  3220. hotspotX = (hotspotX * (int) cursorW) / (int) imageW;
  3221. hotspotY = (hotspotY * (int) cursorH) / (int) imageH;
  3222. g.drawImage (image, Rectangle<float> ((float) imageW, (float) imageH),
  3223. RectanglePlacement::xLeft | RectanglePlacement::yTop | RectanglePlacement::onlyReduceInSize);
  3224. }
  3225. else
  3226. {
  3227. g.drawImageAt (image, 0, 0);
  3228. }
  3229. }
  3230. const unsigned int stride = (cursorW + 7) >> 3;
  3231. HeapBlock<char> maskPlane, sourcePlane;
  3232. maskPlane.calloc (stride * cursorH);
  3233. sourcePlane.calloc (stride * cursorH);
  3234. const bool msbfirst = (BitmapBitOrder (display) == MSBFirst);
  3235. for (int y = (int) cursorH; --y >= 0;)
  3236. {
  3237. for (int x = (int) cursorW; --x >= 0;)
  3238. {
  3239. const char mask = (char) (1 << (msbfirst ? (7 - (x & 7)) : (x & 7)));
  3240. const unsigned int offset = (unsigned int) y * stride + ((unsigned int) x >> 3);
  3241. const Colour c (im.getPixelAt (x, y));
  3242. if (c.getAlpha() >= 128) maskPlane[offset] |= mask;
  3243. if (c.getBrightness() >= 0.5f) sourcePlane[offset] |= mask;
  3244. }
  3245. }
  3246. Pixmap sourcePixmap = XCreatePixmapFromBitmapData (display, root, sourcePlane.getData(), cursorW, cursorH, 0xffff, 0, 1);
  3247. Pixmap maskPixmap = XCreatePixmapFromBitmapData (display, root, maskPlane.getData(), cursorW, cursorH, 0xffff, 0, 1);
  3248. XColor white, black;
  3249. black.red = black.green = black.blue = 0;
  3250. white.red = white.green = white.blue = 0xffff;
  3251. void* result = (void*) XCreatePixmapCursor (display, sourcePixmap, maskPixmap, &white, &black,
  3252. (unsigned int) hotspotX, (unsigned int) hotspotY);
  3253. XFreePixmap (display, sourcePixmap);
  3254. XFreePixmap (display, maskPixmap);
  3255. return result;
  3256. }
  3257. void MouseCursor::deleteMouseCursor (void* const cursorHandle, const bool)
  3258. {
  3259. if (cursorHandle != nullptr && display != nullptr)
  3260. {
  3261. ScopedXLock xlock;
  3262. XFreeCursor (display, (Cursor) cursorHandle);
  3263. }
  3264. }
  3265. void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType type)
  3266. {
  3267. if (display == nullptr)
  3268. return None;
  3269. unsigned int shape;
  3270. switch (type)
  3271. {
  3272. case NormalCursor:
  3273. case ParentCursor: return None; // Use parent cursor
  3274. case NoCursor: return CustomMouseCursorInfo (Image (Image::ARGB, 16, 16, true), 0, 0).create();
  3275. case WaitCursor: shape = XC_watch; break;
  3276. case IBeamCursor: shape = XC_xterm; break;
  3277. case PointingHandCursor: shape = XC_hand2; break;
  3278. case LeftRightResizeCursor: shape = XC_sb_h_double_arrow; break;
  3279. case UpDownResizeCursor: shape = XC_sb_v_double_arrow; break;
  3280. case UpDownLeftRightResizeCursor: shape = XC_fleur; break;
  3281. case TopEdgeResizeCursor: shape = XC_top_side; break;
  3282. case BottomEdgeResizeCursor: shape = XC_bottom_side; break;
  3283. case LeftEdgeResizeCursor: shape = XC_left_side; break;
  3284. case RightEdgeResizeCursor: shape = XC_right_side; break;
  3285. case TopLeftCornerResizeCursor: shape = XC_top_left_corner; break;
  3286. case TopRightCornerResizeCursor: shape = XC_top_right_corner; break;
  3287. case BottomLeftCornerResizeCursor: shape = XC_bottom_left_corner; break;
  3288. case BottomRightCornerResizeCursor: shape = XC_bottom_right_corner; break;
  3289. case CrosshairCursor: shape = XC_crosshair; break;
  3290. case DraggingHandCursor: return createDraggingHandCursor();
  3291. case CopyingCursor:
  3292. {
  3293. static unsigned char copyCursorData[] = { 71,73,70,56,57,97,21,0,21,0,145,0,0,0,0,0,255,255,255,0,
  3294. 128,128,255,255,255,33,249,4,1,0,0,3,0,44,0,0,0,0,21,0, 21,0,0,2,72,4,134,169,171,16,199,98,11,79,90,71,161,93,56,111,
  3295. 78,133,218,215,137,31,82,154,100,200,86,91,202,142,12,108,212,87,235,174, 15,54,214,126,237,226,37,96,59,141,16,37,18,201,142,157,230,204,51,112,
  3296. 252,114,147,74,83,5,50,68,147,208,217,16,71,149,252,124,5,0,59,0,0 };
  3297. const int copyCursorSize = 119;
  3298. return CustomMouseCursorInfo (ImageFileFormat::loadFrom (copyCursorData, copyCursorSize), 1, 3).create();
  3299. }
  3300. default:
  3301. jassertfalse;
  3302. return None;
  3303. }
  3304. ScopedXLock xlock;
  3305. return (void*) XCreateFontCursor (display, shape);
  3306. }
  3307. void MouseCursor::showInWindow (ComponentPeer* peer) const
  3308. {
  3309. if (LinuxComponentPeer* const lp = dynamic_cast<LinuxComponentPeer*> (peer))
  3310. lp->showMouseCursor ((Cursor) getHandle());
  3311. }
  3312. void MouseCursor::showInAllWindows() const
  3313. {
  3314. for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
  3315. showInWindow (ComponentPeer::getPeer (i));
  3316. }
  3317. //==============================================================================
  3318. Image juce_createIconForFile (const File& /* file */)
  3319. {
  3320. return Image();
  3321. }
  3322. //==============================================================================
  3323. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool canMoveFiles)
  3324. {
  3325. if (files.size() == 0)
  3326. return false;
  3327. if (MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0))
  3328. if (Component* sourceComp = draggingSource->getComponentUnderMouse())
  3329. if (LinuxComponentPeer* const lp = dynamic_cast<LinuxComponentPeer*> (sourceComp->getPeer()))
  3330. return lp->externalDragFileInit (files, canMoveFiles);
  3331. // This method must be called in response to a component's mouseDown or mouseDrag event!
  3332. jassertfalse;
  3333. return false;
  3334. }
  3335. bool DragAndDropContainer::performExternalDragDropOfText (const String& text)
  3336. {
  3337. if (text.isEmpty())
  3338. return false;
  3339. if (MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0))
  3340. if (Component* sourceComp = draggingSource->getComponentUnderMouse())
  3341. if (LinuxComponentPeer* const lp = dynamic_cast<LinuxComponentPeer*> (sourceComp->getPeer()))
  3342. return lp->externalDragTextInit (text);
  3343. // This method must be called in response to a component's mouseDown or mouseDrag event!
  3344. jassertfalse;
  3345. return false;
  3346. }
  3347. //==============================================================================
  3348. void LookAndFeel::playAlertSound()
  3349. {
  3350. std::cout << "\a" << std::flush;
  3351. }
  3352. //==============================================================================
  3353. Rectangle<int> juce_LinuxScaledToPhysicalBounds(ComponentPeer* peer, const Rectangle<int>& bounds)
  3354. {
  3355. Rectangle<int> retval = bounds;
  3356. if (LinuxComponentPeer* linuxPeer = dynamic_cast<LinuxComponentPeer*> (peer))
  3357. retval *= linuxPeer->getCurrentScale();
  3358. return retval;
  3359. }
  3360. void juce_LinuxAddRepaintListener (ComponentPeer* peer, Component* dummy)
  3361. {
  3362. if (LinuxComponentPeer* linuxPeer = dynamic_cast<LinuxComponentPeer*> (peer))
  3363. linuxPeer->addOpenGLRepaintListener (dummy);
  3364. }
  3365. void juce_LinuxRemoveRepaintListener (ComponentPeer* peer, Component* dummy)
  3366. {
  3367. if (LinuxComponentPeer* linuxPeer = dynamic_cast<LinuxComponentPeer*> (peer))
  3368. linuxPeer->removeOpenGLRepaintListener (dummy);
  3369. }
  3370. //==============================================================================
  3371. #if JUCE_MODAL_LOOPS_PERMITTED
  3372. void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,
  3373. const String& title, const String& message,
  3374. Component* /* associatedComponent */)
  3375. {
  3376. AlertWindow::showMessageBox (iconType, title, message);
  3377. }
  3378. #endif
  3379. void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
  3380. const String& title, const String& message,
  3381. Component* associatedComponent,
  3382. ModalComponentManager::Callback* callback)
  3383. {
  3384. AlertWindow::showMessageBoxAsync (iconType, title, message, String(), associatedComponent, callback);
  3385. }
  3386. bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType,
  3387. const String& title, const String& message,
  3388. Component* associatedComponent,
  3389. ModalComponentManager::Callback* callback)
  3390. {
  3391. return AlertWindow::showOkCancelBox (iconType, title, message, String(), String(),
  3392. associatedComponent, callback);
  3393. }
  3394. int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType,
  3395. const String& title, const String& message,
  3396. Component* associatedComponent,
  3397. ModalComponentManager::Callback* callback)
  3398. {
  3399. return AlertWindow::showYesNoCancelBox (iconType, title, message,
  3400. String(), String(), String(),
  3401. associatedComponent, callback);
  3402. }
  3403. //==============================================================================
  3404. const int KeyPress::spaceKey = XK_space & 0xff;
  3405. const int KeyPress::returnKey = XK_Return & 0xff;
  3406. const int KeyPress::escapeKey = XK_Escape & 0xff;
  3407. const int KeyPress::backspaceKey = XK_BackSpace & 0xff;
  3408. const int KeyPress::leftKey = (XK_Left & 0xff) | Keys::extendedKeyModifier;
  3409. const int KeyPress::rightKey = (XK_Right & 0xff) | Keys::extendedKeyModifier;
  3410. const int KeyPress::upKey = (XK_Up & 0xff) | Keys::extendedKeyModifier;
  3411. const int KeyPress::downKey = (XK_Down & 0xff) | Keys::extendedKeyModifier;
  3412. const int KeyPress::pageUpKey = (XK_Page_Up & 0xff) | Keys::extendedKeyModifier;
  3413. const int KeyPress::pageDownKey = (XK_Page_Down & 0xff) | Keys::extendedKeyModifier;
  3414. const int KeyPress::endKey = (XK_End & 0xff) | Keys::extendedKeyModifier;
  3415. const int KeyPress::homeKey = (XK_Home & 0xff) | Keys::extendedKeyModifier;
  3416. const int KeyPress::insertKey = (XK_Insert & 0xff) | Keys::extendedKeyModifier;
  3417. const int KeyPress::deleteKey = (XK_Delete & 0xff) | Keys::extendedKeyModifier;
  3418. const int KeyPress::tabKey = XK_Tab & 0xff;
  3419. const int KeyPress::F1Key = (XK_F1 & 0xff) | Keys::extendedKeyModifier;
  3420. const int KeyPress::F2Key = (XK_F2 & 0xff) | Keys::extendedKeyModifier;
  3421. const int KeyPress::F3Key = (XK_F3 & 0xff) | Keys::extendedKeyModifier;
  3422. const int KeyPress::F4Key = (XK_F4 & 0xff) | Keys::extendedKeyModifier;
  3423. const int KeyPress::F5Key = (XK_F5 & 0xff) | Keys::extendedKeyModifier;
  3424. const int KeyPress::F6Key = (XK_F6 & 0xff) | Keys::extendedKeyModifier;
  3425. const int KeyPress::F7Key = (XK_F7 & 0xff) | Keys::extendedKeyModifier;
  3426. const int KeyPress::F8Key = (XK_F8 & 0xff) | Keys::extendedKeyModifier;
  3427. const int KeyPress::F9Key = (XK_F9 & 0xff) | Keys::extendedKeyModifier;
  3428. const int KeyPress::F10Key = (XK_F10 & 0xff) | Keys::extendedKeyModifier;
  3429. const int KeyPress::F11Key = (XK_F11 & 0xff) | Keys::extendedKeyModifier;
  3430. const int KeyPress::F12Key = (XK_F12 & 0xff) | Keys::extendedKeyModifier;
  3431. const int KeyPress::F13Key = (XK_F13 & 0xff) | Keys::extendedKeyModifier;
  3432. const int KeyPress::F14Key = (XK_F14 & 0xff) | Keys::extendedKeyModifier;
  3433. const int KeyPress::F15Key = (XK_F15 & 0xff) | Keys::extendedKeyModifier;
  3434. const int KeyPress::F16Key = (XK_F16 & 0xff) | Keys::extendedKeyModifier;
  3435. const int KeyPress::numberPad0 = (XK_KP_0 & 0xff) | Keys::extendedKeyModifier;
  3436. const int KeyPress::numberPad1 = (XK_KP_1 & 0xff) | Keys::extendedKeyModifier;
  3437. const int KeyPress::numberPad2 = (XK_KP_2 & 0xff) | Keys::extendedKeyModifier;
  3438. const int KeyPress::numberPad3 = (XK_KP_3 & 0xff) | Keys::extendedKeyModifier;
  3439. const int KeyPress::numberPad4 = (XK_KP_4 & 0xff) | Keys::extendedKeyModifier;
  3440. const int KeyPress::numberPad5 = (XK_KP_5 & 0xff) | Keys::extendedKeyModifier;
  3441. const int KeyPress::numberPad6 = (XK_KP_6 & 0xff) | Keys::extendedKeyModifier;
  3442. const int KeyPress::numberPad7 = (XK_KP_7 & 0xff)| Keys::extendedKeyModifier;
  3443. const int KeyPress::numberPad8 = (XK_KP_8 & 0xff)| Keys::extendedKeyModifier;
  3444. const int KeyPress::numberPad9 = (XK_KP_9 & 0xff)| Keys::extendedKeyModifier;
  3445. const int KeyPress::numberPadAdd = (XK_KP_Add & 0xff)| Keys::extendedKeyModifier;
  3446. const int KeyPress::numberPadSubtract = (XK_KP_Subtract & 0xff)| Keys::extendedKeyModifier;
  3447. const int KeyPress::numberPadMultiply = (XK_KP_Multiply & 0xff)| Keys::extendedKeyModifier;
  3448. const int KeyPress::numberPadDivide = (XK_KP_Divide & 0xff)| Keys::extendedKeyModifier;
  3449. const int KeyPress::numberPadSeparator = (XK_KP_Separator & 0xff)| Keys::extendedKeyModifier;
  3450. const int KeyPress::numberPadDecimalPoint = (XK_KP_Decimal & 0xff)| Keys::extendedKeyModifier;
  3451. const int KeyPress::numberPadEquals = (XK_KP_Equal & 0xff)| Keys::extendedKeyModifier;
  3452. const int KeyPress::numberPadDelete = (XK_KP_Delete & 0xff)| Keys::extendedKeyModifier;
  3453. const int KeyPress::playKey = ((int) 0xffeeff00) | Keys::extendedKeyModifier;
  3454. const int KeyPress::stopKey = ((int) 0xffeeff01) | Keys::extendedKeyModifier;
  3455. const int KeyPress::fastForwardKey = ((int) 0xffeeff02) | Keys::extendedKeyModifier;
  3456. const int KeyPress::rewindKey = ((int) 0xffeeff03) | Keys::extendedKeyModifier;