mirror of
https://github.com/gnustep/libs-back.git
synced 2025-04-22 07:21:02 +00:00
* Source/cairo/Win32CairoSurface.m (-initWithDevice:): Make
* safer against the surface being deallocated during this method. * Source/cairo/Win32CairoSurface.m (WIN32Server-contentsOfScreen:inRect:): Screen grabbing code. * Headers/win32/WIN32Server.h, * Source/win32/WIN32Server.m (-monitorHandleForScreen:, -createHdcForScreen:, deleteScreenHdc:): Add helper methods for screen grabbing. Patch by Marcian Lytwyn <marcian.lytwyn@advcsi.com> git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@36612 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
803afa868a
commit
c536fdb0f2
4 changed files with 215 additions and 36 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
|||
2013-05-11 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Source/cairo/Win32CairoSurface.m (-initWithDevice:): Make safer
|
||||
against the surface being deallocated during this method.
|
||||
* Source/cairo/Win32CairoSurface.m
|
||||
(WIN32Server-contentsOfScreen:inRect:): Screen grabbing code.
|
||||
* Headers/win32/WIN32Server.h,
|
||||
* Source/win32/WIN32Server.m (-monitorHandleForScreen:,
|
||||
-createHdcForScreen:, deleteScreenHdc:): Add helper methods for screen grabbing.
|
||||
Patch by Marcian Lytwyn <marcian.lytwyn@advcsi.com>
|
||||
|
||||
2013-04-24 23:10-EDT Gregory John Casamento <greg.casamento@gmail.com>
|
||||
|
||||
* Source/cairo/CairoGState.m: Added code in -drawGradient:
|
||||
|
|
|
@ -114,6 +114,9 @@ typedef struct w32serverFlags
|
|||
|
||||
- (void) resizeBackingStoreFor: (HWND)hwnd;
|
||||
|
||||
- (HDC) createHdcForScreen: (int)screen;
|
||||
- (void) deleteScreenHdc: (HDC)hdc;
|
||||
|
||||
@end
|
||||
|
||||
@interface WIN32Server (w32_activate)
|
||||
|
|
|
@ -28,22 +28,22 @@
|
|||
|
||||
#include "cairo/Win32CairoSurface.h"
|
||||
#include "win32/WIN32Geometry.h"
|
||||
#include "win32/WIN32Server.h"
|
||||
#include <cairo-win32.h>
|
||||
|
||||
#define GSWINDEVICE ((HWND)gsDevice)
|
||||
|
||||
@implementation Win32CairoSurface
|
||||
|
||||
|
||||
- (id) initWithDevice: (void *)device
|
||||
{
|
||||
WIN_INTERN *win = (WIN_INTERN *)GetWindowLong((HWND)device, GWL_USERDATA);
|
||||
HDC hDC = GetDC((HWND)device);
|
||||
|
||||
// Save/set initial state...
|
||||
gsDevice = device;
|
||||
_surface = NULL;
|
||||
|
||||
WIN_INTERN *win = (WIN_INTERN *)GetWindowLong(GSWINDEVICE, GWL_USERDATA);
|
||||
HDC hDC = GetDC(GSWINDEVICE);
|
||||
|
||||
if (hDC == NULL)
|
||||
{
|
||||
NSWarnMLog(@"Win32CairoSurface line: %d : no device context", __LINE__);
|
||||
|
@ -124,15 +124,16 @@
|
|||
cairo_surface_destroy(window);
|
||||
|
||||
// Release the device context...
|
||||
ReleaseDC(GSWINDEVICE, hDC);
|
||||
ReleaseDC((HWND)device, hDC);
|
||||
}
|
||||
|
||||
if (self)
|
||||
if (win && self)
|
||||
{
|
||||
// We need this for handleExposeEvent in WIN32Server...
|
||||
win->surface = (void*)self;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -158,11 +159,12 @@
|
|||
|
||||
- (NSString*) description
|
||||
{
|
||||
HDC shdc = NULL;
|
||||
HDC shdc = NULL;
|
||||
|
||||
if (_surface)
|
||||
{
|
||||
shdc = cairo_win32_surface_get_dc(_surface);
|
||||
}
|
||||
{
|
||||
shdc = cairo_win32_surface_get_dc(_surface);
|
||||
}
|
||||
NSMutableString *description = AUTORELEASE([[super description] mutableCopy]);
|
||||
[description appendFormat: @" size: %@",NSStringFromSize([self size])];
|
||||
[description appendFormat: @" _surface: %p",_surface];
|
||||
|
@ -239,12 +241,12 @@
|
|||
cairo_paint(context);
|
||||
|
||||
if (cairo_status(context) != CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
NSWarnMLog(@"cairo expose error - status: _surface: %s window: %s windowCtxt: %s",
|
||||
cairo_status_to_string(cairo_surface_status(_surface)),
|
||||
cairo_status_to_string(cairo_surface_status(window)),
|
||||
cairo_status_to_string(cairo_status(context)));
|
||||
}
|
||||
{
|
||||
NSWarnMLog(@"cairo expose error - status: _surface: %s window: %s windowCtxt: %s",
|
||||
cairo_status_to_string(cairo_surface_status(_surface)),
|
||||
cairo_status_to_string(cairo_surface_status(window)),
|
||||
cairo_status_to_string(cairo_status(context)));
|
||||
}
|
||||
|
||||
// Cleanup...
|
||||
cairo_destroy(context);
|
||||
|
@ -264,3 +266,115 @@
|
|||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation WIN32Server (ScreenCapture)
|
||||
|
||||
- (NSImage *) contentsOfScreen: (int)screen inRect: (NSRect)rect
|
||||
{
|
||||
NSImage *result = nil;
|
||||
HDC hdc = [self createHdcForScreen: screen];
|
||||
|
||||
// We need a screen device context for this to work...
|
||||
if (hdc == NULL)
|
||||
{
|
||||
NSWarnMLog(@"invalid screen request: %d", screen);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert rect to flipped coordinates
|
||||
NSRect boundsForScreen = [self boundsForScreen: screen];
|
||||
NSInteger width = rect.size.width;
|
||||
NSInteger height = rect.size.height;
|
||||
NSBitmapImageRep *bmp;
|
||||
cairo_surface_t *src, *dest;
|
||||
|
||||
rect.origin.y = boundsForScreen.size.height - NSMaxY(rect);
|
||||
|
||||
// Create a bitmap representation for capturing the screen area...
|
||||
bmp = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL
|
||||
pixelsWide: width
|
||||
pixelsHigh: height
|
||||
bitsPerSample: 8
|
||||
samplesPerPixel: 4
|
||||
hasAlpha: YES
|
||||
isPlanar: NO
|
||||
colorSpaceName: NSDeviceRGBColorSpace
|
||||
bitmapFormat: 0
|
||||
bytesPerRow: 0
|
||||
bitsPerPixel: 32] autorelease];
|
||||
|
||||
// Create the required surfaces...
|
||||
src = cairo_win32_surface_create(hdc);
|
||||
dst = cairo_image_surface_create_for_data([bmp bitmapData],
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
width, height,
|
||||
[bmp bytesPerRow]);
|
||||
|
||||
// Ensure we were able to generate the required surfaces...
|
||||
if (cairo_surface_status(src) != CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
NSWarnMLog(@"cairo screen surface error status: %s\n",
|
||||
cairo_status_to_string(cairo_surface_status(src)));
|
||||
}
|
||||
else if (cairo_surface_status(dst) != CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
NSWarnMLog(@"cairo screen surface error status: %s\n",
|
||||
cairo_status_to_string(cairo_surface_status(dst)));
|
||||
cairo_surface_destroy(src);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Capture the requested screen rectangle...
|
||||
cairo_t *cr = cairo_create(dst);
|
||||
cairo_set_source_surface(cr, src, -1 * rect.origin.x, -1 * rect.origin.y);
|
||||
cairo_paint(cr);
|
||||
cairo_destroy(cr);
|
||||
|
||||
// Cleanup the cairo surfaces...
|
||||
cairo_surface_destroy(src);
|
||||
cairo_surface_destroy(dst);
|
||||
[self deleteScreenHdc: hdc];
|
||||
|
||||
// Convert BGRA to RGBA
|
||||
// Original code located in XGCairSurface.m
|
||||
{
|
||||
NSInteger stride;
|
||||
NSInteger x, y;
|
||||
unsigned char *cdata;
|
||||
|
||||
stride = [bmp bytesPerRow];
|
||||
cdata = [bmp bitmapData];
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
NSInteger i = (y * stride) + (x * 4);
|
||||
unsigned char d = cdata[i];
|
||||
|
||||
#if GS_WORDS_BIGENDIAN
|
||||
cdata[i + 0] = cdata[i + 1];
|
||||
cdata[i + 1] = cdata[i + 2];
|
||||
cdata[i + 2] = cdata[i + 3];
|
||||
cdata[i + 3] = d;
|
||||
#else
|
||||
cdata[i + 0] = cdata[i + 2];
|
||||
//cdata[i + 1] = cdata[i + 1];
|
||||
cdata[i + 2] = d;
|
||||
//cdata[i + 3] = cdata[i + 3];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the image and add the bitmap representation...
|
||||
result = [[[NSImage alloc] initWithSize: NSMakeSize(width, height)] autorelease];
|
||||
[result addRepresentation: bmp];
|
||||
}
|
||||
}
|
||||
|
||||
// Return whatever we got...
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -91,6 +91,8 @@ static unsigned int mask_for_keystate(BYTE *keyState);
|
|||
CGFloat h = lprcMonitor->bottom - lprcMonitor->top;
|
||||
CGFloat x = lprcMonitor->left;
|
||||
CGFloat y = h - lprcMonitor->bottom;
|
||||
|
||||
_hMonitor = hMonitor;
|
||||
_frame = NSMakeRect(x, y, w, h);
|
||||
memcpy(&_rect, lprcMonitor, sizeof(RECT));
|
||||
}
|
||||
|
@ -338,7 +340,7 @@ BOOL CALLBACK LoadDisplayMonitorInfo(HMONITOR hMonitor,
|
|||
[self _initWin32Context];
|
||||
[super initWithAttributes: info];
|
||||
|
||||
monitorInfo = [NSMutableArray array];
|
||||
monitorInfo = [[NSMutableArray alloc] init];
|
||||
EnumDisplayMonitors(NULL, NULL, (MONITORENUMPROC)LoadDisplayMonitorInfo, (LPARAM)monitorInfo);
|
||||
|
||||
[self setupRunLoopInputSourcesForMode: NSDefaultRunLoopMode];
|
||||
|
@ -392,6 +394,7 @@ BOOL CALLBACK LoadDisplayMonitorInfo(HMONITOR hMonitor,
|
|||
- (void) dealloc
|
||||
{
|
||||
[self _destroyWin32Context];
|
||||
RELEASE(monitorInfo);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -474,33 +477,81 @@ LRESULT CALLBACK windowEnumCallback(HWND hwnd, LPARAM lParam)
|
|||
{
|
||||
if (screen < [monitorInfo count])
|
||||
{
|
||||
return [[monitorInfo objectAtIndex:screen] frame];
|
||||
return [[monitorInfo objectAtIndex: screen] frame];
|
||||
}
|
||||
return NSZeroRect;
|
||||
}
|
||||
|
||||
- (NSWindowDepth) windowDepthForScreen: (int)screen
|
||||
- (HMONITOR) monitorHandleForScreen: (int)screen
|
||||
{
|
||||
HDC hdc = 0;
|
||||
int bits = 0;
|
||||
//int planes;
|
||||
|
||||
if (screen < [monitorInfo count])
|
||||
{
|
||||
MONITORINFOEX mix = { 0 };
|
||||
mix.cbSize = sizeof(MONITORINFOEX);
|
||||
HMONITOR hMonitor = [[monitorInfo objectAtIndex:screen] hMonitor];
|
||||
|
||||
if (GetMonitorInfo(hMonitor, (LPMONITORINFO)&mix))
|
||||
{
|
||||
hdc = CreateDC("DISPLAY", mix.szDevice, NULL, NULL);
|
||||
bits = GetDeviceCaps(hdc, BITSPIXEL) / 3;
|
||||
//planes = GetDeviceCaps(hdc, PLANES);
|
||||
//NSLog(@"bits %d planes %d", bits, planes);
|
||||
ReleaseDC(NULL, hdc);
|
||||
}
|
||||
return [[monitorInfo objectAtIndex: screen] hMonitor];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSWarnMLog(@"invalid screen number: %d", screen);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
- (HDC) createHdcForScreen: (int)screen
|
||||
{
|
||||
HDC hdc = NULL;
|
||||
HMONITOR hMonitor = [self monitorHandleForScreen: screen];
|
||||
|
||||
if (hMonitor == NULL)
|
||||
{
|
||||
NSWarnMLog(@"error obtaining monitor handle for screen: %d", screen);
|
||||
}
|
||||
else
|
||||
{
|
||||
MONITORINFOEX mix = { 0 };
|
||||
mix.cbSize = sizeof(MONITORINFOEX);
|
||||
|
||||
if (GetMonitorInfo(hMonitor, (LPMONITORINFO)&mix) == 0)
|
||||
{
|
||||
NSWarnMLog(@"error obtaining monitor info for screen: %d status: %d",
|
||||
screen, GetLastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
hdc = CreateDC("DISPLAY", mix.szDevice, NULL, NULL);
|
||||
if (hdc == NULL)
|
||||
{
|
||||
NSWarnMLog(@"error creating HDC for screen: %d - status: %d",
|
||||
screen, GetLastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hdc;
|
||||
}
|
||||
|
||||
- (void) deleteScreenHdc: (HDC)hdc
|
||||
{
|
||||
if (hdc == NULL)
|
||||
{
|
||||
NSWarnMLog(@"HDC is NULL");
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteDC(hdc);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSWindowDepth) windowDepthForScreen: (int)screen
|
||||
{
|
||||
HDC hdc = [self createHdcForScreen:screen];
|
||||
int bits = 0;
|
||||
|
||||
if (hdc)
|
||||
{
|
||||
bits = GetDeviceCaps(hdc, BITSPIXEL) / 3;
|
||||
//planes = GetDeviceCaps(hdc, PLANES);
|
||||
//NSLog(@"bits %d planes %d", bits, planes);
|
||||
[self deleteScreenHdc:hdc];
|
||||
}
|
||||
|
||||
return (_GSRGBBitValue | bits);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue