0.009_001 release
[imager-screenshot.git] / scdarwin.c
CommitLineData
bc99c241
TC
1/* Darwin support via OpenGL */
2#include "imext.h"
3#include "imss.h"
4#include <ApplicationServices/ApplicationServices.h>
5#include "OpenGL/OpenGL.h"
6#include "OpenGL/gl.h"
7#include "OpenGL/glu.h"
8#include "OpenGL/glext.h"
9
10i_img *
11imss_darwin(i_img_dim left, i_img_dim top, i_img_dim right, i_img_dim bottom) {
12 CGDisplayCount count;
13 CGDisplayErr err;
14 CGRect rect;
15 CGLPixelFormatObj pix;
16 GLint npix;
17 CGLContextObj ctx;
18 i_img *im;
19 CGDirectDisplayID disp;
20 i_img_dim screen_width, screen_height;
21 i_img_dim width, height;
22
23 CGLPixelFormatAttribute pix_attrs[] =
24 {
25 kCGLPFADisplayMask, 0, /* filled in later */
26 kCGLPFAColorSize, 24,
27 kCGLPFAAlphaSize, 0,
28 kCGLPFAFullScreen,
29 0
30 };
31
32 i_clear_error();
33
34 disp = CGMainDisplayID();
0cc0b6d7
TC
35 if (!disp) {
36 i_push_error(0, "No main display");
37 return NULL;
38 }
bc99c241
TC
39
40 /* for now, only interested in the first display */
41 rect = CGDisplayBounds(disp);
42 screen_width = rect.size.width;
43 screen_height = rect.size.height;
44
45 /* adjust negative/zero values to window size */
46 if (left < 0)
47 left += screen_width;
48 if (top < 0)
49 top += screen_height;
50 if (right <= 0)
51 right += screen_width;
52 if (bottom <= 0)
53 bottom += screen_height;
54
55 /* clamp */
56 if (left < 0)
57 left = 0;
58 if (right > screen_width)
59 right = screen_width;
60 if (top < 0)
61 top = 0;
62 if (bottom > screen_height)
63 bottom = screen_height;
64
65 /* validate */
66 if (right <= left || bottom <= top) {
67 i_push_error(0, "image would be empty");
68 return NULL;
69 }
70
71 width = right - left;
72 height = bottom - top;
73
74 /* select a pixel format */
75 pix_attrs[1] = CGDisplayIDToOpenGLDisplayMask(disp);
76 err = CGLChoosePixelFormat(pix_attrs, &pix, &npix);
77 if (err) {
78 i_push_errorf(err, "CGLChoosePixelFormat: %d", (int)err);
79 return NULL;
80 }
81 if (!npix) {
0cc0b6d7 82 i_push_error(0, "No pixel format found - hidden display?");
bc99c241
TC
83 return NULL;
84 }
85
86 /* make ourselves a context */
87 err = CGLCreateContext(pix, NULL, &ctx);
88 CGLDestroyPixelFormat(pix);
89 if (err) {
90 i_push_errorf(err, "CGLCreateContext: %d", (int)err);
91 return NULL;
92 }
93
94 err = CGLSetCurrentContext(ctx);
95 if (err) {
96 i_push_errorf(err, "CGLSetCurrentContext: %d", (int)err);
97 return NULL;
98 }
99
100 err = CGLSetFullScreen(ctx);
101 if (err) {
102 i_push_errorf(err, "CGLSetFullScreen: %d", (int)err);
103 return NULL;
104 }
105
106 /* capture */
107 im = i_img_8_new(width, height, 3);
108 if (im) {
109 size_t line_size = width * 4;
110 size_t buf_size = line_size * height;
111 unsigned char *buf = malloc(buf_size);
112 i_img_dim y = height - 1;
113 i_color *bufp = (i_color *)buf; /* hackish */
114
115 /* GL has the vertical axis going from bottom to top, so translate it */
116
117 glReadBuffer(GL_FRONT);
118 glReadPixels(left, screen_height - top - height, width, height,
0cc0b6d7 119 GL_RGBA, GL_UNSIGNED_BYTE, buf);
bc99c241
TC
120
121 /* transfer */
122 while (y >= 0) {
123 i_plin(im, 0, width, y, bufp);
124 bufp += width;
125 --y;
126 }
127
128 free(buf);
0cc0b6d7
TC
129
130 i_tags_setn(&im->tags, "ss_window_width", width);
131 i_tags_setn(&im->tags, "ss_window_height", height);
132 i_tags_set(&im->tags, "ss_type", "Darwin", 6);
133 i_tags_setn(&im->tags, "ss_left", left);
134 i_tags_setn(&im->tags, "ss_top", top);
bc99c241
TC
135 }
136
137 /* clean up */
138 CGLSetCurrentContext(NULL);
139 CGLDestroyContext(ctx);
140
141 return im;
142}