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.

3310 lines
110KB

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