From 2990717d6e2548837d0a81916c85299105b27b0c Mon Sep 17 00:00:00 2001 From: ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> Date: Sat, 11 Jan 2020 14:51:30 +0100 Subject: [PATCH] Implement Fl_Window::icon() and default_icon() for macOS The implementation is effective for macOS 10.10 and above. Demo program test/device uses the new implementation. --- src/Fl_cocoa.mm | 61 ++++++++++++++++++++ src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H | 7 +++ src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx | 1 + src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H | 6 ++ src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx | 12 +--- test/device.cxx | 4 ++ 6 files changed, 80 insertions(+), 11 deletions(-) diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm index cb634a43c..3771b4312 100644 --- a/src/Fl_cocoa.mm +++ b/src/Fl_cocoa.mm @@ -582,6 +582,7 @@ void Fl_Cocoa_Screen_Driver::breakMacEventLoop() #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 if (views_use_CA) [(FLView*)[self contentView] reset_aux_bitmap]; #endif + [[self standardWindowButton:NSWindowDocumentIconButton] setImage:nil]; [super close]; // when a fullscreen window is closed, windowDidResize may be sent after the close message was sent // and before the FLWindow receives the final dealloc message @@ -1133,6 +1134,7 @@ static FLTextView *fltextview_instance = nil; - (BOOL)windowShouldClose:(id)fl; - (void)anyWindowWillClose:(NSNotification *)notif; - (void)doNothing:(id)unused; +- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu; @end @@ -1390,6 +1392,9 @@ static FLWindowDelegate *flwindowdelegate_instance = nil; { return; } +- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu { + return NO; +} @end @interface FLAppDelegate : NSObject @@ -3075,6 +3080,16 @@ Fl_X* Fl_Cocoa_Window_Driver::makeWindow() [cw setLevel:winlevel]; q_set_window_title(cw, w->label(), w->iconlabel()); + NSImage *icon = icon_image; // is a window or default icon present? + if (!icon) icon = ((Fl_Cocoa_Screen_Driver*)Fl::screen_driver())->default_icon; + if (icon && (winstyle & NSTitledWindowMask) && w->label() && strlen(w->label())>0) { + [cw setRepresentedFilename:[NSString stringWithFormat:@"/%@", [cw title]]]; + NSButton *icon_button = [cw standardWindowButton:NSWindowDocumentIconButton]; + if (icon_button) { + [icon setSize:[icon_button frame].size]; + [icon_button setImage:icon]; + } + } if (!force_position()) { if (w->modal()) { [cw center]; @@ -4435,6 +4450,52 @@ char *Fl_Darwin_System_Driver::preference_rootnode(Fl_Preferences *prefs, Fl_Pre return filename; } +Fl_Cocoa_Window_Driver::~Fl_Cocoa_Window_Driver() +{ + if (shape_data_) { + if (shape_data_->mask) { + CGImageRelease(shape_data_->mask); + } + delete shape_data_; + } + [icon_image release]; +} + +static NSImage* rgb_to_nsimage(const Fl_RGB_Image *rgb) { + if (!rgb) return nil; + int ld = rgb->ld(); + if (!ld) ld = rgb->w() * rgb->d(); + NSImage *win_icon = nil; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 + if (fl_mac_os_version >= 101000) { + NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:rgb->w() pixelsHigh:rgb->h() + bitsPerSample:8 samplesPerPixel:rgb->d() hasAlpha:!(rgb->d() & 1) isPlanar:NO + colorSpaceName:(rgb->d()<=2) ? NSDeviceWhiteColorSpace : NSDeviceRGBColorSpace + bitmapFormat:NSAlphaNonpremultipliedBitmapFormat bytesPerRow:ld bitsPerPixel:rgb->d()*8]; // 10.4 + memcpy([bitmap bitmapData], rgb->array, rgb->h() * ld); + win_icon = [[NSImage alloc] initWithSize:NSMakeSize(0, 0)]; + [win_icon addRepresentation:bitmap]; + [bitmap release]; + } +#endif + return win_icon; +} + +void Fl_Cocoa_Window_Driver::icons(const Fl_RGB_Image *icons[], int count) { + [icon_image release]; + icon_image = nil; + if (count >= 1 && pWindow->border() && pWindow->label() && strlen(pWindow->label())) { + icon_image = rgb_to_nsimage(icons[0]); + } +} + +void Fl_Cocoa_Screen_Driver::default_icons(const Fl_RGB_Image *icons[], int count) { + [default_icon release]; + default_icon = nil; + if (count >= 1) { + default_icon = rgb_to_nsimage(icons[0]); + } +} // // End of "$Id$". diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H index faf5b8520..97dd28a77 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H +++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.H @@ -41,6 +41,11 @@ class Fl_Window; class Fl_Input; class Fl_RGB_Image; +#ifdef __OBJC__ +@class NSImage; +#else +class NSImage; +#endif class FL_EXPORT Fl_Cocoa_Screen_Driver : public Fl_Screen_Driver { @@ -54,6 +59,7 @@ protected: static int insertion_point_height; static bool insertion_point_location_is_valid; public: + NSImage *default_icon; Fl_Cocoa_Screen_Driver(); static int next_marked_length; // next length of marked text after current marked text will have been replaced static void breakMacEventLoop(); @@ -100,6 +106,7 @@ public: virtual float scale(int n) {return scale_;} virtual void scale(int n, float f) { scale_ = f;} virtual Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win, bool may_capture_subwins, bool *did_capture_subwins); + virtual void default_icons(const Fl_RGB_Image *icons[], int count); private: float scale_; }; diff --git a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx index 34e1c80fd..835169e3e 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx +++ b/src/drivers/Cocoa/Fl_Cocoa_Screen_Driver.cxx @@ -79,6 +79,7 @@ static Fl_Text_Editor::Key_Binding extra_bindings[] = { Fl_Cocoa_Screen_Driver::Fl_Cocoa_Screen_Driver() { text_editor_extra_key_bindings = extra_bindings; scale_ = 1.; + default_icon = nil; } diff --git a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H index 6de52e5db..9ef5d46c9 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H +++ b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H @@ -33,12 +33,14 @@ class Fl_Window; #ifdef __OBJC__ @class CALayer; @class NSCursor; +@class NSImage; @class FLWindow; @class NSOpenGLContext; @class NSOpenGLPixelFormat; #else class CALayer; class NSCursor; +class NSImage; class FLWindow; class NSOpenGLContext; class NSOpenGLPixelFormat; @@ -153,6 +155,10 @@ public: static void GLcontext_makecurrent(NSOpenGLContext*); // uses Objective-c static void GL_cleardrawable(void); // uses Objective-c static void gl_start(NSOpenGLContext*); // uses Objective-c + + //icons + virtual void icons(const Fl_RGB_Image *icons[], int count); + NSImage *icon_image; }; #endif // FL_COCOA_WINDOW_DRIVER_H diff --git a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx index 43ae44664..35daffd22 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx +++ b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx @@ -52,17 +52,7 @@ Fl_Cocoa_Window_Driver::Fl_Cocoa_Window_Driver(Fl_Window *win) { cursor = nil; window_flags_ = 0; -} - - -Fl_Cocoa_Window_Driver::~Fl_Cocoa_Window_Driver() -{ - if (shape_data_) { - if (shape_data_->mask) { - CGImageRelease(shape_data_->mask); - } - delete shape_data_; - } + icon_image = NULL; } diff --git a/test/device.cxx b/test/device.cxx index 94b7a7f25..964e4da84 100644 --- a/test/device.cxx +++ b/test/device.cxx @@ -754,6 +754,10 @@ int main(int argc, char ** argv) { w3->end(); w2->end(); + Fl_RGB_Image *rgba_icon = new Fl_RGB_Image(pixmap); + Fl_Window::default_icon(rgba_icon); + //w2->icon(rgba_icon); + delete rgba_icon; w2->show(argc, argv); Fl::run();