PageRenderTime 29ms CodeModel.GetById 2ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/filesystems/procfs/procfs_displays.cc

http://macfuse.googlecode.com/
C++ | 305 lines | 224 code | 64 blank | 17 comment | 18 complexity | 7ca3aa752edf214a0028d15edb5f4cbb MD5 | raw file
  1/*
  2 * MacFUSE-Based procfs
  3 * Display Files
  4 *
  5 * Thanks to Daniel Waylonis <http://nekotech.com> for image processing code.
  6 */
  7
  8#include <OpenGL/OpenGL.h>
  9#include <OpenGL/gl.h>
 10#include <Accelerate/Accelerate.h>
 11#include <IOKit/graphics/IOGraphicsLib.h>
 12#include <ApplicationServices/ApplicationServices.h>
 13
 14extern "C" {
 15
 16#include "procfs_displays.h"
 17
 18#define MAX_DISPLAYS 8
 19
 20static CGLContextObj CreateScreenGLContext(CGDirectDisplayID targetDisplay);
 21static void ReleaseScreenGLContext(CGLContextObj context);
 22static void CaptureScreenRectToBuffer(CGRect srcRect, vImage_Buffer *buffer);
 23static void *CreateFullScreenXRGB32(CGDirectDisplayID targetDisplay,
 24                                    int *width, int *height, int *rowBytes);
 25static CFMutableDataRef CreatePNGDataFromXRGB32Raster(void *raster,
 26                                                       int width, int height,
 27                                                       int bytesPerRow);
 28
 29static CGLContextObj
 30CreateScreenGLContext(CGDirectDisplayID targetDisplay)
 31{
 32    CGOpenGLDisplayMask displayMask;
 33    CGLPixelFormatObj   pixelFormatObj;
 34    GLint               numPixelFormats;
 35
 36    displayMask = CGDisplayIDToOpenGLDisplayMask(targetDisplay);
 37
 38    CGLPixelFormatAttribute attribs[] = {
 39        kCGLPFAFullScreen,
 40        kCGLPFADisplayMask,
 41        (CGLPixelFormatAttribute)displayMask,
 42        (CGLPixelFormatAttribute)NULL
 43    };
 44
 45    CGLContextObj context = NULL;
 46  
 47    /* Build a full-screen GL context */
 48
 49    CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats);
 50    CGLCreateContext(pixelFormatObj, NULL, &context);
 51    CGLDestroyPixelFormat(pixelFormatObj);
 52    CGLSetCurrentContext(context);
 53    CGLSetFullScreen(context);
 54
 55    return context;
 56}
 57
 58static void
 59ReleaseScreenGLContext(CGLContextObj context)
 60{
 61    CGLSetCurrentContext(NULL);
 62    CGLClearDrawable(context);
 63    CGLDestroyContext(context);
 64}
 65
 66static void
 67CaptureScreenRectToBuffer(CGRect srcRect, vImage_Buffer *buffer)
 68{
 69    /* Configure data packing and alignment for store operation. */
 70    /* 4-byte-aligned pixels packed. */
 71
 72    glPixelStorei(GL_PACK_ALIGNMENT, 4);
 73    glPixelStorei(GL_PACK_ROW_LENGTH, buffer->rowBytes / 4);
 74    glPixelStorei(GL_PACK_SKIP_ROWS, 0);
 75    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
 76  
 77#if __BIG_ENDIAN__
 78    GLenum pixelDataType = GL_UNSIGNED_INT_8_8_8_8_REV;
 79#else
 80    GLenum pixelDataType = GL_UNSIGNED_INT_8_8_8_8;
 81#endif /* __BIG_ENDIAN__ */
 82
 83    /*
 84     * Fetch data in XRGB format to our buffer (no alpha needed because we are
 85     * reading from the framebuffer, which has no alpha).
 86     */
 87
 88    glReadPixels((GLint)srcRect.origin.x, (GLint)srcRect.origin.y,
 89                 (GLint)srcRect.size.width, (GLint)srcRect.size.height,
 90                 GL_BGRA, pixelDataType, buffer->data);
 91  
 92    /*
 93     * Vertically reflect in place (OpenGL uses inverted coordinate space,
 94     * so the image is upside down in memory with respect to what we want.
 95     */
 96    vImageVerticalReflect_ARGB8888(buffer, buffer, kvImageNoFlags);
 97}
 98
 99static void *
