]> icculus.org git repositories - theoddone33/hhexen.git/blob - x11/xshmext.cpp
Initial revision
[theoddone33/hhexen.git] / x11 / xshmext.cpp
1 //============================================================================
2 //
3 // $Id$
4 //
5 // MIT Shared Memory Extension for X
6 //
7 //============================================================================
8
9
10 #include <stdio.h>
11 #include "xshmext.h"
12 #include <X11/Xutil.h>
13
14
15 //-----------------------------------------------------------------------------
16
17
18 // Shared memory error handler routine used temporarily by allocSHM().
19
20 static int _shmError;
21
22 static int (*_origErrorHandler)(Display*, XErrorEvent*);
23
24 static int _shmErrorHandler( Display* d, XErrorEvent* e )
25 {
26     _shmError++;
27     if( e->error_code == BadAccess )
28         fprintf( stderr, "ShmImage: failed to attach shared memory\n" );
29     else
30         (*_origErrorHandler)( d, e );
31     return 0;
32
33
34
35 static void* allocSHM( XShmSegmentInfo* si, Display* dis, int size )
36 {
37     si->shmaddr = 0;
38     si->shmid = shmget( IPC_PRIVATE, size, IPC_CREAT | 0777 );
39     if( si->shmid != -1 )
40     {
41         si->shmaddr = (char*) shmat( si->shmid, 0, 0 );
42         if( si->shmaddr != (char*) -1 )
43         {
44             si->readOnly = False;
45
46             // Attach the memory to the X Server.
47
48             _shmError = 0;
49             _origErrorHandler = XSetErrorHandler( _shmErrorHandler );
50             XShmAttach( dis, si );
51             XSync( dis, True );    // wait for error or ok
52             XSetErrorHandler( _origErrorHandler );
53             if( _shmError )
54             {
55                 shmdt( si->shmaddr );
56                 shmctl( si->shmid, IPC_RMID, 0 );
57                 si->shmaddr = 0;
58             }
59         }
60         else
61         {
62             shmctl( si->shmid, IPC_RMID, 0 );
63             si->shmaddr = 0;
64         }
65     }
66
67     return si->shmaddr;
68 }
69
70
71 static void freeSHM( XShmSegmentInfo* si, Display* dis )
72 {
73     if( si->shmaddr )
74     {
75         XShmDetach( dis, si );
76         //XSync( dis, False );//need server to detach so can remove id?
77
78         shmdt( si->shmaddr );
79         shmctl( si->shmid, IPC_RMID, 0 );
80     }
81 }
82
83
84 static int bytesPerLine( int width, int depth )
85 {
86     int bpl;
87
88     // TODO: Find out how to correctly calculate a Pixmap bytesPerLine that is
89     // guaranteed to be accurate on any X server.
90     // The important thing is that we don't calculate a value less that what
91     // is actually used by the server.
92
93     if( depth < 9 )
94     {
95         if( depth == 1 )
96             bpl = (width + 7) / 8;
97         else
98             bpl = width;
99     }
100     else
101     {
102         if( depth > 16 )
103             bpl = width * 4;
104         else
105             bpl = width * 2;
106     }
107
108     // Pad to 4 byte boundary.
109     if( bpl & 3 )
110         bpl += (4 - (bpl & 3));
111
112     return bpl;
113 }
114
115
116 //-----------------------------------------------------------------------------
117
118
119 /**
120   \class ShmImage xshmext.h
121   \brief The ShmImage class is an X11 XImage allocated in shared memory.
122 */
123
124
125 /**
126   \fn XImage* ShmImage::image()
127   Returns 0 if the constructor failed.
128 */
129
130
131 /**
132   Check to see if the XShm extensions are supported.
133   Returns the XEvent completion type or zero if XShm is not available to
134   the display.
135 */
136
137 int ShmImage::query( Display* dis )
138 {
139     if( ! XShmQueryExtension( dis ) )
140         return 0;
141
142     return completionType( dis );
143 }
144
145
146 ShmImage::ShmImage( Display* dis, int width, int height, XVisualInfo* vis )
147 {
148     _display = dis;
149
150     // Query here for safety?
151
152     _XImage = XShmCreateImage( _display, vis->visual, vis->depth, ZPixmap,
153                                NULL, &_si, width, height );
154     if( _XImage )
155     {
156         _XImage->data = (char*) allocSHM( &_si, _display,
157                                   _XImage->bytes_per_line * _XImage->height );
158         if( ! _XImage->data )
159         {
160             XDestroyImage( _XImage );
161             _XImage = 0;
162         }
163     }
164 }
165
166
167 ShmImage::~ShmImage()
168 {
169     if( _si.shmaddr )
170         freeSHM( &_si, _display );
171
172     if( _XImage )
173         XDestroyImage( _XImage );
174 }
175
176
177 //-----------------------------------------------------------------------------
178
179
180 /**
181   \class ShmPixmap xshmext.h
182   \brief The ShmPixmap class is an X11 Pixmap allocated in shared memory.
183 */
184
185
186 /**
187   \fn Pixmap* ShmPixmap::pixmap()
188   Returns 0 if the constructor failed.
189 */
190
191
192 /**
193   Check to see if the XShmPixmap extensions are supported.
194   Returns the XEvent completion type or zero if XShm is not available to
195   the display.
196 */
197
198 int ShmPixmap::query( Display* dis )
199 {
200     if( ! XShmPixmapFormat( dis ) )
201         return 0;
202
203     return ShmImage::query( dis );
204 }
205
206
207 ShmPixmap::ShmPixmap( Display* dis, Drawable draw, int width, int height,
208                       int depth )
209 {
210     _display = dis;
211
212     // Query here for safety?
213
214     if( depth < 1 )
215         depth = XDefaultDepth( _display, XDefaultScreen( _display ) );
216
217     allocSHM( &_si, _display, bytesPerLine( width, depth ) * height );
218     if( _si.shmaddr )
219     {
220         _pix = XShmCreatePixmap( _display, draw, _si.shmaddr, &_si,
221                                  width, height, depth );
222     }
223 }
224
225
226 ShmPixmap::~ShmPixmap()
227 {
228     if( _si.shmaddr )
229         freeSHM( &_si, _display );
230
231     if( _pix )
232         XFreePixmap( _display, _pix );
233 }
234
235
236 // EOF