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 124KB

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