From 367dfa994219cc9535cf3f147793ef99fef7e208 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Fri, 26 Mar 2010 13:20:48 +0000 Subject: [PATCH] Added linux ARGB mouse cursor support. --- .../Source/model/jucer_ProjectExport_MSVC.h | 4 +- .../Source/model/jucer_ProjectExport_XCode.h | 2 +- juce_Config.h | 7 + juce_amalgamated.cpp | 383 ++++++++++-------- juce_amalgamated.h | 4 + src/io/files/juce_File.cpp | 2 +- src/native/common/juce_posix_SharedCode.h | 2 +- src/native/linux/juce_linux_NativeIncludes.h | 5 + src/native/linux/juce_linux_Windowing.cpp | 375 +++++++++-------- 9 files changed, 443 insertions(+), 341 deletions(-) diff --git a/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_MSVC.h b/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_MSVC.h index 0710d2e005..1081bac2e3 100644 --- a/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_MSVC.h +++ b/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_MSVC.h @@ -490,7 +490,7 @@ private: compiler->setAttribute ("ProgramDataBaseFileName", windowsStylePath (intermediatesPath + "/")); compiler->setAttribute ("WarningLevel", "3"); compiler->setAttribute ("SuppressStartupBanner", "true"); - + if (getExtraCompilerFlags().toString().isNotEmpty()) compiler->setAttribute ("AdditionalOptions", getExtraCompilerFlags().toString().trim()); } @@ -531,7 +531,7 @@ private: linker->setAttribute ("TargetMachine", "1"); String extraLinkerOptions (getExtraLinkerFlags().toString()); - + if (isRTAS()) { extraLinkerOptions += " /FORCE:multiple"; diff --git a/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_XCode.h b/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_XCode.h index b3dfb66fc3..0d85312b2c 100644 --- a/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_XCode.h +++ b/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_XCode.h @@ -393,7 +393,7 @@ private: settings.add ("HEADER_SEARCH_PATHS = \"" + getHeaderSearchPaths (config).joinIntoString (" ") + " $(inherited)\""); settings.add ("GCC_OPTIMIZATION_LEVEL = " + config.getGCCOptimisationFlag()); settings.add ("INFOPLIST_FILE = " + infoPlistFile.getFileName()); - + if (getExtraCompilerFlags().toString().isNotEmpty()) settings.add ("OTHER_CPLUSPLUSFLAGS = " + getExtraCompilerFlags().toString()); diff --git a/juce_Config.h b/juce_Config.h index 7e31635d8f..ead832e266 100644 --- a/juce_Config.h +++ b/juce_Config.h @@ -188,6 +188,13 @@ //#define JUCE_USE_XRENDER 1 #endif +/** JUCE_USE_XCURSOR: Uses XCursor to allow ARGB cursor on Linux. This is best left turned on + unless you have a good reason to disable it. +*/ +#ifndef JUCE_USE_XCURSOR + #define JUCE_USE_XCURSOR 1 +#endif + //============================================================================= /** JUCE_PLUGINHOST_VST: Enables the VST audio plugin hosting classes. This requires the Steinberg VST SDK to be installed on your machine, and should be left turned off unless diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index a70cb369b4..a7031d1a52 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -243,6 +243,10 @@ //#define JUCE_USE_XRENDER 1 #endif +#ifndef JUCE_USE_XCURSOR + #define JUCE_USE_XCURSOR 1 +#endif + #ifndef JUCE_PLUGINHOST_VST // #define JUCE_PLUGINHOST_VST 1 #endif @@ -534,6 +538,11 @@ public: #include #endif +#if JUCE_USE_XCURSOR + // If you're missing this header, try installing the libxcursor-dev package + #include +#endif + #if JUCE_OPENGL #include #endif @@ -5772,7 +5781,7 @@ static const String parseAbsolutePath (String path) "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute path if that's what was supplied, or would evaluate a partial path relative to the CWD. */ - jassert (path.startsWith (T("./"))); // (assume that a path "./xyz" is deliberately intended to be relative to the CWD) + jassert (path.startsWith (T("./")) || path.startsWith (T("../"))); // (assume that a path "./xyz" is deliberately intended to be relative to the CWD) return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName(); } @@ -227952,7 +227961,7 @@ const File juce_getExecutableFile() { Dl_info exeInfo; dladdr ((const void*) juce_getExecutableFile, &exeInfo); - return File (String::fromUTF8 (exeInfo.dli_fname)); + return File::getCurrentWorkingDirectory().getChildFile (String::fromUTF8 (exeInfo.dli_fname)); } // if this file doesn't exist, find a parent of it that does.. @@ -230853,6 +230862,10 @@ void Font::getPlatformDefaultFontNames (String& defaultSans, String& defaultSeri // compiled on its own). #if JUCE_INCLUDED_FILE +// These are defined in juce_linux_Messaging.cpp +extern Display* display; +extern XContext improbableNumber; + namespace Atoms { enum ProtocolItems @@ -230879,85 +230892,42 @@ namespace Atoms { atomsInitialised = true; - Protocols = XInternAtom (display, "WM_PROTOCOLS", True); - ProtocolList [TAKE_FOCUS] = XInternAtom (display, "WM_TAKE_FOCUS", True); - ProtocolList [DELETE_WINDOW] = XInternAtom (display, "WM_DELETE_WINDOW", True); - ChangeState = XInternAtom (display, "WM_CHANGE_STATE", True); - State = XInternAtom (display, "WM_STATE", True); - ActiveWin = XInternAtom (display, "_NET_ACTIVE_WINDOW", False); - Pid = XInternAtom (display, "_NET_WM_PID", False); - WindowType = XInternAtom (display, "_NET_WM_WINDOW_TYPE", True); - WindowState = XInternAtom (display, "_NET_WM_WINDOW_STATE", True); + Protocols = XInternAtom (display, "WM_PROTOCOLS", True); + ProtocolList [TAKE_FOCUS] = XInternAtom (display, "WM_TAKE_FOCUS", True); + ProtocolList [DELETE_WINDOW] = XInternAtom (display, "WM_DELETE_WINDOW", True); + ChangeState = XInternAtom (display, "WM_CHANGE_STATE", True); + State = XInternAtom (display, "WM_STATE", True); + ActiveWin = XInternAtom (display, "_NET_ACTIVE_WINDOW", False); + Pid = XInternAtom (display, "_NET_WM_PID", False); + WindowType = XInternAtom (display, "_NET_WM_WINDOW_TYPE", True); + WindowState = XInternAtom (display, "_NET_WM_WINDOW_STATE", True); - XdndAware = XInternAtom (display, "XdndAware", False); - XdndEnter = XInternAtom (display, "XdndEnter", False); - XdndLeave = XInternAtom (display, "XdndLeave", False); - XdndPosition = XInternAtom (display, "XdndPosition", False); - XdndStatus = XInternAtom (display, "XdndStatus", False); - XdndDrop = XInternAtom (display, "XdndDrop", False); - XdndFinished = XInternAtom (display, "XdndFinished", False); - XdndSelection = XInternAtom (display, "XdndSelection", False); + XdndAware = XInternAtom (display, "XdndAware", False); + XdndEnter = XInternAtom (display, "XdndEnter", False); + XdndLeave = XInternAtom (display, "XdndLeave", False); + XdndPosition = XInternAtom (display, "XdndPosition", False); + XdndStatus = XInternAtom (display, "XdndStatus", False); + XdndDrop = XInternAtom (display, "XdndDrop", False); + XdndFinished = XInternAtom (display, "XdndFinished", False); + XdndSelection = XInternAtom (display, "XdndSelection", False); - XdndTypeList = XInternAtom (display, "XdndTypeList", False); - XdndActionList = XInternAtom (display, "XdndActionList", False); - XdndActionCopy = XInternAtom (display, "XdndActionCopy", False); - XdndActionDescription = XInternAtom (display, "XdndActionDescription", False); + XdndTypeList = XInternAtom (display, "XdndTypeList", False); + XdndActionList = XInternAtom (display, "XdndActionList", False); + XdndActionCopy = XInternAtom (display, "XdndActionCopy", False); + XdndActionDescription = XInternAtom (display, "XdndActionDescription", False); - allowedMimeTypes [0] = XInternAtom (display, "text/plain", False); - allowedMimeTypes [1] = XInternAtom (display, "text/uri-list", False); + allowedMimeTypes[0] = XInternAtom (display, "text/plain", False); + allowedMimeTypes[1] = XInternAtom (display, "text/uri-list", False); - allowedActions [0] = XInternAtom (display, "XdndActionMove", False); - allowedActions [1] = XdndActionCopy; - allowedActions [2] = XInternAtom (display, "XdndActionLink", False); - allowedActions [3] = XInternAtom (display, "XdndActionAsk", False); - allowedActions [4] = XInternAtom (display, "XdndActionPrivate", False); + allowedActions[0] = XInternAtom (display, "XdndActionMove", False); + allowedActions[1] = XdndActionCopy; + allowedActions[2] = XInternAtom (display, "XdndActionLink", False); + allowedActions[3] = XInternAtom (display, "XdndActionAsk", False); + allowedActions[4] = XInternAtom (display, "XdndActionPrivate", False); } } } -enum SystemTrayValues -{ - SYSTEM_TRAY_REQUEST_DOCK = 0, - SYSTEM_TRAY_BEGIN_MESSAGE = 1, - SYSTEM_TRAY_CANCEL_MESSAGE = 2 -}; - -static XErrorHandler oldHandler = 0; -static int trappedErrorCode = 0; - -extern "C" int errorTrapHandler (Display* dpy, XErrorEvent* err) -{ - trappedErrorCode = err->error_code; - return 0; -} - -static void trapErrors() -{ - trappedErrorCode = 0; - oldHandler = XSetErrorHandler (errorTrapHandler); -} - -static bool untrapErrors() -{ - XSetErrorHandler (oldHandler); - return (trappedErrorCode == 0); -} - -static bool isActiveApplication = false; - -bool Process::isForegroundProcess() -{ - return isActiveApplication; -} - -// These are defined in juce_linux_Messaging.cpp -extern Display* display; -extern XContext improbableNumber; - -static const int eventMask = NoEventMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask - | EnterWindowMask | LeaveWindowMask | PointerMotionMask | KeymapStateMask - | ExposureMask | StructureNotifyMask | FocusChangeMask; - namespace Keys { enum MouseButtons @@ -231009,68 +230979,79 @@ bool KeyPress::isKeyCurrentlyDown (const int keyCode) throw() } #if JUCE_USE_XSHM -static bool isShmAvailable() throw() +namespace XSHMHelpers { - static bool isChecked = false; - static bool isAvailable = false; - - if (! isChecked) + static int trappedErrorCode = 0; + extern "C" int errorTrapHandler (Display*, XErrorEvent* err) { - isChecked = true; - - int major, minor; - Bool pixmaps; - - ScopedXLock xlock; - - if (XShmQueryVersion (display, &major, &minor, &pixmaps)) - { - trapErrors(); - - XShmSegmentInfo segmentInfo; - zerostruct (segmentInfo); - XImage* xImage = XShmCreateImage (display, DefaultVisual (display, DefaultScreen (display)), - 24, ZPixmap, 0, &segmentInfo, 50, 50); - - if ((segmentInfo.shmid = shmget (IPC_PRIVATE, - xImage->bytes_per_line * xImage->height, - IPC_CREAT | 0777)) >= 0) - { - segmentInfo.shmaddr = (char*) shmat (segmentInfo.shmid, 0, 0); - - if (segmentInfo.shmaddr != (void*) -1) - { - segmentInfo.readOnly = False; - xImage->data = segmentInfo.shmaddr; - XSync (display, False); - - if (XShmAttach (display, &segmentInfo) != 0) - { - XSync (display, False); - XShmDetach (display, &segmentInfo); - - isAvailable = true; - } - } - - XFlush (display); - XDestroyImage (xImage); - - shmdt (segmentInfo.shmaddr); - } - - shmctl (segmentInfo.shmid, IPC_RMID, 0); - - isAvailable &= untrapErrors(); - } + trappedErrorCode = err->error_code; + return 0; } - return isAvailable; + static bool isShmAvailable() throw() + { + static bool isChecked = false; + static bool isAvailable = false; + + if (! isChecked) + { + isChecked = true; + int major, minor; + Bool pixmaps; + + ScopedXLock xlock; + + if (XShmQueryVersion (display, &major, &minor, &pixmaps)) + { + trappedErrorCode = 0; + XErrorHandler oldHandler = XSetErrorHandler (errorTrapHandler); + + XShmSegmentInfo segmentInfo; + zerostruct (segmentInfo); + XImage* xImage = XShmCreateImage (display, DefaultVisual (display, DefaultScreen (display)), + 24, ZPixmap, 0, &segmentInfo, 50, 50); + + if ((segmentInfo.shmid = shmget (IPC_PRIVATE, + xImage->bytes_per_line * xImage->height, + IPC_CREAT | 0777)) >= 0) + { + segmentInfo.shmaddr = (char*) shmat (segmentInfo.shmid, 0, 0); + + if (segmentInfo.shmaddr != (void*) -1) + { + segmentInfo.readOnly = False; + xImage->data = segmentInfo.shmaddr; + XSync (display, False); + + if (XShmAttach (display, &segmentInfo) != 0) + { + XSync (display, False); + XShmDetach (display, &segmentInfo); + + isAvailable = true; + } + } + + XFlush (display); + XDestroyImage (xImage); + + shmdt (segmentInfo.shmaddr); + } + + shmctl (segmentInfo.shmid, IPC_RMID, 0); + + XSetErrorHandler (oldHandler); + if (trappedErrorCode != 0) + isAvailable = false; + } + } + + return isAvailable; + } } #endif #if JUCE_USE_XRENDER - namespace XRender { typedef Status (*tXRenderQueryVersion) (Display*, int*, int*); @@ -231085,26 +231066,21 @@ namespace XRender static bool isAvailable() { - static bool isChecked = false; - static bool isAvailable = false; + static bool hasLoaded = false; - if (! isChecked) + if (! hasLoaded) { ScopedXLock xlock; + hasLoaded = true; - isChecked = true; + void* h = dlopen ("libXrender.so", RTLD_GLOBAL | RTLD_NOW); - if (xRenderQueryVersion == 0) + if (h != 0) { - void* h = dlopen ("libXrender.so", RTLD_GLOBAL | RTLD_NOW); - - if (h != 0) - { - xRenderQueryVersion = (tXRenderQueryVersion) dlsym (h, "XRenderQueryVersion"); - xRenderFindStandardFormat = (tXrenderFindStandardFormat) dlsym (h, "XrenderFindStandardFormat"); - xRenderFindFormat = (tXRenderFindFormat) dlsym (h, "XRenderFindFormat"); - xRenderFindVisualFormat = (tXRenderFindVisualFormat) dlsym (h, "XRenderFindVisualFormat"); - } + xRenderQueryVersion = (tXRenderQueryVersion) dlsym (h, "XRenderQueryVersion"); + xRenderFindStandardFormat = (tXrenderFindStandardFormat) dlsym (h, "XrenderFindStandardFormat"); + xRenderFindFormat = (tXRenderFindFormat) dlsym (h, "XRenderFindFormat"); + xRenderFindVisualFormat = (tXRenderFindVisualFormat) dlsym (h, "XRenderFindVisualFormat"); } if (xRenderQueryVersion != 0 @@ -231114,11 +231090,13 @@ namespace XRender { int major, minor; if (xRenderQueryVersion (display, &major, &minor)) - isAvailable = true; + return true; } + + xRenderQueryVersion = 0; } - return isAvailable; + return xRenderQueryVersion != 0; } static XRenderPictFormat* findPictureFormat() @@ -231161,7 +231139,6 @@ namespace XRender return pictFormat; } } - #endif namespace Visuals @@ -231224,7 +231201,7 @@ namespace Visuals if (desiredDepth == 32) { #if JUCE_USE_XSHM - if (isShmAvailable()) + if (XSHMHelpers::isShmAvailable()) { #if JUCE_USE_XRENDER if (XRender::isAvailable()) @@ -231311,7 +231288,7 @@ public: #if JUCE_USE_XSHM usingXShm = false; - if ((imageDepth > 16) && isShmAvailable()) + if ((imageDepth > 16) && XSHMHelpers::isShmAvailable()) { zerostruct (segmentInfo); @@ -232579,7 +232556,7 @@ public: ev.xclient.message_type = XInternAtom (display, "_NET_SYSTEM_TRAY_OPCODE", False); ev.xclient.format = 32; ev.xclient.data.l[0] = CurrentTime; - ev.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK; + ev.xclient.data.l[1] = 0 /*SYSTEM_TRAY_REQUEST_DOCK*/; ev.xclient.data.l[2] = windowH; ev.xclient.data.l[3] = 0; ev.xclient.data.l[4] = 0; @@ -232613,6 +232590,7 @@ public: bool dontRepaint; static ModifierKeys currentModifiers; + static bool isActiveApplication; private: @@ -232626,7 +232604,7 @@ private: #if JUCE_USE_XSHM shmCompletedDrawing = true; - useARGBImagesForRendering = isShmAvailable(); + useARGBImagesForRendering = XSHMHelpers::isShmAvailable(); if (useARGBImagesForRendering) { @@ -233048,7 +233026,7 @@ private: swa.background_pixmap = None; swa.colormap = colormap; swa.override_redirect = getComponent()->isAlwaysOnTop() ? True : False; - swa.event_mask = eventMask; + swa.event_mask = getAllEventsMask(); Window wndH = XCreateWindow (display, root, 0, 0, 1, 1, @@ -233164,10 +233142,17 @@ private: XSync (display, false); XEvent event; - while (XCheckWindowEvent (display, windowH, eventMask, &event) == True) + while (XCheckWindowEvent (display, windowH, getAllEventsMask(), &event) == True) {} } + static int getAllEventsMask() throw() + { + return NoEventMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask + | EnterWindowMask | LeaveWindowMask | PointerMotionMask | KeymapStateMask + | ExposureMask | StructureNotifyMask | FocusChangeMask; + } + static int64 getEventTime (::Time t) { static int64 eventTimeOffset = 0x12345678; @@ -233512,9 +233497,15 @@ private: }; ModifierKeys LinuxComponentPeer::currentModifiers; +bool LinuxComponentPeer::isActiveApplication = false; int LinuxComponentPeer::pointerMap[5]; Point LinuxComponentPeer::lastMousePos; +bool Process::isForegroundProcess() +{ + return LinuxComponentPeer::isActiveApplication; +} + void ModifierKeys::updateCurrentModifiers() throw() { currentModifiers = LinuxComponentPeer::currentModifiers; @@ -233753,29 +233744,87 @@ bool Desktop::isScreenSaverEnabled() throw() void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hotspotY) throw() { ScopedXLock xlock; - Window root = RootWindow (display, DefaultScreen (display)); const unsigned int imageW = image.getWidth(); const unsigned int imageH = image.getHeight(); - unsigned int cursorW, cursorH; +#if JUCE_USE_XCURSOR + { + typedef XcursorBool (*tXcursorSupportsARGB) (Display*); + typedef XcursorImage* (*tXcursorImageCreate) (int, int); + typedef void (*tXcursorImageDestroy) (XcursorImage*); + typedef Cursor (*tXcursorImageLoadCursor) (Display*, const XcursorImage*); + + static tXcursorSupportsARGB xXcursorSupportsARGB = 0; + static tXcursorImageCreate xXcursorImageCreate = 0; + static tXcursorImageDestroy xXcursorImageDestroy = 0; + static tXcursorImageLoadCursor xXcursorImageLoadCursor = 0; + static bool hasBeenLoaded = false; + + if (! hasBeenLoaded) + { + hasBeenLoaded = true; + void* h = dlopen ("libXcursor.so", RTLD_GLOBAL | RTLD_NOW); + + if (h != 0) + { + xXcursorSupportsARGB = (tXcursorSupportsARGB) dlsym (h, "XcursorSupportsARGB"); + xXcursorImageCreate = (tXcursorImageCreate) dlsym (h, "XcursorImageCreate"); + xXcursorImageLoadCursor = (tXcursorImageLoadCursor) dlsym (h, "XcursorImageLoadCursor"); + xXcursorImageDestroy = (tXcursorImageDestroy) dlsym (h, "XcursorImageDestroy"); + + if (xXcursorSupportsARGB == 0 || xXcursorImageCreate == 0 + || xXcursorImageLoadCursor == 0 || xXcursorImageDestroy == 0 + || ! xXcursorSupportsARGB (display)) + xXcursorSupportsARGB = 0; + } + } + + if (xXcursorSupportsARGB != 0) + { + XcursorImage* xcImage = xXcursorImageCreate (imageW, imageH); + + if (xcImage != 0) + { + xcImage->xhot = hotspotX; + xcImage->yhot = hotspotY; + XcursorPixel* dest = xcImage->pixels; + + for (int y = 0; y < (int) imageH; ++y) + for (int x = 0; x < (int) imageW; ++x) + *dest++ = image.getPixelAt (x, y).getARGB(); + + void* result = (void*) xXcursorImageLoadCursor (display, xcImage); + xXcursorImageDestroy (xcImage); + + if (result != 0) + return result; + } + } + } +#endif + + Window root = RootWindow (display, DefaultScreen (display)); + unsigned int cursorW, cursorH; if (! XQueryBestCursor (display, root, imageW, imageH, &cursorW, &cursorH)) return 0; Image im (Image::ARGB, cursorW, cursorH, true); - Graphics g (im); - - if (imageW > cursorW || imageH > cursorH) { - hotspotX = (hotspotX * cursorW) / imageW; - hotspotY = (hotspotY * cursorH) / imageH; + Graphics g (im); - g.drawImageWithin (&image, 0, 0, imageW, imageH, - RectanglePlacement::xLeft | RectanglePlacement::yTop | RectanglePlacement::onlyReduceInSize, - false); - } - else - { - g.drawImageAt (&image, 0, 0); + if (imageW > cursorW || imageH > cursorH) + { + hotspotX = (hotspotX * cursorW) / imageW; + hotspotY = (hotspotY * cursorH) / imageH; + + g.drawImageWithin (&image, 0, 0, imageW, imageH, + RectanglePlacement::xLeft | RectanglePlacement::yTop | RectanglePlacement::onlyReduceInSize, + false); + } + else + { + g.drawImageAt (&image, 0, 0); + } } const int stride = (cursorW + 7) >> 3; @@ -233848,7 +233897,7 @@ void* juce_createStandardMouseCursor (MouseCursor::StandardCursorType type) thro 247,154,191,119,110,240,193,128,193,95,163,56,60,234,98,135,2,0,59 }; const int dragHandDataSize = 99; - const ScopedPointer im (ImageFileFormat::loadFrom ((const char*) dragHandData, dragHandDataSize)); + const ScopedPointer im (ImageFileFormat::loadFrom (dragHandData, dragHandDataSize)); return juce_createMouseCursorFromImage (*im, 8, 7); } @@ -233862,7 +233911,7 @@ void* juce_createStandardMouseCursor (MouseCursor::StandardCursorType type) thro 252,114,147,74,83,5,50,68,147,208,217,16,71,149,252,124,5,0,59,0,0 }; const int copyCursorSize = 119; - const ScopedPointer im (ImageFileFormat::loadFrom ((const char*) copyCursorData, copyCursorSize)); + const ScopedPointer im (ImageFileFormat::loadFrom (copyCursorData, copyCursorSize)); return juce_createMouseCursorFromImage (*im, 1, 3); } @@ -237917,7 +237966,7 @@ const File juce_getExecutableFile() { Dl_info exeInfo; dladdr ((const void*) juce_getExecutableFile, &exeInfo); - return File (String::fromUTF8 (exeInfo.dli_fname)); + return File::getCurrentWorkingDirectory().getChildFile (String::fromUTF8 (exeInfo.dli_fname)); } // if this file doesn't exist, find a parent of it that does.. diff --git a/juce_amalgamated.h b/juce_amalgamated.h index a800a46304..41b835b2be 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -264,6 +264,10 @@ //#define JUCE_USE_XRENDER 1 #endif +#ifndef JUCE_USE_XCURSOR + #define JUCE_USE_XCURSOR 1 +#endif + #ifndef JUCE_PLUGINHOST_VST // #define JUCE_PLUGINHOST_VST 1 #endif diff --git a/src/io/files/juce_File.cpp b/src/io/files/juce_File.cpp index 8f73efdb56..07f9955c4d 100644 --- a/src/io/files/juce_File.cpp +++ b/src/io/files/juce_File.cpp @@ -182,7 +182,7 @@ static const String parseAbsolutePath (String path) "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute path if that's what was supplied, or would evaluate a partial path relative to the CWD. */ - jassert (path.startsWith (T("./"))); // (assume that a path "./xyz" is deliberately intended to be relative to the CWD) + jassert (path.startsWith (T("./")) || path.startsWith (T("../"))); // (assume that a path "./xyz" is deliberately intended to be relative to the CWD) return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName(); } diff --git a/src/native/common/juce_posix_SharedCode.h b/src/native/common/juce_posix_SharedCode.h index c650398d4b..6e55b9bf6a 100644 --- a/src/native/common/juce_posix_SharedCode.h +++ b/src/native/common/juce_posix_SharedCode.h @@ -362,7 +362,7 @@ const File juce_getExecutableFile() { Dl_info exeInfo; dladdr ((const void*) juce_getExecutableFile, &exeInfo); - return File (String::fromUTF8 (exeInfo.dli_fname)); + return File::getCurrentWorkingDirectory().getChildFile (String::fromUTF8 (exeInfo.dli_fname)); } //============================================================================== diff --git a/src/native/linux/juce_linux_NativeIncludes.h b/src/native/linux/juce_linux_NativeIncludes.h index 3dee05039f..7386444772 100644 --- a/src/native/linux/juce_linux_NativeIncludes.h +++ b/src/native/linux/juce_linux_NativeIncludes.h @@ -91,6 +91,11 @@ #include #endif +#if JUCE_USE_XCURSOR + // If you're missing this header, try installing the libxcursor-dev package + #include +#endif + #if JUCE_OPENGL /* Got an include error here? diff --git a/src/native/linux/juce_linux_Windowing.cpp b/src/native/linux/juce_linux_Windowing.cpp index 5ce15f49fb..319250bd12 100644 --- a/src/native/linux/juce_linux_Windowing.cpp +++ b/src/native/linux/juce_linux_Windowing.cpp @@ -27,6 +27,11 @@ // compiled on its own). #if JUCE_INCLUDED_FILE +//============================================================================== +// These are defined in juce_linux_Messaging.cpp +extern Display* display; +extern XContext improbableNumber; + //============================================================================== namespace Atoms { @@ -55,89 +60,42 @@ namespace Atoms { atomsInitialised = true; - Protocols = XInternAtom (display, "WM_PROTOCOLS", True); - ProtocolList [TAKE_FOCUS] = XInternAtom (display, "WM_TAKE_FOCUS", True); - ProtocolList [DELETE_WINDOW] = XInternAtom (display, "WM_DELETE_WINDOW", True); - ChangeState = XInternAtom (display, "WM_CHANGE_STATE", True); - State = XInternAtom (display, "WM_STATE", True); - ActiveWin = XInternAtom (display, "_NET_ACTIVE_WINDOW", False); - Pid = XInternAtom (display, "_NET_WM_PID", False); - WindowType = XInternAtom (display, "_NET_WM_WINDOW_TYPE", True); - WindowState = XInternAtom (display, "_NET_WM_WINDOW_STATE", True); + Protocols = XInternAtom (display, "WM_PROTOCOLS", True); + ProtocolList [TAKE_FOCUS] = XInternAtom (display, "WM_TAKE_FOCUS", True); + ProtocolList [DELETE_WINDOW] = XInternAtom (display, "WM_DELETE_WINDOW", True); + ChangeState = XInternAtom (display, "WM_CHANGE_STATE", True); + State = XInternAtom (display, "WM_STATE", True); + ActiveWin = XInternAtom (display, "_NET_ACTIVE_WINDOW", False); + Pid = XInternAtom (display, "_NET_WM_PID", False); + WindowType = XInternAtom (display, "_NET_WM_WINDOW_TYPE", True); + WindowState = XInternAtom (display, "_NET_WM_WINDOW_STATE", True); - XdndAware = XInternAtom (display, "XdndAware", False); - XdndEnter = XInternAtom (display, "XdndEnter", False); - XdndLeave = XInternAtom (display, "XdndLeave", False); - XdndPosition = XInternAtom (display, "XdndPosition", False); - XdndStatus = XInternAtom (display, "XdndStatus", False); - XdndDrop = XInternAtom (display, "XdndDrop", False); - XdndFinished = XInternAtom (display, "XdndFinished", False); - XdndSelection = XInternAtom (display, "XdndSelection", False); + XdndAware = XInternAtom (display, "XdndAware", False); + XdndEnter = XInternAtom (display, "XdndEnter", False); + XdndLeave = XInternAtom (display, "XdndLeave", False); + XdndPosition = XInternAtom (display, "XdndPosition", False); + XdndStatus = XInternAtom (display, "XdndStatus", False); + XdndDrop = XInternAtom (display, "XdndDrop", False); + XdndFinished = XInternAtom (display, "XdndFinished", False); + XdndSelection = XInternAtom (display, "XdndSelection", False); - XdndTypeList = XInternAtom (display, "XdndTypeList", False); - XdndActionList = XInternAtom (display, "XdndActionList", False); - XdndActionCopy = XInternAtom (display, "XdndActionCopy", False); - XdndActionDescription = XInternAtom (display, "XdndActionDescription", False); + XdndTypeList = XInternAtom (display, "XdndTypeList", False); + XdndActionList = XInternAtom (display, "XdndActionList", False); + XdndActionCopy = XInternAtom (display, "XdndActionCopy", False); + XdndActionDescription = XInternAtom (display, "XdndActionDescription", False); - allowedMimeTypes [0] = XInternAtom (display, "text/plain", False); - allowedMimeTypes [1] = XInternAtom (display, "text/uri-list", False); + allowedMimeTypes[0] = XInternAtom (display, "text/plain", False); + allowedMimeTypes[1] = XInternAtom (display, "text/uri-list", False); - allowedActions [0] = XInternAtom (display, "XdndActionMove", False); - allowedActions [1] = XdndActionCopy; - allowedActions [2] = XInternAtom (display, "XdndActionLink", False); - allowedActions [3] = XInternAtom (display, "XdndActionAsk", False); - allowedActions [4] = XInternAtom (display, "XdndActionPrivate", False); + allowedActions[0] = XInternAtom (display, "XdndActionMove", False); + allowedActions[1] = XdndActionCopy; + allowedActions[2] = XInternAtom (display, "XdndActionLink", False); + allowedActions[3] = XInternAtom (display, "XdndActionAsk", False); + allowedActions[4] = XInternAtom (display, "XdndActionPrivate", False); } } } -//============================================================================== -enum SystemTrayValues -{ - SYSTEM_TRAY_REQUEST_DOCK = 0, - SYSTEM_TRAY_BEGIN_MESSAGE = 1, - SYSTEM_TRAY_CANCEL_MESSAGE = 2 -}; - -static XErrorHandler oldHandler = 0; -static int trappedErrorCode = 0; - -extern "C" int errorTrapHandler (Display* dpy, XErrorEvent* err) -{ - trappedErrorCode = err->error_code; - return 0; -} - -static void trapErrors() -{ - trappedErrorCode = 0; - oldHandler = XSetErrorHandler (errorTrapHandler); -} - -static bool untrapErrors() -{ - XSetErrorHandler (oldHandler); - return (trappedErrorCode == 0); -} - - -//============================================================================== -static bool isActiveApplication = false; - -bool Process::isForegroundProcess() -{ - return isActiveApplication; -} - -//============================================================================== -// These are defined in juce_linux_Messaging.cpp -extern Display* display; -extern XContext improbableNumber; - -static const int eventMask = NoEventMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask - | EnterWindowMask | LeaveWindowMask | PointerMotionMask | KeymapStateMask - | ExposureMask | StructureNotifyMask | FocusChangeMask; - //============================================================================== namespace Keys { @@ -191,69 +149,80 @@ bool KeyPress::isKeyCurrentlyDown (const int keyCode) throw() //============================================================================== #if JUCE_USE_XSHM -static bool isShmAvailable() throw() +namespace XSHMHelpers { - static bool isChecked = false; - static bool isAvailable = false; - - if (! isChecked) + static int trappedErrorCode = 0; + extern "C" int errorTrapHandler (Display*, XErrorEvent* err) { - isChecked = true; - - int major, minor; - Bool pixmaps; - - ScopedXLock xlock; - - if (XShmQueryVersion (display, &major, &minor, &pixmaps)) - { - trapErrors(); - - XShmSegmentInfo segmentInfo; - zerostruct (segmentInfo); - XImage* xImage = XShmCreateImage (display, DefaultVisual (display, DefaultScreen (display)), - 24, ZPixmap, 0, &segmentInfo, 50, 50); - - if ((segmentInfo.shmid = shmget (IPC_PRIVATE, - xImage->bytes_per_line * xImage->height, - IPC_CREAT | 0777)) >= 0) - { - segmentInfo.shmaddr = (char*) shmat (segmentInfo.shmid, 0, 0); - - if (segmentInfo.shmaddr != (void*) -1) - { - segmentInfo.readOnly = False; - xImage->data = segmentInfo.shmaddr; - XSync (display, False); - - if (XShmAttach (display, &segmentInfo) != 0) - { - XSync (display, False); - XShmDetach (display, &segmentInfo); - - isAvailable = true; - } - } - - XFlush (display); - XDestroyImage (xImage); - - shmdt (segmentInfo.shmaddr); - } - - shmctl (segmentInfo.shmid, IPC_RMID, 0); - - isAvailable &= untrapErrors(); - } + trappedErrorCode = err->error_code; + return 0; } - return isAvailable; + static bool isShmAvailable() throw() + { + static bool isChecked = false; + static bool isAvailable = false; + + if (! isChecked) + { + isChecked = true; + int major, minor; + Bool pixmaps; + + ScopedXLock xlock; + + if (XShmQueryVersion (display, &major, &minor, &pixmaps)) + { + trappedErrorCode = 0; + XErrorHandler oldHandler = XSetErrorHandler (errorTrapHandler); + + XShmSegmentInfo segmentInfo; + zerostruct (segmentInfo); + XImage* xImage = XShmCreateImage (display, DefaultVisual (display, DefaultScreen (display)), + 24, ZPixmap, 0, &segmentInfo, 50, 50); + + if ((segmentInfo.shmid = shmget (IPC_PRIVATE, + xImage->bytes_per_line * xImage->height, + IPC_CREAT | 0777)) >= 0) + { + segmentInfo.shmaddr = (char*) shmat (segmentInfo.shmid, 0, 0); + + if (segmentInfo.shmaddr != (void*) -1) + { + segmentInfo.readOnly = False; + xImage->data = segmentInfo.shmaddr; + XSync (display, False); + + if (XShmAttach (display, &segmentInfo) != 0) + { + XSync (display, False); + XShmDetach (display, &segmentInfo); + + isAvailable = true; + } + } + + XFlush (display); + XDestroyImage (xImage); + + shmdt (segmentInfo.shmaddr); + } + + shmctl (segmentInfo.shmid, IPC_RMID, 0); + + XSetErrorHandler (oldHandler); + if (trappedErrorCode != 0) + isAvailable = false; + } + } + + return isAvailable; + } } #endif //============================================================================== #if JUCE_USE_XRENDER - namespace XRender { typedef Status (*tXRenderQueryVersion) (Display*, int*, int*); @@ -268,26 +237,21 @@ namespace XRender static bool isAvailable() { - static bool isChecked = false; - static bool isAvailable = false; + static bool hasLoaded = false; - if (! isChecked) + if (! hasLoaded) { ScopedXLock xlock; + hasLoaded = true; - isChecked = true; + void* h = dlopen ("libXrender.so", RTLD_GLOBAL | RTLD_NOW); - if (xRenderQueryVersion == 0) + if (h != 0) { - void* h = dlopen ("libXrender.so", RTLD_GLOBAL | RTLD_NOW); - - if (h != 0) - { - xRenderQueryVersion = (tXRenderQueryVersion) dlsym (h, "XRenderQueryVersion"); - xRenderFindStandardFormat = (tXrenderFindStandardFormat) dlsym (h, "XrenderFindStandardFormat"); - xRenderFindFormat = (tXRenderFindFormat) dlsym (h, "XRenderFindFormat"); - xRenderFindVisualFormat = (tXRenderFindVisualFormat) dlsym (h, "XRenderFindVisualFormat"); - } + xRenderQueryVersion = (tXRenderQueryVersion) dlsym (h, "XRenderQueryVersion"); + xRenderFindStandardFormat = (tXrenderFindStandardFormat) dlsym (h, "XrenderFindStandardFormat"); + xRenderFindFormat = (tXRenderFindFormat) dlsym (h, "XRenderFindFormat"); + xRenderFindVisualFormat = (tXRenderFindVisualFormat) dlsym (h, "XRenderFindVisualFormat"); } if (xRenderQueryVersion != 0 @@ -297,11 +261,13 @@ namespace XRender { int major, minor; if (xRenderQueryVersion (display, &major, &minor)) - isAvailable = true; + return true; } + + xRenderQueryVersion = 0; } - return isAvailable; + return xRenderQueryVersion != 0; } static XRenderPictFormat* findPictureFormat() @@ -344,10 +310,8 @@ namespace XRender return pictFormat; } } - #endif - //============================================================================== namespace Visuals { @@ -409,7 +373,7 @@ namespace Visuals if (desiredDepth == 32) { #if JUCE_USE_XSHM - if (isShmAvailable()) + if (XSHMHelpers::isShmAvailable()) { #if JUCE_USE_XRENDER if (XRender::isAvailable()) @@ -497,7 +461,7 @@ public: #if JUCE_USE_XSHM usingXShm = false; - if ((imageDepth > 16) && isShmAvailable()) + if ((imageDepth > 16) && XSHMHelpers::isShmAvailable()) { zerostruct (segmentInfo); @@ -1771,7 +1735,7 @@ public: ev.xclient.message_type = XInternAtom (display, "_NET_SYSTEM_TRAY_OPCODE", False); ev.xclient.format = 32; ev.xclient.data.l[0] = CurrentTime; - ev.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK; + ev.xclient.data.l[1] = 0 /*SYSTEM_TRAY_REQUEST_DOCK*/; ev.xclient.data.l[2] = windowH; ev.xclient.data.l[3] = 0; ev.xclient.data.l[4] = 0; @@ -1806,6 +1770,7 @@ public: bool dontRepaint; static ModifierKeys currentModifiers; + static bool isActiveApplication; private: //============================================================================== @@ -1819,7 +1784,7 @@ private: #if JUCE_USE_XSHM shmCompletedDrawing = true; - useARGBImagesForRendering = isShmAvailable(); + useARGBImagesForRendering = XSHMHelpers::isShmAvailable(); if (useARGBImagesForRendering) { @@ -2247,7 +2212,7 @@ private: swa.background_pixmap = None; swa.colormap = colormap; swa.override_redirect = getComponent()->isAlwaysOnTop() ? True : False; - swa.event_mask = eventMask; + swa.event_mask = getAllEventsMask(); Window wndH = XCreateWindow (display, root, 0, 0, 1, 1, @@ -2363,10 +2328,17 @@ private: XSync (display, false); XEvent event; - while (XCheckWindowEvent (display, windowH, eventMask, &event) == True) + while (XCheckWindowEvent (display, windowH, getAllEventsMask(), &event) == True) {} } + static int getAllEventsMask() throw() + { + return NoEventMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask + | EnterWindowMask | LeaveWindowMask | PointerMotionMask | KeymapStateMask + | ExposureMask | StructureNotifyMask | FocusChangeMask; + } + static int64 getEventTime (::Time t) { static int64 eventTimeOffset = 0x12345678; @@ -2712,9 +2684,16 @@ private: }; ModifierKeys LinuxComponentPeer::currentModifiers; +bool LinuxComponentPeer::isActiveApplication = false; int LinuxComponentPeer::pointerMap[5]; Point LinuxComponentPeer::lastMousePos; +//============================================================================== +bool Process::isForegroundProcess() +{ + return LinuxComponentPeer::isActiveApplication; +} + //============================================================================== void ModifierKeys::updateCurrentModifiers() throw() { @@ -2964,29 +2943,87 @@ bool Desktop::isScreenSaverEnabled() throw() void* juce_createMouseCursorFromImage (const Image& image, int hotspotX, int hotspotY) throw() { ScopedXLock xlock; - Window root = RootWindow (display, DefaultScreen (display)); const unsigned int imageW = image.getWidth(); const unsigned int imageH = image.getHeight(); - unsigned int cursorW, cursorH; +#if JUCE_USE_XCURSOR + { + typedef XcursorBool (*tXcursorSupportsARGB) (Display*); + typedef XcursorImage* (*tXcursorImageCreate) (int, int); + typedef void (*tXcursorImageDestroy) (XcursorImage*); + typedef Cursor (*tXcursorImageLoadCursor) (Display*, const XcursorImage*); + + static tXcursorSupportsARGB xXcursorSupportsARGB = 0; + static tXcursorImageCreate xXcursorImageCreate = 0; + static tXcursorImageDestroy xXcursorImageDestroy = 0; + static tXcursorImageLoadCursor xXcursorImageLoadCursor = 0; + static bool hasBeenLoaded = false; + + if (! hasBeenLoaded) + { + hasBeenLoaded = true; + void* h = dlopen ("libXcursor.so", RTLD_GLOBAL | RTLD_NOW); + + if (h != 0) + { + xXcursorSupportsARGB = (tXcursorSupportsARGB) dlsym (h, "XcursorSupportsARGB"); + xXcursorImageCreate = (tXcursorImageCreate) dlsym (h, "XcursorImageCreate"); + xXcursorImageLoadCursor = (tXcursorImageLoadCursor) dlsym (h, "XcursorImageLoadCursor"); + xXcursorImageDestroy = (tXcursorImageDestroy) dlsym (h, "XcursorImageDestroy"); + + if (xXcursorSupportsARGB == 0 || xXcursorImageCreate == 0 + || xXcursorImageLoadCursor == 0 || xXcursorImageDestroy == 0 + || ! xXcursorSupportsARGB (display)) + xXcursorSupportsARGB = 0; + } + } + + if (xXcursorSupportsARGB != 0) + { + XcursorImage* xcImage = xXcursorImageCreate (imageW, imageH); + + if (xcImage != 0) + { + xcImage->xhot = hotspotX; + xcImage->yhot = hotspotY; + XcursorPixel* dest = xcImage->pixels; + + for (int y = 0; y < (int) imageH; ++y) + for (int x = 0; x < (int) imageW; ++x) + *dest++ = image.getPixelAt (x, y).getARGB(); + + void* result = (void*) xXcursorImageLoadCursor (display, xcImage); + xXcursorImageDestroy (xcImage); + + if (result != 0) + return result; + } + } + } +#endif + + Window root = RootWindow (display, DefaultScreen (display)); + unsigned int cursorW, cursorH; if (! XQueryBestCursor (display, root, imageW, imageH, &cursorW, &cursorH)) return 0; Image im (Image::ARGB, cursorW, cursorH, true); - Graphics g (im); - - if (imageW > cursorW || imageH > cursorH) { - hotspotX = (hotspotX * cursorW) / imageW; - hotspotY = (hotspotY * cursorH) / imageH; + Graphics g (im); - g.drawImageWithin (&image, 0, 0, imageW, imageH, - RectanglePlacement::xLeft | RectanglePlacement::yTop | RectanglePlacement::onlyReduceInSize, - false); - } - else - { - g.drawImageAt (&image, 0, 0); + if (imageW > cursorW || imageH > cursorH) + { + hotspotX = (hotspotX * cursorW) / imageW; + hotspotY = (hotspotY * cursorH) / imageH; + + g.drawImageWithin (&image, 0, 0, imageW, imageH, + RectanglePlacement::xLeft | RectanglePlacement::yTop | RectanglePlacement::onlyReduceInSize, + false); + } + else + { + g.drawImageAt (&image, 0, 0); + } } const int stride = (cursorW + 7) >> 3; @@ -3059,7 +3096,7 @@ void* juce_createStandardMouseCursor (MouseCursor::StandardCursorType type) thro 247,154,191,119,110,240,193,128,193,95,163,56,60,234,98,135,2,0,59 }; const int dragHandDataSize = 99; - const ScopedPointer im (ImageFileFormat::loadFrom ((const char*) dragHandData, dragHandDataSize)); + const ScopedPointer im (ImageFileFormat::loadFrom (dragHandData, dragHandDataSize)); return juce_createMouseCursorFromImage (*im, 8, 7); } @@ -3073,7 +3110,7 @@ void* juce_createStandardMouseCursor (MouseCursor::StandardCursorType type) thro 252,114,147,74,83,5,50,68,147,208,217,16,71,149,252,124,5,0,59,0,0 }; const int copyCursorSize = 119; - const ScopedPointer im (ImageFileFormat::loadFrom ((const char*) copyCursorData, copyCursorSize)); + const ScopedPointer im (ImageFileFormat::loadFrom (copyCursorData, copyCursorSize)); return juce_createMouseCursorFromImage (*im, 1, 3); }