1 /* Copyright (C)2004 Landmark Graphics Corporation
2 * Copyright (C)2005, 2006 Sun Microsystems, Inc.
3 * Copyright (C)2009, 2014, 2018-2019 D. R. Commander
4 *
5 * This library is free software and may be redistributed and/or modified under
6 * the terms of the wxWindows Library License, Version 3.1 or (at your option)
7 * any later version. The full license is in the LICENSE.txt file included
8 * with this distribution.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * wxWindows Library License for more details.
14 */
15
16 /* This library abstracts X Video drawing */
17 #include <string.h>
18 #include <stdlib.h>
19 #include "fbxv.h"
20 #include "x11err.h"
21
22
23 static int errorLine = -1;
24 static FILE *warningFile = NULL;
25
26
27 static char lastError[1024] = "No error";
28
29 #define THROW(m) \
30 { \
31 snprintf(lastError, 1023, "%s", m); errorLine = __LINE__; goto finally; \
32 }
33
34 #define TRY_X11(f) \
35 { \
36 int __err = 0; \
37 if((__err = (f)) != Success) \
38 { \
39 snprintf(lastError, 1023, \
40 "X11 %s Error (window may have disappeared)", x11error(__err)); \
41 errorLine = __LINE__; goto finally; \
42 } \
43 }
44
45 #define ERRIFNOT(f) \
46 { \
47 if(!(f)) \
48 { \
49 snprintf(lastError, 1023, "X11 Error (window may have disappeared)"); \
50 errorLine = __LINE__; goto finally; \
51 } \
52 }
53
54
55 #ifdef USESHM
56 static unsigned long serial = 0; static int extok = 1;
57 static XErrorHandler prevHandler = NULL;
58
59 #ifndef X_ShmAttach
60 #define X_ShmAttach 1
61 #endif
62
xhandler(Display * dpy,XErrorEvent * e)63 static int xhandler(Display *dpy, XErrorEvent *e)
64 {
65 if(e->serial == serial && (e->minor_code == X_ShmAttach
66 && e->error_code == BadAccess))
67 {
68 extok = 0; return 0;
69 }
70 if(prevHandler && prevHandler != xhandler) return prevHandler(dpy, e);
71 else return 0;
72 }
73 #endif
74
75
fbxv_geterrmsg(void)76 char *fbxv_geterrmsg(void)
77 {
78 return lastError;
79 }
80
81
fbxv_geterrline(void)82 int fbxv_geterrline(void)
83 {
84 return errorLine;
85 }
86
87
fbxv_printwarnings(FILE * stream)88 void fbxv_printwarnings(FILE *stream)
89 {
90 warningFile = stream;
91 }
92
93
fbxv_init(fbxv_struct * fb,Display * dpy,Window win,int width_,int height_,int format,int useShm)94 int fbxv_init(fbxv_struct *fb, Display *dpy, Window win, int width_,
95 int height_, int format, int useShm)
96 {
97 int width, height, k, shmok = 1, nformats;
98 unsigned int dummy1, dummy2, dummy3, dummy4, dummy5, i, j, nadaptors = 0;
99 XWindowAttributes xwa;
100 XvAdaptorInfo *ai = NULL;
101 XvImageFormatValues *ifv = NULL;
102
103 if(!fb) THROW("Invalid argument");
104
105 if(!dpy || !win) THROW("Invalid argument");
106 ERRIFNOT(XGetWindowAttributes(dpy, win, &xwa));
107 if(width_ > 0) width = width_; else width = xwa.width;
108 if(height_ > 0) height = height_; else height = xwa.height;
109 if(fb->dpy == dpy && fb->win == win)
110 {
111 if(width == fb->reqwidth && height == fb->reqheight && fb->xvi && fb->xgc
112 && fb->xvi->data)
113 return 0;
114 else if(fbxv_term(fb) == -1) return -1;
115 }
116 memset(fb, 0, sizeof(fbxv_struct));
117 fb->dpy = dpy; fb->win = win;
118 fb->reqwidth = width; fb->reqheight = height;
119
120 if(XvQueryExtension(dpy, &dummy1, &dummy2, &dummy3, &dummy4, &dummy5)
121 != Success)
122 THROW("X Video Extension not available");
123 if(XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &nadaptors, &ai) != Success)
124 THROW("Could not query X Video adaptors");
125 if(nadaptors < 1 || !ai) THROW("No X Video adaptors available");
126
127 fb->port = -1;
128 for(i = 0; i < nadaptors; i++)
129 {
130 for(j = ai[i].base_id; j < ai[i].base_id + ai[i].num_ports; j++)
131 {
132 nformats = 0;
133 ifv = XvListImageFormats(dpy, j, &nformats);
134 if(ifv && nformats > 0)
135 {
136 for(k = 0; k < nformats; k++)
137 {
138 if(ifv[k].id == format)
139 {
140 XFree(ifv); fb->port = j;
141 goto found;
142 }
143 }
144 }
145 XFree(ifv);
146 }
147 }
148 found:
149 XvFreeAdaptorInfo(ai); ai = NULL;
150 if(fb->port == -1)
151 THROW("The X Video implementation on the 2D X Server does not support the desired pixel format");
152
153 #ifdef USESHM
154 if(useShm && XShmQueryExtension(fb->dpy))
155 {
156 static int alreadyWarned = 0;
157 fb->shminfo.shmid = -1;
158 if(!(fb->xvi = XvShmCreateImage(dpy, fb->port, format, 0, width, height,
159 &fb->shminfo)))
160 {
161 useShm = 0; goto noshm;
162 }
163 if((fb->shminfo.shmid = shmget(IPC_PRIVATE, fb->xvi->data_size,
164 IPC_CREAT | 0777)) == -1)
165 {
166 useShm = 0; XFree(fb->xvi); goto noshm;
167 }
168 if((fb->shminfo.shmaddr = fb->xvi->data =
169 (char *)shmat(fb->shminfo.shmid, 0, 0)) == (char *)-1)
170 {
171 useShm = 0; XFree(fb->xvi); shmctl(fb->shminfo.shmid, IPC_RMID, 0);
172 goto noshm;
173 }
174 fb->shminfo.readOnly = False;
175 XLockDisplay(dpy);
176 XSync(dpy, False);
177 prevHandler = XSetErrorHandler(xhandler);
178 extok = 1;
179 serial = NextRequest(dpy);
180 XShmAttach(dpy, &fb->shminfo);
181 XSync(dpy, False);
182 XSetErrorHandler(prevHandler);
183 shmok = extok;
184 if(!alreadyWarned && !shmok && warningFile)
185 {
186 fprintf(warningFile,
187 "[FBX] WARNING: MIT-SHM extension failed to initialize (this is normal on a\n");
188 fprintf(warningFile, "[FBX] remote X connection.)\n");
189 alreadyWarned = 1;
190 }
191 XUnlockDisplay(dpy);
192 shmctl(fb->shminfo.shmid, IPC_RMID, 0);
193 if(!shmok)
194 {
195 useShm = 0; XFree(fb->xvi); shmdt(fb->shminfo.shmaddr);
196 shmctl(fb->shminfo.shmid, IPC_RMID, 0); goto noshm;
197 }
198 fb->xattach = 1; fb->shm = 1;
199 }
200 else if(useShm)
201 {
202 static int alreadyWarned = 0;
203 if(!alreadyWarned && warningFile)
204 {
205 fprintf(warningFile, "[FBX] WARNING: MIT-SHM extension not available.\n");
206 alreadyWarned = 1;
207 }
208 useShm = 0;
209 }
210 noshm:
211 if(!useShm)
212 #endif
213 {
214 if(!(fb->xvi = XvCreateImage(dpy, fb->port, format, 0, width, height)))
215 THROW("Could not create XvImage structure");
216 if(!(fb->xvi->data = malloc(fb->xvi->data_size)))
217 THROW("Memory allocation failure");
218 }
219 if(!(fb->xgc = XCreateGC(dpy, win, 0, NULL)))
220 THROW("Could not create X11 graphics context");
221 return 0;
222
223 finally:
224 fbxv_term(fb);
225 return -1;
226 }
227
228
fbxv_write(fbxv_struct * fb,int srcX_,int srcY_,int srcWidth_,int srcHeight_,int dstX_,int dstY_,int dstWidth,int dstHeight)229 int fbxv_write(fbxv_struct *fb, int srcX_, int srcY_, int srcWidth_,
230 int srcHeight_, int dstX_, int dstY_, int dstWidth, int dstHeight)
231 {
232 int srcX, srcY, dstX, dstY, srcWidth, srcHeight;
233 if(!fb) THROW("Invalid argument");
234
235 srcX = srcX_ >= 0 ? srcX_ : 0;
236 srcY = srcY_ >= 0 ? srcY_ : 0;
237 srcWidth = srcWidth_ > 0 ? srcWidth_ : fb->xvi->width;
238 srcHeight = srcHeight_ > 0 ? srcHeight_ : fb->xvi->height;
239 dstX = dstX_ >= 0 ? dstX_ : 0;
240 dstY = dstY_ >= 0 ? dstY_ : 0;
241
242 if(srcWidth > fb->xvi->width) srcWidth = fb->xvi->width;
243 if(srcHeight > fb->xvi->height) srcHeight = fb->xvi->height;
244 if(srcX + srcWidth > fb->xvi->width) srcWidth = fb->xvi->width - srcX;
245 if(srcY + srcHeight > fb->xvi->height) srcHeight = fb->xvi->height - srcY;
246
247 #ifdef USESHM
248 if(fb->shm)
249 {
250 if(!fb->xattach)
251 {
252 ERRIFNOT(XShmAttach(fb->dpy, &fb->shminfo)); fb->xattach = 1;
253 }
254 TRY_X11(XvShmPutImage(fb->dpy, fb->port, fb->win, fb->xgc, fb->xvi, srcX,
255 srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, False));
256 }
257 else
258 #endif
259
260 TRY_X11(XvPutImage(fb->dpy, fb->port, fb->win, fb->xgc, fb->xvi, srcX, srcY,
261 srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight));
262 XFlush(fb->dpy);
263 XSync(fb->dpy, False);
264 return 0;
265
266 finally:
267 return -1;
268 }
269
270
fbxv_term(fbxv_struct * fb)271 int fbxv_term(fbxv_struct *fb)
272 {
273 if(!fb) THROW("Invalid argument");
274 if(fb->xvi && !fb->shm)
275 {
276 free(fb->xvi->data); fb->xvi->data = NULL;
277 }
278
279 #ifdef USESHM
280 if(fb->shm)
281 {
282 if(fb->xattach)
283 {
284 XShmDetach(fb->dpy, &fb->shminfo); XSync(fb->dpy, False);
285 }
286 if(fb->shminfo.shmaddr != NULL) shmdt(fb->shminfo.shmaddr);
287 if(fb->shminfo.shmid != -1) shmctl(fb->shminfo.shmid, IPC_RMID, 0);
288 }
289 #endif
290
291 if(fb->xvi) XFree(fb->xvi);
292 if(fb->xgc) XFreeGC(fb->dpy, fb->xgc);
293 memset(fb, 0, sizeof(fbxv_struct));
294 return 0;
295
296 finally:
297 return -1;
298 }
299