100CreateFullScreenXRGB32(CGDirectDisplayID targetDisplay,
101                       int *width, int *height, int *rowBytes)
102{
103    GLint viewport[4];
104    long  bytes;
105    void *raster = NULL;
106
107    CGLContextObj context = CreateScreenGLContext(targetDisplay);
108    CGLSetCurrentContext(context);
109    glReadBuffer(GL_FRONT);
110    glGetIntegerv(GL_VIEWPORT, viewport);
111    glFinish();
112  
113    *width = viewport[2];
114    *height = viewport[3];
115    *rowBytes = (((*width) * 4) + 3) & ~3;
116    bytes = (*rowBytes) * (*height);
117
118    raster = malloc(bytes);
119    if (!raster) {
120        goto out;
121    }
122  
123    vImage_Buffer buffer;
124    buffer.data = raster;
125    buffer.height = *height;
126    buffer.width = *width;
127    buffer.rowBytes = *rowBytes;
128  
129    CaptureScreenRectToBuffer(CGRectMake(0, 0, *width, *height), &buffer);
130
131out:
132    ReleaseScreenGLContext(context);
133  
134    return raster;
135}
136
137static CFMutableDataRef
138CreatePNGDataFromXRGB32Raster(void *raster, int width, int height, 
139                               int bytesPerRow)
140{
141    CGColorSpaceRef colorSpace;
142    CGContextRef    context;
143    CGImageRef      image = NULL;
144
145    colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
146    context = CGBitmapContextCreate(raster, width, height, 8, bytesPerRow,
147                                    colorSpace, kCGImageAlphaNoneSkipFirst);
148
149    if (context) {
150        image = CGBitmapContextCreateImage(context);
151        CGContextRelease(context);
152    }
153  
154    if (!image) {
155        return NULL;
156    }
157  
158    CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
159    CGImageDestinationRef dest = 
160        CGImageDestinationCreateWithData((CFMutableDataRef)data, kUTTypePNG,
161                                         1, nil);
162  
163    if (dest) {
164        CGImageDestinationAddImage(dest, image, nil);
165        CGImageDestinationFinalize(dest);
166        CFRelease(dest);
167    }
168  
169    CGImageRelease(image);
170    CGColorSpaceRelease(colorSpace);
171  
172    return data;
173}
174
175static CGDirectDisplayID
176PROCFS_GetDisplayIDForDisplayAtIndex(unsigned int index)
177{
178    CGDisplayErr      dErr;
179    CGDisplayCount    displayCount;
180    CGDisplayCount    maxDisplays = MAX_DISPLAYS;
181    CGDirectDisplayID onlineDisplays[MAX_DISPLAYS];
182
183    dErr = CGGetOnlineDisplayList(maxDisplays, onlineDisplays, &displayCount);
184
185    if (dErr != kCGErrorSuccess) {
186        displayCount = 0;
187    }
188
189    if ((index < 0) || (index > (displayCount - 1))) {
190        return 0;
191    }
192
193    return onlineDisplays[index];
194}
195
196CGDisplayCount
197PROCFS_GetDisplayCount(void)
198{
199    CGDisplayErr      dErr;
200    CGDisplayCount    displayCount;
201    CGDisplayCount    maxDisplays = MAX_DISPLAYS;
202    CGDirectDisplayID onlineDisplays[MAX_DISPLAYS];
203
204    dErr = CGGetOnlineDisplayList(maxDisplays, onlineDisplays, &displayCount);
205
206    if (dErr != kCGErrorSuccess) {
207        displayCount = 0;
208    }
209
210    return displayCount;
211}
212
213int
214PROCFS_GetInfoForDisplayAtIndex(unsigned int index, char *buf, size_t *size)
215{
216    CGDirectDisplayID d = PROCFS_GetDisplayIDForDisplayAtIndex(index);
217    size_t insize = *size;
218
219    if (d == 0) {
220        return -1;
221    }
222
223    size_t acc = 0;
224
225    acc += snprintf(buf + acc, insize - acc, "%-20s%ldx%ld\n", "resolution",
226                    CGDisplayPixelsWide(d), CGDisplayPixelsHigh(d));
227    acc += snprintf(buf + acc, insize - acc, "%-20s%p\n", "base address",
228                    CGDisplayBaseAddress(d));
229    acc += snprintf(buf + acc, insize - acc, "%-20s%ld\n", "bits per pixel",
230                    CGDisplayBitsPerPixel(d));
231    acc += snprintf(buf + acc, insize - acc, "%-20s%ld\n", "bits per sample",
232                    CGDisplayBitsPerSample(d));
233    acc += snprintf(buf + acc, insize - acc, "%-20s%ld\n", "samples per pixel",
234                    CGDisplaySamplesPerPixel(d));
235    acc += snprintf(buf + acc, insize - acc, "%-20s%ld\n", "bytes per row",
236                    CGDisplayBytesPerRow(d));
237    acc += snprintf(buf + acc, insize - acc, "%-20s%s\n", "main display",
238                    CGDisplayIsMain(d) ? "yes" : "no");
239    acc += snprintf(buf + acc, insize - acc, "%-20s%s\n", "builtin display",
240                    CGDisplayIsBuiltin(d) ? "yes" : "no");
241    acc += snprintf(buf + acc, insize - acc, "%-20s%s\n", "OpenGL acceleration",
242                    CGDisplayUsesOpenGLAcceleration(d) ? "yes" : "no");
243    acc += snprintf(buf + acc, insize - acc, "%-20s%08x\n", "model number",
244                    CGDisplayModelNumber(d));
245    acc += snprintf(buf + acc, insize - acc, "%-20s%08x\n", "serial number",
246                    CGDisplaySerialNumber(d));
247    acc += snprintf(buf + acc, insize - acc, "%-20s%08x\n", "unit number",
248                    CGDisplayUnitNumber(d));
249    acc += snprintf(buf + acc, insize - acc, "%-20s%08x\n", "vendor number",
250                    CGDisplayVendorNumber(d));
251
252    *size = acc;
253
254    return 0;
255}
256
257off_t
258PROCFS_GetPNGSizeForDisplayAtIndex(unsigned int index)
259{
260    CGDirectDisplayID targetDisplay =
261        PROCFS_GetDisplayIDForDisplayAtIndex(index);
262
263    if (targetDisplay == 0) {
264        return (off_t)0;
265    }
266
267    off_t size = ((off_t)CGDisplayPixelsWide(targetDisplay) *
268                  (off_t)CGDisplayPixelsHigh(targetDisplay) *
269                  (off_t)3) + (off_t)8192;
270
271    return size;
272}
273
274int
275PROCFS_GetPNGForDisplayAtIndex(unsigned int index, CFMutableDataRef *data)
276{
277    CGDirectDisplayID targetDisplay =
278        PROCFS_GetDisplayIDForDisplayAtIndex(index);
279
280    *data = (CFMutableDataRef)0;
281
282    if (targetDisplay == 0) {
283        return -1;
284    }
285
286    void *raster = NULL;
287    int width, height, rowBytes;
288
289    raster = CreateFullScreenXRGB32(targetDisplay, &width, &height, &rowBytes);
290    if (!raster) {
291        return -1;
292    }
293
294    *data = CreatePNGDataFromXRGB32Raster(raster, width, height, rowBytes);
295
296    free(raster);
297
298    if (!*data) {
299        return -1;
300    }
301
302    return 0;
303}
304
305} /* extern "C" */