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