diff --git a/extras/Introjucer/Source/Utility/jucer_RelativePath.h b/extras/Introjucer/Source/Utility/jucer_RelativePath.h index fca49da2bb..a40481519e 100644 --- a/extras/Introjucer/Source/Utility/jucer_RelativePath.h +++ b/extras/Introjucer/Source/Utility/jucer_RelativePath.h @@ -116,9 +116,11 @@ private: static bool isAbsolute (const String& path) { return File::isAbsolutePath (path) + || path.startsWithChar ('/') // (needed because File::isAbsolutePath will ignore forward-slashes on win32) || path.startsWithChar ('$') || path.startsWithChar ('~') - || (CharacterFunctions::isLetter (path[0]) && path[1] == ':'); + || (CharacterFunctions::isLetter (path[0]) && path[1] == ':') + || path.startsWithIgnoreCase ("smb:"); } }; diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index db0ea0793f..0233e54e29 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -71803,7 +71803,7 @@ int PopupMenu::getNumItems() const noexcept int num = 0; for (int i = items.size(); --i >= 0;) - if (! (items.getUnchecked(i))->isSeparator) + if (! items.getUnchecked(i)->isSeparator) ++num; return num; @@ -246395,41 +246395,44 @@ void MessageManager::doPlatformSpecificShutdown() // compiled on its own). #if JUCE_INCLUDED_FILE -static int CALLBACK wfontEnum2 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) +namespace FontEnumerators { - if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) + int CALLBACK fontEnum2 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) { - const String fontName (lpelfe->elfLogFont.lfFaceName); + if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) + { + const String fontName (lpelfe->elfLogFont.lfFaceName); - ((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters ("@")); - } + ((StringArray*) lParam)->addIfNotAlreadyThere (fontName.removeCharacters ("@")); + } - return 1; -} + return 1; + } -static int CALLBACK wfontEnum1 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) -{ - if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) + int CALLBACK fontEnum1 (ENUMLOGFONTEXW* lpelfe, NEWTEXTMETRICEXW*, int type, LPARAM lParam) { - LOGFONTW lf = { 0 }; - lf.lfWeight = FW_DONTCARE; - lf.lfOutPrecision = OUT_OUTLINE_PRECIS; - lf.lfQuality = DEFAULT_QUALITY; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf.lfPitchAndFamily = FF_DONTCARE; + if (lpelfe != nullptr && (type & RASTER_FONTTYPE) == 0) + { + LOGFONTW lf = { 0 }; + lf.lfWeight = FW_DONTCARE; + lf.lfOutPrecision = OUT_OUTLINE_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfPitchAndFamily = FF_DONTCARE; - const String fontName (lpelfe->elfLogFont.lfFaceName); - fontName.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); + const String fontName (lpelfe->elfLogFont.lfFaceName); + fontName.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); - HDC dc = CreateCompatibleDC (0); - EnumFontFamiliesEx (dc, &lf, - (FONTENUMPROCW) &wfontEnum2, - lParam, 0); - DeleteDC (dc); - } + HDC dc = CreateCompatibleDC (0); + EnumFontFamiliesEx (dc, &lf, + (FONTENUMPROCW) &fontEnum2, + lParam, 0); + DeleteDC (dc); + } - return 1; + return 1; + } } StringArray Font::findAllTypefaceNames() @@ -246447,7 +246450,7 @@ StringArray Font::findAllTypefaceNames() lf.lfPitchAndFamily = FF_DONTCARE; EnumFontFamiliesEx (dc, &lf, - (FONTENUMPROCW) &wfontEnum1, + (FONTENUMPROCW) &FontEnumerators::fontEnum1, (LPARAM) &results, 0); } @@ -246477,123 +246480,21 @@ void Font::getPlatformDefaultFontNames (String& defaultSans, String& defaultSeri } } -class FontDCHolder : private DeletedAtShutdown -{ -public: - - FontDCHolder() - : fontH (0), previousFontH (0), dc (0), numKPs (0), size (0), - bold (false), italic (false) - { - } - - ~FontDCHolder() - { - deleteDCAndFont(); - clearSingletonInstance(); - } - - juce_DeclareSingleton_SingleThreaded_Minimal (FontDCHolder); - - HDC loadFont (const String& fontName_, const bool bold_, const bool italic_, const int size_) - { - if (fontName != fontName_ || bold != bold_ || italic != italic_ || size != size_) - { - fontName = fontName_; - bold = bold_; - italic = italic_; - size = size_; - - deleteDCAndFont(); - - dc = CreateCompatibleDC (0); - SetMapperFlags (dc, 0); - SetMapMode (dc, MM_TEXT); - - LOGFONTW lf = { 0 }; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - lf.lfOutPrecision = OUT_OUTLINE_PRECIS; - lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - lf.lfQuality = PROOF_QUALITY; - lf.lfItalic = (BYTE) (italic ? TRUE : FALSE); - lf.lfWeight = bold ? FW_BOLD : FW_NORMAL; - lf.lfHeight = size > 0 ? size : -256; - fontName.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); - - HFONT standardSizedFont = CreateFontIndirect (&lf); - - if (standardSizedFont != 0) - { - if ((previousFontH = SelectObject (dc, standardSizedFont)) != 0) - { - fontH = standardSizedFont; - - if (size == 0) - { - OUTLINETEXTMETRIC otm; - if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0) - { - lf.lfHeight = -(int) otm.otmEMSquare; - fontH = CreateFontIndirect (&lf); - - SelectObject (dc, fontH); - DeleteObject (standardSizedFont); - } - } - } - } - } - - return dc; - } - -private: - - HFONT fontH; - HGDIOBJ previousFontH; - HDC dc; - String fontName; - HeapBlock kps; - int numKPs, size; - bool bold, italic; - - void deleteDCAndFont() - { - if (dc != 0) - { - SelectObject (dc, previousFontH); // Replacing the previous font before deleting the DC avoids a warning in BoundsChecker - DeleteDC (dc); - dc = 0; - } - - if (fontH != 0) - { - DeleteObject (fontH); - fontH = 0; - } - - kps.free(); - } - - JUCE_DECLARE_NON_COPYABLE (FontDCHolder); -}; - -juce_ImplementSingleton_SingleThreaded (FontDCHolder); - class WindowsTypeface : public Typeface { public: WindowsTypeface (const Font& font) : Typeface (font.getTypefaceName()), + fontH (0), + previousFontH (0), + dc (CreateCompatibleDC (0)), ascent (1.0f), defaultGlyph (-1), bold (font.isBold()), italic (font.isItalic()) { - HDC dc = getDC(); + loadFont(); - TEXTMETRIC tm; if (GetTextMetrics (dc, &tm)) { ascent = tm.tmAscent / (float) tm.tmHeight; @@ -246602,12 +246503,20 @@ public: } } + ~WindowsTypeface() + { + SelectObject (dc, previousFontH); // Replacing the previous font before deleting the DC avoids a warning in BoundsChecker + DeleteDC (dc); + + if (fontH != 0) + DeleteObject (fontH); + } + float getAscent() const { return ascent; } float getDescent() const { return 1.0f - ascent; } float getStringWidth (const String& text) { - HDC dc = getDC(); const CharPointer_UTF16 utf16 (text.toUTF16()); const int numChars = utf16.length(); HeapBlock results (numChars + 1); @@ -246626,7 +246535,6 @@ public: void getGlyphPositions (const String& text, Array & resultGlyphs, Array & xOffsets) { - HDC dc = getDC(); const CharPointer_UTF16 utf16 (text.toUTF16()); const int numChars = utf16.length(); HeapBlock results (numChars + 1); @@ -246652,12 +246560,6 @@ public: bool getOutlineForGlyph (int glyphNumber, Path& glyphPath) { - HDC dc = getDC(); - - TEXTMETRIC tm; - if (! GetTextMetrics (dc, &tm)) - return false; - if (glyphNumber < 0) glyphNumber = defaultGlyph; @@ -246673,16 +246575,13 @@ public: const TTPOLYGONHEADER* pheader = reinterpret_cast (data.getData()); - const float height = (float) tm.tmHeight; - const float scaleX = 1.0f / height; - const float scaleY = -1.0f / height; + const float scaleX = 1.0f / tm.tmHeight; + const float scaleY = -scaleX; while ((char*) pheader < data + bufSize) { - float x = scaleX * pheader->pfxStart.x.value; - float y = scaleY * pheader->pfxStart.y.value; - - glyphPath.startNewSubPath (x, y); + glyphPath.startNewSubPath (scaleX * pheader->pfxStart.x.value, + scaleY * pheader->pfxStart.y.value); const TTPOLYCURVE* curve = (const TTPOLYCURVE*) ((const char*) pheader + sizeof (TTPOLYGONHEADER)); const char* const curveEnd = ((const char*) pheader) + pheader->cb; @@ -246692,12 +246591,8 @@ public: if (curve->wType == TT_PRIM_LINE) { for (int i = 0; i < curve->cpfx; ++i) - { - x = scaleX * curve->apfx[i].x.value; - y = scaleY * curve->apfx[i].y.value; - - glyphPath.lineTo (x, y); - } + glyphPath.lineTo (scaleX * curve->apfx[i].x.value, + scaleY * curve->apfx[i].y.value); } else if (curve->wType == TT_PRIM_QSPLINE) { @@ -246705,23 +246600,16 @@ public: { const float x2 = scaleX * curve->apfx[i].x.value; const float y2 = scaleY * curve->apfx[i].y.value; - float x3, y3; + float x3 = scaleX * curve->apfx[i + 1].x.value; + float y3 = scaleY * curve->apfx[i + 1].y.value; if (i < curve->cpfx - 2) { - x3 = 0.5f * (x2 + scaleX * curve->apfx[i + 1].x.value); - y3 = 0.5f * (y2 + scaleY * curve->apfx[i + 1].y.value); - } - else - { - x3 = scaleX * curve->apfx[i + 1].x.value; - y3 = scaleY * curve->apfx[i + 1].y.value; + x3 = 0.5f * (x2 + x3); + y3 = 0.5f * (y2 + y3); } glyphPath.quadraticTo (x2, y2, x3, y3); - - x = x3; - y = y3; } } @@ -246739,6 +246627,10 @@ public: private: static const MAT2 identityMatrix; + HFONT fontH; + HGDIOBJ previousFontH; + HDC dc; + TEXTMETRIC tm; float ascent; int defaultGlyph; bool bold, italic; @@ -246762,6 +246654,43 @@ private: SortedSet kerningPairs; + void loadFont() + { + SetMapperFlags (dc, 0); + SetMapMode (dc, MM_TEXT); + + LOGFONTW lf = { 0 }; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfOutPrecision = OUT_OUTLINE_PRECIS; + lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + lf.lfQuality = PROOF_QUALITY; + lf.lfItalic = (BYTE) (italic ? TRUE : FALSE); + lf.lfWeight = bold ? FW_BOLD : FW_NORMAL; + lf.lfHeight = -256; + name.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); + + HFONT standardSizedFont = CreateFontIndirect (&lf); + + if (standardSizedFont != 0) + { + if ((previousFontH = SelectObject (dc, standardSizedFont)) != 0) + { + fontH = standardSizedFont; + + OUTLINETEXTMETRIC otm; + if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0) + { + lf.lfHeight = -(int) otm.otmEMSquare; + fontH = CreateFontIndirect (&lf); + + SelectObject (dc, fontH); + DeleteObject (standardSizedFont); + } + } + } + } + void createKerningPairs (HDC dc, const float height) { HeapBlock rawKerning; @@ -246821,10 +246750,6 @@ private: if (index < 0) { - TEXTMETRIC tm; - if (! GetTextMetrics (dc, &tm)) - return 0; - kp.glyph2 = -1; kp.kerning = getGlyphWidth (dc, kp.glyph1) / (float) tm.tmHeight; kerningPairs.add (kp); @@ -246835,11 +246760,6 @@ private: return kerningPairs.getReference (index).kerning; } - HDC getDC() const - { - return FontDCHolder::getInstance()->loadFont (name, bold, italic, 0); - } - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsTypeface); }; @@ -248357,7 +248277,7 @@ public: { setMinimised (false); - if (fullScreen != shouldBeFullScreen) + if (isFullScreen() != shouldBeFullScreen) { fullScreen = shouldBeFullScreen; const WeakReference deletionChecker (component); @@ -281766,10 +281686,7 @@ public: [menu setAutoenablesItems: false]; [menu update]; [parentItem setTag: tag]; - - if (! [[parentItem submenu] equals: menu]) // NB this comparison is needed to avoid a strange - [parentItem setSubmenu: menu]; // crash deep inside Apple code when no windows are focused.. - + [parentItem setSubmenu: menu]; [menu release]; } @@ -281817,7 +281734,7 @@ public: } if (Time::getMillisecondCounter() > lastUpdateTime + 500) - menuBarItemsChanged (nullptr); + (new AsyncMenuUpdater())->post(); } void invoke (const int commandId, ApplicationCommandManager* const commandManager, const int topLevelIndex) const @@ -282003,6 +281920,21 @@ private: if (mods.isCommandDown()) m |= NSCommandKeyMask; return m; } + + class AsyncMenuUpdater : public CallbackMessage + { + public: + AsyncMenuUpdater() {} + + void messageCallback() + { + if (JuceMainMenuHandler::instance != nullptr) + JuceMainMenuHandler::instance->menuBarItemsChanged (nullptr); + } + + private: + JUCE_DECLARE_NON_COPYABLE (AsyncMenuUpdater); + }; }; JuceMainMenuHandler* JuceMainMenuHandler::instance = nullptr; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 8bcfd17a42..85f5794a2a 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -43845,8 +43845,7 @@ public: zero, because that's used to indicate that the user didn't select anything. @param itemText the text to show. - @param isActive if false, the item will be shown 'greyed-out' and can't be - picked + @param isEnabled if false, the item will be shown 'greyed-out' and can't be picked @param isTicked if true, the item will be shown with a tick next to it @param iconToUse if this is non-zero, it should be an image that will be displayed to the left of the item. This method will take its @@ -43857,7 +43856,7 @@ public: */ void addItem (int itemResultId, const String& itemText, - bool isActive = true, + bool isEnabled = true, bool isTicked = false, const Image& iconToUse = Image::null); @@ -43882,7 +43881,7 @@ public: void addColouredItem (int itemResultId, const String& itemText, const Colour& itemTextColour, - bool isActive = true, + bool isEnabled = true, bool isTicked = false, const Image& iconToUse = Image::null); @@ -43912,7 +43911,7 @@ public: */ void addSubMenu (const String& subMenuName, const PopupMenu& subMenu, - bool isActive = true, + bool isEnabled = true, const Image& iconToUse = Image::null, bool isTicked = false); diff --git a/src/gui/components/menus/juce_PopupMenu.cpp b/src/gui/components/menus/juce_PopupMenu.cpp index c5385e5669..595005d861 100644 --- a/src/gui/components/menus/juce_PopupMenu.cpp +++ b/src/gui/components/menus/juce_PopupMenu.cpp @@ -1608,7 +1608,7 @@ int PopupMenu::getNumItems() const noexcept int num = 0; for (int i = items.size(); --i >= 0;) - if (! (items.getUnchecked(i))->isSeparator) + if (! items.getUnchecked(i)->isSeparator) ++num; return num; diff --git a/src/gui/components/menus/juce_PopupMenu.h b/src/gui/components/menus/juce_PopupMenu.h index e7c4b40d46..a28f3b2021 100644 --- a/src/gui/components/menus/juce_PopupMenu.h +++ b/src/gui/components/menus/juce_PopupMenu.h @@ -105,8 +105,7 @@ public: zero, because that's used to indicate that the user didn't select anything. @param itemText the text to show. - @param isActive if false, the item will be shown 'greyed-out' and can't be - picked + @param isEnabled if false, the item will be shown 'greyed-out' and can't be picked @param isTicked if true, the item will be shown with a tick next to it @param iconToUse if this is non-zero, it should be an image that will be displayed to the left of the item. This method will take its @@ -117,7 +116,7 @@ public: */ void addItem (int itemResultId, const String& itemText, - bool isActive = true, + bool isEnabled = true, bool isTicked = false, const Image& iconToUse = Image::null); @@ -143,7 +142,7 @@ public: void addColouredItem (int itemResultId, const String& itemText, const Colour& itemTextColour, - bool isActive = true, + bool isEnabled = true, bool isTicked = false, const Image& iconToUse = Image::null); @@ -173,7 +172,7 @@ public: */ void addSubMenu (const String& subMenuName, const PopupMenu& subMenu, - bool isActive = true, + bool isEnabled = true, const Image& iconToUse = Image::null, bool isTicked = false); diff --git a/src/native/mac/juce_mac_MainMenu.mm b/src/native/mac/juce_mac_MainMenu.mm index 362f47d3d2..f24e14090f 100644 --- a/src/native/mac/juce_mac_MainMenu.mm +++ b/src/native/mac/juce_mac_MainMenu.mm @@ -121,10 +121,7 @@ public: [menu setAutoenablesItems: false]; [menu update]; [parentItem setTag: tag]; - - if (! [[parentItem submenu] equals: menu]) // NB this comparison is needed to avoid a strange - [parentItem setSubmenu: menu]; // crash deep inside Apple code when no windows are focused.. - + [parentItem setSubmenu: menu]; [menu release]; } @@ -172,7 +169,7 @@ public: } if (Time::getMillisecondCounter() > lastUpdateTime + 500) - menuBarItemsChanged (nullptr); + (new AsyncMenuUpdater())->post(); } void invoke (const int commandId, ApplicationCommandManager* const commandManager, const int topLevelIndex) const @@ -358,6 +355,21 @@ private: if (mods.isCommandDown()) m |= NSCommandKeyMask; return m; } + + class AsyncMenuUpdater : public CallbackMessage + { + public: + AsyncMenuUpdater() {} + + void messageCallback() + { + if (JuceMainMenuHandler::instance != nullptr) + JuceMainMenuHandler::instance->menuBarItemsChanged (nullptr); + } + + private: + JUCE_DECLARE_NON_COPYABLE (AsyncMenuUpdater); + }; }; JuceMainMenuHandler* JuceMainMenuHandler::instance = nullptr; diff --git a/src/native/windows/juce_win32_Windowing.cpp b/src/native/windows/juce_win32_Windowing.cpp index 2c16e7ec4b..04e401b278 100644 --- a/src/native/windows/juce_win32_Windowing.cpp +++ b/src/native/windows/juce_win32_Windowing.cpp @@ -648,7 +648,7 @@ public: { setMinimised (false); - if (fullScreen != shouldBeFullScreen) + if (isFullScreen() != shouldBeFullScreen) { fullScreen = shouldBeFullScreen; const WeakReference deletionChecker (component);