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.

3251 lines
108KB

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