Atrinik Client  4.0
video.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
30 #include <global.h>
31 #include <toolkit/x11.h>
32 
36 x11_display_type SDL_display;
40 x11_window_type SDL_window;
41 
45 void video_init(void)
46 {
47  SDL_SysWMinfo info;
48 
50 
51  if (!video_set_size()) {
52  LOG(ERROR, "Couldn't set video size: %s", SDL_GetError());
53  exit(1);
54  }
55 
56  SDL_display = NULL;
57 
58  /* Grab the window manager specific information. */
59  SDL_VERSION(&info.version);
60 
61  if (SDL_GetWMInfo(&info)) {
62 #if defined(HAVE_X11)
63 
64  if (info.subsystem == SDL_SYSWM_X11) {
65  SDL_display = info.info.x11.display;
66  SDL_window = info.info.x11.window;
67  } else {
68  LOG(BUG, "SDL is not running on X11 display.");
69  }
70 
71 #elif defined(WIN32)
72  SDL_window = SDL_display = info.window;
73 #endif
74  }
75 }
76 
77 #if defined(HAVE_X11)
78 
108 static void
109 video_mask_from_icon (SDL_Surface *icon,
110  Uint8 *mask,
111  int flags)
112 {
113  HARD_ASSERT(icon != NULL);
114  HARD_ASSERT(mask != NULL);
115 
116 #define SET_MASKBIT(icon, x, y, mask) \
117  mask[(y * ((icon->w + 7) / 8)) + (x / 8)] &= ~(0x1 << (7 - (x % 8)))
118 
119  Uint32 colorkey = icon->format->colorkey;
120  switch (icon->format->BytesPerPixel) {
121  case 1:
122  for (int y = 0; y < icon->h; ++y) {
123  Uint8 *pixels = (Uint8 *) icon->pixels + y * icon->pitch;
124  for (int x = 0; x < icon->w; ++x) {
125  if (*pixels++ == colorkey) {
126  SET_MASKBIT(icon, x, y, mask);
127  }
128  }
129  }
130 
131  break;
132 
133  case 2:
134  for (int y = 0; y < icon->h; ++y) {
135  Uint16 *pixels = (Uint16 *) icon->pixels + y * icon->pitch / 2;
136  for (int x = 0; x < icon->w; ++x) {
137  if ((flags & 0x1) && *pixels == colorkey) {
138  SET_MASKBIT(icon, x, y, mask);
139  } else if ((flags & 0x2) &&
140  (*pixels & icon->format->Amask) == 0) {
141  SET_MASKBIT(icon, x, y, mask);
142  }
143 
144  pixels++;
145  }
146  }
147 
148  break;
149 
150  case 4:
151  for (int y = 0; y < icon->h; ++y) {
152  Uint32 *pixels = (Uint32 *) icon->pixels + y * icon->pitch / 4;
153  for (int x = 0; x < icon->w; ++x) {
154  if ((flags & 0x1) && *pixels == colorkey) {
155  SET_MASKBIT(icon, x, y, mask);
156  } else if ((flags & 0x2) &&
157  (*pixels & icon->format->Amask) == 0) {
158  SET_MASKBIT(icon, x, y, mask);
159  }
160 
161  pixels++;
162  }
163  }
164 
165  break;
166  }
167 
168 #undef SET_MASKBIT
169 }
170 
203 static void
204 video_set_icon_x11 (SDL_Surface *icon,
205  x11_display_type display,
206  x11_window_type win,
207  Atom net_wm_icon)
208 {
209  HARD_ASSERT(icon != NULL);
210 
211  size_t mask_len = icon->h * (icon->w + 7) / 8;
212  int flags = 0;
213  Uint8 *mask = emalloc(mask_len);
214  memset(mask, ~0, mask_len);
215 
216  if (icon->flags & SDL_SRCCOLORKEY) {
217  flags |= 0x1;
218  }
219 
220  if (icon->flags & SDL_SRCALPHA) {
221  flags |= 0x2;
222  }
223 
224  if (flags != 0x0) {
225  video_mask_from_icon(icon, mask, flags);
226  }
227 
228  /* Convert the icon to ARGB for modern window managers */
229  SDL_PixelFormat format;
230  SDL_memset(&format, 0, sizeof(format));
231  format.BitsPerPixel = 32;
232  format.BytesPerPixel = 4;
233 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
234  format.Rshift = 8;
235  format.Gshift = 16;
236  format.Bshift = 24;
237  format.Ashift = 0;
238 #else
239  format.Rshift = 16;
240  format.Gshift = 8;
241  format.Bshift = 0;
242  format.Ashift = 24;
243 #endif
244  format.Rmask = 0xFF << format.Rshift;
245  format.Gmask = 0xFF << format.Gshift;
246  format.Bmask = 0xFF << format.Bshift;
247  format.Amask = 0xFF << format.Ashift;
248  format.alpha = SDL_ALPHA_OPAQUE;
249 
250  SDL_Surface *surface = SDL_ConvertSurface(icon, &format, 0);
251  if (surface == NULL) {
252  goto out;
253  }
254 
255  size_t prop_size = 2 + (icon->w * icon->h);
256  long *prop_data = emalloc(prop_size * sizeof(*prop_data));
257 
258  prop_data[0] = icon->w;
259  prop_data[1] = icon->h;
260 
261  long *dst = &prop_data[2];
262  size_t maskidx = 0;
263  for (int y = 0; y < icon->h; ++y) {
264  Uint32 *src = (Uint32 *) ((Uint8 *) surface->pixels +
265  y * surface->pitch);
266 
267  for (int x = 0; x < icon->w; ++x) {
268  const Uint32 pixel = *(src++);
269 
270  if (mask[maskidx / 8] & (1 << (7 - (maskidx % 8)))) {
271  *dst++ = pixel | format.Amask;
272  } else {
273  *dst++ = pixel & ~format.Amask;
274  }
275 
276  maskidx++;
277  }
278  }
279 
280  XChangeProperty(display,
281  win,
282  net_wm_icon,
283  XA_CARDINAL,
284  32,
285  PropModeReplace,
286  (unsigned char *) prop_data,
287  prop_size);
288  efree(prop_data);
289 
290 out:
291  if (surface != NULL) {
292  SDL_FreeSurface(surface);
293  }
294 
295  efree(mask);
296 }
297 #endif
298 
305 void
306 video_set_icon (SDL_Surface *icon)
307 {
308  HARD_ASSERT(icon != NULL);
309 
310 #if defined(HAVE_X11)
311  Atom net_wm_icon = XInternAtom(SDL_display, "_NET_WM_ICON", False);
312  if (net_wm_icon) {
313  video_set_icon_x11(icon,
314  SDL_display,
315  x11_window_get_parent(SDL_display, SDL_window),
316  net_wm_icon);
317  goto out;
318  }
319 #endif
320 
321  SDL_WM_SetIcon(icon, NULL);
322 
323  /* Avoid compilation warnings */
324  goto out;
325 out:
326  SDL_FreeSurface(icon);
327 }
328 
334 int video_get_bpp(void)
335 {
336  return SDL_GetVideoInfo()->vfmt->BitsPerPixel;
337 }
338 
344 int video_set_size(void)
345 {
346  SDL_Surface *new;
347 
348  /* Try to set the video mode. */
350 
351  if (new) {
352  ScreenSurface = new;
353  return 1;
354  }
355 
356  return 0;
357 }
358 
365 uint32_t get_video_flags(void)
366 {
368  return SDL_FULLSCREEN | SDL_SWSURFACE | SDL_HWACCEL | SDL_HWPALETTE | SDL_DOUBLEBUF | SDL_ANYFORMAT;
369  } else {
370  return SDL_SWSURFACE | SDL_SWSURFACE | SDL_HWACCEL | SDL_HWPALETTE | SDL_ANYFORMAT | SDL_RESIZABLE;
371  }
372 }
373 
392 int video_fullscreen_toggle(SDL_Surface **surface, uint32_t *flags)
393 {
394  size_t framesize = 0;
395  void *pixels = NULL;
396  SDL_Rect clip;
397  uint32_t tmpflags = 0;
398  int w = 0;
399  int h = 0;
400  int bpp = 0;
401  int grabmouse, showmouse;
402 
403  grabmouse = SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON;
404  showmouse = SDL_ShowCursor(-1);
405 
406  if ((!surface) || (!(*surface))) {
407  return 0;
408  }
409 
410  if (SDL_WM_ToggleFullScreen(*surface)) {
411  if (flags) {
412  *flags ^= SDL_FULLSCREEN;
413  }
414 
415  return 1;
416  }
417 
418  if (!(SDL_GetVideoInfo()->wm_available)) {
419  return 0;
420  }
421 
422  tmpflags = (*surface)->flags;
423  w = (*surface)->w;
424  h = (*surface)->h;
425  bpp = (*surface)->format->BitsPerPixel;
426 
427  if (flags == NULL) {
428  flags = &tmpflags;
429  }
430 
431  if ((*surface = SDL_SetVideoMode(w, h, bpp, *flags)) == NULL) {
432  *surface = SDL_SetVideoMode(w, h, bpp, tmpflags);
433  } else {
434  return 1;
435  }
436 
437  SDL_GetClipRect(*surface, &clip);
438 
439  /* Save the contents of the screen. */
440  if ((!(tmpflags & SDL_OPENGL)) && (!(tmpflags & SDL_OPENGLBLIT))) {
441  framesize = (w * h) * (size_t) (*surface)->format->BytesPerPixel;
442  pixels = emalloc(framesize);
443 
444  if (pixels == NULL) {
445  return 0;
446  }
447 
448  memcpy(pixels, (*surface)->pixels, framesize);
449  }
450 
451  if (grabmouse) {
452  SDL_WM_GrabInput(SDL_GRAB_OFF);
453  }
454 
455  SDL_ShowCursor(1);
456 
457  *surface = SDL_SetVideoMode(w, h, bpp, (*flags) ^ SDL_FULLSCREEN);
458 
459  if (*surface != NULL) {
460  *flags ^= SDL_FULLSCREEN;
461  } else {
462  *surface = SDL_SetVideoMode(w, h, bpp, tmpflags);
463 
464  if (*surface == NULL) {
465  if (pixels) {
466  efree(pixels);
467  }
468 
469  return 0;
470  }
471  }
472 
473  /* Unfortunately, you lose your OpenGL image until the next frame... */
474  if (pixels) {
475  memcpy((*surface)->pixels, pixels, framesize);
476  efree(pixels);
477  }
478 
479  SDL_SetClipRect(*surface, &clip);
480 
481  if (grabmouse) {
482  SDL_WM_GrabInput(SDL_GRAB_ON);
483  }
484 
485  SDL_ShowCursor(showmouse);
486 
487  return 1;
488 }
void list_vid_modes(void)
Definition: main.c:404
uint32_t get_video_flags(void)
Definition: video.c:365
int video_fullscreen_toggle(SDL_Surface **surface, uint32_t *flags)
Definition: video.c:392
SDL_Surface * ScreenSurface
Definition: main.c:47
int video_get_bpp(void)
Definition: video.c:334
int64_t setting_get_int(int cat, int setting)
Definition: settings.c:414
x11_display_type SDL_display
Definition: video.c:36
int video_set_size(void)
Definition: video.c:344
x11_window_type SDL_window
Definition: video.c:40
void video_init(void)
Definition: video.c:45
void video_set_icon(SDL_Surface *icon)
Definition: video.c:306