2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 // (This file gets included by juce_linux_NativeCode.cpp, rather than being
27 // compiled on its own).
28 #if JUCE_INCLUDED_FILE
30 //==============================================================================
31 // These are defined in juce_linux_Messaging.cpp
32 extern Display
* display
;
33 extern XContext windowHandleXContext
;
35 //==============================================================================
45 static Atom Protocols
, ProtocolList
[3], ChangeState
, State
,
46 ActiveWin
, Pid
, WindowType
, WindowState
,
47 XdndAware
, XdndEnter
, XdndLeave
, XdndPosition
, XdndStatus
,
48 XdndDrop
, XdndFinished
, XdndSelection
, XdndTypeList
, XdndActionList
,
49 XdndActionDescription
, XdndActionCopy
,
53 const unsigned long DndVersion
= 3;
55 //==============================================================================
56 static void initialiseAtoms()
58 static bool atomsInitialised
= false;
60 if (! atomsInitialised
)
62 atomsInitialised
= true;
64 Protocols
= XInternAtom (display
, "WM_PROTOCOLS", True
);
65 ProtocolList
[TAKE_FOCUS
] = XInternAtom (display
, "WM_TAKE_FOCUS", True
);
66 ProtocolList
[DELETE_WINDOW
] = XInternAtom (display
, "WM_DELETE_WINDOW", True
);
67 ProtocolList
[PING
] = XInternAtom (display
, "_NET_WM_PING", True
);
68 ChangeState
= XInternAtom (display
, "WM_CHANGE_STATE", True
);
69 State
= XInternAtom (display
, "WM_STATE", True
);
70 ActiveWin
= XInternAtom (display
, "_NET_ACTIVE_WINDOW", False
);
71 Pid
= XInternAtom (display
, "_NET_WM_PID", False
);
72 WindowType
= XInternAtom (display
, "_NET_WM_WINDOW_TYPE", True
);
73 WindowState
= XInternAtom (display
, "_NET_WM_STATE", True
);
75 XdndAware
= XInternAtom (display
, "XdndAware", False
);
76 XdndEnter
= XInternAtom (display
, "XdndEnter", False
);
77 XdndLeave
= XInternAtom (display
, "XdndLeave", False
);
78 XdndPosition
= XInternAtom (display
, "XdndPosition", False
);
79 XdndStatus
= XInternAtom (display
, "XdndStatus", False
);
80 XdndDrop
= XInternAtom (display
, "XdndDrop", False
);
81 XdndFinished
= XInternAtom (display
, "XdndFinished", False
);
82 XdndSelection
= XInternAtom (display
, "XdndSelection", False
);
84 XdndTypeList
= XInternAtom (display
, "XdndTypeList", False
);
85 XdndActionList
= XInternAtom (display
, "XdndActionList", False
);
86 XdndActionCopy
= XInternAtom (display
, "XdndActionCopy", False
);
87 XdndActionDescription
= XInternAtom (display
, "XdndActionDescription", False
);
89 allowedMimeTypes
[0] = XInternAtom (display
, "text/plain", False
);
90 allowedMimeTypes
[1] = XInternAtom (display
, "text/uri-list", False
);
92 allowedActions
[0] = XInternAtom (display
, "XdndActionMove", False
);
93 allowedActions
[1] = XdndActionCopy
;
94 allowedActions
[2] = XInternAtom (display
, "XdndActionLink", False
);
95 allowedActions
[3] = XInternAtom (display
, "XdndActionAsk", False
);
96 allowedActions
[4] = XInternAtom (display
, "XdndActionPrivate", False
);
101 //==============================================================================
114 static int AltMask
= 0;
115 static int NumLockMask
= 0;
116 static bool numLock
= false;
117 static bool capsLock
= false;
118 static char keyStates
[32];
119 static const int extendedKeyModifier
= 0x10000000;
122 bool KeyPress::isKeyCurrentlyDown (const int keyCode
)
126 if (keyCode
& Keys::extendedKeyModifier
)
128 keysym
= 0xff00 | (keyCode
& 0xff);
134 if (keysym
== (XK_Tab
& 0xff)
135 || keysym
== (XK_Return
& 0xff)
136 || keysym
== (XK_Escape
& 0xff)
137 || keysym
== (XK_BackSpace
& 0xff))
145 const int keycode
= XKeysymToKeycode (display
, keysym
);
147 const int keybyte
= keycode
>> 3;
148 const int keybit
= (1 << (keycode
& 7));
149 return (Keys::keyStates
[keybyte
] & keybit
) != 0;
152 //==============================================================================
154 namespace XSHMHelpers
156 static int trappedErrorCode
= 0;
157 extern "C" int errorTrapHandler (Display
*, XErrorEvent
* err
)
159 trappedErrorCode
= err
->error_code
;
163 static bool isShmAvailable() noexcept
165 static bool isChecked
= false;
166 static bool isAvailable
= false;
176 if (XShmQueryVersion (display
, &major
, &minor
, &pixmaps
))
178 trappedErrorCode
= 0;
179 XErrorHandler oldHandler
= XSetErrorHandler (errorTrapHandler
);
181 XShmSegmentInfo segmentInfo
= { 0 };
182 XImage
* xImage
= XShmCreateImage (display
, DefaultVisual (display
, DefaultScreen (display
)),
183 24, ZPixmap
, 0, &segmentInfo
, 50, 50);
185 if ((segmentInfo
.shmid
= shmget (IPC_PRIVATE
,
186 xImage
->bytes_per_line
* xImage
->height
,
187 IPC_CREAT
| 0777)) >= 0)
189 segmentInfo
.shmaddr
= (char*) shmat (segmentInfo
.shmid
, 0, 0);
191 if (segmentInfo
.shmaddr
!= (void*) -1)
193 segmentInfo
.readOnly
= False
;
194 xImage
->data
= segmentInfo
.shmaddr
;
195 XSync (display
, False
);
197 if (XShmAttach (display
, &segmentInfo
) != 0)
199 XSync (display
, False
);
200 XShmDetach (display
, &segmentInfo
);
207 XDestroyImage (xImage
);
209 shmdt (segmentInfo
.shmaddr
);
212 shmctl (segmentInfo
.shmid
, IPC_RMID
, 0);
214 XSetErrorHandler (oldHandler
);
215 if (trappedErrorCode
!= 0)
225 //==============================================================================
229 typedef Status (*tXRenderQueryVersion
) (Display
*, int*, int*);
230 typedef XRenderPictFormat
* (*tXrenderFindStandardFormat
) (Display
*, int);
231 typedef XRenderPictFormat
* (*tXRenderFindFormat
) (Display
*, unsigned long, XRenderPictFormat
*, int);
232 typedef XRenderPictFormat
* (*tXRenderFindVisualFormat
) (Display
*, Visual
*);
234 static tXRenderQueryVersion xRenderQueryVersion
= 0;
235 static tXrenderFindStandardFormat xRenderFindStandardFormat
= 0;
236 static tXRenderFindFormat xRenderFindFormat
= 0;
237 static tXRenderFindVisualFormat xRenderFindVisualFormat
= 0;
239 static bool isAvailable()
241 static bool hasLoaded
= false;
248 void* h
= dlopen ("libXrender.so", RTLD_GLOBAL
| RTLD_NOW
);
252 xRenderQueryVersion
= (tXRenderQueryVersion
) dlsym (h
, "XRenderQueryVersion");
253 xRenderFindStandardFormat
= (tXrenderFindStandardFormat
) dlsym (h
, "XrenderFindStandardFormat");
254 xRenderFindFormat
= (tXRenderFindFormat
) dlsym (h
, "XRenderFindFormat");
255 xRenderFindVisualFormat
= (tXRenderFindVisualFormat
) dlsym (h
, "XRenderFindVisualFormat");
258 if (xRenderQueryVersion
!= 0
259 && xRenderFindStandardFormat
!= 0
260 && xRenderFindFormat
!= 0
261 && xRenderFindVisualFormat
!= 0)
264 if (xRenderQueryVersion (display
, &major
, &minor
))
268 xRenderQueryVersion
= 0;
271 return xRenderQueryVersion
!= 0;
274 static XRenderPictFormat
* findPictureFormat()
278 XRenderPictFormat
* pictFormat
= nullptr;
282 pictFormat
= xRenderFindStandardFormat (display
, PictStandardARGB32
);
286 XRenderPictFormat desiredFormat
;
287 desiredFormat
.type
= PictTypeDirect
;
288 desiredFormat
.depth
= 32;
290 desiredFormat
.direct
.alphaMask
= 0xff;
291 desiredFormat
.direct
.redMask
= 0xff;
292 desiredFormat
.direct
.greenMask
= 0xff;
293 desiredFormat
.direct
.blueMask
= 0xff;
295 desiredFormat
.direct
.alpha
= 24;
296 desiredFormat
.direct
.red
= 16;
297 desiredFormat
.direct
.green
= 8;
298 desiredFormat
.direct
.blue
= 0;
300 pictFormat
= xRenderFindFormat (display
,
301 PictFormatType
| PictFormatDepth
302 | PictFormatRedMask
| PictFormatRed
303 | PictFormatGreenMask
| PictFormatGreen
304 | PictFormatBlueMask
| PictFormatBlue
305 | PictFormatAlphaMask
| PictFormatAlpha
,
316 //==============================================================================
319 static Visual
* findVisualWithDepth (const int desiredDepth
) noexcept
323 Visual
* visual
= nullptr;
325 long desiredMask
= VisualNoMask
;
326 XVisualInfo desiredVisual
;
328 desiredVisual
.screen
= DefaultScreen (display
);
329 desiredVisual
.depth
= desiredDepth
;
331 desiredMask
= VisualScreenMask
| VisualDepthMask
;
333 if (desiredDepth
== 32)
335 desiredVisual
.c_class
= TrueColor
;
336 desiredVisual
.red_mask
= 0x00FF0000;
337 desiredVisual
.green_mask
= 0x0000FF00;
338 desiredVisual
.blue_mask
= 0x000000FF;
339 desiredVisual
.bits_per_rgb
= 8;
341 desiredMask
|= VisualClassMask
;
342 desiredMask
|= VisualRedMaskMask
;
343 desiredMask
|= VisualGreenMaskMask
;
344 desiredMask
|= VisualBlueMaskMask
;
345 desiredMask
|= VisualBitsPerRGBMask
;
348 XVisualInfo
* xvinfos
= XGetVisualInfo (display
,
355 for (int i
= 0; i
< numVisuals
; i
++)
357 if (xvinfos
[i
].depth
== desiredDepth
)
359 visual
= xvinfos
[i
].visual
;
370 static Visual
* findVisualFormat (const int desiredDepth
, int& matchedDepth
) noexcept
372 Visual
* visual
= nullptr;
374 if (desiredDepth
== 32)
377 if (XSHMHelpers::isShmAvailable())
380 if (XRender::isAvailable())
382 XRenderPictFormat
* pictFormat
= XRender::findPictureFormat();
387 XVisualInfo desiredVisual
;
388 desiredVisual
.screen
= DefaultScreen (display
);
389 desiredVisual
.depth
= 32;
390 desiredVisual
.bits_per_rgb
= 8;
392 XVisualInfo
* xvinfos
= XGetVisualInfo (display
,
393 VisualScreenMask
| VisualDepthMask
| VisualBitsPerRGBMask
,
394 &desiredVisual
, &numVisuals
);
397 for (int i
= 0; i
< numVisuals
; ++i
)
399 XRenderPictFormat
* pictVisualFormat
= XRender::xRenderFindVisualFormat (display
, xvinfos
[i
].visual
);
401 if (pictVisualFormat
!= 0
402 && pictVisualFormat
->type
== PictTypeDirect
403 && pictVisualFormat
->direct
.alphaMask
)
405 visual
= xvinfos
[i
].visual
;
418 visual
= findVisualWithDepth (32);
426 if (visual
== 0 && desiredDepth
>= 24)
428 visual
= findVisualWithDepth (24);
433 if (visual
== 0 && desiredDepth
>= 16)
435 visual
= findVisualWithDepth (16);
444 //==============================================================================
445 class XBitmapImage
: public Image::SharedImage
448 //==============================================================================
449 XBitmapImage (const Image::PixelFormat format_
, const int w
, const int h
,
450 const bool clearImage
, const int imageDepth_
, Visual
* visual
)
451 : Image::SharedImage (format_
, w
, h
),
452 imageDepth (imageDepth_
),
455 jassert (format_
== Image::RGB
|| format_
== Image::ARGB
);
457 pixelStride
= (format_
== Image::RGB
) ? 3 : 4;
458 lineStride
= ((w
* pixelStride
+ 3) & ~3);
465 if ((imageDepth
> 16) && XSHMHelpers::isShmAvailable())
467 zerostruct (segmentInfo
);
469 segmentInfo
.shmid
= -1;
470 segmentInfo
.shmaddr
= (char *) -1;
471 segmentInfo
.readOnly
= False
;
473 xImage
= XShmCreateImage (display
, visual
, imageDepth
, ZPixmap
, 0, &segmentInfo
, w
, h
);
477 if ((segmentInfo
.shmid
= shmget (IPC_PRIVATE
,
478 xImage
->bytes_per_line
* xImage
->height
,
479 IPC_CREAT
| 0777)) >= 0)
481 if (segmentInfo
.shmid
!= -1)
483 segmentInfo
.shmaddr
= (char*) shmat (segmentInfo
.shmid
, 0, 0);
485 if (segmentInfo
.shmaddr
!= (void*) -1)
487 segmentInfo
.readOnly
= False
;
489 xImage
->data
= segmentInfo
.shmaddr
;
490 imageData
= (uint8
*) segmentInfo
.shmaddr
;
492 if (XShmAttach (display
, &segmentInfo
) != 0)
499 shmctl (segmentInfo
.shmid
, IPC_RMID
, 0);
509 imageDataAllocated
.allocate (lineStride
* h
, format_
== Image::ARGB
&& clearImage
);
510 imageData
= imageDataAllocated
;
512 xImage
= (XImage
*) ::calloc (1, sizeof (XImage
));
517 xImage
->format
= ZPixmap
;
518 xImage
->data
= (char*) imageData
;
519 xImage
->byte_order
= ImageByteOrder (display
);
520 xImage
->bitmap_unit
= BitmapUnit (display
);
521 xImage
->bitmap_bit_order
= BitmapBitOrder (display
);
522 xImage
->bitmap_pad
= 32;
523 xImage
->depth
= pixelStride
* 8;
524 xImage
->bytes_per_line
= lineStride
;
525 xImage
->bits_per_pixel
= pixelStride
* 8;
526 xImage
->red_mask
= 0x00FF0000;
527 xImage
->green_mask
= 0x0000FF00;
528 xImage
->blue_mask
= 0x000000FF;
530 if (imageDepth
== 16)
532 const int pixelStride
= 2;
533 const int lineStride
= ((w
* pixelStride
+ 3) & ~3);
535 imageData16Bit
.malloc (lineStride
* h
);
536 xImage
->data
= imageData16Bit
;
537 xImage
->bitmap_pad
= 16;
538 xImage
->depth
= pixelStride
* 8;
539 xImage
->bytes_per_line
= lineStride
;
540 xImage
->bits_per_pixel
= pixelStride
* 8;
541 xImage
->red_mask
= visual
->red_mask
;
542 xImage
->green_mask
= visual
->green_mask
;
543 xImage
->blue_mask
= visual
->blue_mask
;
546 if (! XInitImage (xImage
))
556 XFreeGC (display
, gc
);
561 XShmDetach (display
, &segmentInfo
);
564 XDestroyImage (xImage
);
566 shmdt (segmentInfo
.shmaddr
);
567 shmctl (segmentInfo
.shmid
, IPC_RMID
, 0);
572 xImage
->data
= nullptr;
573 XDestroyImage (xImage
);
577 Image::ImageType
getType() const { return Image::NativeImage
; }
579 LowLevelGraphicsContext
* createLowLevelContext()
581 return new LowLevelGraphicsSoftwareRenderer (Image (this));
584 void initialiseBitmapData (Image::BitmapData
& bitmap
, int x
, int y
, Image::BitmapData::ReadWriteMode
/*mode*/)
586 bitmap
.data
= imageData
+ x
* pixelStride
+ y
* lineStride
;
587 bitmap
.pixelFormat
= format
;
588 bitmap
.lineStride
= lineStride
;
589 bitmap
.pixelStride
= pixelStride
;
598 void blitToWindow (Window window
, int dx
, int dy
, int dw
, int dh
, int sx
, int sy
)
605 gcvalues
.foreground
= None
;
606 gcvalues
.background
= None
;
607 gcvalues
.function
= GXcopy
;
608 gcvalues
.plane_mask
= AllPlanes
;
609 gcvalues
.clip_mask
= None
;
610 gcvalues
.graphics_exposures
= False
;
612 gc
= XCreateGC (display
, window
,
613 GCBackground
| GCForeground
| GCFunction
| GCPlaneMask
| GCClipMask
| GCGraphicsExposures
,
617 if (imageDepth
== 16)
619 const uint32 rMask
= xImage
->red_mask
;
620 const uint32 rShiftL
= jmax (0, getShiftNeeded (rMask
));
621 const uint32 rShiftR
= jmax (0, -getShiftNeeded (rMask
));
622 const uint32 gMask
= xImage
->green_mask
;
623 const uint32 gShiftL
= jmax (0, getShiftNeeded (gMask
));
624 const uint32 gShiftR
= jmax (0, -getShiftNeeded (gMask
));
625 const uint32 bMask
= xImage
->blue_mask
;
626 const uint32 bShiftL
= jmax (0, getShiftNeeded (bMask
));
627 const uint32 bShiftR
= jmax (0, -getShiftNeeded (bMask
));
629 const Image::BitmapData
srcData (Image (this), Image::BitmapData::readOnly
);
631 for (int y
= sy
; y
< sy
+ dh
; ++y
)
633 const uint8
* p
= srcData
.getPixelPointer (sx
, y
);
635 for (int x
= sx
; x
< sx
+ dw
; ++x
)
637 const PixelRGB
* const pixel
= (const PixelRGB
*) p
;
638 p
+= srcData
.pixelStride
;
640 XPutPixel (xImage
, x
, y
,
641 (((((uint32
) pixel
->getRed()) << rShiftL
) >> rShiftR
) & rMask
)
642 | (((((uint32
) pixel
->getGreen()) << gShiftL
) >> gShiftR
) & gMask
)
643 | (((((uint32
) pixel
->getBlue()) << bShiftL
) >> bShiftR
) & bMask
));
648 // blit results to screen.
651 XShmPutImage (display
, (::Drawable
) window
, gc
, xImage
, sx
, sy
, dx
, dy
, dw
, dh
, True
);
654 XPutImage (display
, (::Drawable
) window
, gc
, xImage
, sx
, sy
, dx
, dy
, dw
, dh
);
657 //==============================================================================
660 const int imageDepth
;
661 HeapBlock
<uint8
> imageDataAllocated
;
662 HeapBlock
<char> imageData16Bit
;
663 int pixelStride
, lineStride
;
668 XShmSegmentInfo segmentInfo
;
672 static int getShiftNeeded (const uint32 mask
) noexcept
674 for (int i
= 32; --i
>= 0;)
675 if (((mask
>> i
) & 1) != 0)
682 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XBitmapImage
);
685 namespace PixmapHelpers
687 Pixmap
createColourPixmapFromImage (Display
* display
, const Image
& image
)
691 const int width
= image
.getWidth();
692 const int height
= image
.getHeight();
693 HeapBlock
<uint32
> colour (width
* height
);
696 for (int y
= 0; y
< height
; ++y
)
697 for (int x
= 0; x
< width
; ++x
)
698 colour
[index
++] = image
.getPixelAt (x
, y
).getARGB();
700 XImage
* ximage
= XCreateImage (display
, CopyFromParent
, 24, ZPixmap
,
701 0, reinterpret_cast<char*> (colour
.getData()),
702 width
, height
, 32, 0);
704 Pixmap pixmap
= XCreatePixmap (display
, DefaultRootWindow (display
),
707 GC gc
= XCreateGC (display
, pixmap
, 0, 0);
708 XPutImage (display
, pixmap
, gc
, ximage
, 0, 0, 0, 0, width
, height
);
709 XFreeGC (display
, gc
);
714 Pixmap
createMaskPixmapFromImage (Display
* display
, const Image
& image
)
718 const int width
= image
.getWidth();
719 const int height
= image
.getHeight();
720 const int stride
= (width
+ 7) >> 3;
721 HeapBlock
<char> mask
;
722 mask
.calloc (stride
* height
);
723 const bool msbfirst
= (BitmapBitOrder (display
) == MSBFirst
);
725 for (int y
= 0; y
< height
; ++y
)
727 for (int x
= 0; x
< width
; ++x
)
729 const char bit
= (char) (1 << (msbfirst
? (7 - (x
& 7)) : (x
& 7)));
730 const int offset
= y
* stride
+ (x
>> 3);
732 if (image
.getPixelAt (x
, y
).getAlpha() >= 128)
737 return XCreatePixmapFromBitmapData (display
, DefaultRootWindow (display
),
738 mask
.getData(), width
, height
, 1, 0, 1);
743 //==============================================================================
744 class LinuxComponentPeer
: public ComponentPeer
747 //==============================================================================
748 LinuxComponentPeer (Component
* const component
, const int windowStyleFlags
, Window parentToAddTo
)
749 : ComponentPeer (component
, windowStyleFlags
),
750 windowH (0), parentWindow (0),
751 wx (0), wy (0), ww (0), wh (0),
752 fullScreen (false), mapped (false),
753 visual (0), depth (0)
755 // it's dangerous to create a window on a thread other than the message thread..
756 jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
758 repainter
= new LinuxRepaintManager (this);
760 createWindow (parentToAddTo
);
762 setTitle (component
->getName());
765 ~LinuxComponentPeer()
767 // it's dangerous to delete a window on a thread other than the message thread..
768 jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
777 //==============================================================================
778 void* getNativeHandle() const
780 return (void*) windowH
;
783 static LinuxComponentPeer
* getPeerFor (Window windowHandle
) noexcept
788 if (! XFindContext (display
, (XID
) windowHandle
, windowHandleXContext
, &peer
))
790 if (peer
!= nullptr && ! ComponentPeer::isValidPeer ((LinuxComponentPeer
*) peer
))
794 return (LinuxComponentPeer
*) peer
;
797 void setVisible (bool shouldBeVisible
)
801 XMapWindow (display
, windowH
);
803 XUnmapWindow (display
, windowH
);
806 void setTitle (const String
& title
)
808 XTextProperty nameProperty
;
809 char* strings
[] = { const_cast <char*> (title
.toUTF8().getAddress()) };
812 if (XStringListToTextProperty (strings
, 1, &nameProperty
))
814 XSetWMName (display
, windowH
, &nameProperty
);
815 XSetWMIconName (display
, windowH
, &nameProperty
);
817 XFree (nameProperty
.value
);
821 void setBounds (int x
, int y
, int w
, int h
, bool isNowFullScreen
)
823 fullScreen
= isNowFullScreen
;
827 WeakReference
<Component
> deletionChecker (component
);
836 // Make sure the Window manager does what we want
837 XSizeHints
* hints
= XAllocSizeHints();
838 hints
->flags
= USSize
| USPosition
;
844 if ((getStyleFlags() & (windowHasTitleBar
| windowIsResizable
)) == windowHasTitleBar
)
846 hints
->min_width
= hints
->max_width
= hints
->width
;
847 hints
->min_height
= hints
->max_height
= hints
->height
;
848 hints
->flags
|= PMinSize
| PMaxSize
;
851 XSetWMNormalHints (display
, windowH
, hints
);
854 XMoveResizeWindow (display
, windowH
,
855 wx
- windowBorder
.getLeft(),
856 wy
- windowBorder
.getTop(), ww
, wh
);
858 if (deletionChecker
!= 0)
861 handleMovedOrResized();
866 void setPosition (int x
, int y
) { setBounds (x
, y
, ww
, wh
, false); }
867 void setSize (int w
, int h
) { setBounds (wx
, wy
, w
, h
, false); }
868 const Rectangle
<int> getBounds() const { return Rectangle
<int> (wx
, wy
, ww
, wh
); }
869 const Point
<int> getScreenPosition() const { return Point
<int> (wx
, wy
); }
871 const Point
<int> localToGlobal (const Point
<int>& relativePosition
)
873 return relativePosition
+ getScreenPosition();
876 const Point
<int> globalToLocal (const Point
<int>& screenPosition
)
878 return screenPosition
- getScreenPosition();
881 void setAlpha (float newAlpha
)
886 void setMinimised (bool shouldBeMinimised
)
888 if (shouldBeMinimised
)
890 Window root
= RootWindow (display
, DefaultScreen (display
));
892 XClientMessageEvent clientMsg
;
893 clientMsg
.display
= display
;
894 clientMsg
.window
= windowH
;
895 clientMsg
.type
= ClientMessage
;
896 clientMsg
.format
= 32;
897 clientMsg
.message_type
= Atoms::ChangeState
;
898 clientMsg
.data
.l
[0] = IconicState
;
901 XSendEvent (display
, root
, false, SubstructureRedirectMask
| SubstructureNotifyMask
, (XEvent
*) &clientMsg
);
909 bool isMinimised() const
911 bool minimised
= false;
913 unsigned char* stateProp
;
914 unsigned long nitems
, bytesLeft
;
919 if (XGetWindowProperty (display
, windowH
, Atoms::State
, 0, 64, False
,
920 Atoms::State
, &actualType
, &actualFormat
, &nitems
, &bytesLeft
,
921 &stateProp
) == Success
922 && actualType
== Atoms::State
923 && actualFormat
== 32
926 if (((unsigned long*) stateProp
)[0] == IconicState
)
935 void setFullScreen (const bool shouldBeFullScreen
)
937 Rectangle
<int> r (lastNonFullscreenBounds
); // (get a copy of this before de-minimising)
939 setMinimised (false);
941 if (fullScreen
!= shouldBeFullScreen
)
943 if (shouldBeFullScreen
)
944 r
= Desktop::getInstance().getMainMonitorArea();
947 setBounds (r
.getX(), r
.getY(), r
.getWidth(), r
.getHeight(), shouldBeFullScreen
);
949 getComponent()->repaint();
953 bool isFullScreen() const
958 bool isChildWindowOf (Window possibleParent
) const
960 Window
* windowList
= nullptr;
961 uint32 windowListSize
= 0;
965 if (XQueryTree (display
, windowH
, &root
, &parent
, &windowList
, &windowListSize
) != 0)
970 return parent
== possibleParent
;
976 bool isFrontWindow() const
978 Window
* windowList
= nullptr;
979 uint32 windowListSize
= 0;
983 Window parent
, root
= RootWindow (display
, DefaultScreen (display
));
985 if (XQueryTree (display
, root
, &root
, &parent
, &windowList
, &windowListSize
) != 0)
987 for (int i
= windowListSize
; --i
>= 0;)
989 LinuxComponentPeer
* const peer
= LinuxComponentPeer::getPeerFor (windowList
[i
]);
993 result
= (peer
== this);
1005 bool contains (const Point
<int>& position
, bool trueIfInAChildWindow
) const
1007 if (! (isPositiveAndBelow (position
.getX(), ww
) && isPositiveAndBelow (position
.getY(), wh
)))
1010 for (int i
= Desktop::getInstance().getNumComponents(); --i
>= 0;)
1012 Component
* const c
= Desktop::getInstance().getComponent (i
);
1014 if (c
== getComponent())
1017 if (c
->contains (position
+ Point
<int> (wx
, wy
) - c
->getScreenPosition()))
1021 if (trueIfInAChildWindow
)
1024 ::Window root
, child
;
1025 unsigned int bw
, depth
;
1029 if (! XGetGeometry (display
, (::Drawable
) windowH
, &root
,
1030 &wx
, &wy
, (unsigned int*) &w
, (unsigned int*) &h
,
1036 if (! XTranslateCoordinates (display
, windowH
, windowH
, position
.getX(), position
.getY(), &wx
, &wy
, &child
))
1039 return child
== None
;
1042 const BorderSize
<int> getFrameSize() const
1044 return BorderSize
<int>();
1047 bool setAlwaysOnTop (bool alwaysOnTop
)
1052 void toFront (bool makeActive
)
1061 ev
.xclient
.type
= ClientMessage
;
1062 ev
.xclient
.serial
= 0;
1063 ev
.xclient
.send_event
= True
;
1064 ev
.xclient
.message_type
= Atoms::ActiveWin
;
1065 ev
.xclient
.window
= windowH
;
1066 ev
.xclient
.format
= 32;
1067 ev
.xclient
.data
.l
[0] = 2;
1068 ev
.xclient
.data
.l
[1] = CurrentTime
;
1069 ev
.xclient
.data
.l
[2] = 0;
1070 ev
.xclient
.data
.l
[3] = 0;
1071 ev
.xclient
.data
.l
[4] = 0;
1075 XSendEvent (display
, RootWindow (display
, DefaultScreen (display
)),
1076 False
, SubstructureRedirectMask
| SubstructureNotifyMask
, &ev
);
1078 XWindowAttributes attr
;
1079 XGetWindowAttributes (display
, windowH
, &attr
);
1081 if (component
->isAlwaysOnTop())
1082 XRaiseWindow (display
, windowH
);
1084 XSync (display
, False
);
1087 handleBroughtToFront();
1090 void toBehind (ComponentPeer
* other
)
1092 LinuxComponentPeer
* const otherPeer
= dynamic_cast <LinuxComponentPeer
*> (other
);
1093 jassert (otherPeer
!= nullptr); // wrong type of window?
1095 if (otherPeer
!= nullptr)
1097 setMinimised (false);
1099 Window newStack
[] = { otherPeer
->windowH
, windowH
};
1102 XRestackWindows (display
, newStack
, 2);
1106 bool isFocused() const
1109 Window focusedWindow
= 0;
1111 XGetInputFocus (display
, &focusedWindow
, &revert
);
1113 return focusedWindow
== windowH
;
1118 XWindowAttributes atts
;
1122 && XGetWindowAttributes (display
, windowH
, &atts
)
1123 && atts
.map_state
== IsViewable
1126 XSetInputFocus (display
, windowH
, RevertToParent
, CurrentTime
);
1127 isActiveApplication
= true;
1131 void textInputRequired (const Point
<int>&)
1135 void repaint (const Rectangle
<int>& area
)
1137 repainter
->repaint (area
.getIntersection (getComponent()->getLocalBounds()));
1140 void performAnyPendingRepaintsNow()
1142 repainter
->performAnyPendingRepaintsNow();
1145 void setIcon (const Image
& newIcon
)
1147 const int dataSize
= newIcon
.getWidth() * newIcon
.getHeight() + 2;
1148 HeapBlock
<unsigned long> data (dataSize
);
1151 data
[index
++] = newIcon
.getWidth();
1152 data
[index
++] = newIcon
.getHeight();
1154 for (int y
= 0; y
< newIcon
.getHeight(); ++y
)
1155 for (int x
= 0; x
< newIcon
.getWidth(); ++x
)
1156 data
[index
++] = newIcon
.getPixelAt (x
, y
).getARGB();
1159 XChangeProperty (display
, windowH
,
1160 XInternAtom (display
, "_NET_WM_ICON", False
),
1161 XA_CARDINAL
, 32, PropModeReplace
,
1162 reinterpret_cast<unsigned char*> (data
.getData()), dataSize
);
1164 deleteIconPixmaps();
1166 XWMHints
* wmHints
= XGetWMHints (display
, windowH
);
1169 wmHints
= XAllocWMHints();
1171 wmHints
->flags
|= IconPixmapHint
| IconMaskHint
;
1172 wmHints
->icon_pixmap
= PixmapHelpers::createColourPixmapFromImage (display
, newIcon
);
1173 wmHints
->icon_mask
= PixmapHelpers::createMaskPixmapFromImage (display
, newIcon
);
1175 XSetWMHints (display
, windowH
, wmHints
);
1178 XSync (display
, False
);
1181 void deleteIconPixmaps()
1184 XWMHints
* wmHints
= XGetWMHints (display
, windowH
);
1188 if ((wmHints
->flags
& IconPixmapHint
) != 0)
1190 wmHints
->flags
&= ~IconPixmapHint
;
1191 XFreePixmap (display
, wmHints
->icon_pixmap
);
1194 if ((wmHints
->flags
& IconMaskHint
) != 0)
1196 wmHints
->flags
&= ~IconMaskHint
;
1197 XFreePixmap (display
, wmHints
->icon_mask
);
1200 XSetWMHints (display
, windowH
, wmHints
);
1205 //==============================================================================
1206 void handleWindowMessage (XEvent
* event
)
1208 switch (event
->xany
.type
)
1210 case 2: /* KeyPress */ handleKeyPressEvent ((XKeyEvent
*) &event
->xkey
); break;
1211 case KeyRelease
: handleKeyReleaseEvent ((const XKeyEvent
*) &event
->xkey
); break;
1212 case ButtonPress
: handleButtonPressEvent ((const XButtonPressedEvent
*) &event
->xbutton
); break;
1213 case ButtonRelease
: handleButtonReleaseEvent ((const XButtonReleasedEvent
*) &event
->xbutton
); break;
1214 case MotionNotify
: handleMotionNotifyEvent ((const XPointerMovedEvent
*) &event
->xmotion
); break;
1215 case EnterNotify
: handleEnterNotifyEvent ((const XEnterWindowEvent
*) &event
->xcrossing
); break;
1216 case LeaveNotify
: handleLeaveNotifyEvent ((const XLeaveWindowEvent
*) &event
->xcrossing
); break;
1217 case FocusIn
: handleFocusInEvent(); break;
1218 case FocusOut
: handleFocusOutEvent(); break;
1219 case Expose
: handleExposeEvent ((XExposeEvent
*) &event
->xexpose
); break;
1220 case MappingNotify
: handleMappingNotify ((XMappingEvent
*) &event
->xmapping
); break;
1221 case ClientMessage
: handleClientMessageEvent ((XClientMessageEvent
*) &event
->xclient
, event
); break;
1222 case SelectionNotify
: handleDragAndDropSelection (event
); break;
1223 case ConfigureNotify
: handleConfigureNotifyEvent ((XConfigureEvent
*) &event
->xconfigure
); break;
1224 case ReparentNotify
: handleReparentNotifyEvent(); break;
1225 case GravityNotify
: handleGravityNotify(); break;
1227 case CirculateNotify
:
1230 // Think we can ignore these
1235 handleBroughtToFront();
1242 case SelectionClear
:
1243 case SelectionRequest
:
1250 if (event
->xany
.type
== XShmGetEventBase (display
))
1251 repainter
->notifyPaintCompleted();
1258 void handleKeyPressEvent (XKeyEvent
* const keyEvent
)
1260 char utf8
[64] = { 0 };
1261 juce_wchar unicodeChar
= 0;
1263 bool keyDownChange
= false;
1268 updateKeyStates (keyEvent
->keycode
, true);
1270 const char* oldLocale
= ::setlocale (LC_ALL
, 0);
1271 ::setlocale (LC_ALL
, "");
1272 XLookupString (keyEvent
, utf8
, sizeof (utf8
), &sym
, 0);
1273 ::setlocale (LC_ALL
, oldLocale
);
1275 unicodeChar
= String::fromUTF8 (utf8
, sizeof (utf8
) - 1) [0];
1276 keyCode
= (int) unicodeChar
;
1279 keyCode
= XKeycodeToKeysym (display
, keyEvent
->keycode
, currentModifiers
.isShiftDown() ? 1 : 0);
1281 keyDownChange
= (sym
!= NoSymbol
) && ! updateKeyModifiersFromSym (sym
, true);
1284 const ModifierKeys
oldMods (currentModifiers
);
1285 bool keyPressed
= false;
1287 if ((sym
& 0xff00) == 0xff00)
1289 switch (sym
) // Translate keypad
1291 case XK_KP_Divide
: keyCode
= XK_slash
; break;
1292 case XK_KP_Multiply
: keyCode
= XK_asterisk
; break;
1293 case XK_KP_Subtract
: keyCode
= XK_hyphen
; break;
1294 case XK_KP_Add
: keyCode
= XK_plus
; break;
1295 case XK_KP_Enter
: keyCode
= XK_Return
; break;
1296 case XK_KP_Decimal
: keyCode
= Keys::numLock
? XK_period
: XK_Delete
; break;
1297 case XK_KP_0
: keyCode
= Keys::numLock
? XK_0
: XK_Insert
; break;
1298 case XK_KP_1
: keyCode
= Keys::numLock
? XK_1
: XK_End
; break;
1299 case XK_KP_2
: keyCode
= Keys::numLock
? XK_2
: XK_Down
; break;
1300 case XK_KP_3
: keyCode
= Keys::numLock
? XK_3
: XK_Page_Down
; break;
1301 case XK_KP_4
: keyCode
= Keys::numLock
? XK_4
: XK_Left
; break;
1302 case XK_KP_5
: keyCode
= XK_5
; break;
1303 case XK_KP_6
: keyCode
= Keys::numLock
? XK_6
: XK_Right
; break;
1304 case XK_KP_7
: keyCode
= Keys::numLock
? XK_7
: XK_Home
; break;
1305 case XK_KP_8
: keyCode
= Keys::numLock
? XK_8
: XK_Up
; break;
1306 case XK_KP_9
: keyCode
= Keys::numLock
? XK_9
: XK_Page_Up
; break;
1323 keyCode
= (sym
& 0xff) | Keys::extendedKeyModifier
;
1335 if (sym
>= XK_F1
&& sym
<= XK_F16
)
1338 keyCode
= (sym
& 0xff) | Keys::extendedKeyModifier
;
1344 if (utf8
[0] != 0 || ((sym
& 0xff00) == 0 && sym
>= 8))
1347 if (oldMods
!= currentModifiers
)
1348 handleModifierKeysChange();
1351 handleKeyUpOrDown (true);
1354 handleKeyPress (keyCode
, unicodeChar
);
1357 void handleKeyReleaseEvent (const XKeyEvent
* const keyEvent
)
1359 updateKeyStates (keyEvent
->keycode
, false);
1364 sym
= XKeycodeToKeysym (display
, keyEvent
->keycode
, 0);
1367 const ModifierKeys
oldMods (currentModifiers
);
1368 const bool keyDownChange
= (sym
!= NoSymbol
) && ! updateKeyModifiersFromSym (sym
, false);
1370 if (oldMods
!= currentModifiers
)
1371 handleModifierKeysChange();
1374 handleKeyUpOrDown (false);
1377 void handleButtonPressEvent (const XButtonPressedEvent
* const buttonPressEvent
)
1379 updateKeyModifiers (buttonPressEvent
->state
);
1381 bool buttonMsg
= false;
1382 const int map
= pointerMap
[buttonPressEvent
->button
- Button1
];
1384 if (map
== Keys::WheelUp
|| map
== Keys::WheelDown
)
1386 handleMouseWheel (0, Point
<int> (buttonPressEvent
->x
, buttonPressEvent
->y
),
1387 getEventTime (buttonPressEvent
->time
), 0, map
== Keys::WheelDown
? -84.0f
: 84.0f
);
1389 if (map
== Keys::LeftButton
)
1391 currentModifiers
= currentModifiers
.withFlags (ModifierKeys::leftButtonModifier
);
1394 else if (map
== Keys::RightButton
)
1396 currentModifiers
= currentModifiers
.withFlags (ModifierKeys::rightButtonModifier
);
1399 else if (map
== Keys::MiddleButton
)
1401 currentModifiers
= currentModifiers
.withFlags (ModifierKeys::middleButtonModifier
);
1409 handleMouseEvent (0, Point
<int> (buttonPressEvent
->x
, buttonPressEvent
->y
), currentModifiers
,
1410 getEventTime (buttonPressEvent
->time
));
1413 clearLastMousePos();
1416 void handleButtonReleaseEvent (const XButtonReleasedEvent
* const buttonRelEvent
)
1418 updateKeyModifiers (buttonRelEvent
->state
);
1419 const int map
= pointerMap
[buttonRelEvent
->button
- Button1
];
1421 if (map
== Keys::LeftButton
) currentModifiers
= currentModifiers
.withoutFlags (ModifierKeys::leftButtonModifier
);
1422 else if (map
== Keys::RightButton
) currentModifiers
= currentModifiers
.withoutFlags (ModifierKeys::rightButtonModifier
);
1423 else if (map
== Keys::MiddleButton
) currentModifiers
= currentModifiers
.withoutFlags (ModifierKeys::middleButtonModifier
);
1425 handleMouseEvent (0, Point
<int> (buttonRelEvent
->x
, buttonRelEvent
->y
), currentModifiers
,
1426 getEventTime (buttonRelEvent
->time
));
1428 clearLastMousePos();
1431 void handleMotionNotifyEvent (const XPointerMovedEvent
* const movedEvent
)
1433 updateKeyModifiers (movedEvent
->state
);
1434 const Point
<int> mousePos (movedEvent
->x_root
, movedEvent
->y_root
);
1436 if (lastMousePos
!= mousePos
)
1438 lastMousePos
= mousePos
;
1440 if (parentWindow
!= nullptr && (styleFlags
& windowHasTitleBar
) == 0)
1442 Window wRoot
= 0, wParent
= 0;
1446 unsigned int numChildren
;
1447 Window
* wChild
= nullptr;
1448 XQueryTree (display
, windowH
, &wRoot
, &wParent
, &wChild
, &numChildren
);
1452 && wParent
!= windowH
1453 && wParent
!= wRoot
)
1455 parentWindow
= wParent
;
1464 handleMouseEvent (0, mousePos
- getScreenPosition(), currentModifiers
, getEventTime (movedEvent
->time
));
1468 void handleEnterNotifyEvent (const XEnterWindowEvent
* const enterEvent
)
1470 clearLastMousePos();
1472 if (! currentModifiers
.isAnyMouseButtonDown())
1474 updateKeyModifiers (enterEvent
->state
);
1475 handleMouseEvent (0, Point
<int> (enterEvent
->x
, enterEvent
->y
), currentModifiers
, getEventTime (enterEvent
->time
));
1479 void handleLeaveNotifyEvent (const XLeaveWindowEvent
* const leaveEvent
)
1481 // Suppress the normal leave if we've got a pointer grab, or if
1482 // it's a bogus one caused by clicking a mouse button when running
1483 // in a Window manager
1484 if (((! currentModifiers
.isAnyMouseButtonDown()) && leaveEvent
->mode
== NotifyNormal
)
1485 || leaveEvent
->mode
== NotifyUngrab
)
1487 updateKeyModifiers (leaveEvent
->state
);
1488 handleMouseEvent (0, Point
<int> (leaveEvent
->x
, leaveEvent
->y
), currentModifiers
, getEventTime (leaveEvent
->time
));
1492 void handleFocusInEvent()
1494 isActiveApplication
= true;
1499 void handleFocusOutEvent()
1501 isActiveApplication
= false;
1506 void handleExposeEvent (XExposeEvent
* exposeEvent
)
1508 // Batch together all pending expose events
1512 if (exposeEvent
->window
!= windowH
)
1515 XTranslateCoordinates (display
, exposeEvent
->window
, windowH
,
1516 exposeEvent
->x
, exposeEvent
->y
, &exposeEvent
->x
, &exposeEvent
->y
,
1520 repaint (Rectangle
<int> (exposeEvent
->x
, exposeEvent
->y
,
1521 exposeEvent
->width
, exposeEvent
->height
));
1523 while (XEventsQueued (display
, QueuedAfterFlush
) > 0)
1525 XPeekEvent (display
, (XEvent
*) &nextEvent
);
1526 if (nextEvent
.type
!= Expose
|| nextEvent
.xany
.window
!= exposeEvent
->window
)
1529 XNextEvent (display
, (XEvent
*) &nextEvent
);
1530 XExposeEvent
* nextExposeEvent
= (XExposeEvent
*) &nextEvent
.xexpose
;
1531 repaint (Rectangle
<int> (nextExposeEvent
->x
, nextExposeEvent
->y
,
1532 nextExposeEvent
->width
, nextExposeEvent
->height
));
1536 void handleConfigureNotifyEvent (XConfigureEvent
* const confEvent
)
1540 handleMovedOrResized();
1542 // if the native title bar is dragged, need to tell any active menus, etc.
1543 if ((styleFlags
& windowHasTitleBar
) != 0
1544 && component
->isCurrentlyBlockedByAnotherModalComponent())
1546 Component
* const currentModalComp
= Component::getCurrentlyModalComponent();
1548 if (currentModalComp
!= 0)
1549 currentModalComp
->inputAttemptWhenModal();
1552 if (confEvent
->window
== windowH
1553 && confEvent
->above
!= 0
1556 handleBroughtToFront();
1560 void handleReparentNotifyEvent()
1564 Window
* wChild
= nullptr;
1565 unsigned int numChildren
;
1569 XQueryTree (display
, windowH
, &wRoot
, &parentWindow
, &wChild
, &numChildren
);
1572 if (parentWindow
== windowH
|| parentWindow
== wRoot
)
1575 handleGravityNotify();
1578 void handleGravityNotify()
1582 handleMovedOrResized();
1585 void handleMappingNotify (XMappingEvent
* const mappingEvent
)
1587 if (mappingEvent
->request
!= MappingPointer
)
1589 // Deal with modifier/keyboard mapping
1591 XRefreshKeyboardMapping (mappingEvent
);
1592 updateModifierMappings();
1596 void handleClientMessageEvent (XClientMessageEvent
* const clientMsg
, XEvent
* event
)
1598 if (clientMsg
->message_type
== Atoms::Protocols
&& clientMsg
->format
== 32)
1600 const Atom atom
= (Atom
) clientMsg
->data
.l
[0];
1602 if (atom
== Atoms::ProtocolList
[Atoms::PING
])
1604 Window root
= RootWindow (display
, DefaultScreen (display
));
1606 clientMsg
->window
= root
;
1608 XSendEvent (display
, root
, False
, NoEventMask
, event
);
1611 else if (atom
== Atoms::ProtocolList
[Atoms::TAKE_FOCUS
])
1613 XWindowAttributes atts
;
1616 if (clientMsg
->window
!= 0
1617 && XGetWindowAttributes (display
, clientMsg
->window
, &atts
))
1619 if (atts
.map_state
== IsViewable
)
1620 XSetInputFocus (display
, clientMsg
->window
, RevertToParent
, clientMsg
->data
.l
[1]);
1623 else if (atom
== Atoms::ProtocolList
[Atoms::DELETE_WINDOW
])
1625 handleUserClosingWindow();
1628 else if (clientMsg
->message_type
== Atoms::XdndEnter
)
1630 handleDragAndDropEnter (clientMsg
);
1632 else if (clientMsg
->message_type
== Atoms::XdndLeave
)
1636 else if (clientMsg
->message_type
== Atoms::XdndPosition
)
1638 handleDragAndDropPosition (clientMsg
);
1640 else if (clientMsg
->message_type
== Atoms::XdndDrop
)
1642 handleDragAndDropDrop (clientMsg
);
1644 else if (clientMsg
->message_type
== Atoms::XdndStatus
)
1646 handleDragAndDropStatus (clientMsg
);
1648 else if (clientMsg
->message_type
== Atoms::XdndFinished
)
1654 //==============================================================================
1655 void showMouseCursor (Cursor cursor
) noexcept
1658 XDefineCursor (display
, windowH
, cursor
);
1661 //==============================================================================
1662 void setTaskBarIcon (const Image
& image
)
1665 taskbarImage
= image
;
1667 Screen
* const screen
= XDefaultScreenOfDisplay (display
);
1668 const int screenNumber
= XScreenNumberOfScreen (screen
);
1670 String
screenAtom ("_NET_SYSTEM_TRAY_S");
1671 screenAtom
<< screenNumber
;
1672 Atom selectionAtom
= XInternAtom (display
, screenAtom
.toUTF8(), false);
1674 XGrabServer (display
);
1675 Window managerWin
= XGetSelectionOwner (display
, selectionAtom
);
1677 if (managerWin
!= None
)
1678 XSelectInput (display
, managerWin
, StructureNotifyMask
);
1680 XUngrabServer (display
);
1683 if (managerWin
!= None
)
1686 ev
.xclient
.type
= ClientMessage
;
1687 ev
.xclient
.window
= managerWin
;
1688 ev
.xclient
.message_type
= XInternAtom (display
, "_NET_SYSTEM_TRAY_OPCODE", False
);
1689 ev
.xclient
.format
= 32;
1690 ev
.xclient
.data
.l
[0] = CurrentTime
;
1691 ev
.xclient
.data
.l
[1] = 0 /*SYSTEM_TRAY_REQUEST_DOCK*/;
1692 ev
.xclient
.data
.l
[2] = windowH
;
1693 ev
.xclient
.data
.l
[3] = 0;
1694 ev
.xclient
.data
.l
[4] = 0;
1696 XSendEvent (display
, managerWin
, False
, NoEventMask
, &ev
);
1697 XSync (display
, False
);
1700 // For older KDE's ...
1702 Atom trayAtom
= XInternAtom (display
, "KWM_DOCKWINDOW", false);
1703 XChangeProperty (display
, windowH
, trayAtom
, trayAtom
, 32, PropModeReplace
, (unsigned char*) &atomData
, 1);
1705 // For more recent KDE's...
1706 trayAtom
= XInternAtom (display
, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", false);
1707 XChangeProperty (display
, windowH
, trayAtom
, XA_WINDOW
, 32, PropModeReplace
, (unsigned char*) &windowH
, 1);
1709 // a minimum size must be specified for GNOME and Xfce, otherwise the icon is displayed with a width of 1
1710 XSizeHints
* hints
= XAllocSizeHints();
1711 hints
->flags
= PMinSize
;
1712 hints
->min_width
= 22;
1713 hints
->min_height
= 22;
1714 XSetWMNormalHints (display
, windowH
, hints
);
1718 const Image
& getTaskbarIcon() const noexcept
{ return taskbarImage
; }
1720 //==============================================================================
1723 static ModifierKeys currentModifiers
;
1724 static bool isActiveApplication
;
1727 //==============================================================================
1728 class LinuxRepaintManager
: public Timer
1731 LinuxRepaintManager (LinuxComponentPeer
* const peer_
)
1733 lastTimeImageUsed (0)
1736 shmCompletedDrawing
= true;
1738 useARGBImagesForRendering
= XSHMHelpers::isShmAvailable();
1740 if (useARGBImagesForRendering
)
1743 XShmSegmentInfo segmentinfo
;
1745 XImage
* const testImage
1746 = XShmCreateImage (display
, DefaultVisual (display
, DefaultScreen (display
)),
1747 24, ZPixmap
, 0, &segmentinfo
, 64, 64);
1749 useARGBImagesForRendering
= (testImage
->bits_per_pixel
== 32);
1750 XDestroyImage (testImage
);
1755 void timerCallback()
1758 if (! shmCompletedDrawing
)
1761 if (! regionsNeedingRepaint
.isEmpty())
1764 performAnyPendingRepaintsNow();
1766 else if (Time::getApproximateMillisecondCounter() > lastTimeImageUsed
+ 3000)
1769 image
= Image::null
;
1773 void repaint (const Rectangle
<int>& area
)
1775 if (! isTimerRunning())
1776 startTimer (repaintTimerPeriod
);
1778 regionsNeedingRepaint
.add (area
);
1781 void performAnyPendingRepaintsNow()
1784 if (! shmCompletedDrawing
)
1786 startTimer (repaintTimerPeriod
);
1791 peer
->clearMaskedRegion();
1793 RectangleList
originalRepaintRegion (regionsNeedingRepaint
);
1794 regionsNeedingRepaint
.clear();
1795 const Rectangle
<int> totalArea (originalRepaintRegion
.getBounds());
1797 if (! totalArea
.isEmpty())
1799 if (image
.isNull() || image
.getWidth() < totalArea
.getWidth()
1800 || image
.getHeight() < totalArea
.getHeight())
1803 image
= Image (new XBitmapImage (useARGBImagesForRendering
? Image::ARGB
1806 image
= Image (new XBitmapImage (Image::RGB
,
1808 (totalArea
.getWidth() + 31) & ~31,
1809 (totalArea
.getHeight() + 31) & ~31,
1810 false, peer
->depth
, peer
->visual
));
1813 startTimer (repaintTimerPeriod
);
1815 RectangleList
adjustedList (originalRepaintRegion
);
1816 adjustedList
.offsetAll (-totalArea
.getX(), -totalArea
.getY());
1817 LowLevelGraphicsSoftwareRenderer
context (image
, -totalArea
.getX(), -totalArea
.getY(), adjustedList
);
1819 if (peer
->depth
== 32)
1821 RectangleList::Iterator
i (originalRepaintRegion
);
1824 image
.clear (*i
.getRectangle() - totalArea
.getPosition());
1827 peer
->handlePaint (context
);
1829 if (! peer
->maskedRegion
.isEmpty())
1830 originalRepaintRegion
.subtract (peer
->maskedRegion
);
1832 for (RectangleList::Iterator
i (originalRepaintRegion
); i
.next();)
1835 shmCompletedDrawing
= false;
1837 const Rectangle
<int>& r
= *i
.getRectangle();
1839 static_cast<XBitmapImage
*> (image
.getSharedImage())
1840 ->blitToWindow (peer
->windowH
,
1841 r
.getX(), r
.getY(), r
.getWidth(), r
.getHeight(),
1842 r
.getX() - totalArea
.getX(), r
.getY() - totalArea
.getY());
1846 lastTimeImageUsed
= Time::getApproximateMillisecondCounter();
1847 startTimer (repaintTimerPeriod
);
1851 void notifyPaintCompleted() { shmCompletedDrawing
= true; }
1855 enum { repaintTimerPeriod
= 1000 / 100 };
1857 LinuxComponentPeer
* const peer
;
1859 uint32 lastTimeImageUsed
;
1860 RectangleList regionsNeedingRepaint
;
1863 bool useARGBImagesForRendering
, shmCompletedDrawing
;
1865 JUCE_DECLARE_NON_COPYABLE (LinuxRepaintManager
);
1868 ScopedPointer
<LinuxRepaintManager
> repainter
;
1870 friend class LinuxRepaintManager
;
1871 Window windowH
, parentWindow
;
1874 bool fullScreen
, mapped
;
1877 BorderSize
<int> windowBorder
;
1881 unsigned long flags
;
1882 unsigned long functions
;
1883 unsigned long decorations
;
1885 unsigned long status
;
1888 static void updateKeyStates (const int keycode
, const bool press
) noexcept
1890 const int keybyte
= keycode
>> 3;
1891 const int keybit
= (1 << (keycode
& 7));
1894 Keys::keyStates
[keybyte
] |= keybit
;
1896 Keys::keyStates
[keybyte
] &= ~keybit
;
1899 static void updateKeyModifiers (const int status
) noexcept
1903 if ((status
& ShiftMask
) != 0) keyMods
|= ModifierKeys::shiftModifier
;
1904 if ((status
& ControlMask
) != 0) keyMods
|= ModifierKeys::ctrlModifier
;
1905 if ((status
& Keys::AltMask
) != 0) keyMods
|= ModifierKeys::altModifier
;
1907 currentModifiers
= currentModifiers
.withOnlyMouseButtons().withFlags (keyMods
);
1909 Keys::numLock
= ((status
& Keys::NumLockMask
) != 0);
1910 Keys::capsLock
= ((status
& LockMask
) != 0);
1913 static bool updateKeyModifiersFromSym (KeySym sym
, const bool press
) noexcept
1916 bool isModifier
= true;
1922 modifier
= ModifierKeys::shiftModifier
;
1927 modifier
= ModifierKeys::ctrlModifier
;
1932 modifier
= ModifierKeys::altModifier
;
1937 Keys::numLock
= ! Keys::numLock
;
1943 Keys::capsLock
= ! Keys::capsLock
;
1947 case XK_Scroll_Lock
:
1958 currentModifiers
= currentModifiers
.withFlags (modifier
);
1960 currentModifiers
= currentModifiers
.withoutFlags (modifier
);
1966 // Alt and Num lock are not defined by standard X
1967 // modifier constants: check what they're mapped to
1968 static void updateModifierMappings() noexcept
1971 const int altLeftCode
= XKeysymToKeycode (display
, XK_Alt_L
);
1972 const int numLockCode
= XKeysymToKeycode (display
, XK_Num_Lock
);
1975 Keys::NumLockMask
= 0;
1977 XModifierKeymap
* mapping
= XGetModifierMapping (display
);
1981 for (int i
= 0; i
< 8; i
++)
1983 if (mapping
->modifiermap
[i
<< 1] == altLeftCode
)
1984 Keys::AltMask
= 1 << i
;
1985 else if (mapping
->modifiermap
[i
<< 1] == numLockCode
)
1986 Keys::NumLockMask
= 1 << i
;
1989 XFreeModifiermap (mapping
);
1993 //==============================================================================
1994 void removeWindowDecorations (Window wndH
)
1996 Atom hints
= XInternAtom (display
, "_MOTIF_WM_HINTS", True
);
2000 MotifWmHints motifHints
= { 0 };
2001 motifHints
.flags
= 2; /* MWM_HINTS_DECORATIONS */
2002 motifHints
.decorations
= 0;
2005 XChangeProperty (display
, wndH
, hints
, hints
, 32, PropModeReplace
,
2006 (unsigned char*) &motifHints
, 4);
2009 hints
= XInternAtom (display
, "_WIN_HINTS", True
);
2013 long gnomeHints
= 0;
2016 XChangeProperty (display
, wndH
, hints
, hints
, 32, PropModeReplace
,
2017 (unsigned char*) &gnomeHints
, 1);
2020 hints
= XInternAtom (display
, "KWM_WIN_DECORATION", True
);
2024 long kwmHints
= 2; /*KDE_tinyDecoration*/
2027 XChangeProperty (display
, wndH
, hints
, hints
, 32, PropModeReplace
,
2028 (unsigned char*) &kwmHints
, 1);
2032 void addWindowButtons (Window wndH
)
2035 Atom hints
= XInternAtom (display
, "_MOTIF_WM_HINTS", True
);
2039 MotifWmHints motifHints
= { 0 };
2040 motifHints
.flags
= 1 | 2; /* MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS */
2041 motifHints
.decorations
= 2 /* MWM_DECOR_BORDER */ | 8 /* MWM_DECOR_TITLE */ | 16; /* MWM_DECOR_MENU */
2043 motifHints
.functions
= 4 /* MWM_FUNC_MOVE */;
2045 if ((styleFlags
& windowHasCloseButton
) != 0)
2046 motifHints
.functions
|= 32; /* MWM_FUNC_CLOSE */
2048 if ((styleFlags
& windowHasMinimiseButton
) != 0)
2050 motifHints
.functions
|= 8; /* MWM_FUNC_MINIMIZE */
2051 motifHints
.decorations
|= 0x20; /* MWM_DECOR_MINIMIZE */
2054 if ((styleFlags
& windowHasMaximiseButton
) != 0)
2056 motifHints
.functions
|= 0x10; /* MWM_FUNC_MAXIMIZE */
2057 motifHints
.decorations
|= 0x40; /* MWM_DECOR_MAXIMIZE */
2060 if ((styleFlags
& windowIsResizable
) != 0)
2062 motifHints
.functions
|= 2; /* MWM_FUNC_RESIZE */
2063 motifHints
.decorations
|= 0x4; /* MWM_DECOR_RESIZEH */
2066 XChangeProperty (display
, wndH
, hints
, hints
, 32, 0, (unsigned char*) &motifHints
, 5);
2069 hints
= XInternAtom (display
, "_NET_WM_ALLOWED_ACTIONS", True
);
2076 if ((styleFlags
& windowIsResizable
) != 0)
2077 netHints
[num
++] = XInternAtom (display
, "_NET_WM_ACTION_RESIZE", True
);
2079 if ((styleFlags
& windowHasMaximiseButton
) != 0)
2080 netHints
[num
++] = XInternAtom (display
, "_NET_WM_ACTION_FULLSCREEN", True
);
2082 if ((styleFlags
& windowHasMinimiseButton
) != 0)
2083 netHints
[num
++] = XInternAtom (display
, "_NET_WM_ACTION_MINIMIZE", True
);
2085 if ((styleFlags
& windowHasCloseButton
) != 0)
2086 netHints
[num
++] = XInternAtom (display
, "_NET_WM_ACTION_CLOSE", True
);
2088 XChangeProperty (display
, wndH
, hints
, XA_ATOM
, 32, PropModeReplace
, (unsigned char*) &netHints
, num
);
2092 void setWindowType()
2097 if ((styleFlags
& windowIsTemporary
) != 0
2098 || ((styleFlags
& windowHasDropShadow
) == 0 && Desktop::canUseSemiTransparentWindows()))
2099 netHints
[numHints
++] = XInternAtom (display
, "_NET_WM_WINDOW_TYPE_COMBO", True
);
2101 netHints
[numHints
++] = XInternAtom (display
, "_NET_WM_WINDOW_TYPE_NORMAL", True
);
2103 netHints
[numHints
++] = XInternAtom (display
, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True
);
2105 XChangeProperty (display
, windowH
, Atoms::WindowType
, XA_ATOM
, 32, PropModeReplace
,
2106 (unsigned char*) &netHints
, numHints
);
2110 if ((styleFlags
& windowAppearsOnTaskbar
) == 0)
2111 netHints
[numHints
++] = XInternAtom (display
, "_NET_WM_STATE_SKIP_TASKBAR", True
);
2113 if (component
->isAlwaysOnTop())
2114 netHints
[numHints
++] = XInternAtom (display
, "_NET_WM_STATE_ABOVE", True
);
2117 XChangeProperty (display
, windowH
, Atoms::WindowState
, XA_ATOM
, 32, PropModeReplace
,
2118 (unsigned char*) &netHints
, numHints
);
2121 void createWindow (Window parentToAddTo
)
2124 Atoms::initialiseAtoms();
2127 // Get defaults for various properties
2128 const int screen
= DefaultScreen (display
);
2129 Window root
= RootWindow (display
, screen
);
2131 // Try to obtain a 32-bit visual or fallback to 24 or 16
2132 visual
= Visuals::findVisualFormat ((styleFlags
& windowIsSemiTransparent
) ? 32 : 24, depth
);
2136 Logger::outputDebugString ("ERROR: System doesn't support 32, 24 or 16 bit RGB display.\n");
2137 Process::terminate();
2140 // Create and install a colormap suitable fr our visual
2141 Colormap colormap
= XCreateColormap (display
, root
, visual
, AllocNone
);
2142 XInstallColormap (display
, colormap
);
2144 // Set up the window attributes
2145 XSetWindowAttributes swa
;
2146 swa
.border_pixel
= 0;
2147 swa
.background_pixmap
= None
;
2148 swa
.colormap
= colormap
;
2149 swa
.event_mask
= getAllEventsMask();
2151 windowH
= XCreateWindow (display
, parentToAddTo
!= 0 ? parentToAddTo
: root
,
2153 0, depth
, InputOutput
, visual
,
2154 CWBorderPixel
| CWColormap
| CWBackPixmap
| CWEventMask
,
2157 XGrabButton (display
, AnyButton
, AnyModifier
, windowH
, False
,
2158 ButtonPressMask
| ButtonReleaseMask
| EnterWindowMask
| LeaveWindowMask
| PointerMotionMask
,
2159 GrabModeAsync
, GrabModeAsync
, None
, None
);
2161 // Set the window context to identify the window handle object
2162 if (XSaveContext (display
, (XID
) windowH
, windowHandleXContext
, (XPointer
) this))
2166 Logger::outputDebugString ("Failed to create context information for window.\n");
2167 XDestroyWindow (display
, windowH
);
2172 // Set window manager hints
2173 XWMHints
* wmHints
= XAllocWMHints();
2174 wmHints
->flags
= InputHint
| StateHint
;
2175 wmHints
->input
= True
; // Locally active input model
2176 wmHints
->initial_state
= NormalState
;
2177 XSetWMHints (display
, windowH
, wmHints
);
2180 // Set the window type
2183 // Define decoration
2184 if ((styleFlags
& windowHasTitleBar
) == 0)
2185 removeWindowDecorations (windowH
);
2187 addWindowButtons (windowH
);
2189 setTitle (getComponent()->getName());
2191 // Associate the PID, allowing to be shut down when something goes wrong
2192 unsigned long pid
= getpid();
2193 XChangeProperty (display
, windowH
, Atoms::Pid
, XA_CARDINAL
, 32, PropModeReplace
,
2194 (unsigned char*) &pid
, 1);
2196 // Set window manager protocols
2197 XChangeProperty (display
, windowH
, Atoms::Protocols
, XA_ATOM
, 32, PropModeReplace
,
2198 (unsigned char*) Atoms::ProtocolList
, 2);
2200 // Set drag and drop flags
2201 XChangeProperty (display
, windowH
, Atoms::XdndTypeList
, XA_ATOM
, 32, PropModeReplace
,
2202 (const unsigned char*) Atoms::allowedMimeTypes
, numElementsInArray (Atoms::allowedMimeTypes
));
2204 XChangeProperty (display
, windowH
, Atoms::XdndActionList
, XA_ATOM
, 32, PropModeReplace
,
2205 (const unsigned char*) Atoms::allowedActions
, numElementsInArray (Atoms::allowedActions
));
2207 XChangeProperty (display
, windowH
, Atoms::XdndActionDescription
, XA_STRING
, 8, PropModeReplace
,
2208 (const unsigned char*) "", 0);
2210 unsigned long dndVersion
= Atoms::DndVersion
;
2211 XChangeProperty (display
, windowH
, Atoms::XdndAware
, XA_ATOM
, 32, PropModeReplace
,
2212 (const unsigned char*) &dndVersion
, 1);
2214 // Initialise the pointer and keyboard mapping
2215 // This is not the same as the logical pointer mapping the X server uses:
2216 // we don't mess with this.
2217 static bool mappingInitialised
= false;
2219 if (! mappingInitialised
)
2221 mappingInitialised
= true;
2223 const int numButtons
= XGetPointerMapping (display
, 0, 0);
2225 if (numButtons
== 2)
2227 pointerMap
[0] = Keys::LeftButton
;
2228 pointerMap
[1] = Keys::RightButton
;
2229 pointerMap
[2] = pointerMap
[3] = pointerMap
[4] = Keys::NoButton
;
2231 else if (numButtons
>= 3)
2233 pointerMap
[0] = Keys::LeftButton
;
2234 pointerMap
[1] = Keys::MiddleButton
;
2235 pointerMap
[2] = Keys::RightButton
;
2237 if (numButtons
>= 5)
2239 pointerMap
[3] = Keys::WheelUp
;
2240 pointerMap
[4] = Keys::WheelDown
;
2244 updateModifierMappings();
2248 void destroyWindow()
2252 XPointer handlePointer
;
2253 if (! XFindContext (display
, (XID
) windowH
, windowHandleXContext
, &handlePointer
))
2254 XDeleteContext (display
, (XID
) windowH
, windowHandleXContext
);
2256 XDestroyWindow (display
, windowH
);
2258 // Wait for it to complete and then remove any events for this
2259 // window from the event queue.
2260 XSync (display
, false);
2263 while (XCheckWindowEvent (display
, windowH
, getAllEventsMask(), &event
) == True
)
2267 static int getAllEventsMask() noexcept
2269 return NoEventMask
| KeyPressMask
| KeyReleaseMask
| ButtonPressMask
| ButtonReleaseMask
2270 | EnterWindowMask
| LeaveWindowMask
| PointerMotionMask
| KeymapStateMask
2271 | ExposureMask
| StructureNotifyMask
| FocusChangeMask
;
2274 static int64
getEventTime (::Time t
)
2276 static int64 eventTimeOffset
= 0x12345678;
2277 const int64 thisMessageTime
= t
;
2279 if (eventTimeOffset
== 0x12345678)
2280 eventTimeOffset
= Time::currentTimeMillis() - thisMessageTime
;
2282 return eventTimeOffset
+ thisMessageTime
;
2285 void updateBorderSize()
2287 if ((styleFlags
& windowHasTitleBar
) == 0)
2289 windowBorder
= BorderSize
<int> (0);
2291 else if (windowBorder
.getTopAndBottom() == 0 && windowBorder
.getLeftAndRight() == 0)
2294 Atom hints
= XInternAtom (display
, "_NET_FRAME_EXTENTS", True
);
2298 unsigned char* data
= nullptr;
2299 unsigned long nitems
, bytesLeft
;
2303 if (XGetWindowProperty (display
, windowH
, hints
, 0, 4, False
,
2304 XA_CARDINAL
, &actualType
, &actualFormat
, &nitems
, &bytesLeft
,
2307 const unsigned long* const sizes
= (const unsigned long*) data
;
2309 if (actualFormat
== 32)
2310 windowBorder
= BorderSize
<int> ((int) sizes
[2], (int) sizes
[0],
2311 (int) sizes
[3], (int) sizes
[1]);
2321 jassert (windowH
!= 0);
2325 unsigned int bw
, depth
;
2328 if (! XGetGeometry (display
, (::Drawable
) windowH
, &root
,
2329 &wx
, &wy
, (unsigned int*) &ww
, (unsigned int*) &wh
,
2332 wx
= wy
= ww
= wh
= 0;
2334 else if (! XTranslateCoordinates (display
, windowH
, root
, 0, 0, &wx
, &wy
, &child
))
2341 //==============================================================================
2342 void resetDragAndDrop()
2344 dragAndDropFiles
.clear();
2345 lastDropPos
= Point
<int> (-1, -1);
2346 dragAndDropCurrentMimeType
= 0;
2347 dragAndDropSourceWindow
= 0;
2348 srcMimeTypeAtomList
.clear();
2351 void sendDragAndDropMessage (XClientMessageEvent
& msg
)
2353 msg
.type
= ClientMessage
;
2354 msg
.display
= display
;
2355 msg
.window
= dragAndDropSourceWindow
;
2357 msg
.data
.l
[0] = windowH
;
2360 XSendEvent (display
, dragAndDropSourceWindow
, False
, 0, (XEvent
*) &msg
);
2363 void sendDragAndDropStatus (const bool acceptDrop
, Atom dropAction
)
2365 XClientMessageEvent msg
= { 0 };
2366 msg
.message_type
= Atoms::XdndStatus
;
2367 msg
.data
.l
[1] = (acceptDrop
? 1 : 0) | 2; // 2 indicates that we want to receive position messages
2368 msg
.data
.l
[4] = dropAction
;
2370 sendDragAndDropMessage (msg
);
2373 void sendDragAndDropLeave()
2375 XClientMessageEvent msg
= { 0 };
2376 msg
.message_type
= Atoms::XdndLeave
;
2377 sendDragAndDropMessage (msg
);
2380 void sendDragAndDropFinish()
2382 XClientMessageEvent msg
= { 0 };
2383 msg
.message_type
= Atoms::XdndFinished
;
2384 sendDragAndDropMessage (msg
);
2387 void handleDragAndDropStatus (const XClientMessageEvent
* const clientMsg
)
2389 if ((clientMsg
->data
.l
[1] & 1) == 0)
2391 sendDragAndDropLeave();
2393 if (dragAndDropFiles
.size() > 0)
2394 handleFileDragExit (dragAndDropFiles
);
2396 dragAndDropFiles
.clear();
2400 void handleDragAndDropPosition (const XClientMessageEvent
* const clientMsg
)
2402 if (dragAndDropSourceWindow
== 0)
2405 dragAndDropSourceWindow
= clientMsg
->data
.l
[0];
2407 Point
<int> dropPos ((int) clientMsg
->data
.l
[2] >> 16,
2408 (int) clientMsg
->data
.l
[2] & 0xffff);
2409 dropPos
-= getScreenPosition();
2411 if (lastDropPos
!= dropPos
)
2413 lastDropPos
= dropPos
;
2414 dragAndDropTimestamp
= clientMsg
->data
.l
[3];
2416 Atom targetAction
= Atoms::XdndActionCopy
;
2418 for (int i
= numElementsInArray (Atoms::allowedActions
); --i
>= 0;)
2420 if ((Atom
) clientMsg
->data
.l
[4] == Atoms::allowedActions
[i
])
2422 targetAction
= Atoms::allowedActions
[i
];
2427 sendDragAndDropStatus (true, targetAction
);
2429 if (dragAndDropFiles
.size() == 0)
2430 updateDraggedFileList (clientMsg
);
2432 if (dragAndDropFiles
.size() > 0)
2433 handleFileDragMove (dragAndDropFiles
, dropPos
);
2437 void handleDragAndDropDrop (const XClientMessageEvent
* const clientMsg
)
2439 if (dragAndDropFiles
.size() == 0)
2440 updateDraggedFileList (clientMsg
);
2442 const StringArray
files (dragAndDropFiles
);
2443 const Point
<int> lastPos (lastDropPos
);
2445 sendDragAndDropFinish();
2448 if (files
.size() > 0)
2449 handleFileDragDrop (files
, lastPos
);
2452 void handleDragAndDropEnter (const XClientMessageEvent
* const clientMsg
)
2454 dragAndDropFiles
.clear();
2455 srcMimeTypeAtomList
.clear();
2457 dragAndDropCurrentMimeType
= 0;
2458 const unsigned long dndCurrentVersion
= static_cast <unsigned long> (clientMsg
->data
.l
[1] & 0xff000000) >> 24;
2460 if (dndCurrentVersion
< 3 || dndCurrentVersion
> Atoms::DndVersion
)
2462 dragAndDropSourceWindow
= 0;
2466 dragAndDropSourceWindow
= clientMsg
->data
.l
[0];
2468 if ((clientMsg
->data
.l
[1] & 1) != 0)
2472 unsigned long count
= 0, remaining
= 0;
2473 unsigned char* data
= 0;
2476 XGetWindowProperty (display
, dragAndDropSourceWindow
, Atoms::XdndTypeList
,
2477 0, 0x8000000L
, False
, XA_ATOM
, &actual
, &format
,
2478 &count
, &remaining
, &data
);
2482 if (actual
== XA_ATOM
&& format
== 32 && count
!= 0)
2484 const unsigned long* const types
= (const unsigned long*) data
;
2486 for (unsigned int i
= 0; i
< count
; ++i
)
2487 if (types
[i
] != None
)
2488 srcMimeTypeAtomList
.add (types
[i
]);
2495 if (srcMimeTypeAtomList
.size() == 0)
2497 for (int i
= 2; i
< 5; ++i
)
2498 if (clientMsg
->data
.l
[i
] != None
)
2499 srcMimeTypeAtomList
.add (clientMsg
->data
.l
[i
]);
2501 if (srcMimeTypeAtomList
.size() == 0)
2503 dragAndDropSourceWindow
= 0;
2508 for (int i
= 0; i
< srcMimeTypeAtomList
.size() && dragAndDropCurrentMimeType
== 0; ++i
)
2509 for (int j
= 0; j
< numElementsInArray (Atoms::allowedMimeTypes
); ++j
)
2510 if (srcMimeTypeAtomList
[i
] == Atoms::allowedMimeTypes
[j
])
2511 dragAndDropCurrentMimeType
= Atoms::allowedMimeTypes
[j
];
2513 handleDragAndDropPosition (clientMsg
);
2516 void handleDragAndDropSelection (const XEvent
* const evt
)
2518 dragAndDropFiles
.clear();
2520 if (evt
->xselection
.property
!= 0)
2525 MemoryBlock dropData
;
2531 unsigned long count
= 0, remaining
= 0;
2535 if (XGetWindowProperty (display
, evt
->xany
.window
, evt
->xselection
.property
,
2536 dropData
.getSize() / 4, 65536, 1, AnyPropertyType
, &actual
,
2537 &format
, &count
, &remaining
, &data
) == Success
)
2539 dropData
.append (data
, count
* format
/ 8);
2552 lines
.addLines (dropData
.toString());
2555 for (int i
= 0; i
< lines
.size(); ++i
)
2556 dragAndDropFiles
.add (URL::removeEscapeChars (lines
[i
].fromFirstOccurrenceOf ("file://", false, true)));
2558 dragAndDropFiles
.trim();
2559 dragAndDropFiles
.removeEmptyStrings();
2563 void updateDraggedFileList (const XClientMessageEvent
* const clientMsg
)
2565 dragAndDropFiles
.clear();
2567 if (dragAndDropSourceWindow
!= None
2568 && dragAndDropCurrentMimeType
!= 0)
2570 dragAndDropTimestamp
= clientMsg
->data
.l
[2];
2573 XConvertSelection (display
,
2574 Atoms::XdndSelection
,
2575 dragAndDropCurrentMimeType
,
2576 XInternAtom (display
, "JXSelectionWindowProperty", 0),
2578 dragAndDropTimestamp
);
2582 StringArray dragAndDropFiles
;
2583 int dragAndDropTimestamp
;
2584 Point
<int> lastDropPos
;
2586 Atom dragAndDropCurrentMimeType
;
2587 Window dragAndDropSourceWindow
;
2589 Array
<Atom
> srcMimeTypeAtomList
;
2591 static int pointerMap
[5];
2592 static Point
<int> lastMousePos
;
2594 static void clearLastMousePos() noexcept
2596 lastMousePos
= Point
<int> (0x100000, 0x100000);
2599 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LinuxComponentPeer
);
2602 ModifierKeys
LinuxComponentPeer::currentModifiers
;
2603 bool LinuxComponentPeer::isActiveApplication
= false;
2604 int LinuxComponentPeer::pointerMap
[5];
2605 Point
<int> LinuxComponentPeer::lastMousePos
;
2607 //==============================================================================
2608 bool Process::isForegroundProcess()
2610 return LinuxComponentPeer::isActiveApplication
;
2613 //==============================================================================
2614 void ModifierKeys::updateCurrentModifiers() noexcept
2616 currentModifiers
= LinuxComponentPeer::currentModifiers
;
2619 const ModifierKeys
ModifierKeys::getCurrentModifiersRealtime() noexcept
2622 int x
, y
, winx
, winy
;
2628 if (XQueryPointer (display
, RootWindow (display
, DefaultScreen (display
)),
2629 &root
, &child
, &x
, &y
, &winx
, &winy
, &mask
) != False
)
2631 if ((mask
& Button1Mask
) != 0) mouseMods
|= ModifierKeys::leftButtonModifier
;
2632 if ((mask
& Button2Mask
) != 0) mouseMods
|= ModifierKeys::middleButtonModifier
;
2633 if ((mask
& Button3Mask
) != 0) mouseMods
|= ModifierKeys::rightButtonModifier
;
2636 LinuxComponentPeer::currentModifiers
= LinuxComponentPeer::currentModifiers
.withoutMouseButtons().withFlags (mouseMods
);
2637 return LinuxComponentPeer::currentModifiers
;
2641 //==============================================================================
2642 void Desktop::setKioskComponent (Component
* kioskModeComponent
, bool enableOrDisable
, bool allowMenusAndBars
)
2644 if (enableOrDisable
)
2645 kioskModeComponent
->setBounds (Desktop::getInstance().getMainMonitorArea (false));
2648 //==============================================================================
2649 ComponentPeer
* Component::createNewPeer (int styleFlags
, void* nativeWindowToAttachTo
)
2651 return new LinuxComponentPeer (this, styleFlags
, (Window
) nativeWindowToAttachTo
);
2655 //==============================================================================
2656 // (this callback is hooked up in the messaging code)
2657 void juce_windowMessageReceive (XEvent
* event
)
2659 if (event
->xany
.window
!= None
)
2661 LinuxComponentPeer
* const peer
= LinuxComponentPeer::getPeerFor (event
->xany
.window
);
2663 if (ComponentPeer::isValidPeer (peer
))
2664 peer
->handleWindowMessage (event
);
2668 switch (event
->xany
.type
)
2672 const XKeymapEvent
* const keymapEvent
= (const XKeymapEvent
*) &event
->xkeymap
;
2673 memcpy (Keys::keyStates
, keymapEvent
->key_vector
, 32);
2683 //==============================================================================
2684 void Desktop::getCurrentMonitorPositions (Array
<Rectangle
<int> >& monitorCoords
, const bool /*clipToWorkArea*/)
2689 #if JUCE_USE_XINERAMA
2690 int major_opcode
, first_event
, first_error
;
2693 if (XQueryExtension (display
, "XINERAMA", &major_opcode
, &first_event
, &first_error
))
2695 typedef Bool (*tXineramaIsActive
) (Display
*);
2696 typedef XineramaScreenInfo
* (*tXineramaQueryScreens
) (Display
*, int*);
2698 static tXineramaIsActive xXineramaIsActive
= 0;
2699 static tXineramaQueryScreens xXineramaQueryScreens
= 0;
2701 if (xXineramaIsActive
== 0 || xXineramaQueryScreens
== 0)
2703 void* h
= dlopen ("libXinerama.so", RTLD_GLOBAL
| RTLD_NOW
);
2706 h
= dlopen ("libXinerama.so.1", RTLD_GLOBAL
| RTLD_NOW
);
2710 xXineramaIsActive
= (tXineramaIsActive
) dlsym (h
, "XineramaIsActive");
2711 xXineramaQueryScreens
= (tXineramaQueryScreens
) dlsym (h
, "XineramaQueryScreens");
2715 if (xXineramaIsActive
!= 0
2716 && xXineramaQueryScreens
!= 0
2717 && xXineramaIsActive (display
))
2719 int numMonitors
= 0;
2720 XineramaScreenInfo
* const screens
= xXineramaQueryScreens (display
, &numMonitors
);
2724 for (int i
= numMonitors
; --i
>= 0;)
2726 int index
= screens
[i
].screen_number
;
2730 while (monitorCoords
.size() < index
)
2731 monitorCoords
.add (Rectangle
<int>());
2733 monitorCoords
.set (index
, Rectangle
<int> (screens
[i
].x_org
,
2736 screens
[i
].height
));
2745 if (monitorCoords
.size() == 0)
2748 Atom hints
= XInternAtom (display
, "_NET_WORKAREA", True
);
2752 const int numMonitors
= ScreenCount (display
);
2754 for (int i
= 0; i
< numMonitors
; ++i
)
2756 Window root
= RootWindow (display
, i
);
2758 unsigned long nitems
, bytesLeft
;
2761 unsigned char* data
= nullptr;
2763 if (XGetWindowProperty (display
, root
, hints
, 0, 4, False
,
2764 XA_CARDINAL
, &actualType
, &actualFormat
, &nitems
, &bytesLeft
,
2767 const long* const position
= (const long*) data
;
2769 if (actualType
== XA_CARDINAL
&& actualFormat
== 32 && nitems
== 4)
2770 monitorCoords
.add (Rectangle
<int> (position
[0], position
[1],
2771 position
[2], position
[3]));
2778 if (monitorCoords
.size() == 0)
2780 monitorCoords
.add (Rectangle
<int> (DisplayWidth (display
, DefaultScreen (display
)),
2781 DisplayHeight (display
, DefaultScreen (display
))));
2786 //==============================================================================
2787 void Desktop::createMouseInputSources()
2789 mouseSources
.add (new MouseInputSource (0, true));
2792 bool Desktop::canUseSemiTransparentWindows() noexcept
2794 int matchedDepth
= 0;
2795 const int desiredDepth
= 32;
2797 return Visuals::findVisualFormat (desiredDepth
, matchedDepth
) != 0
2798 && (matchedDepth
== desiredDepth
);
2801 const Point
<int> MouseInputSource::getCurrentMousePosition()
2804 int x
, y
, winx
, winy
;
2809 if (XQueryPointer (display
,
2810 RootWindow (display
, DefaultScreen (display
)),
2812 &x
, &y
, &winx
, &winy
, &mask
) == False
)
2814 // Pointer not on the default screen
2818 return Point
<int> (x
, y
);
2821 void Desktop::setMousePosition (const Point
<int>& newPosition
)
2824 Window root
= RootWindow (display
, DefaultScreen (display
));
2825 XWarpPointer (display
, None
, root
, 0, 0, 0, 0, newPosition
.getX(), newPosition
.getY());
2828 Desktop::DisplayOrientation
Desktop::getCurrentOrientation() const
2833 //==============================================================================
2834 static bool screenSaverAllowed
= true;
2836 void Desktop::setScreenSaverEnabled (const bool isEnabled
)
2838 if (screenSaverAllowed
!= isEnabled
)
2840 screenSaverAllowed
= isEnabled
;
2842 typedef void (*tXScreenSaverSuspend
) (Display
*, Bool
);
2843 static tXScreenSaverSuspend xScreenSaverSuspend
= 0;
2845 if (xScreenSaverSuspend
== 0)
2847 void* h
= dlopen ("libXss.so", RTLD_GLOBAL
| RTLD_NOW
);
2850 xScreenSaverSuspend
= (tXScreenSaverSuspend
) dlsym (h
, "XScreenSaverSuspend");
2854 if (xScreenSaverSuspend
!= 0)
2855 xScreenSaverSuspend (display
, ! isEnabled
);
2859 bool Desktop::isScreenSaverEnabled()
2861 return screenSaverAllowed
;
2864 //==============================================================================
2865 void* MouseCursor::createMouseCursorFromImage (const Image
& image
, int hotspotX
, int hotspotY
)
2868 const unsigned int imageW
= image
.getWidth();
2869 const unsigned int imageH
= image
.getHeight();
2871 #if JUCE_USE_XCURSOR
2873 typedef XcursorBool (*tXcursorSupportsARGB
) (Display
*);
2874 typedef XcursorImage
* (*tXcursorImageCreate
) (int, int);
2875 typedef void (*tXcursorImageDestroy
) (XcursorImage
*);
2876 typedef Cursor (*tXcursorImageLoadCursor
) (Display
*, const XcursorImage
*);
2878 static tXcursorSupportsARGB xXcursorSupportsARGB
= 0;
2879 static tXcursorImageCreate xXcursorImageCreate
= 0;
2880 static tXcursorImageDestroy xXcursorImageDestroy
= 0;
2881 static tXcursorImageLoadCursor xXcursorImageLoadCursor
= 0;
2882 static bool hasBeenLoaded
= false;
2884 if (! hasBeenLoaded
)
2886 hasBeenLoaded
= true;
2887 void* h
= dlopen ("libXcursor.so", RTLD_GLOBAL
| RTLD_NOW
);
2891 xXcursorSupportsARGB
= (tXcursorSupportsARGB
) dlsym (h
, "XcursorSupportsARGB");
2892 xXcursorImageCreate
= (tXcursorImageCreate
) dlsym (h
, "XcursorImageCreate");
2893 xXcursorImageLoadCursor
= (tXcursorImageLoadCursor
) dlsym (h
, "XcursorImageLoadCursor");
2894 xXcursorImageDestroy
= (tXcursorImageDestroy
) dlsym (h
, "XcursorImageDestroy");
2896 if (xXcursorSupportsARGB
== 0 || xXcursorImageCreate
== 0
2897 || xXcursorImageLoadCursor
== 0 || xXcursorImageDestroy
== 0
2898 || ! xXcursorSupportsARGB (display
))
2899 xXcursorSupportsARGB
= 0;
2903 if (xXcursorSupportsARGB
!= 0)
2905 XcursorImage
* xcImage
= xXcursorImageCreate (imageW
, imageH
);
2909 xcImage
->xhot
= hotspotX
;
2910 xcImage
->yhot
= hotspotY
;
2911 XcursorPixel
* dest
= xcImage
->pixels
;
2913 for (int y
= 0; y
< (int) imageH
; ++y
)
2914 for (int x
= 0; x
< (int) imageW
; ++x
)
2915 *dest
++ = image
.getPixelAt (x
, y
).getARGB();
2917 void* result
= (void*) xXcursorImageLoadCursor (display
, xcImage
);
2918 xXcursorImageDestroy (xcImage
);
2927 Window root
= RootWindow (display
, DefaultScreen (display
));
2928 unsigned int cursorW
, cursorH
;
2929 if (! XQueryBestCursor (display
, root
, imageW
, imageH
, &cursorW
, &cursorH
))
2932 Image
im (Image::ARGB
, cursorW
, cursorH
, true);
2937 if (imageW
> cursorW
|| imageH
> cursorH
)
2939 hotspotX
= (hotspotX
* cursorW
) / imageW
;
2940 hotspotY
= (hotspotY
* cursorH
) / imageH
;
2942 g
.drawImageWithin (image
, 0, 0, imageW
, imageH
,
2943 RectanglePlacement::xLeft
| RectanglePlacement::yTop
| RectanglePlacement::onlyReduceInSize
,
2948 g
.drawImageAt (image
, 0, 0);
2952 const int stride
= (cursorW
+ 7) >> 3;
2953 HeapBlock
<char> maskPlane
, sourcePlane
;
2954 maskPlane
.calloc (stride
* cursorH
);
2955 sourcePlane
.calloc (stride
* cursorH
);
2957 const bool msbfirst
= (BitmapBitOrder (display
) == MSBFirst
);
2959 for (int y
= cursorH
; --y
>= 0;)
2961 for (int x
= cursorW
; --x
>= 0;)
2963 const char mask
= (char) (1 << (msbfirst
? (7 - (x
& 7)) : (x
& 7)));
2964 const int offset
= y
* stride
+ (x
>> 3);
2966 const Colour
c (im
.getPixelAt (x
, y
));
2968 if (c
.getAlpha() >= 128)
2969 maskPlane
[offset
] |= mask
;
2971 if (c
.getBrightness() >= 0.5f
)
2972 sourcePlane
[offset
] |= mask
;
2976 Pixmap sourcePixmap
= XCreatePixmapFromBitmapData (display
, root
, sourcePlane
.getData(), cursorW
, cursorH
, 0xffff, 0, 1);
2977 Pixmap maskPixmap
= XCreatePixmapFromBitmapData (display
, root
, maskPlane
.getData(), cursorW
, cursorH
, 0xffff, 0, 1);
2979 XColor white
, black
;
2980 black
.red
= black
.green
= black
.blue
= 0;
2981 white
.red
= white
.green
= white
.blue
= 0xffff;
2983 void* result
= (void*) XCreatePixmapCursor (display
, sourcePixmap
, maskPixmap
, &white
, &black
, hotspotX
, hotspotY
);
2985 XFreePixmap (display
, sourcePixmap
);
2986 XFreePixmap (display
, maskPixmap
);
2991 void MouseCursor::deleteMouseCursor (void* const cursorHandle
, const bool)
2994 if (cursorHandle
!= 0)
2995 XFreeCursor (display
, (Cursor
) cursorHandle
);
2998 void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType type
)
3004 case NormalCursor
: return None
; // Use parent cursor
3005 case NoCursor
: return createMouseCursorFromImage (Image (Image::ARGB
, 16, 16, true), 0, 0);
3007 case WaitCursor
: shape
= XC_watch
; break;
3008 case IBeamCursor
: shape
= XC_xterm
; break;
3009 case PointingHandCursor
: shape
= XC_hand2
; break;
3010 case LeftRightResizeCursor
: shape
= XC_sb_h_double_arrow
; break;
3011 case UpDownResizeCursor
: shape
= XC_sb_v_double_arrow
; break;
3012 case UpDownLeftRightResizeCursor
: shape
= XC_fleur
; break;
3013 case TopEdgeResizeCursor
: shape
= XC_top_side
; break;
3014 case BottomEdgeResizeCursor
: shape
= XC_bottom_side
; break;
3015 case LeftEdgeResizeCursor
: shape
= XC_left_side
; break;
3016 case RightEdgeResizeCursor
: shape
= XC_right_side
; break;
3017 case TopLeftCornerResizeCursor
: shape
= XC_top_left_corner
; break;
3018 case TopRightCornerResizeCursor
: shape
= XC_top_right_corner
; break;
3019 case BottomLeftCornerResizeCursor
: shape
= XC_bottom_left_corner
; break;
3020 case BottomRightCornerResizeCursor
: shape
= XC_bottom_right_corner
; break;
3021 case CrosshairCursor
: shape
= XC_crosshair
; break;
3023 case DraggingHandCursor
:
3025 static unsigned char dragHandData
[] = { 71,73,70,56,57,97,16,0,16,0,145,2,0,0,0,0,255,255,255,0,
3026 0,0,0,0,0,33,249,4,1,0,0,2,0,44,0,0,0,0,16,0, 16,0,0,2,52,148,47,0,200,185,16,130,90,12,74,139,107,84,123,39,
3027 132,117,151,116,132,146,248,60,209,138,98,22,203,114,34,236,37,52,77,217, 247,154,191,119,110,240,193,128,193,95,163,56,60,234,98,135,2,0,59 };
3028 const int dragHandDataSize
= 99;
3030 return createMouseCursorFromImage (ImageFileFormat::loadFrom (dragHandData
, dragHandDataSize
), 8, 7);
3035 static unsigned char copyCursorData
[] = { 71,73,70,56,57,97,21,0,21,0,145,0,0,0,0,0,255,255,255,0,
3036 128,128,255,255,255,33,249,4,1,0,0,3,0,44,0,0,0,0,21,0, 21,0,0,2,72,4,134,169,171,16,199,98,11,79,90,71,161,93,56,111,
3037 78,133,218,215,137,31,82,154,100,200,86,91,202,142,12,108,212,87,235,174, 15,54,214,126,237,226,37,96,59,141,16,37,18,201,142,157,230,204,51,112,
3038 252,114,147,74,83,5,50,68,147,208,217,16,71,149,252,124,5,0,59,0,0 };
3039 const int copyCursorSize
= 119;
3041 return createMouseCursorFromImage (ImageFileFormat::loadFrom (copyCursorData
, copyCursorSize
), 1, 3);
3050 return (void*) XCreateFontCursor (display
, shape
);
3053 void MouseCursor::showInWindow (ComponentPeer
* peer
) const
3055 LinuxComponentPeer
* const lp
= dynamic_cast <LinuxComponentPeer
*> (peer
);
3058 lp
->showMouseCursor ((Cursor
) getHandle());
3061 void MouseCursor::showInAllWindows() const
3063 for (int i
= ComponentPeer::getNumPeers(); --i
>= 0;)
3064 showInWindow (ComponentPeer::getPeer (i
));
3067 //==============================================================================
3068 Image
juce_createIconForFile (const File
& file
)
3073 Image::SharedImage
* Image::SharedImage::createNativeImage (PixelFormat format
, int width
, int height
, bool clearImage
)
3075 return createSoftwareImage (format
, width
, height
, clearImage
);
3079 //==============================================================================
3083 //==============================================================================
3084 class WindowedGLContext
: public OpenGLContext
3087 WindowedGLContext (Component
* const component
,
3088 const OpenGLPixelFormat
& pixelFormat_
,
3089 GLXContext sharedContext
)
3090 : renderContext (0),
3092 pixelFormat (pixelFormat_
),
3095 jassert (component
!= nullptr);
3096 LinuxComponentPeer
* const peer
= dynamic_cast <LinuxComponentPeer
*> (component
->getTopLevelComponent()->getPeer());
3097 if (peer
== nullptr)
3101 XSync (display
, False
);
3105 attribs
[n
++] = GLX_RGBA
;
3106 attribs
[n
++] = GLX_DOUBLEBUFFER
;
3107 attribs
[n
++] = GLX_RED_SIZE
;
3108 attribs
[n
++] = pixelFormat
.redBits
;
3109 attribs
[n
++] = GLX_GREEN_SIZE
;
3110 attribs
[n
++] = pixelFormat
.greenBits
;
3111 attribs
[n
++] = GLX_BLUE_SIZE
;
3112 attribs
[n
++] = pixelFormat
.blueBits
;
3113 attribs
[n
++] = GLX_ALPHA_SIZE
;
3114 attribs
[n
++] = pixelFormat
.alphaBits
;
3115 attribs
[n
++] = GLX_DEPTH_SIZE
;
3116 attribs
[n
++] = pixelFormat
.depthBufferBits
;
3117 attribs
[n
++] = GLX_STENCIL_SIZE
;
3118 attribs
[n
++] = pixelFormat
.stencilBufferBits
;
3119 attribs
[n
++] = GLX_ACCUM_RED_SIZE
;
3120 attribs
[n
++] = pixelFormat
.accumulationBufferRedBits
;
3121 attribs
[n
++] = GLX_ACCUM_GREEN_SIZE
;
3122 attribs
[n
++] = pixelFormat
.accumulationBufferGreenBits
;
3123 attribs
[n
++] = GLX_ACCUM_BLUE_SIZE
;
3124 attribs
[n
++] = pixelFormat
.accumulationBufferBlueBits
;
3125 attribs
[n
++] = GLX_ACCUM_ALPHA_SIZE
;
3126 attribs
[n
++] = pixelFormat
.accumulationBufferAlphaBits
;
3128 // xxx not sure how to do fullSceneAntiAliasingNumSamples on linux..
3130 attribs
[n
++] = None
;
3132 XVisualInfo
* const bestVisual
= glXChooseVisual (display
, DefaultScreen (display
), attribs
);
3134 if (bestVisual
== 0)
3137 renderContext
= glXCreateContext (display
, bestVisual
, sharedContext
, GL_TRUE
);
3139 Window windowH
= (Window
) peer
->getNativeHandle();
3141 Colormap colourMap
= XCreateColormap (display
, windowH
, bestVisual
->visual
, AllocNone
);
3142 XSetWindowAttributes swa
;
3143 swa
.colormap
= colourMap
;
3144 swa
.border_pixel
= 0;
3145 swa
.event_mask
= ExposureMask
| StructureNotifyMask
;
3147 embeddedWindow
= XCreateWindow (display
, windowH
,
3152 CWBorderPixel
| CWColormap
| CWEventMask
,
3155 XSaveContext (display
, (XID
) embeddedWindow
, windowHandleXContext
, (XPointer
) peer
);
3157 XMapWindow (display
, embeddedWindow
);
3158 XFreeColormap (display
, colourMap
);
3161 XSync (display
, False
);
3164 ~WindowedGLContext()
3169 XUnmapWindow (display
, embeddedWindow
);
3170 XDestroyWindow (display
, embeddedWindow
);
3173 void deleteContext()
3177 if (renderContext
!= 0)
3180 glXDestroyContext (display
, renderContext
);
3181 renderContext
= nullptr;
3185 bool makeActive() const noexcept
3187 jassert (renderContext
!= 0);
3190 return glXMakeCurrent (display
, embeddedWindow
, renderContext
)
3191 && XSync (display
, False
);
3194 bool makeInactive() const noexcept
3197 return (! isActive()) || glXMakeCurrent (display
, None
, 0);
3200 bool isActive() const noexcept
3203 return glXGetCurrentContext() == renderContext
;
3206 const OpenGLPixelFormat
getPixelFormat() const
3211 void* getRawContext() const noexcept
3213 return renderContext
;
3216 void updateWindowPosition (const Rectangle
<int>& bounds
)
3219 XMoveResizeWindow (display
, embeddedWindow
,
3220 bounds
.getX(), bounds
.getY(), jmax (1, bounds
.getWidth()), jmax (1, bounds
.getHeight()));
3226 glXSwapBuffers (display
, embeddedWindow
);
3229 bool setSwapInterval (const int numFramesPerSwap
)
3231 static PFNGLXSWAPINTERVALSGIPROC GLXSwapIntervalSGI
= (PFNGLXSWAPINTERVALSGIPROC
) glXGetProcAddress ((const GLubyte
*) "glXSwapIntervalSGI");
3233 if (GLXSwapIntervalSGI
!= 0)
3235 swapInterval
= numFramesPerSwap
;
3236 GLXSwapIntervalSGI (numFramesPerSwap
);
3243 int getSwapInterval() const
3245 return swapInterval
;
3252 //==============================================================================
3253 GLXContext renderContext
;
3256 Window embeddedWindow
;
3257 OpenGLPixelFormat pixelFormat
;
3260 //==============================================================================
3261 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowedGLContext
);
3264 //==============================================================================
3265 OpenGLContext
* OpenGLComponent::createContext()
3267 ScopedPointer
<WindowedGLContext
> c (new WindowedGLContext (this, preferredPixelFormat
,
3268 contextToShareListsWith
!= 0 ? (GLXContext
) contextToShareListsWith
->getRawContext() : 0));
3270 return (c
->renderContext
!= 0) ? c
.release() : nullptr;
3273 void juce_glViewport (const int w
, const int h
)
3275 glViewport (0, 0, w
, h
);
3278 void OpenGLPixelFormat::getAvailablePixelFormats (Component
* component
,
3279 OwnedArray
<OpenGLPixelFormat
>& results
)
3281 results
.add (new OpenGLPixelFormat()); // xxx
3287 //==============================================================================
3288 bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray
& files
, const bool canMoveFiles
)
3290 jassertfalse
; // not implemented!
3294 bool DragAndDropContainer::performExternalDragDropOfText (const String
& text
)
3296 jassertfalse
; // not implemented!
3300 //==============================================================================
3301 void SystemTrayIconComponent::setIconImage (const Image
& newImage
)
3303 if (! isOnDesktop ())
3306 LinuxComponentPeer
* const wp
= dynamic_cast <LinuxComponentPeer
*> (getPeer());
3310 wp
->setTaskBarIcon (newImage
);
3318 void SystemTrayIconComponent::paint (Graphics
& g
)
3320 LinuxComponentPeer
* const wp
= dynamic_cast <LinuxComponentPeer
*> (getPeer());
3324 g
.drawImageWithin (wp
->getTaskbarIcon(), 0, 0, getWidth(), getHeight(),
3325 RectanglePlacement::xLeft
| RectanglePlacement::yTop
| RectanglePlacement::onlyReduceInSize
,
3330 void SystemTrayIconComponent::setIconTooltip (const String
& tooltip
)
3332 // xxx not yet implemented!
3336 //==============================================================================
3337 void PlatformUtilities::beep()
3339 std::cout
<< "\a" << std::flush
;
3343 //==============================================================================
3344 void JUCE_CALLTYPE
NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType
,
3345 const String
& title
, const String
& message
,
3346 Component
* associatedComponent
)
3348 AlertWindow::showMessageBox (AlertWindow::NoIcon
, title
, message
);
3351 void JUCE_CALLTYPE
NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType
,
3352 const String
& title
, const String
& message
,
3353 Component
* associatedComponent
)
3355 AlertWindow::showMessageBoxAsync (AlertWindow::NoIcon
, title
, message
);
3358 bool JUCE_CALLTYPE
NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType
,
3359 const String
& title
, const String
& message
,
3360 Component
* associatedComponent
,
3361 ModalComponentManager::Callback
* callback
)
3363 return AlertWindow::showOkCancelBox (iconType
, title
, message
, String::empty
, String::empty
,
3364 associatedComponent
, callback
);
3367 int JUCE_CALLTYPE
NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType
,
3368 const String
& title
, const String
& message
,
3369 Component
* associatedComponent
,
3370 ModalComponentManager::Callback
* callback
)
3372 return AlertWindow::showYesNoCancelBox (iconType
, title
, message
,
3373 String::empty
, String::empty
, String::empty
,
3374 associatedComponent
, callback
);
3378 //==============================================================================
3379 const int KeyPress::spaceKey
= XK_space
& 0xff;
3380 const int KeyPress::returnKey
= XK_Return
& 0xff;
3381 const int KeyPress::escapeKey
= XK_Escape
& 0xff;
3382 const int KeyPress::backspaceKey
= XK_BackSpace
& 0xff;
3383 const int KeyPress::leftKey
= (XK_Left
& 0xff) | Keys::extendedKeyModifier
;
3384 const int KeyPress::rightKey
= (XK_Right
& 0xff) | Keys::extendedKeyModifier
;
3385 const int KeyPress::upKey
= (XK_Up
& 0xff) | Keys::extendedKeyModifier
;
3386 const int KeyPress::downKey
= (XK_Down
& 0xff) | Keys::extendedKeyModifier
;
3387 const int KeyPress::pageUpKey
= (XK_Page_Up
& 0xff) | Keys::extendedKeyModifier
;
3388 const int KeyPress::pageDownKey
= (XK_Page_Down
& 0xff) | Keys::extendedKeyModifier
;
3389 const int KeyPress::endKey
= (XK_End
& 0xff) | Keys::extendedKeyModifier
;
3390 const int KeyPress::homeKey
= (XK_Home
& 0xff) | Keys::extendedKeyModifier
;
3391 const int KeyPress::insertKey
= (XK_Insert
& 0xff) | Keys::extendedKeyModifier
;
3392 const int KeyPress::deleteKey
= (XK_Delete
& 0xff) | Keys::extendedKeyModifier
;
3393 const int KeyPress::tabKey
= XK_Tab
& 0xff;
3394 const int KeyPress::F1Key
= (XK_F1
& 0xff) | Keys::extendedKeyModifier
;
3395 const int KeyPress::F2Key
= (XK_F2
& 0xff) | Keys::extendedKeyModifier
;
3396 const int KeyPress::F3Key
= (XK_F3
& 0xff) | Keys::extendedKeyModifier
;
3397 const int KeyPress::F4Key
= (XK_F4
& 0xff) | Keys::extendedKeyModifier
;
3398 const int KeyPress::F5Key
= (XK_F5
& 0xff) | Keys::extendedKeyModifier
;
3399 const int KeyPress::F6Key
= (XK_F6
& 0xff) | Keys::extendedKeyModifier
;
3400 const int KeyPress::F7Key
= (XK_F7
& 0xff) | Keys::extendedKeyModifier
;
3401 const int KeyPress::F8Key
= (XK_F8
& 0xff) | Keys::extendedKeyModifier
;
3402 const int KeyPress::F9Key
= (XK_F9
& 0xff) | Keys::extendedKeyModifier
;
3403 const int KeyPress::F10Key
= (XK_F10
& 0xff) | Keys::extendedKeyModifier
;
3404 const int KeyPress::F11Key
= (XK_F11
& 0xff) | Keys::extendedKeyModifier
;
3405 const int KeyPress::F12Key
= (XK_F12
& 0xff) | Keys::extendedKeyModifier
;
3406 const int KeyPress::F13Key
= (XK_F13
& 0xff) | Keys::extendedKeyModifier
;
3407 const int KeyPress::F14Key
= (XK_F14
& 0xff) | Keys::extendedKeyModifier
;
3408 const int KeyPress::F15Key
= (XK_F15
& 0xff) | Keys::extendedKeyModifier
;
3409 const int KeyPress::F16Key
= (XK_F16
& 0xff) | Keys::extendedKeyModifier
;
3410 const int KeyPress::numberPad0
= (XK_KP_0
& 0xff) | Keys::extendedKeyModifier
;
3411 const int KeyPress::numberPad1
= (XK_KP_1
& 0xff) | Keys::extendedKeyModifier
;
3412 const int KeyPress::numberPad2
= (XK_KP_2
& 0xff) | Keys::extendedKeyModifier
;
3413 const int KeyPress::numberPad3
= (XK_KP_3
& 0xff) | Keys::extendedKeyModifier
;
3414 const int KeyPress::numberPad4
= (XK_KP_4
& 0xff) | Keys::extendedKeyModifier
;
3415 const int KeyPress::numberPad5
= (XK_KP_5
& 0xff) | Keys::extendedKeyModifier
;
3416 const int KeyPress::numberPad6
= (XK_KP_6
& 0xff) | Keys::extendedKeyModifier
;
3417 const int KeyPress::numberPad7
= (XK_KP_7
& 0xff)| Keys::extendedKeyModifier
;
3418 const int KeyPress::numberPad8
= (XK_KP_8
& 0xff)| Keys::extendedKeyModifier
;
3419 const int KeyPress::numberPad9
= (XK_KP_9
& 0xff)| Keys::extendedKeyModifier
;
3420 const int KeyPress::numberPadAdd
= (XK_KP_Add
& 0xff)| Keys::extendedKeyModifier
;
3421 const int KeyPress::numberPadSubtract
= (XK_KP_Subtract
& 0xff)| Keys::extendedKeyModifier
;
3422 const int KeyPress::numberPadMultiply
= (XK_KP_Multiply
& 0xff)| Keys::extendedKeyModifier
;
3423 const int KeyPress::numberPadDivide
= (XK_KP_Divide
& 0xff)| Keys::extendedKeyModifier
;
3424 const int KeyPress::numberPadSeparator
= (XK_KP_Separator
& 0xff)| Keys::extendedKeyModifier
;
3425 const int KeyPress::numberPadDecimalPoint
= (XK_KP_Decimal
& 0xff)| Keys::extendedKeyModifier
;
3426 const int KeyPress::numberPadEquals
= (XK_KP_Equal
& 0xff)| Keys::extendedKeyModifier
;
3427 const int KeyPress::numberPadDelete
= (XK_KP_Delete
& 0xff)| Keys::extendedKeyModifier
;
3428 const int KeyPress::playKey
= (0xffeeff00) | Keys::extendedKeyModifier
;
3429 const int KeyPress::stopKey
= (0xffeeff01) | Keys::extendedKeyModifier
;
3430 const int KeyPress::fastForwardKey
= (0xffeeff02) | Keys::extendedKeyModifier
;
3431 const int KeyPress::rewindKey
= (0xffeeff03) | Keys::extendedKeyModifier
;