1/*
2 *
3Copyright 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24 *
25 * Author:  Bob Scheifler and Keith Packard, MIT X Consortium
26 */
27
28/* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */
29
30#ifdef HAVE_CONFIG_H
31#include <config.h>
32#endif
33#include <stdio.h>
34#include <X11/Xlibint.h>
35#include <X11/ImUtil.h>
36#include <X11/extensions/XShm.h>
37#include <X11/extensions/shmproto.h>
38#include <X11/extensions/Xext.h>
39#include <X11/extensions/extutil.h>
40
41static XExtensionInfo _shm_info_data;
42static XExtensionInfo *shm_info = &_shm_info_data;
43static const char *shm_extension_name = SHMNAME;
44
45#define ShmCheckExtension(dpy,i,val) \
46  XextCheckExtension (dpy, i, shm_extension_name, val)
47
48/*****************************************************************************
49 *                                                                           *
50 *			   private utility routines                          *
51 *                                                                           *
52 *****************************************************************************/
53
54static int close_display(Display *dpy, XExtCodes *codes);
55static char *error_string(Display *dpy, int code, XExtCodes *codes,
56			  char *buf, int n);
57static Bool wire_to_event (Display *dpy, XEvent *re, xEvent *event);
58static Status event_to_wire (Display *dpy, XEvent *re, xEvent *event);
59static /* const */ XExtensionHooks shm_extension_hooks = {
60    NULL,				/* create_gc */
61    NULL,				/* copy_gc */
62    NULL,				/* flush_gc */
63    NULL,				/* free_gc */
64    NULL,				/* create_font */
65    NULL,				/* free_font */
66    close_display,			/* close_display */
67    wire_to_event,			/* wire_to_event */
68    event_to_wire,			/* event_to_wire */
69    NULL,				/* error */
70    error_string,			/* error_string */
71};
72
73static const char *shm_error_list[] = {
74    "BadShmSeg",			/* BadShmSeg */
75};
76
77static XEXT_GENERATE_FIND_DISPLAY (find_display, shm_info, shm_extension_name,
78				   &shm_extension_hooks, ShmNumberEvents, NULL)
79
80static XEXT_GENERATE_CLOSE_DISPLAY (close_display, shm_info)
81
82static XEXT_GENERATE_ERROR_STRING (error_string, shm_extension_name,
83				   ShmNumberErrors, shm_error_list)
84
85
86static Bool
87wire_to_event (Display *dpy, XEvent *re, xEvent *event)
88{
89    XExtDisplayInfo *info = find_display (dpy);
90    XShmCompletionEvent	*se;
91    xShmCompletionEvent	*sevent;
92
93    ShmCheckExtension (dpy, info, False);
94
95    switch ((event->u.u.type & 0x7f) - info->codes->first_event) {
96    case ShmCompletion:
97	se = (XShmCompletionEvent *) re;
98	sevent = (xShmCompletionEvent *) event;
99	se->type = sevent->type & 0x7f;
100	se->serial = _XSetLastRequestRead(dpy,(xGenericReply *) event);
101	se->send_event = (sevent->type & 0x80) != 0;
102	se->display = dpy;
103	se->drawable = sevent->drawable;
104	se->major_code = sevent->majorEvent;
105	se->minor_code = sevent->minorEvent;
106	se->shmseg = sevent->shmseg;
107	se->offset = sevent->offset;
108    	return True;
109    }
110    return False;
111}
112
113static Status
114event_to_wire (Display *dpy, XEvent *re, xEvent *event)
115{
116    XExtDisplayInfo *info = find_display (dpy);
117    XShmCompletionEvent	*se;
118    xShmCompletionEvent	*sevent;
119
120    ShmCheckExtension (dpy, info, 0);
121
122    switch ((re->type & 0x7f) - info->codes->first_event) {
123    case ShmCompletion:
124    	se = (XShmCompletionEvent *) re;
125	sevent = (xShmCompletionEvent *) event;
126    	sevent->type = se->type | (se->send_event ? 0x80 : 0);
127    	sevent->sequenceNumber = se->serial & 0xffff;
128    	sevent->drawable = se->drawable;
129    	sevent->majorEvent = se->major_code;
130    	sevent->minorEvent = se->minor_code;
131    	sevent->shmseg = se->shmseg;
132    	sevent->offset = se->offset;
133    	return True;
134    }
135    return False;
136}
137
138/*****************************************************************************
139 *                                                                           *
140 *		    public Shared Memory Extension routines                  *
141 *                                                                           *
142 *****************************************************************************/
143
144Bool XShmQueryExtension (Display *dpy /*  int *event_basep, *error_basep */)
145{
146    XExtDisplayInfo *info = find_display (dpy);
147
148    if (XextHasExtension(info)) {
149/*	*event_basep = info->codes->first_event;
150	*error_basep = info->codes->error_event; */
151	return True;
152    } else {
153	return False;
154    }
155}
156
157
158int XShmGetEventBase(Display *dpy)
159{
160    XExtDisplayInfo *info = find_display (dpy);
161
162    if (XextHasExtension(info)) {
163	return info->codes->first_event;
164    } else {
165	return -1;
166    }
167}
168
169
170Bool XShmQueryVersion(
171    Display *dpy,
172    int *majorVersion,
173    int *minorVersion,
174    Bool *sharedPixmaps)
175{
176    XExtDisplayInfo *info = find_display (dpy);
177    xShmQueryVersionReply rep;
178    register xShmQueryVersionReq *req;
179
180    ShmCheckExtension (dpy, info, False);
181
182    LockDisplay(dpy);
183    GetReq(ShmQueryVersion, req);
184    req->reqType = info->codes->major_opcode;
185    req->shmReqType = X_ShmQueryVersion;
186    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
187	UnlockDisplay(dpy);
188	SyncHandle();
189	return False;
190    }
191    *majorVersion = rep.majorVersion;
192    *minorVersion = rep.minorVersion;
193    *sharedPixmaps = rep.sharedPixmaps ? True : False;
194    UnlockDisplay(dpy);
195    SyncHandle();
196    return True;
197}
198
199
200int XShmPixmapFormat(Display *dpy)
201{
202    XExtDisplayInfo *info = find_display (dpy);
203    xShmQueryVersionReply rep;
204    register xShmQueryVersionReq *req;
205
206    ShmCheckExtension (dpy, info, False);
207
208    LockDisplay(dpy);
209    GetReq(ShmQueryVersion, req);
210    req->reqType = info->codes->major_opcode;
211    req->shmReqType = X_ShmQueryVersion;
212    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
213	UnlockDisplay(dpy);
214	SyncHandle();
215	return 0;
216    }
217    UnlockDisplay(dpy);
218    SyncHandle();
219    if (rep.sharedPixmaps &&
220	(rep.majorVersion > 1 || rep.minorVersion > 0))
221	return rep.pixmapFormat;
222    return 0;
223}
224
225
226Bool XShmAttach(Display *dpy, XShmSegmentInfo *shminfo)
227{
228    XExtDisplayInfo *info = find_display (dpy);
229    register xShmAttachReq *req;
230
231    ShmCheckExtension (dpy, info, 0);
232
233    LockDisplay(dpy);
234    GetReq(ShmAttach, req);
235    req->reqType = info->codes->major_opcode;
236    req->shmReqType = X_ShmAttach;
237    req->shmseg = shminfo->shmseg = XAllocID(dpy);
238    req->shmid = shminfo->shmid;
239    req->readOnly = shminfo->readOnly ? xTrue : xFalse;
240    UnlockDisplay(dpy);
241    SyncHandle();
242    return 1;
243}
244
245
246Bool XShmDetach(Display *dpy, XShmSegmentInfo *shminfo)
247{
248    XExtDisplayInfo *info = find_display (dpy);
249    register xShmDetachReq *req;
250
251    ShmCheckExtension (dpy, info, 0);
252
253    LockDisplay(dpy);
254    GetReq(ShmDetach, req);
255    req->reqType = info->codes->major_opcode;
256    req->shmReqType = X_ShmDetach;
257    req->shmseg = shminfo->shmseg;
258    UnlockDisplay(dpy);
259    SyncHandle();
260    return 1;
261}
262
263static int _XShmDestroyImage (XImage *ximage)
264{
265	Xfree(ximage);
266	return 1;
267}
268
269#define ROUNDUP(nbytes, pad) ((((nbytes) + ((pad) - 1)) / (pad)) * (pad))
270
271XImage *XShmCreateImage (
272    register Display *dpy,
273    register Visual *visual,
274    unsigned int depth,
275    int format,
276    char *data,
277    XShmSegmentInfo *shminfo,
278    unsigned int width,
279    unsigned int height)
280{
281    register XImage *image;
282
283    image = Xcalloc(1, sizeof(XImage));
284    if (!image)
285	return image;
286    image->data = data;
287    image->obdata = (char *)shminfo;
288    image->width = width;
289    image->height = height;
290    image->depth = depth;
291    image->format = format;
292    image->byte_order = dpy->byte_order;
293    image->bitmap_unit = dpy->bitmap_unit;
294    image->bitmap_bit_order = dpy->bitmap_bit_order;
295    image->bitmap_pad = _XGetScanlinePad(dpy, depth);
296    image->xoffset = 0;
297    if (visual) {
298	image->red_mask = visual->red_mask;
299	image->green_mask = visual->green_mask;
300	image->blue_mask = visual->blue_mask;
301    } else {
302	image->red_mask = image->green_mask = image->blue_mask = 0;
303    }
304    if (format == ZPixmap)
305	image->bits_per_pixel = _XGetBitsPerPixel(dpy, (int)depth);
306    else
307	image->bits_per_pixel = 1;
308    image->bytes_per_line = ROUNDUP((image->bits_per_pixel * width),
309				    image->bitmap_pad) >> 3;
310    _XInitImageFuncPtrs(image);
311    image->f.destroy_image = _XShmDestroyImage;
312    return image;
313}
314
315Bool XShmPutImage (
316    register Display *dpy,
317    Drawable d,
318    GC gc,
319    register XImage *image,
320    int src_x, int src_y, int dst_x, int dst_y,
321    unsigned int src_width, unsigned int src_height,
322    Bool send_event)
323{
324    XExtDisplayInfo *info = find_display (dpy);
325    XShmSegmentInfo *shminfo = (XShmSegmentInfo *)image->obdata;
326    register xShmPutImageReq *req;
327
328    ShmCheckExtension (dpy, info, 0);
329    if (!shminfo) return 0;
330
331    LockDisplay(dpy);
332    FlushGC(dpy, gc);
333    GetReq(ShmPutImage, req);
334    req->reqType = info->codes->major_opcode;
335    req->shmReqType = X_ShmPutImage;
336    req->drawable = d;
337    req->gc = gc->gid;
338    req->srcX = src_x;
339    req->srcY = src_y;
340    req->srcWidth = src_width;
341    req->srcHeight = src_height;
342    req->dstX = dst_x;
343    req->dstY = dst_y;
344    req->totalWidth = image->width;
345    req->totalHeight = image->height;
346    req->depth = image->depth;
347    req->format = image->format;
348    req->sendEvent = send_event;
349    req->shmseg = shminfo->shmseg;
350    req->offset = image->data - shminfo->shmaddr;
351    UnlockDisplay(dpy);
352    SyncHandle();
353    return 1;
354}
355
356
357Bool XShmGetImage(
358    register Display *dpy,
359    Drawable d,
360    XImage *image,
361    int x, int y,
362    unsigned long plane_mask)
363{
364    XExtDisplayInfo *info = find_display (dpy);
365    XShmSegmentInfo *shminfo = (XShmSegmentInfo *)image->obdata;
366    register xShmGetImageReq *req;
367    xShmGetImageReply rep;
368    register Visual *visual;
369
370    ShmCheckExtension (dpy, info, 0);
371    if (!shminfo) return 0;
372
373    LockDisplay(dpy);
374    GetReq(ShmGetImage, req);
375    req->reqType = info->codes->major_opcode;
376    req->shmReqType = X_ShmGetImage;
377    req->drawable = d;
378    req->x = x;
379    req->y = y;
380    req->width = image->width;
381    req->height = image->height;
382    req->planeMask = plane_mask;
383    req->format = image->format;
384    req->shmseg = shminfo->shmseg;
385    req->offset = image->data - shminfo->shmaddr;
386    if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
387	UnlockDisplay(dpy);
388	SyncHandle();
389	return 0;
390    }
391    visual = _XVIDtoVisual(dpy, rep.visual);
392    if (visual) {
393    	image->red_mask = visual->red_mask;
394    	image->green_mask = visual->green_mask;
395    	image->blue_mask = visual->blue_mask;
396    } else {
397	image->red_mask = image->green_mask = image->blue_mask = 0;
398    }
399    UnlockDisplay(dpy);
400    SyncHandle();
401    return 1;
402}
403
404Pixmap XShmCreatePixmap (
405    register Display *dpy,
406    Drawable d,
407    char *data,
408    XShmSegmentInfo *shminfo,
409    unsigned int width, unsigned int height, unsigned int depth)
410{
411    XExtDisplayInfo *info = find_display (dpy);
412    Pixmap pid;
413    register xShmCreatePixmapReq *req;
414
415    ShmCheckExtension (dpy, info, 0);
416
417    LockDisplay(dpy);
418    GetReq(ShmCreatePixmap, req);
419    req->reqType = info->codes->major_opcode;
420    req->shmReqType = X_ShmCreatePixmap;
421    req->drawable = d;
422    req->width = width;
423    req->height = height;
424    req->depth = depth;
425    req->shmseg = shminfo->shmseg;
426    req->offset = data - shminfo->shmaddr;
427    pid = req->pid = XAllocID(dpy);
428    UnlockDisplay(dpy);
429    SyncHandle();
430    return pid;
431}
432