FreeBASIC  0.91.0
gfx_driver_x11.c
Go to the documentation of this file.
1 /* X11 gfx driver */
2 
3 #ifndef DISABLE_X11
4 
5 #include "../fb_gfx.h"
6 #include "fb_gfx_x11.h"
7 #include <sys/shm.h>
8 
9 static int driver_init(char *title, int w, int h, int depth, int refresh_rate, int flags);
10 
12 {
13  "X11", /* char *name; */
14  driver_init, /* int (*init)(int w, int h, char *title, int fullscreen); */
15  fb_hX11Exit, /* void (*exit)(void); */
16  fb_hX11Lock, /* void (*lock)(void); */
17  fb_hX11Unlock, /* void (*unlock)(void); */
18  fb_hX11SetPalette, /* void (*set_palette)(int index, int r, int g, int b); */
19  fb_hX11WaitVSync, /* void (*wait_vsync)(void); */
20  fb_hX11GetMouse, /* int (*get_mouse)(int *x, int *y, int *z, int *buttons, int *clip); */
21  fb_hX11SetMouse, /* void (*set_mouse)(int x, int y, int cursor, int clip); */
22  fb_hX11SetWindowTitle, /* void (*set_window_title)(char *title); */
23  fb_hX11SetWindowPos, /* int (*set_window_pos)(int x, int y); */
24  fb_hX11FetchModes, /* int *(*fetch_modes)(void); */
25  NULL, /* void (*flip)(void); */
26  NULL /* void (*poll_events)(void); */
27 };
28 
29 
30 static XImage *image, *shape_image;
31 static Pixmap shape_pixmap;
32 static GC shape_gc;
33 static XShmSegmentInfo shm_info;
34 static BLITTER *blitter;
35 static int is_shm;
36 static void (*update_mask)(unsigned char *src, unsigned char *mask, int w, int h);
37 
38 
39 /*:::::*/
40 static void update_mask_8(unsigned char *pixel, unsigned char *mask, int w, int h)
41 {
42  int x, b;
43  unsigned char *p = pixel;
44 
45  for(; h; h--) {
46  b = 0;
47  for (x = 0; x < w; x++) {
48  if (*p++ != 0)
49  b |= 1 << (x & 0x7);
50  if ((x & 0x7) == 0x7) {
51  *mask++ = b;
52  b = 0;
53  }
54  }
55  if (w & 0x7)
56  *mask++ = b;
57  }
58 }
59 
60 
61 /*:::::*/
62 static void update_mask_16(unsigned char *pixel, unsigned char *mask, int w, int h)
63 {
64  int x, b;
65  unsigned short *p = (unsigned short *)pixel;
66 
67  for(; h; h--) {
68  b = 0;
69  for (x = 0; x < w; x++) {
70  if (*p++ != MASK_COLOR_16)
71  b |= 1 << (x & 0x7);
72  if ((x & 0x7) == 0x7) {
73  *mask++ = b;
74  b = 0;
75  }
76  }
77  if (w & 0x7)
78  *mask++ = b;
79  }
80 }
81 
82 
83 /*:::::*/
84 static void update_mask_32(unsigned char *pixel, unsigned char *mask, int w, int h)
85 {
86  int x, b;
87  unsigned int *p = (unsigned int *)pixel;
88 
89  for(; h; h--) {
90  b = 0;
91  for (x = 0; x < w; x++) {
92  if (((*p++) & ~MASK_A_32) != MASK_COLOR_32)
93  b |= 1 << (x & 0x7);
94  if ((x & 0x7) == 0x7) {
95  *mask++ = b;
96  b = 0;
97  }
98  }
99  if (w & 0x7)
100  *mask++ = b;
101  }
102 }
103 
104 
105 /*:::::*/
106 static int x11_init(void)
107 {
108  XGCValues values;
109  int x = 0, y = 0, h, is_rgb = FALSE;
110  char *display_name;
111 
112  image = NULL;
113  shape_image = NULL;
114  is_shm = FALSE;
115 
116  if ((fb_x11.visual_depth >= 24) && (fb_x11.visual->red_mask == 0xFF))
117  is_rgb = TRUE;
118  else if ((fb_x11.visual_depth >= 15) && (fb_x11.visual->red_mask == 0x1F))
119  is_rgb = TRUE;
121  if (!blitter)
122  return -1;
123 
124  if (!(fb_x11.flags & DRIVER_FULLSCREEN)) {
125  x = (XDisplayWidth(fb_x11.display, fb_x11.screen) - fb_x11.w) >> 1;
126  y = (XDisplayHeight(fb_x11.display, fb_x11.screen) - fb_x11.h) >> 1;
127  }
128  fb_hX11InitWindow(x, y);
129 
131  shape_image = XCreateImage(fb_x11.display, fb_x11.visual, 1, XYBitmap, 0, NULL, fb_x11.w, fb_x11.h, 8, 0);
132  shape_image->data = calloc(1, shape_image->bytes_per_line * shape_image->height);
133  shape_pixmap = XCreateBitmapFromData(fb_x11.display, fb_x11.window,
134  shape_image->data, fb_x11.w, fb_x11.h);
135  values.foreground = 1;
136  values.background = 0;
137  shape_gc = XCreateGC(fb_x11.display, shape_pixmap, GCForeground | GCBackground, &values);
138  if (__fb_gfx->bpp == 1)
140  else if (__fb_gfx->bpp == 2)
142  else
144  }
145 
147  display_name = XDisplayName(NULL);
148  if (((!display_name[0]) || (display_name[0] == ':') || (!strncmp(display_name, "unix:", 5))) &&
149  (XShmQueryExtension(fb_x11.display))) {
151  if (fb_hX11EnterFullscreen(&h)) {
153  return -1;
154  }
155  XReparentWindow(fb_x11.display, fb_x11.window, fb_x11.fswindow, 0, 0);
156  XMoveResizeWindow(fb_x11.display, fb_x11.fswindow, 0,0,fb_x11.w, h);
157  XMoveResizeWindow(fb_x11.display, fb_x11.window, 0, 0, fb_x11.w, h);
158  fb_x11.display_offset = (h - fb_x11.h) >> 1;
159  }
160  is_shm = TRUE;
161  image = XShmCreateImage(fb_x11.display, fb_x11.visual, XDefaultDepth(fb_x11.display, fb_x11.screen),
162  ZPixmap, 0, &shm_info, fb_x11.w, fb_x11.h);
163  if (image) {
164  shm_info.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height, IPC_CREAT | 0777);
165  shm_info.shmaddr = image->data = shmat(shm_info.shmid, 0, 0);
166  shm_info.readOnly = False;
167  if (!XShmAttach(fb_x11.display, &shm_info)) {
168  shmdt(shm_info.shmaddr);
169  shmctl(shm_info.shmid, IPC_RMID, 0);
170  XDestroyImage(image);
171  image = NULL;
172  }
173  }
174  }
175  else if (fb_x11.flags & DRIVER_FULLSCREEN)
176  return -1;
177  if (!image) {
178  is_shm = FALSE;
179  image = XCreateImage(fb_x11.display, fb_x11.visual, XDefaultDepth(fb_x11.display, fb_x11.screen),
180  ZPixmap, 0, NULL, fb_x11.w, fb_x11.h, 32, 0);
181  image->data = malloc(image->bytes_per_line * image->height);
182  if (!image->data) {
183  XDestroyImage(image);
184  image = NULL;
185  }
186  }
187  if (!image)
188  return -1;
189 
190  return 0;
191 }
192 
193 /*:::::*/
194 void fb_hX11WaitUnmapped(Window w)
195 {
196  XEvent e;
197  do {
198  XMaskEvent(fb_x11.display, StructureNotifyMask, &e);
199  } while ((e.type != UnmapNotify) || (e.xmap.event != w));
200 }
201 
202 /*:::::*/
203 static void x11_exit(void)
204 {
207  XUnmapWindow(fb_x11.display, fb_x11.window);
210  XUnmapWindow(fb_x11.display, fb_x11.fswindow);
211  XSync(fb_x11.display, False);
212  } else {
213  if (!(fb_x11.flags & DRIVER_NO_FRAME)) {
214  XUnmapWindow(fb_x11.display, fb_x11.wmwindow);
216  }
217  }
218  if (image) {
219  if (is_shm) {
220  XShmDetach(fb_x11.display, &shm_info);
221  shmdt(shm_info.shmaddr);
222  shmctl(shm_info.shmid, IPC_RMID, 0);
223  }
224  XDestroyImage(image);
225  }
226  if (shape_image) {
227  XDestroyImage(shape_image);
228  XFreePixmap(fb_x11.display, shape_pixmap);
229  }
230 }
231 
232 
233 /*:::::*/
234 static void x11_update(void)
235 {
236  int i, y, h;
237 
238  blitter((unsigned char *)image->data, image->bytes_per_line);
239  for (i = 0; i < fb_x11.h; i++) {
240  if (__fb_gfx->dirty[i]) {
241  for (y = i, h = 0; (i < fb_x11.h) && __fb_gfx->dirty[i]; h++, i++)
242  ;
243  if (shape_image) {
244  update_mask((unsigned char *)__fb_gfx->framebuffer + (y * __fb_gfx->pitch),
245  (unsigned char *)shape_image->data + (y * shape_image->bytes_per_line), fb_x11.w, h);
246  XPutImage(fb_x11.display, shape_pixmap, shape_gc, shape_image, 0, y, 0, y, fb_x11.w, h);
247  XShapeCombineMask(fb_x11.display, fb_x11.window, ShapeBounding, 0, 0, shape_pixmap, ShapeSet);
248  }
249  if (is_shm)
250  XShmPutImage(fb_x11.display, fb_x11.window, fb_x11.gc, image, 0, y, 0, y + fb_x11.display_offset, fb_x11.w, h, False);
251  else
252  XPutImage(fb_x11.display, fb_x11.window, fb_x11.gc, image, 0, y, 0, y + fb_x11.display_offset, fb_x11.w, h);
253  }
254  }
256 }
257 
258 
259 /*:::::*/
260 static int driver_init(char *title, int w, int h, int depth_arg, int refresh_rate, int flags)
261 {
262  int depth = MAX(8, depth_arg);
263  if (flags & DRIVER_OPENGL)
264  return -1;
265  fb_hMemSet(&fb_x11, 0, sizeof(fb_x11));
266  fb_x11.init = x11_init;
267  fb_x11.exit = x11_exit;
269  return fb_hX11Init(title, w, h, depth, refresh_rate, flags);
270 }
271 
272 #endif