4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bccapture.h"
23 #include "bcresources.h"
24 #include "bcwindowbase.h"
25 #include "bccmodels.h"
30 #include <X11/Xutil.h>
38 // 24 bpp unpacked: 0bgr
41 BC_Capture::BC_Capture(int w, int h, const char *display_path)
48 init_window(display_path);
53 BC_Capture::~BC_Capture()
56 XCloseDisplay(display);
59 int BC_Capture::init_window(const char *display_path)
62 if(display_path && display_path[0] == 0) display_path = NULL;
63 if((display = XOpenDisplay(display_path)) == NULL)
65 printf(_("cannot connect to X server.\n"));
66 if(getenv("DISPLAY") == NULL)
67 printf(_("'DISPLAY' environment variable not set.\n"));
72 screen = DefaultScreen(display);
73 rootwin = RootWindow(display, screen);
74 vis = DefaultVisual(display, screen);
75 default_depth = DefaultDepth(display, screen);
76 client_byte_order = (*(const u_int32_t*)"a ") & 0x00000001;
77 server_byte_order = (XImageByteOrder(display) == MSBFirst) ? 0 : 1;
80 ximage = XCreateImage(display,
90 bits_per_pixel = ximage->bits_per_pixel;
91 XDestroyImage(ximage);
92 bitmap_color_model = BC_WindowBase::evaluate_color_model(client_byte_order, server_byte_order, bits_per_pixel);
95 // This doesn't ensure the X Server is on the local host
96 if(use_shm && !XShmQueryExtension(display))
104 int BC_Capture::allocate_data()
107 if(!display) return 1;
110 ximage = XShmCreateImage(display, vis, default_depth, ZPixmap, (char*)NULL, &shm_info, w, h);
112 shm_info.shmid = shmget(IPC_PRIVATE, h * ximage->bytes_per_line, IPC_CREAT | 0600);
113 if(shm_info.shmid == -1)
115 perror("BC_Capture::allocate_data shmget");
118 data = (unsigned char *)shmat(shm_info.shmid, NULL, 0);
119 shmctl(shm_info.shmid, IPC_RMID, 0);
120 ximage->data = shm_info.shmaddr = (char*)data; // setting ximage->data stops BadValue
121 shm_info.readOnly = 0;
123 // Crashes here if remote server.
124 BC_Resources::error = 0;
125 XShmAttach(display, &shm_info);
126 XSync(display, False);
127 if(BC_Resources::error)
129 XDestroyImage(ximage);
130 shmdt(shm_info.shmaddr);
137 // need to use bytes_per_line for some X servers
139 ximage = XCreateImage(display, vis, default_depth, ZPixmap, 0, (char*)data, w, h, 8, 0);
140 data = (unsigned char*)malloc(h * ximage->bytes_per_line);
141 XDestroyImage(ximage);
143 ximage = XCreateImage(display, vis, default_depth, ZPixmap, 0, (char*)data, w, h, 8, 0);
146 row_data = new unsigned char*[h];
147 for(int i = 0; i < h; i++)
149 row_data[i] = &data[i * ximage->bytes_per_line];
151 // This differs from the depth parameter of the top_level.
152 bits_per_pixel = ximage->bits_per_pixel;
156 int BC_Capture::delete_data()
158 if(!display) return 1;
163 XShmDetach(display, &shm_info);
164 XDestroyImage(ximage);
165 shmdt(shm_info.shmaddr);
169 XDestroyImage(ximage);
172 // data is automatically freed by XDestroyImage
180 int BC_Capture::get_w() { return w; }
181 int BC_Capture::get_h() { return h; }
183 // Capture a frame from the screen
184 #define CAPTURE_FRAME_HEAD \
185 for(int i = 0; i < h; i++) \
187 unsigned char *input_row = row_data[i]; \
188 unsigned char *output_row = (unsigned char*)frame->get_rows()[i]; \
189 for(int j = 0; j < w; j++) \
192 #define CAPTURE_FRAME_TAIL \
198 int BC_Capture::capture_frame(VFrame *frame, int &x1, int &y1)
200 if(!display) return 1;
203 if(x1 > get_top_w() - w) x1 = get_top_w() - w;
204 if(y1 > get_top_h() - h) y1 = get_top_h() - h;
209 XShmGetImage(display, rootwin, ximage, x1, y1, 0xffffffff);
211 XGetSubImage(display, rootwin, x1, y1, w, h, 0xffffffff, ZPixmap, ximage, 0, 0);
213 BC_CModels::transfer(frame->get_rows(), row_data,
214 frame->get_y(), frame->get_u(), frame->get_v(), 0,
215 0, 0, 0, 0, w, h, 0, 0,
216 frame->get_w(), frame->get_h(),
217 bitmap_color_model, frame->get_color_model(),
218 0, frame->get_w(), w);
223 int BC_Capture::get_top_w()
225 Screen *screen_ptr = XDefaultScreenOfDisplay(display);
226 return WidthOfScreen(screen_ptr);
229 int BC_Capture::get_top_h()
231 Screen *screen_ptr = XDefaultScreenOfDisplay(display);
232 return HeightOfScreen(screen_ptr);