]> git.sesse.net Git - ccbs/blob - bigscreen/tinyptc/xshm.c
Only allocate space for four digits in the score screen -- if somebody actually gets...
[ccbs] / bigscreen / tinyptc / xshm.c
1 /*
2  * TinyPTC x11 v0.7.3 X Shared Memory Extension target
3  * Copyright (C) 2000-2002 Alessandro Gatti <a.gatti@tiscali.it>
4  *
5  * http://www.sourceforge.net/projects/tinyptc/
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  * 
21  */
22
23 /* #includes */
24
25 #include <X11/Xlib.h>
26 #include <X11/Xutil.h>
27 #include <X11/extensions/XShm.h>
28 #include <sys/ipc.h>
29 #include <sys/shm.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <limits.h>
34 #include "tinyptc.h"
35
36 #ifdef __PTC_XSHM__
37
38 #define __PTC_FROM_SOURCE
39
40 #include "xshm.h"
41
42 /* Open the screen */
43
44 int
45 ptc_open (char *title, int width, int height)
46 {
47   /* Open a display on the current root window */
48   ptc_display = XOpenDisplay (NULL);
49   if (ptc_display == NULL)
50     {
51       return PTC_FAILURE;
52     }
53   /* Get the default screen associated with the previously opened display */
54   ptc_screen = DefaultScreen (ptc_display);
55   /* Get the default visual */
56   ptc_visual = DefaultVisual (ptc_display, ptc_screen);
57   /* Get screen bitdepth */
58   ptc_depth = DefaultDepth (ptc_display, ptc_screen);
59   /* Get a pointer to the supported pixmap formats */
60   ptc_pixmap_formats =
61     XListPixmapFormats (ptc_display, &ptc_pixmap_format_count);
62   /* Check if there's one that's suitable */
63   for (ptc_pixmap_counter = 0; ptc_pixmap_counter < ptc_pixmap_format_count;
64        ptc_pixmap_counter++)
65     {
66       if (ptc_depth == ptc_pixmap_formats[ptc_pixmap_counter].depth)
67         {
68           /* Set the right value */
69           ptc_converter_depth =
70             ptc_pixmap_formats[ptc_pixmap_counter].bits_per_pixel;
71         }
72     }
73   XFree (ptc_pixmap_formats);
74 #ifdef __PTC_ENABLE_CONVERSIONS__
75   /* Check if a converter is avaliable */
76   ptc_convert =
77     ptc_request_converter (ptc_converter_depth, ptc_visual->red_mask,
78                            ptc_visual->green_mask, ptc_visual->blue_mask);
79   if (!ptc_convert)
80     {
81       /* Close the display */
82       XCloseDisplay (ptc_display);
83       return 0;
84     }
85   /* Get the actual bytes-per-pixel value */
86   switch (ptc_converter_depth)
87     {
88     case 8:
89       ptc_output_pitch = 1;
90       break;
91     case 15:
92       ptc_output_pitch = 2;
93       break;
94     case 16:
95       ptc_output_pitch = 2;
96       break;
97     case 24:
98       ptc_output_pitch = 3;
99       break;
100     case 32:
101       ptc_output_pitch = 4;
102       break;
103     }
104   /* Allocate the temporary buffer */
105   ptc_buffer = (char *) malloc (width * height * ptc_output_pitch);
106   if (ptc_buffer == NULL)
107     {
108       XCloseDisplay (ptc_display);
109       return PTC_FAILURE;
110     }
111 #else
112   /* It runs only on a 32bpp display if no conversions were activated */
113   if (ptc_converter_depth != 32)
114     {
115       XCloseDisplay (ptc_display);
116       return PTC_FAILURE;
117     }
118 #endif /* __PTC_ENABLE_CONVERSIONS__ */
119   /* Check for XShm extension */
120   if (!XShmQueryExtension (ptc_display))
121     {
122       XCloseDisplay (ptc_display);
123       return PTC_FAILURE;
124     }
125   /* Get screen dimensions */
126   ptc_screen_width = DisplayWidth (ptc_display, ptc_screen);
127   ptc_screen_height = DisplayHeight (ptc_display, ptc_screen);
128   /* Get the default root window */
129   ptc_root_window = DefaultRootWindow (ptc_display);
130   /* Initialize window's attribute structure */
131   ptc_window_attributes.border_pixel = BlackPixel (ptc_display, ptc_screen);
132   ptc_window_attributes.background_pixel =
133     BlackPixel (ptc_display, ptc_screen);
134   ptc_window_attributes.backing_store = NotUseful;
135 #ifdef __PTC_CENTER_WINDOW__
136   /* Center the window on the screen */
137   ptc_x_position = (ptc_screen_width - width) / 2;
138   ptc_y_position = (ptc_screen_height - height) / 2;
139 #else
140   /* Dock the window on the top-left corner */
141   ptc_x_position = 0;
142   ptc_y_position = 0;
143 #endif /* __PTC_CENTER_WINDOW__ */
144   /* Create the window */
145   ptc_window =
146     XCreateWindow (ptc_display, ptc_root_window, ptc_x_position,
147                    ptc_y_position, width, height, 0, ptc_depth, InputOutput,
148                    ptc_visual, CWBackPixel | CWBorderPixel | CWBackingStore,
149                    &ptc_window_attributes);
150   /* Set the window's name */
151   XStoreName (ptc_display, ptc_window, title);
152   /* Tell the server to report only keypress-related events */
153   XSelectInput (ptc_display, ptc_window, KeyPressMask | KeyReleaseMask);
154   /* Initialize window's sizehint definition structure */
155   ptc_window_sizehints.flags = PPosition | PMinSize | PMaxSize;
156   ptc_window_sizehints.x = 0;
157   ptc_window_sizehints.y = 0;
158   ptc_window_sizehints.min_width = width;
159   ptc_window_sizehints.max_width = width;
160   ptc_window_sizehints.min_height = height;
161   ptc_window_sizehints.max_height = height;
162   /* Set the window's sizehint */
163   XSetWMNormalHints (ptc_display, ptc_window, &ptc_window_sizehints);
164   /* Clear the window */
165   XClearWindow (ptc_display, ptc_window);
166   /* Put the window on top of the others */
167   XMapRaised (ptc_display, ptc_window);
168   /* Clear event queue */
169   XFlush (ptc_display);
170   /* Get the default graphic context */
171   ptc_window_gc = DefaultGC (ptc_display, ptc_screen);
172   /* Create an XShmImage */
173   ptc_ximage =
174     XShmCreateImage (ptc_display, ptc_visual, ptc_depth, ZPixmap, 0,
175                      &ptc_shm_segment, width, height);
176   /* Get a shared segment */
177   ptc_shm_segment.shmid =
178     shmget (IPC_PRIVATE, ptc_ximage->bytes_per_line * ptc_ximage->height,
179             IPC_CREAT | 0777);
180   /* Initialize XShmImage data buffer pointer */
181   ptc_ximage->data = (char *)shmat (ptc_shm_segment.shmid, 0, 0);
182   /* Save buffer address */
183   ptc_shm_segment.shmaddr = ptc_ximage->data;
184   /* Put the segment in read/write */
185   ptc_shm_segment.readOnly = False;
186   /* Attach the segment to the display */
187   if (!XShmAttach (ptc_display, &ptc_shm_segment))
188     {
189       /* Destroy the image */
190       XDestroyImage (ptc_ximage);
191       /* Detach the buffer from the segment */
192       shmdt (ptc_shm_segment.shmaddr);
193       /* Remove the segment */
194       shmctl (ptc_shm_segment.shmid, IPC_RMID, 0);
195       /* Destroy the window */
196       XDestroyWindow (ptc_display, ptc_window);
197       /* Close the display */
198       XCloseDisplay (ptc_display);
199       return PTC_FAILURE;
200     }
201   /* Save windowsize values */
202   ptc_viewport_width = width;
203   ptc_viewport_height = height;
204   return PTC_SUCCESS;
205 }
206
207 /* Update the screen */
208
209 int
210 ptc_update (void *buffer)
211
212   char *ptc_buffer;
213                 
214   ptc_buffer=(char *)buffer;
215   /* Copy buffer data into the XShmImage */
216 #ifdef __PTC_ENABLE_CONVERSIONS__
217   ptc_source_index = 0;
218   ptc_destination_index = 0;
219   /* Convert the image line by line */
220   for (ptc_blitcounter = 0; ptc_blitcounter < ptc_viewport_height;
221        ptc_blitcounter++)
222     {
223       /* Conversion */
224       ptc_convert (ptc_buffer + ptc_source_index,
225                    (ptc_ximage->data) + ptc_destination_index,
226                    ptc_viewport_width);
227       /* Pointers update */
228       ptc_source_index += ptc_viewport_width * sizeof (int);
229       ptc_destination_index += ptc_viewport_width * ptc_output_pitch;
230     }
231 #else
232   /* Blit the image */
233   memcpy (ptc_ximage->data, buffer,
234           ptc_viewport_width * ptc_viewport_height * sizeof (int));
235 #endif /* __PTC_ENABLE_CONVERSIONS__ */
236   /* Synchronize the event queue */
237   XSync (ptc_display, 0);
238   /* Put the buffer on the window */
239   XShmPutImage (ptc_display, ptc_window, ptc_window_gc, ptc_ximage, 0, 0, 0,
240                 0, ptc_viewport_width, ptc_viewport_height, False);
241   /* Process incoming events */
242   if (ptc_process_events ())
243     {
244 #ifdef __PTC_CLEANUP_CALLBACK__
245       ptc_cleanup_callback ();
246 #endif /* __PTC_CLEANUP_CALLBACK__ */
247       ptc_close ();
248       exit (0);
249     }
250   return PTC_SUCCESS;
251 }
252
253 /* Process events */
254
255 int
256 ptc_process_events (void)
257 {
258   XEvent ptc_xevent;
259   KeySym ptc_keysym;
260   /* Check if there are events waiting in the display's queue */
261   if (XPending (ptc_display))
262     {
263       /* Get the next event in queue */
264       XNextEvent (ptc_display, &ptc_xevent);
265       /* Check if it's a keypress event */
266       if (ptc_xevent.type == KeyPress)
267         {
268           /* Get the keysym */
269           ptc_keysym = XLookupKeysym (&ptc_xevent.xkey, 0);
270           /* Check if the key pressed was a function one */
271           if ((ptc_keysym >> 8) == __PTC_FUNCTION_KEY__)
272             {
273               /* Check if it was the escape key */
274               if ((ptc_keysym & 0xFF) == __PTC_ESCAPE_KEY__)
275                 {
276                   return PTC_SUCCESS;
277                 }
278             }
279         }
280     }
281   return PTC_FAILURE;
282 }
283
284 /* Close the screen */
285
286 void
287 ptc_close (void)
288 {
289   /* Detach the segment from the display */
290   XShmDetach (ptc_display, &ptc_shm_segment);
291   /* Destroy the XShmImage */
292   XDestroyImage (ptc_ximage);
293   /* Detach the buffer from the segment */
294   shmdt (ptc_shm_segment.shmaddr);
295   /* Remove the segment */
296   shmctl (ptc_shm_segment.shmid, IPC_RMID, 0);
297   /* Close the window */
298   XDestroyWindow (ptc_display, ptc_window);
299   /* Close the display */
300   XCloseDisplay (ptc_display);
301   /* Deallocate the buffer */
302   if (ptc_buffer)
303     {
304       free (ptc_buffer);
305     }
306 }
307
308 #endif /* __PTC_XSHM__ */