Simpler macOS implementation of capture of window titlebars.
This commit is contained in:
parent
5830226aab
commit
0d8385a652
@ -64,7 +64,6 @@ public:
|
|||||||
void origin(int *x, int *y);
|
void origin(int *x, int *y);
|
||||||
void origin(int x, int y);
|
void origin(int x, int y);
|
||||||
int printable_rect(int *w, int *h);
|
int printable_rect(int *w, int *h);
|
||||||
virtual void draw_decorated_window(Fl_Window *win, int x_offset = 0, int y_offset = 0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,7 +103,6 @@ public:
|
|||||||
void untranslate(void);
|
void untranslate(void);
|
||||||
int end_page (void);
|
int end_page (void);
|
||||||
void end_job (void);
|
void end_job (void);
|
||||||
void draw_decorated_window(Fl_Window *win, int x_offset = 0, int y_offset = 0);
|
|
||||||
void set_current(void);
|
void set_current(void);
|
||||||
virtual bool is_current();
|
virtual bool is_current();
|
||||||
|
|
||||||
|
@ -61,10 +61,6 @@ int Fl_Copy_Surface::printable_rect(int *w, int *h) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fl_Copy_Surface::draw_decorated_window(Fl_Window *win, int x_offset, int y_offset) {
|
|
||||||
if (platform_surface) platform_surface->draw_decorated_window(win, x_offset, y_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\cond DriverDev
|
\cond DriverDev
|
||||||
\addtogroup DriverDeveloper
|
\addtogroup DriverDeveloper
|
||||||
|
@ -39,7 +39,6 @@ void Fl_Printer::translate(int x, int y) {}
|
|||||||
void Fl_Printer::untranslate(void) {}
|
void Fl_Printer::untranslate(void) {}
|
||||||
int Fl_Printer::end_page (void) {return 1;}
|
int Fl_Printer::end_page (void) {return 1;}
|
||||||
void Fl_Printer::end_job (void) {}
|
void Fl_Printer::end_job (void) {}
|
||||||
void Fl_Printer::draw_decorated_window(Fl_Window* win, int delta_x, int delta_y) {}
|
|
||||||
void Fl_Printer::set_current(void) {}
|
void Fl_Printer::set_current(void) {}
|
||||||
bool Fl_Printer::is_current(void) {return false;}
|
bool Fl_Printer::is_current(void) {return false;}
|
||||||
Fl_Printer::~Fl_Printer(void) {}
|
Fl_Printer::~Fl_Printer(void) {}
|
||||||
@ -199,11 +198,6 @@ void Fl_Printer::end_job (void)
|
|||||||
printer->end_job();
|
printer->end_job();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fl_Printer::draw_decorated_window(Fl_Window* win, int delta_x, int delta_y)
|
|
||||||
{
|
|
||||||
printer->draw_decorated_window(win, delta_x, delta_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Fl_Printer::set_current(void)
|
void Fl_Printer::set_current(void)
|
||||||
{
|
{
|
||||||
printer->set_current();
|
printer->set_current();
|
||||||
|
@ -4362,44 +4362,35 @@ int Fl_Cocoa_Window_Driver::decorated_h()
|
|||||||
return h() + bt/s;
|
return h() + bt/s;
|
||||||
}
|
}
|
||||||
|
|
||||||
CALayer *Fl_Cocoa_Window_Driver::get_titlebar_layer()
|
void Fl_Cocoa_Window_Driver::draw_titlebar_to_context(CGContextRef gc, int w, int h)
|
||||||
{
|
{
|
||||||
// a compilation warning appears with SDK 10.5, so we require SDK 10.6 instead
|
FLWindow *nswin = fl_xid(pWindow);
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
[nswin makeMainWindow];
|
||||||
return fl_mac_os_version >= 101000 ? [[[fl_xid(pWindow) standardWindowButton:NSWindowCloseButton] superview] layer] : nil; // 10.5
|
[NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:NO];
|
||||||
#else
|
CGImageRef img;
|
||||||
return nil;
|
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
|
||||||
|
if (fl_mac_os_version >= 100600) { // verified OK from 10.6
|
||||||
|
NSInteger win_id = [nswin windowNumber];
|
||||||
|
CFArrayRef array = CFArrayCreate(NULL, (const void**)&win_id, 1, NULL);
|
||||||
|
CGRect rr = NSRectToCGRect([nswin frame]);
|
||||||
|
rr.origin.y = CGDisplayBounds(CGMainDisplayID()).size.height - (rr.origin.y + rr.size.height);
|
||||||
|
rr.size.height = h;
|
||||||
|
img = CGWindowListCreateImageFromArray(rr, array, kCGWindowImageBoundsIgnoreFraming); // 10.5
|
||||||
|
CFRelease(array);
|
||||||
|
} else
|
||||||
#endif
|
#endif
|
||||||
}
|
{
|
||||||
|
Fl_Graphics_Driver::default_driver().scale(1);
|
||||||
void Fl_Cocoa_Window_Driver::draw_layer_to_context(CALayer *layer, CGContextRef gc, int w, int h)
|
img = CGImage_from_window_rect(0, -h, w, h, false);
|
||||||
{
|
Fl_Graphics_Driver::default_driver().scale(Fl::screen_driver()->scale(screen_num()));
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
}
|
||||||
|
if (img) {
|
||||||
CGContextSaveGState(gc);
|
CGContextSaveGState(gc);
|
||||||
clip_to_rounded_corners(gc, w, h);
|
clip_to_rounded_corners(gc, w, h);
|
||||||
if (fl_mac_os_version < 101500) { // exact OS threshold might be lower
|
|
||||||
CGContextSetRGBFillColor(gc, .79, .79, .79, 1.); // equiv. to FL_DARK1
|
|
||||||
CGContextFillRect(gc, CGRectMake(0, 0, w, h));
|
|
||||||
}
|
|
||||||
CGContextSetShouldAntialias(gc, true);
|
|
||||||
if (fl_mac_os_version >= 101500) {
|
|
||||||
FLWindow *flwin = fl_xid(pWindow);
|
|
||||||
[flwin makeMainWindow];
|
|
||||||
[NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:NO];
|
|
||||||
NSInteger win_id = [flwin windowNumber];
|
|
||||||
CFArrayRef array = CFArrayCreate(NULL, (const void**)&win_id, 1, NULL);
|
|
||||||
NSRect rr = [flwin frame];
|
|
||||||
rr.origin.y += rr.size.height - h;
|
|
||||||
rr.size.height = h;
|
|
||||||
rr.origin.y = CGDisplayBounds(CGMainDisplayID()).size.height - (rr.origin.y + rr.size.height);
|
|
||||||
CGImageRef img = CGWindowListCreateImageFromArray(rr, array, kCGWindowImageBoundsIgnoreFraming); // 10.5
|
|
||||||
CFRelease(array);
|
|
||||||
CGContextDrawImage(gc, CGRectMake(0, 0, w, h), img);
|
CGContextDrawImage(gc, CGRectMake(0, 0, w, h), img);
|
||||||
CGImageRelease(img);
|
CGImageRelease(img);
|
||||||
} else
|
|
||||||
[layer renderInContext:gc]; // 10.5
|
|
||||||
CGContextRestoreGState(gc);
|
CGContextRestoreGState(gc);
|
||||||
#endif
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fl_Cocoa_Window_Driver::gl_start(NSOpenGLContext *ctxt) {
|
void Fl_Cocoa_Window_Driver::gl_start(NSOpenGLContext *ctxt) {
|
||||||
|
@ -68,7 +68,6 @@ private:
|
|||||||
void untranslate(void);
|
void untranslate(void);
|
||||||
int end_page (void);
|
int end_page (void);
|
||||||
void end_job (void);
|
void end_job (void);
|
||||||
void draw_decorated_window(Fl_Window *win, int x_offset, int y_offset);
|
|
||||||
~Fl_Cocoa_Printer_Driver(void);
|
~Fl_Cocoa_Printer_Driver(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -388,85 +387,3 @@ void Fl_Cocoa_Printer_Driver::origin(int *x, int *y)
|
|||||||
{
|
{
|
||||||
Fl_Paged_Device::origin(x, y);
|
Fl_Paged_Device::origin(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fl_Cocoa_Printer_Driver::draw_decorated_window(Fl_Window *win, int x_offset, int y_offset)
|
|
||||||
{
|
|
||||||
if (!win->shown() || win->parent() || !win->border() || !win->visible()) {
|
|
||||||
this->print_widget(win, x_offset, y_offset);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int bt, hleft, hright, hbottom;
|
|
||||||
Fl_Cocoa_Window_Driver::driver(win)->decoration_sizes(&bt, &hleft, &hright, &hbottom);
|
|
||||||
float s = Fl::screen_scale(win->screen_num());
|
|
||||||
if (s < 1) y_offset += bt*(1/s-1);
|
|
||||||
CALayer *layer = Fl_Cocoa_Window_Driver::driver(win)->get_titlebar_layer();
|
|
||||||
if (layer) { // if title bar uses a layer
|
|
||||||
CGContextRef gc = (CGContextRef)driver()->gc();
|
|
||||||
CGContextSaveGState(gc);
|
|
||||||
CGContextTranslateCTM(gc, x_offset - 0.5, y_offset + bt - 0.5);
|
|
||||||
CGContextScaleCTM(gc, 1/s, -1/s);
|
|
||||||
Fl_Cocoa_Window_Driver::driver(win)->draw_layer_to_context(layer, gc, win->w() * s, bt);
|
|
||||||
CGContextRestoreGState(gc);
|
|
||||||
bool clip_corners = fl_mac_os_version >= 100600 && !win->parent();
|
|
||||||
if (clip_corners) {
|
|
||||||
CGContextRef gc = (CGContextRef)driver()->gc();
|
|
||||||
CGContextSaveGState(gc);
|
|
||||||
CGContextTranslateCTM(gc, x_offset, y_offset + bt );
|
|
||||||
Fl_Cocoa_Window_Driver::clip_to_rounded_corners(gc, win->w(), win->h());
|
|
||||||
CGContextTranslateCTM(gc, -x_offset, -y_offset - bt);
|
|
||||||
}
|
|
||||||
this->print_widget(win, x_offset, y_offset + bt);
|
|
||||||
if (clip_corners) {
|
|
||||||
CGContextRestoreGState((CGContextRef)driver()->gc());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Fl_Display_Device::display_device()->set_current(); // send win to front and make it current
|
|
||||||
NSString *title = [(NSWindow*)fl_xid(win) title];
|
|
||||||
[title retain];
|
|
||||||
[(NSWindow*)fl_xid(win) setTitle:@""]; // temporarily set a void window title
|
|
||||||
win->show();
|
|
||||||
Fl::check();
|
|
||||||
// capture the window title bar with no title
|
|
||||||
Fl_RGB_Image *top, *left, *bottom, *right;
|
|
||||||
Fl_Window_Driver::driver(win)->capture_titlebar_and_borders(top, left, bottom, right);
|
|
||||||
[(NSWindow*)fl_xid(win) setTitle:title]; // put back the window title
|
|
||||||
this->set_current(); // back to the Fl_Paged_Device
|
|
||||||
top->scale(win->w(), bt/s, 0, 1);
|
|
||||||
top->draw(x_offset, y_offset + bt - bt/s); // print the title bar
|
|
||||||
delete top;
|
|
||||||
if (win->label()) { // print the window title
|
|
||||||
const int skip = 65; // approx width of the zone of the 3 window control buttons
|
|
||||||
float fs = [NSFont systemFontSize]/s;
|
|
||||||
int text_y = y_offset+bt*(1-1/(2*s))+fs/3;
|
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
|
|
||||||
if ( fl_mac_os_version >= 100400 ) { // use Cocoa string drawing with exact title bar font
|
|
||||||
// the exact font is LucidaGrande 13 pts (and HelveticaNeueDeskInterface-Regular with 10.10)
|
|
||||||
NSGraphicsContext *current = [NSGraphicsContext currentContext];
|
|
||||||
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:driver()->gc() flipped:YES]];//10.4
|
|
||||||
NSDictionary *attr = [NSDictionary dictionaryWithObject:[NSFont titleBarFontOfSize:fs]
|
|
||||||
forKey:NSFontAttributeName];
|
|
||||||
NSSize size = [title sizeWithAttributes:attr];
|
|
||||||
int x = x_offset + win->w()/2 - size.width/2;
|
|
||||||
if (x < x_offset+skip) x = x_offset+skip;
|
|
||||||
NSRect r = NSMakeRect(x, text_y , win->w() - skip, bt);
|
|
||||||
[[NSGraphicsContext currentContext] setShouldAntialias:YES];
|
|
||||||
[title drawWithRect:r options:(NSStringDrawingOptions)0 attributes:attr]; // 10.4
|
|
||||||
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
|
|
||||||
[NSGraphicsContext setCurrentContext:current];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
fl_font(FL_HELVETICA, fs);
|
|
||||||
fl_color(FL_BLACK);
|
|
||||||
int x = x_offset + win->w()/2 - fl_width(win->label())/2;
|
|
||||||
if (x < x_offset+skip) x = x_offset+skip;
|
|
||||||
fl_push_clip(x_offset, y_offset + bt - bt/s, win->w(), bt/s);
|
|
||||||
fl_draw(win->label(), x, text_y);
|
|
||||||
fl_pop_clip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[title release];
|
|
||||||
this->print_widget(win, x_offset, y_offset + bt); // print the window inner part
|
|
||||||
}
|
|
||||||
|
@ -139,8 +139,7 @@ public:
|
|||||||
// next 4 are in Fl_cocoa.mm because they use Objective-c
|
// next 4 are in Fl_cocoa.mm because they use Objective-c
|
||||||
virtual void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right);
|
virtual void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left, Fl_RGB_Image*& bottom, Fl_RGB_Image*& right);
|
||||||
virtual void wait_for_expose();
|
virtual void wait_for_expose();
|
||||||
CALayer *get_titlebar_layer();
|
void draw_titlebar_to_context(CGContextRef gc, int w, int h);
|
||||||
void draw_layer_to_context(CALayer *layer, CGContextRef gc, int w, int h);
|
|
||||||
virtual int scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, void (*draw_area)(void*, int,int,int,int), void* data);
|
virtual int scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, void (*draw_area)(void*, int,int,int,int), void* data);
|
||||||
|
|
||||||
// these functions are OpenGL-related and use objective-c
|
// these functions are OpenGL-related and use objective-c
|
||||||
|
@ -316,44 +316,17 @@ void Fl_Cocoa_Window_Driver::capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl
|
|||||||
int htop, hleft, hright, hbottom;
|
int htop, hleft, hright, hbottom;
|
||||||
Fl_Cocoa_Window_Driver::decoration_sizes(&htop, &hleft, &hright, &hbottom);
|
Fl_Cocoa_Window_Driver::decoration_sizes(&htop, &hleft, &hright, &hbottom);
|
||||||
if (htop == 0) return; // when window is fullscreen
|
if (htop == 0) return; // when window is fullscreen
|
||||||
CALayer *layer = get_titlebar_layer();
|
|
||||||
CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
|
CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB();
|
||||||
float s = Fl::screen_driver()->scale(screen_num());
|
float s = Fl::screen_driver()->scale(screen_num());
|
||||||
int scaled_w = int(w() * s);
|
int scaled_w = int(w() * s);
|
||||||
const int factor = (layer && mapped_to_retina() ? 4 : 2); // resolution level for the titlebar (2 == retina's)
|
const int factor = (mapped_to_retina() ? 2 : 1);
|
||||||
int data_w = factor * scaled_w, data_h = factor * htop;
|
int data_w = factor * scaled_w, data_h = factor * htop;
|
||||||
uchar *rgba = new uchar[4 * data_w * data_h];
|
uchar *rgba = new uchar[4 * data_w * data_h];
|
||||||
CGContextRef auxgc = CGBitmapContextCreate(rgba, data_w, data_h, 8, 4 * data_w, cspace, kCGImageAlphaPremultipliedLast);
|
CGContextRef auxgc = CGBitmapContextCreate(rgba, data_w, data_h, 8, 4 * data_w, cspace, kCGImageAlphaPremultipliedLast);
|
||||||
CGColorSpaceRelease(cspace);
|
CGColorSpaceRelease(cspace);
|
||||||
CGContextClearRect(auxgc, CGRectMake(0,0,data_w,data_h));
|
CGContextClearRect(auxgc, CGRectMake(0,0,data_w,data_h));
|
||||||
CGContextScaleCTM(auxgc, factor, factor);
|
CGContextScaleCTM(auxgc, factor, factor);
|
||||||
if (layer) {
|
draw_titlebar_to_context(auxgc, scaled_w, htop);
|
||||||
draw_layer_to_context(layer, auxgc, scaled_w, htop);
|
|
||||||
if (fl_mac_os_version >= 101300 && fl_mac_os_version < 101500) {
|
|
||||||
// drawn layer is left transparent and alpha-premultiplied: demultiply it and set it opaque.
|
|
||||||
uchar *p = rgba;
|
|
||||||
uchar *last = rgba + data_w * data_h * 4;
|
|
||||||
while (p < last) {
|
|
||||||
uchar q = *(p+3);
|
|
||||||
if (q && q != 0xff) {
|
|
||||||
float m = 255./q;
|
|
||||||
*p++ *= m;
|
|
||||||
*p++ *= m;
|
|
||||||
*p++ *= m;
|
|
||||||
*p++ = 0xff;
|
|
||||||
} else p += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Fl_Graphics_Driver::default_driver().scale(1);
|
|
||||||
CGImageRef img = CGImage_from_window_rect(0, -htop, scaled_w, htop, false);
|
|
||||||
Fl_Graphics_Driver::default_driver().scale(s);
|
|
||||||
CGContextSaveGState(auxgc);
|
|
||||||
clip_to_rounded_corners(auxgc, scaled_w, htop);
|
|
||||||
CGContextDrawImage(auxgc, CGRectMake(0, 0, scaled_w, htop), img);
|
|
||||||
CGContextRestoreGState(auxgc);
|
|
||||||
CFRelease(img);
|
|
||||||
}
|
|
||||||
top = new Fl_RGB_Image(rgba, data_w, data_h, 4);
|
top = new Fl_RGB_Image(rgba, data_w, data_h, 4);
|
||||||
top->alloc_array = 1;
|
top->alloc_array = 1;
|
||||||
top->scale(w(),htop, s <1 ? 0 : 1, 1);
|
top->scale(w(),htop, s <1 ? 0 : 1, 1);
|
||||||
|
@ -33,7 +33,6 @@ protected:
|
|||||||
void set_current();
|
void set_current();
|
||||||
void translate(int x, int y);
|
void translate(int x, int y);
|
||||||
void untranslate();
|
void untranslate();
|
||||||
virtual void draw_decorated_window(Fl_Window *win, int x_offset, int y_offset);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* Fl_Quartz_Copy_Surface_Driver_H */
|
#endif /* Fl_Quartz_Copy_Surface_Driver_H */
|
||||||
|
@ -87,19 +87,4 @@ void Fl_Quartz_Copy_Surface_Driver::untranslate() {
|
|||||||
CGContextRestoreGState(gc);
|
CGContextRestoreGState(gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fl_Quartz_Copy_Surface_Driver::draw_decorated_window(Fl_Window *win, int x_offset, int y_offset) {
|
|
||||||
CALayer *layer = Fl_Cocoa_Window_Driver::driver(win)->get_titlebar_layer();
|
|
||||||
if (!layer) {
|
|
||||||
return Fl_Widget_Surface::draw_decorated_window(win, x_offset, y_offset);
|
|
||||||
}
|
|
||||||
CGContextSaveGState(gc);
|
|
||||||
int bt = win->decorated_h() - win->h();
|
|
||||||
CGContextTranslateCTM(gc, x_offset - 0.5, y_offset + bt - 0.5);
|
|
||||||
float s = Fl::screen_scale(win->screen_num());
|
|
||||||
CGContextScaleCTM(gc, 1/s, s >= 1 ? -1/s : -1);
|
|
||||||
Fl_Cocoa_Window_Driver::driver(win)->draw_layer_to_context(layer, gc, win->w() * s, bt*s);
|
|
||||||
CGContextRestoreGState(gc);
|
|
||||||
draw(win, x_offset, y_offset + bt); // print the window inner part
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // FL_CFG_GFX_QUARTZ
|
#endif // FL_CFG_GFX_QUARTZ
|
||||||
|
Loading…
Reference in New Issue
Block a user