From b3634661e6ec840889769d9d7d325de84598729f Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Thu, 26 May 2011 20:00:07 +0100 Subject: [PATCH] Fix for subtle OSX main menu key focus problem. Minor clean-ups. --- .../the jucer/build/linux/jucer_premake.lua | 4 +- extras/the jucer/src/ui/jucer_MainWindow.cpp | 4 - .../src/utility/jucer_ColourEditorComponent.h | 43 ++- juce_amalgamated.cpp | 245 +++++++----------- juce_amalgamated.h | 5 +- src/core/juce_StandardHeader.h | 2 +- src/gui/components/controls/juce_ListBox.h | 3 +- .../windows/juce_DocumentWindow.cpp | 26 +- .../image_file_formats/juce_GIFLoader.cpp | 170 +++++------- src/native/mac/juce_mac_MainMenu.mm | 49 ++-- 10 files changed, 215 insertions(+), 336 deletions(-) diff --git a/extras/the jucer/build/linux/jucer_premake.lua b/extras/the jucer/build/linux/jucer_premake.lua index 09ef281d4c..9de9ea4ea2 100644 --- a/extras/the jucer/build/linux/jucer_premake.lua +++ b/extras/the jucer/build/linux/jucer_premake.lua @@ -32,11 +32,11 @@ package.libpaths = { } package.config["Debug"].links = { - "freetype", "pthread", "X11", "GL", "GLU", "Xinerama", "asound" + "freetype", "pthread", "X11", "GL", "GLU", "Xinerama", "asound", "dl", "Xext" } package.config["Release"].links = { - "freetype", "pthread", "X11", "GL", "GLU", "Xinerama", "asound" + "freetype", "pthread", "X11", "GL", "GLU", "Xinerama", "asound", "dl", "Xext" } package.linkflags = { "static-runtime" } diff --git a/extras/the jucer/src/ui/jucer_MainWindow.cpp b/extras/the jucer/src/ui/jucer_MainWindow.cpp index 9c8b779ea8..8fd90cdeb8 100644 --- a/extras/the jucer/src/ui/jucer_MainWindow.cpp +++ b/extras/the jucer/src/ui/jucer_MainWindow.cpp @@ -45,10 +45,6 @@ public: setBackgroundColour (Colour (0xffe6f0ff)); } - ~MultiDocHolder() - { - } - bool tryToCloseDocument (Component* component) { JucerDocumentHolder* const holder = dynamic_cast (component); diff --git a/extras/the jucer/src/utility/jucer_ColourEditorComponent.h b/extras/the jucer/src/utility/jucer_ColourEditorComponent.h index 7b8daa0bc1..4d14733380 100644 --- a/extras/the jucer/src/utility/jucer_ColourEditorComponent.h +++ b/extras/the jucer/src/utility/jucer_ColourEditorComponent.h @@ -41,10 +41,6 @@ public: { } - ~ColourEditorComponent() - { - } - void paint (Graphics& g) { g.fillAll (Colours::grey); @@ -104,36 +100,31 @@ private: ColourSelectorComp (ColourEditorComponent* owner_, const bool canResetToDefault) : owner (owner_), - defaultButton (0) + defaultButton ("Reset to Default") { - addAndMakeVisible (selector = new ColourSelectorWithSwatches()); - selector->setName ("Colour"); - selector->setCurrentColour (owner->getColour()); - selector->addChangeListener (owner); + addAndMakeVisible (&selector); + selector.setName ("Colour"); + selector.setCurrentColour (owner->getColour()); + selector.addChangeListener (owner); if (canResetToDefault) { - addAndMakeVisible (defaultButton = new TextButton ("Reset to Default")); - defaultButton->addListener (this); + addAndMakeVisible (&defaultButton); + defaultButton.addListener (this); } } - ~ColourSelectorComp() - { - deleteAllChildren(); - } - void resized() { - if (defaultButton != 0) + if (defaultButton.isVisible()) { - selector->setBounds (0, 0, getWidth(), getHeight() - 30); - defaultButton->changeWidthToFitText (22); - defaultButton->setTopLeftPosition (10, getHeight() - 26); + selector.setBounds (0, 0, getWidth(), getHeight() - 30); + defaultButton.changeWidthToFitText (22); + defaultButton.setTopLeftPosition (10, getHeight() - 26); } else { - selector->setBounds (0, 0, getWidth(), getHeight()); + selector.setBounds (0, 0, getWidth(), getHeight()); } } @@ -141,7 +132,7 @@ private: { owner->resetToDefault(); owner->refresh(); - selector->setCurrentColour (owner->getColour()); + selector.setCurrentColour (owner->getColour()); } private: @@ -152,10 +143,6 @@ private: { } - ~ColourSelectorWithSwatches() - { - } - int getNumSwatches() const { return StoredSettings::getInstance()->swatchColours.size(); @@ -173,8 +160,8 @@ private: }; ColourEditorComponent* owner; - ColourSelectorWithSwatches* selector; - TextButton* defaultButton; + ColourSelectorWithSwatches selector; + TextButton defaultButton; }; }; diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 5cee6ff831..a667dc549a 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -79231,12 +79231,9 @@ public: void buttonClicked (Button* button) { - if (button == owner.getMinimiseButton()) - owner.minimiseButtonPressed(); - else if (button == owner.getMaximiseButton()) - owner.maximiseButtonPressed(); - else if (button == owner.getCloseButton()) - owner.closeButtonPressed(); + if (button == owner.getMinimiseButton()) owner.minimiseButtonPressed(); + else if (button == owner.getMaximiseButton()) owner.maximiseButtonPressed(); + else if (button == owner.getCloseButton()) owner.closeButtonPressed(); } private: @@ -79490,14 +79487,9 @@ int DocumentWindow::getDesktopWindowStyleFlags() const { int styleFlags = ResizableWindow::getDesktopWindowStyleFlags(); - if ((requiredButtons & minimiseButton) != 0) - styleFlags |= ComponentPeer::windowHasMinimiseButton; - - if ((requiredButtons & maximiseButton) != 0) - styleFlags |= ComponentPeer::windowHasMaximiseButton; - - if ((requiredButtons & closeButton) != 0) - styleFlags |= ComponentPeer::windowHasCloseButton; + if ((requiredButtons & minimiseButton) != 0) styleFlags |= ComponentPeer::windowHasMinimiseButton; + if ((requiredButtons & maximiseButton) != 0) styleFlags |= ComponentPeer::windowHasMaximiseButton; + if ((requiredButtons & closeButton) != 0) styleFlags |= ComponentPeer::windowHasCloseButton; return styleFlags; } @@ -79538,11 +79530,11 @@ void DocumentWindow::lookAndFeelChanged() if (getCloseButton() != nullptr) { - #if JUCE_MAC + #if JUCE_MAC getCloseButton()->addShortcut (KeyPress ('w', ModifierKeys::commandModifier, 0)); - #else + #else getCloseButton()->addShortcut (KeyPress (KeyPress::F4Key, ModifierKeys::altModifier, 0)); - #endif + #endif } } @@ -97804,22 +97796,19 @@ public: : input (in), dataBlockIsZero (false), fresh (false), finished (false), currentBit (0), lastBit (0), lastByteIndex (0), - codeSize (0), setCodeSize (0), - maxCode (0), maxCodeSize (0), + codeSize (0), setCodeSize (0), maxCode (0), maxCodeSize (0), firstcode (0), oldcode (0), clearCode (0), endCode (0) { int imageWidth, imageHeight; - int transparent = -1; - - if (! (getSizeFromHeader (imageWidth, imageHeight) - && imageWidth > 0 && imageHeight > 0)) + if (! getSizeFromHeader (imageWidth, imageHeight)) return; - unsigned char buf [16]; + uint8 buf [16]; if (in.read (buf, 3) != 3) return; int numColours = 2 << (buf[0] & 7); + int transparent = -1; if ((buf[0] & 0x80) != 0) readPalette (numColours); @@ -97831,36 +97820,33 @@ public: if (buf[0] == '!') { - if (input.read (buf, 1) != 1) - break; - - if (processExtension (buf[0], transparent) < 0) - break; + if (readExtension (transparent)) + continue; - continue; + break; } if (buf[0] != ',') continue; - if (input.read (buf, 9) != 9) - break; - - imageWidth = makeWord (buf[4], buf[5]); - imageHeight = makeWord (buf[6], buf[7]); + if (input.read (buf, 9) == 9) + { + imageWidth = makeWord (buf[4], buf[5]); + imageHeight = makeWord (buf[6], buf[7]); - numColours = 2 << (buf[8] & 7); + numColours = 2 << (buf[8] & 7); - if ((buf[8] & 0x80) != 0) - if (! readPalette (numColours)) - break; + if ((buf[8] & 0x80) != 0) + if (! readPalette (numColours)) + break; - image = Image ((transparent >= 0) ? Image::ARGB : Image::RGB, - imageWidth, imageHeight, (transparent >= 0)); + image = Image (transparent >= 0 ? Image::ARGB : Image::RGB, + imageWidth, imageHeight, transparent >= 0); - image.getProperties()->set ("originalImageHadAlpha", image.hasAlphaChannel()); + image.getProperties()->set ("originalImageHadAlpha", transparent >= 0); - readImage ((buf[8] & 0x40) != 0, transparent); + readImage ((buf[8] & 0x40) != 0, transparent); + } break; } @@ -97870,8 +97856,8 @@ public: private: InputStream& input; - uint8 buffer [300]; - uint8 palette [256][4]; + uint8 buffer [260]; + PixelARGB palette [256]; bool dataBlockIsZero, fresh, finished; int currentBit, lastBit, lastByteIndex; int codeSize, setCodeSize; @@ -97885,19 +97871,17 @@ private: bool getSizeFromHeader (int& w, int& h) { - char b[8]; + char b[6]; - if (input.read (b, 6) == 6) + if (input.read (b, 6) == 6 + && (strncmp ("GIF87a", b, 6) == 0 + || strncmp ("GIF89a", b, 6) == 0)) { - if ((strncmp ("GIF87a", b, 6) == 0) - || (strncmp ("GIF89a", b, 6) == 0)) + if (input.read (b, 4) == 4) { - if (input.read (b, 4) == 4) - { - w = makeWord (b[0], b[1]); - h = makeWord (b[2], b[3]); - return true; - } + w = makeWord (b[0], b[1]); + h = makeWord (b[2], b[3]); + return w > 0 && h > 0; } } @@ -97906,25 +97890,21 @@ private: bool readPalette (const int numCols) { - unsigned char rgb[4]; - for (int i = 0; i < numCols; ++i) { + uint8 rgb[4]; input.read (rgb, 3); - palette [i][0] = rgb[0]; - palette [i][1] = rgb[1]; - palette [i][2] = rgb[2]; - palette [i][3] = 0xff; + palette[i].setARGB (0xff, rgb[0], rgb[1], rgb[2]); + palette[i].premultiply(); } return true; } - int readDataBlock (unsigned char* dest) + int readDataBlock (uint8* const dest) { - unsigned char n; - + uint8 n; if (input.read (&n, 1) == 1) { dataBlockIsZero = (n == 0); @@ -97936,9 +97916,13 @@ private: return -1; } - int processExtension (const int type, int& transparent) + int readExtension (int& transparent) { - unsigned char b [300]; + uint8 type; + if (input.read (&type, 1) != 1) + return false; + + uint8 b [260]; int n = 0; if (type == 0xf9) @@ -97947,7 +97931,7 @@ private: if (n < 0) return 1; - if ((b[0] & 0x1) != 0) + if ((b[0] & 1) != 0) transparent = b[3]; } @@ -97957,7 +97941,7 @@ private: } while (n > 0); - return n; + return n >= 0; } void clearTable() @@ -98030,7 +98014,7 @@ private: if (dataBlockIsZero) return -2; - unsigned char buf [260]; + uint8 buf [260]; int n; while ((n = readDataBlock (buf)) > 0) @@ -98100,7 +98084,7 @@ private: buffer[0] = buffer [lastByteIndex - 2]; buffer[1] = buffer [lastByteIndex - 1]; - const int n = readDataBlock (&buffer[2]); + const int n = readDataBlock (buffer + 2); if (n == 0) finished = true; @@ -98126,66 +98110,40 @@ private: bool readImage (const int interlace, const int transparent) { - { - unsigned char c; - if (input.read (&c, 1) != 1) - return false; + uint8 c; + if (input.read (&c, 1) != 1) + return false; - initialise (c); - } + initialise (c); if (transparent >= 0) - { - palette [transparent][0] = 0; - palette [transparent][1] = 0; - palette [transparent][2] = 0; - palette [transparent][3] = 0; - } + palette [transparent].setARGB (0, 0, 0, 0); - int index; - int xpos = 0, ypos = 0, pass = 0; + int xpos = 0, ypos = 0, yStep = 8, pass = 0; const Image::BitmapData destData (image, Image::BitmapData::writeOnly); - uint8* p = destData.data; - const bool hasAlpha = image.hasAlphaChannel(); + uint8* p = destData.getPixelPointer (0, 0); - while ((index = readLZWByte()) >= 0) + for (;;) { - const uint8* const paletteEntry = palette [index]; - - if (hasAlpha) - { - ((PixelARGB*) p)->setARGB (paletteEntry[3], - paletteEntry[0], - paletteEntry[1], - paletteEntry[2]); + const int index = readLZWByte(); + if (index < 0) + break; - ((PixelARGB*) p)->premultiply(); - } + if (transparent >= 0) + ((PixelARGB*) p)->set (palette [index]); else - { - ((PixelRGB*) p)->setARGB (0, - paletteEntry[0], - paletteEntry[1], - paletteEntry[2]); - } + ((PixelRGB*) p)->set (palette [index]); p += destData.pixelStride; - ++xpos; - if (xpos == destData.width) + if (++xpos == destData.width) { xpos = 0; if (interlace) { - switch (pass) - { - case 0: - case 1: ypos += 8; break; - case 2: ypos += 4; break; - case 3: ypos += 2; break; - } + ypos += yStep; while (ypos >= destData.height) { @@ -98193,29 +98151,27 @@ private: switch (pass) { - case 1: ypos = 4; break; - case 2: ypos = 2; break; - case 3: ypos = 1; break; + case 1: ypos = 4; yStep = 8; break; + case 2: ypos = 2; yStep = 4; break; + case 3: ypos = 1; yStep = 2; break; default: return true; } } } else { - ++ypos; + if (++ypos >= destData.height) + break; } p = destData.getPixelPointer (xpos, ypos); } - - if (ypos >= destData.height) - break; } return true; } - static inline int makeWord (const uint8 a, const uint8 b) { return (b << 8) | a; } + static inline int makeWord (const int a, const int b) { return (b << 8) | a; } JUCE_DECLARE_NON_COPYABLE (GIFLoader); }; @@ -281665,21 +281621,20 @@ public: void updateSubMenu (NSMenuItem* parentItem, const PopupMenu& menuToCopy, const String& name, const int menuId, const int tag) { - [parentItem setTag: tag]; - NSMenu* menu = [parentItem submenu]; - - [menu setTitle: juceStringToNS (name)]; - - while ([menu numberOfItems] > 0) - [menu removeItemAtIndex: 0]; + // Note: This method used to update the contents of the existing menu in-place, but that caused + // weird side-effects which messed-up keyboard focus when switching between windows. By creating + // a new menu and replacing the old one with it, that problem seems to be avoided.. + NSMenu* menu = [[NSMenu alloc] initWithTitle: juceStringToNS (name)]; PopupMenu::MenuItemIterator iter (menuToCopy); - while (iter.next()) addMenuItem (iter, menu, menuId, tag); [menu setAutoenablesItems: false]; [menu update]; + [parentItem setTag: tag]; + [parentItem setSubmenu: menu]; + [menu release]; } void menuBarItemsChanged (MenuBarModel*) @@ -281803,31 +281758,15 @@ public: { const KeyPress& kp = keyPresses.getReference(0); - if (kp.getKeyCode() != KeyPress::backspaceKey - && kp.getKeyCode() != KeyPress::deleteKey) // (adding these is annoying because it flashes the menu bar - // every time you press the key while editing text) + if (kp.getKeyCode() != KeyPress::backspaceKey // (adding these is annoying because it flashes the menu bar + && kp.getKeyCode() != KeyPress::deleteKey) // every time you press the key while editing text) { juce_wchar key = kp.getTextCharacter(); - - if (kp.getKeyCode() == KeyPress::backspaceKey) - key = NSBackspaceCharacter; - else if (kp.getKeyCode() == KeyPress::deleteKey) - key = NSDeleteCharacter; - else if (key == 0) + if (key == 0) key = (juce_wchar) kp.getKeyCode(); - unsigned int mods = 0; - if (kp.getModifiers().isShiftDown()) - mods |= NSShiftKeyMask; - if (kp.getModifiers().isCtrlDown()) - mods |= NSControlKeyMask; - if (kp.getModifiers().isAltDown()) - mods |= NSAlternateKeyMask; - if (kp.getModifiers().isCommandDown()) - mods |= NSCommandKeyMask; - [item setKeyEquivalent: juceStringToNS (String::charToString (key))]; - [item setKeyEquivalentModifierMask: mods]; + [item setKeyEquivalentModifierMask: juceModsToNSMods (kp.getModifiers())]; } } } @@ -281918,6 +281857,16 @@ private: [menu release]; } + + static unsigned int juceModsToNSMods (const ModifierKeys& mods) + { + unsigned int m = 0; + if (mods.isShiftDown()) m |= NSShiftKeyMask; + if (mods.isCtrlDown()) m |= NSControlKeyMask; + if (mods.isAltDown()) m |= NSAlternateKeyMask; + if (mods.isCommandDown()) m |= NSCommandKeyMask; + return m; + } }; JuceMainMenuHandler* JuceMainMenuHandler::instance = nullptr; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index a3df66d8f8..734f056a65 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 93 +#define JUCE_BUILDNUMBER 94 /** Current Juce version number. @@ -47268,8 +47268,7 @@ public: Call this when the number of rows in the list changes, or if you want it to call refreshComponentForRow() on all the row components. - Be careful not to call it from a different thread, though, as it's not - thread-safe. + This must only be called from the main message thread. */ void updateContent(); diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index ee2ea43c49..d1632d3d0d 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 93 +#define JUCE_BUILDNUMBER 94 /** Current Juce version number. diff --git a/src/gui/components/controls/juce_ListBox.h b/src/gui/components/controls/juce_ListBox.h index 4155cf93f1..5bed61cd9c 100644 --- a/src/gui/components/controls/juce_ListBox.h +++ b/src/gui/components/controls/juce_ListBox.h @@ -196,8 +196,7 @@ public: Call this when the number of rows in the list changes, or if you want it to call refreshComponentForRow() on all the row components. - Be careful not to call it from a different thread, though, as it's not - thread-safe. + This must only be called from the main message thread. */ void updateContent(); diff --git a/src/gui/components/windows/juce_DocumentWindow.cpp b/src/gui/components/windows/juce_DocumentWindow.cpp index 06bff5d7a8..87ea679531 100644 --- a/src/gui/components/windows/juce_DocumentWindow.cpp +++ b/src/gui/components/windows/juce_DocumentWindow.cpp @@ -45,12 +45,9 @@ public: void buttonClicked (Button* button) { - if (button == owner.getMinimiseButton()) - owner.minimiseButtonPressed(); - else if (button == owner.getMaximiseButton()) - owner.maximiseButtonPressed(); - else if (button == owner.getCloseButton()) - owner.closeButtonPressed(); + if (button == owner.getMinimiseButton()) owner.minimiseButtonPressed(); + else if (button == owner.getMaximiseButton()) owner.maximiseButtonPressed(); + else if (button == owner.getCloseButton()) owner.closeButtonPressed(); } private: @@ -309,14 +306,9 @@ int DocumentWindow::getDesktopWindowStyleFlags() const { int styleFlags = ResizableWindow::getDesktopWindowStyleFlags(); - if ((requiredButtons & minimiseButton) != 0) - styleFlags |= ComponentPeer::windowHasMinimiseButton; - - if ((requiredButtons & maximiseButton) != 0) - styleFlags |= ComponentPeer::windowHasMaximiseButton; - - if ((requiredButtons & closeButton) != 0) - styleFlags |= ComponentPeer::windowHasCloseButton; + if ((requiredButtons & minimiseButton) != 0) styleFlags |= ComponentPeer::windowHasMinimiseButton; + if ((requiredButtons & maximiseButton) != 0) styleFlags |= ComponentPeer::windowHasMaximiseButton; + if ((requiredButtons & closeButton) != 0) styleFlags |= ComponentPeer::windowHasCloseButton; return styleFlags; } @@ -357,11 +349,11 @@ void DocumentWindow::lookAndFeelChanged() if (getCloseButton() != nullptr) { - #if JUCE_MAC + #if JUCE_MAC getCloseButton()->addShortcut (KeyPress ('w', ModifierKeys::commandModifier, 0)); - #else + #else getCloseButton()->addShortcut (KeyPress (KeyPress::F4Key, ModifierKeys::altModifier, 0)); - #endif + #endif } } diff --git a/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp b/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp index d4a7c41d77..d6d59a03ba 100644 --- a/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp +++ b/src/gui/graphics/imaging/image_file_formats/juce_GIFLoader.cpp @@ -45,22 +45,19 @@ public: : input (in), dataBlockIsZero (false), fresh (false), finished (false), currentBit (0), lastBit (0), lastByteIndex (0), - codeSize (0), setCodeSize (0), - maxCode (0), maxCodeSize (0), + codeSize (0), setCodeSize (0), maxCode (0), maxCodeSize (0), firstcode (0), oldcode (0), clearCode (0), endCode (0) { int imageWidth, imageHeight; - int transparent = -1; - - if (! (getSizeFromHeader (imageWidth, imageHeight) - && imageWidth > 0 && imageHeight > 0)) + if (! getSizeFromHeader (imageWidth, imageHeight)) return; - unsigned char buf [16]; + uint8 buf [16]; if (in.read (buf, 3) != 3) return; int numColours = 2 << (buf[0] & 7); + int transparent = -1; if ((buf[0] & 0x80) != 0) readPalette (numColours); @@ -72,36 +69,33 @@ public: if (buf[0] == '!') { - if (input.read (buf, 1) != 1) - break; - - if (processExtension (buf[0], transparent) < 0) - break; + if (readExtension (transparent)) + continue; - continue; + break; } if (buf[0] != ',') continue; - if (input.read (buf, 9) != 9) - break; - - imageWidth = makeWord (buf[4], buf[5]); - imageHeight = makeWord (buf[6], buf[7]); + if (input.read (buf, 9) == 9) + { + imageWidth = makeWord (buf[4], buf[5]); + imageHeight = makeWord (buf[6], buf[7]); - numColours = 2 << (buf[8] & 7); + numColours = 2 << (buf[8] & 7); - if ((buf[8] & 0x80) != 0) - if (! readPalette (numColours)) - break; + if ((buf[8] & 0x80) != 0) + if (! readPalette (numColours)) + break; - image = Image ((transparent >= 0) ? Image::ARGB : Image::RGB, - imageWidth, imageHeight, (transparent >= 0)); + image = Image (transparent >= 0 ? Image::ARGB : Image::RGB, + imageWidth, imageHeight, transparent >= 0); - image.getProperties()->set ("originalImageHadAlpha", image.hasAlphaChannel()); + image.getProperties()->set ("originalImageHadAlpha", transparent >= 0); - readImage ((buf[8] & 0x40) != 0, transparent); + readImage ((buf[8] & 0x40) != 0, transparent); + } break; } @@ -111,8 +105,8 @@ public: private: InputStream& input; - uint8 buffer [300]; - uint8 palette [256][4]; + uint8 buffer [260]; + PixelARGB palette [256]; bool dataBlockIsZero, fresh, finished; int currentBit, lastBit, lastByteIndex; int codeSize, setCodeSize; @@ -126,19 +120,17 @@ private: bool getSizeFromHeader (int& w, int& h) { - char b[8]; + char b[6]; - if (input.read (b, 6) == 6) + if (input.read (b, 6) == 6 + && (strncmp ("GIF87a", b, 6) == 0 + || strncmp ("GIF89a", b, 6) == 0)) { - if ((strncmp ("GIF87a", b, 6) == 0) - || (strncmp ("GIF89a", b, 6) == 0)) + if (input.read (b, 4) == 4) { - if (input.read (b, 4) == 4) - { - w = makeWord (b[0], b[1]); - h = makeWord (b[2], b[3]); - return true; - } + w = makeWord (b[0], b[1]); + h = makeWord (b[2], b[3]); + return w > 0 && h > 0; } } @@ -147,25 +139,21 @@ private: bool readPalette (const int numCols) { - unsigned char rgb[4]; - for (int i = 0; i < numCols; ++i) { + uint8 rgb[4]; input.read (rgb, 3); - palette [i][0] = rgb[0]; - palette [i][1] = rgb[1]; - palette [i][2] = rgb[2]; - palette [i][3] = 0xff; + palette[i].setARGB (0xff, rgb[0], rgb[1], rgb[2]); + palette[i].premultiply(); } return true; } - int readDataBlock (unsigned char* dest) + int readDataBlock (uint8* const dest) { - unsigned char n; - + uint8 n; if (input.read (&n, 1) == 1) { dataBlockIsZero = (n == 0); @@ -177,9 +165,13 @@ private: return -1; } - int processExtension (const int type, int& transparent) + int readExtension (int& transparent) { - unsigned char b [300]; + uint8 type; + if (input.read (&type, 1) != 1) + return false; + + uint8 b [260]; int n = 0; if (type == 0xf9) @@ -188,7 +180,7 @@ private: if (n < 0) return 1; - if ((b[0] & 0x1) != 0) + if ((b[0] & 1) != 0) transparent = b[3]; } @@ -198,7 +190,7 @@ private: } while (n > 0); - return n; + return n >= 0; } void clearTable() @@ -271,7 +263,7 @@ private: if (dataBlockIsZero) return -2; - unsigned char buf [260]; + uint8 buf [260]; int n; while ((n = readDataBlock (buf)) > 0) @@ -341,7 +333,7 @@ private: buffer[0] = buffer [lastByteIndex - 2]; buffer[1] = buffer [lastByteIndex - 1]; - const int n = readDataBlock (&buffer[2]); + const int n = readDataBlock (buffer + 2); if (n == 0) finished = true; @@ -367,66 +359,40 @@ private: bool readImage (const int interlace, const int transparent) { - { - unsigned char c; - if (input.read (&c, 1) != 1) - return false; + uint8 c; + if (input.read (&c, 1) != 1) + return false; - initialise (c); - } + initialise (c); if (transparent >= 0) - { - palette [transparent][0] = 0; - palette [transparent][1] = 0; - palette [transparent][2] = 0; - palette [transparent][3] = 0; - } + palette [transparent].setARGB (0, 0, 0, 0); - int index; - int xpos = 0, ypos = 0, pass = 0; + int xpos = 0, ypos = 0, yStep = 8, pass = 0; const Image::BitmapData destData (image, Image::BitmapData::writeOnly); - uint8* p = destData.data; - const bool hasAlpha = image.hasAlphaChannel(); + uint8* p = destData.getPixelPointer (0, 0); - while ((index = readLZWByte()) >= 0) + for (;;) { - const uint8* const paletteEntry = palette [index]; - - if (hasAlpha) - { - ((PixelARGB*) p)->setARGB (paletteEntry[3], - paletteEntry[0], - paletteEntry[1], - paletteEntry[2]); + const int index = readLZWByte(); + if (index < 0) + break; - ((PixelARGB*) p)->premultiply(); - } + if (transparent >= 0) + ((PixelARGB*) p)->set (palette [index]); else - { - ((PixelRGB*) p)->setARGB (0, - paletteEntry[0], - paletteEntry[1], - paletteEntry[2]); - } + ((PixelRGB*) p)->set (palette [index]); p += destData.pixelStride; - ++xpos; - if (xpos == destData.width) + if (++xpos == destData.width) { xpos = 0; if (interlace) { - switch (pass) - { - case 0: - case 1: ypos += 8; break; - case 2: ypos += 4; break; - case 3: ypos += 2; break; - } + ypos += yStep; while (ypos >= destData.height) { @@ -434,29 +400,27 @@ private: switch (pass) { - case 1: ypos = 4; break; - case 2: ypos = 2; break; - case 3: ypos = 1; break; + case 1: ypos = 4; yStep = 8; break; + case 2: ypos = 2; yStep = 4; break; + case 3: ypos = 1; yStep = 2; break; default: return true; } } } else { - ++ypos; + if (++ypos >= destData.height) + break; } p = destData.getPixelPointer (xpos, ypos); } - - if (ypos >= destData.height) - break; } return true; } - static inline int makeWord (const uint8 a, const uint8 b) { return (b << 8) | a; } + static inline int makeWord (const int a, const int b) { return (b << 8) | a; } JUCE_DECLARE_NON_COPYABLE (GIFLoader); }; diff --git a/src/native/mac/juce_mac_MainMenu.mm b/src/native/mac/juce_mac_MainMenu.mm index cc314a6464..7817e69bfb 100644 --- a/src/native/mac/juce_mac_MainMenu.mm +++ b/src/native/mac/juce_mac_MainMenu.mm @@ -109,21 +109,20 @@ public: void updateSubMenu (NSMenuItem* parentItem, const PopupMenu& menuToCopy, const String& name, const int menuId, const int tag) { - [parentItem setTag: tag]; - NSMenu* menu = [parentItem submenu]; - - [menu setTitle: juceStringToNS (name)]; - - while ([menu numberOfItems] > 0) - [menu removeItemAtIndex: 0]; + // Note: This method used to update the contents of the existing menu in-place, but that caused + // weird side-effects which messed-up keyboard focus when switching between windows. By creating + // a new menu and replacing the old one with it, that problem seems to be avoided.. + NSMenu* menu = [[NSMenu alloc] initWithTitle: juceStringToNS (name)]; PopupMenu::MenuItemIterator iter (menuToCopy); - while (iter.next()) addMenuItem (iter, menu, menuId, tag); [menu setAutoenablesItems: false]; [menu update]; + [parentItem setTag: tag]; + [parentItem setSubmenu: menu]; + [menu release]; } void menuBarItemsChanged (MenuBarModel*) @@ -247,31 +246,15 @@ public: { const KeyPress& kp = keyPresses.getReference(0); - if (kp.getKeyCode() != KeyPress::backspaceKey - && kp.getKeyCode() != KeyPress::deleteKey) // (adding these is annoying because it flashes the menu bar - // every time you press the key while editing text) + if (kp.getKeyCode() != KeyPress::backspaceKey // (adding these is annoying because it flashes the menu bar + && kp.getKeyCode() != KeyPress::deleteKey) // every time you press the key while editing text) { juce_wchar key = kp.getTextCharacter(); - - if (kp.getKeyCode() == KeyPress::backspaceKey) - key = NSBackspaceCharacter; - else if (kp.getKeyCode() == KeyPress::deleteKey) - key = NSDeleteCharacter; - else if (key == 0) + if (key == 0) key = (juce_wchar) kp.getKeyCode(); - unsigned int mods = 0; - if (kp.getModifiers().isShiftDown()) - mods |= NSShiftKeyMask; - if (kp.getModifiers().isCtrlDown()) - mods |= NSControlKeyMask; - if (kp.getModifiers().isAltDown()) - mods |= NSAlternateKeyMask; - if (kp.getModifiers().isCommandDown()) - mods |= NSCommandKeyMask; - [item setKeyEquivalent: juceStringToNS (String::charToString (key))]; - [item setKeyEquivalentModifierMask: mods]; + [item setKeyEquivalentModifierMask: juceModsToNSMods (kp.getModifiers())]; } } } @@ -362,6 +345,16 @@ private: [menu release]; } + + static unsigned int juceModsToNSMods (const ModifierKeys& mods) + { + unsigned int m = 0; + if (mods.isShiftDown()) m |= NSShiftKeyMask; + if (mods.isCtrlDown()) m |= NSControlKeyMask; + if (mods.isAltDown()) m |= NSAlternateKeyMask; + if (mods.isCommandDown()) m |= NSCommandKeyMask; + return m; + } }; JuceMainMenuHandler* JuceMainMenuHandler::instance = nullptr;