The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

3487 lines
120KB

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