xref: /oneTBB/examples/common/gui/xvideo.cpp (revision c21e688a)
1d86ed7fbStbbdev /*
2*c21e688aSSergey Zheltov     Copyright (c) 2005-2022 Intel Corporation
3d86ed7fbStbbdev 
4d86ed7fbStbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5d86ed7fbStbbdev     you may not use this file except in compliance with the License.
6d86ed7fbStbbdev     You may obtain a copy of the License at
7d86ed7fbStbbdev 
8d86ed7fbStbbdev         http://www.apache.org/licenses/LICENSE-2.0
9d86ed7fbStbbdev 
10d86ed7fbStbbdev     Unless required by applicable law or agreed to in writing, software
11d86ed7fbStbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12d86ed7fbStbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d86ed7fbStbbdev     See the License for the specific language governing permissions and
14d86ed7fbStbbdev     limitations under the License.
15d86ed7fbStbbdev */
16d86ed7fbStbbdev 
17d86ed7fbStbbdev // Uncomment next line to disable shared memory features if you do not have libXext
18d86ed7fbStbbdev // (http://www.xfree86.org/current/mit-shm.html)
19d86ed7fbStbbdev //#define X_NOSHMEM
20d86ed7fbStbbdev 
21d86ed7fbStbbdev // Note that it may happen that the build environment supports the shared-memory extension
22d86ed7fbStbbdev // (so there's no build-time reason to disable the relevant code by defining X_NOSHMEM),
23d86ed7fbStbbdev // but that using shared memory still fails at run time.
24d86ed7fbStbbdev // This situation will (ultimately) cause the error handler set by XSetErrorHandler()
25d86ed7fbStbbdev // to be invoked with XErrorEvent::minor_code==X_ShmAttach. The code below tries to make
26d86ed7fbStbbdev // such a determination at XShmAttach() time, which seems plausible, but unfortunately
27d86ed7fbStbbdev // it has also been observed in a specific environment that the error may be reported
28d86ed7fbStbbdev // at a later time instead, even after video::init_window() has returned.
29d86ed7fbStbbdev // It is not clear whether this may happen in that way in any environment where it might
30d86ed7fbStbbdev // depend on the kind of display, e.g., local vs. over "ssh -X", so #define'ing X_NOSHMEM
31d86ed7fbStbbdev // may not always be the appropriate solution, therefore an environment variable
32d86ed7fbStbbdev // has been introduced to disable shared memory at run time.
33d86ed7fbStbbdev // A diagnostic has been added to advise the user about possible workarounds.
34d86ed7fbStbbdev // X_ShmAttach macro was changed to 1 due to recent changes to X11/extensions/XShm.h header.
35d86ed7fbStbbdev 
36d86ed7fbStbbdev #include "video.hpp"
37d86ed7fbStbbdev #include <string.h>
38d86ed7fbStbbdev #include <stdio.h>
39d86ed7fbStbbdev #include <stdlib.h>
40d86ed7fbStbbdev #include <math.h>
41d86ed7fbStbbdev #include <X11/Xlib.h>
42d86ed7fbStbbdev #include <X11/Xutil.h>
43d86ed7fbStbbdev #include <X11/keysym.h>
44d86ed7fbStbbdev #include <sys/time.h>
45d86ed7fbStbbdev #include <signal.h>
46d86ed7fbStbbdev #include <pthread.h>
47d86ed7fbStbbdev 
48d86ed7fbStbbdev #ifndef X_NOSHMEM
49d86ed7fbStbbdev #include <errno.h>
50d86ed7fbStbbdev #include <X11/extensions/XShm.h>
51d86ed7fbStbbdev #include <sys/ipc.h>
52d86ed7fbStbbdev #include <sys/shm.h>
53d86ed7fbStbbdev 
54d86ed7fbStbbdev static XShmSegmentInfo shmseginfo;
55d86ed7fbStbbdev static Pixmap pixmap = 0;
56d86ed7fbStbbdev static bool already_called_X_ShmAttach = false;
57d86ed7fbStbbdev static bool already_advised_about_NOSHMEM_workarounds = false;
58d86ed7fbStbbdev #endif
5957f524caSIlya Isaev static char *display_name = nullptr;
6057f524caSIlya Isaev static Display *dpy = nullptr;
61d86ed7fbStbbdev static Screen *scrn;
62d86ed7fbStbbdev static Visual *vis;
63d86ed7fbStbbdev static Colormap cmap;
64d86ed7fbStbbdev static GC gc;
65d86ed7fbStbbdev static Window win, rootW;
66d86ed7fbStbbdev static int dispdepth = 0;
67d86ed7fbStbbdev static XGCValues xgcv;
68d86ed7fbStbbdev static XImage *ximage;
69d86ed7fbStbbdev static int x_error = 0;
70d86ed7fbStbbdev static int vidtype = 3;
71d86ed7fbStbbdev int g_sizex, g_sizey;
72d86ed7fbStbbdev static video *g_video = 0;
73d86ed7fbStbbdev unsigned int *g_pImg = 0;
74d86ed7fbStbbdev static int g_fps = 0;
75d86ed7fbStbbdev struct timeval g_time;
76d86ed7fbStbbdev static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
77d86ed7fbStbbdev Atom _XA_WM_DELETE_WINDOW = 0; // like in Xatom.h
78d86ed7fbStbbdev 
79d86ed7fbStbbdev ///////////////////////////////////////////// public methods of video class ///////////////////////
80d86ed7fbStbbdev 
video()81d86ed7fbStbbdev video::video() {
82d86ed7fbStbbdev     assert(g_video == 0);
83d86ed7fbStbbdev     g_video = this;
84d86ed7fbStbbdev     title = "Video";
85d86ed7fbStbbdev     calc_fps = running = false;
86d86ed7fbStbbdev     updating = true;
87d86ed7fbStbbdev }
88d86ed7fbStbbdev 
mask2bits(unsigned int mask,unsigned int & save,depth_t & shift)89d86ed7fbStbbdev inline void mask2bits(unsigned int mask, unsigned int &save, depth_t &shift) {
90d86ed7fbStbbdev     save = mask;
91d86ed7fbStbbdev     if (!mask) {
92d86ed7fbStbbdev         shift = dispdepth / 3;
93d86ed7fbStbbdev         return;
94d86ed7fbStbbdev     }
95d86ed7fbStbbdev     shift = 0;
96d86ed7fbStbbdev     while (!(mask & 1))
97d86ed7fbStbbdev         ++shift, mask >>= 1;
98d86ed7fbStbbdev     int bits = 0;
99d86ed7fbStbbdev     while (mask & 1)
100d86ed7fbStbbdev         ++bits, mask >>= 1;
101d86ed7fbStbbdev     shift += bits - 8;
102d86ed7fbStbbdev }
103d86ed7fbStbbdev 
xerr_handler(Display * dpy_,XErrorEvent * error)104d86ed7fbStbbdev int xerr_handler(Display *dpy_, XErrorEvent *error) {
105d86ed7fbStbbdev     x_error = error->error_code;
106d86ed7fbStbbdev     if (g_video)
107d86ed7fbStbbdev         g_video->running = false;
108d86ed7fbStbbdev #ifndef X_NOSHMEM
109d86ed7fbStbbdev     if (error->minor_code == 1 /*X_ShmAttach*/ && already_called_X_ShmAttach &&
110d86ed7fbStbbdev         !already_advised_about_NOSHMEM_workarounds) {
111d86ed7fbStbbdev         char err[256];
112d86ed7fbStbbdev         XGetErrorText(dpy_, x_error, err, 255);
113d86ed7fbStbbdev         fprintf(stderr, "Warning: Can't attach shared memory to display: %s (%d)\n", err, x_error);
114d86ed7fbStbbdev         fprintf(
115d86ed7fbStbbdev             stderr,
116d86ed7fbStbbdev             "If you are seeing a black output window, сheck if you have installed Xext library and rebuild project");
117d86ed7fbStbbdev         already_advised_about_NOSHMEM_workarounds = true;
118d86ed7fbStbbdev     }
119d86ed7fbStbbdev #else
120d86ed7fbStbbdev     (void)dpy_; // warning prevention
121d86ed7fbStbbdev #endif
122d86ed7fbStbbdev     return 0;
123d86ed7fbStbbdev }
124d86ed7fbStbbdev 
init_window(int xsize,int ysize)125d86ed7fbStbbdev bool video::init_window(int xsize, int ysize) {
126d86ed7fbStbbdev     { //enclose local variables before fail label
127d86ed7fbStbbdev         g_sizex = xsize;
128d86ed7fbStbbdev         g_sizey = ysize;
129d86ed7fbStbbdev 
130d86ed7fbStbbdev         // Open the display
131d86ed7fbStbbdev         if (!dpy) {
132d86ed7fbStbbdev             dpy = XOpenDisplay(display_name);
133d86ed7fbStbbdev             if (!dpy) {
134d86ed7fbStbbdev                 fprintf(stderr, "Can't open X11 display %s\n", XDisplayName(display_name));
135d86ed7fbStbbdev                 goto fail;
136d86ed7fbStbbdev             }
137d86ed7fbStbbdev         }
138d86ed7fbStbbdev         int theScreen = DefaultScreen(dpy);
139d86ed7fbStbbdev         scrn = ScreenOfDisplay(dpy, theScreen);
140d86ed7fbStbbdev         dispdepth = DefaultDepth(dpy, theScreen);
141d86ed7fbStbbdev         XVisualInfo vinfo;
142d86ed7fbStbbdev         if (!((dispdepth >= 15 && dispdepth <= 32 &&
143d86ed7fbStbbdev                XMatchVisualInfo(dpy, theScreen, dispdepth, TrueColor, &vinfo)) ||
144d86ed7fbStbbdev               XMatchVisualInfo(dpy, theScreen, 24, TrueColor, &vinfo) ||
145d86ed7fbStbbdev               XMatchVisualInfo(dpy, theScreen, 32, TrueColor, &vinfo) ||
146d86ed7fbStbbdev               XMatchVisualInfo(dpy, theScreen, 16, TrueColor, &vinfo) ||
147d86ed7fbStbbdev               XMatchVisualInfo(dpy, theScreen, 15, TrueColor, &vinfo))) {
148d86ed7fbStbbdev             fprintf(stderr, "Display has no appropriate True Color visual\n");
149d86ed7fbStbbdev             goto fail;
150d86ed7fbStbbdev         }
151d86ed7fbStbbdev         vis = vinfo.visual;
152d86ed7fbStbbdev         depth = dispdepth = vinfo.depth;
153d86ed7fbStbbdev         mask2bits(vinfo.red_mask, red_mask, red_shift);
154d86ed7fbStbbdev         mask2bits(vinfo.green_mask, green_mask, green_shift);
155d86ed7fbStbbdev         mask2bits(vinfo.blue_mask, blue_mask, blue_shift);
156d86ed7fbStbbdev         rootW = RootWindow(dpy, theScreen);
157d86ed7fbStbbdev         cmap = XCreateColormap(dpy, rootW, vis, AllocNone);
158d86ed7fbStbbdev         XSetWindowAttributes attrs;
159d86ed7fbStbbdev         attrs.backing_store = Always;
160d86ed7fbStbbdev         attrs.colormap = cmap;
161d86ed7fbStbbdev         attrs.event_mask = StructureNotifyMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask;
162d86ed7fbStbbdev         attrs.background_pixel = BlackPixelOfScreen(scrn);
163d86ed7fbStbbdev         attrs.border_pixel = WhitePixelOfScreen(scrn);
164d86ed7fbStbbdev         win = XCreateWindow(dpy,
165d86ed7fbStbbdev                             rootW,
166d86ed7fbStbbdev                             0,
167d86ed7fbStbbdev                             0,
168d86ed7fbStbbdev                             xsize,
169d86ed7fbStbbdev                             ysize,
170d86ed7fbStbbdev                             2,
171d86ed7fbStbbdev                             dispdepth,
172d86ed7fbStbbdev                             InputOutput,
173d86ed7fbStbbdev                             vis,
174d86ed7fbStbbdev                             CWBackingStore | CWColormap | CWEventMask | CWBackPixel | CWBorderPixel,
175d86ed7fbStbbdev                             &attrs);
176d86ed7fbStbbdev         if (!win) {
177d86ed7fbStbbdev             fprintf(stderr, "Can't create the window\n");
178d86ed7fbStbbdev             goto fail;
179d86ed7fbStbbdev         }
180d86ed7fbStbbdev         XSizeHints sh;
181d86ed7fbStbbdev         sh.flags = PSize | PMinSize | PMaxSize;
182d86ed7fbStbbdev         sh.width = sh.min_width = sh.max_width = xsize;
183d86ed7fbStbbdev         sh.height = sh.min_height = sh.max_height = ysize;
18457f524caSIlya Isaev         XSetStandardProperties(dpy, win, g_video->title, g_video->title, None, nullptr, 0, &sh);
185d86ed7fbStbbdev         _XA_WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", false);
186d86ed7fbStbbdev         XSetWMProtocols(dpy, win, &_XA_WM_DELETE_WINDOW, 1);
187d86ed7fbStbbdev         gc = XCreateGC(dpy, win, 0L, &xgcv);
188d86ed7fbStbbdev         XMapRaised(dpy, win);
189d86ed7fbStbbdev         XFlush(dpy);
190d86ed7fbStbbdev #ifdef X_FULLSYNC
191d86ed7fbStbbdev         XSynchronize(dpy, true);
192d86ed7fbStbbdev #endif
193d86ed7fbStbbdev         XSetErrorHandler(xerr_handler);
194d86ed7fbStbbdev 
195d86ed7fbStbbdev         int imgbytes = xsize * ysize * (dispdepth <= 16 ? 2 : 4);
196d86ed7fbStbbdev         const char *vidstr;
197d86ed7fbStbbdev #ifndef X_NOSHMEM
198d86ed7fbStbbdev         int major, minor, pixmaps;
199d86ed7fbStbbdev         if (XShmQueryExtension(dpy) &&
200d86ed7fbStbbdev             XShmQueryVersion(dpy, &major, &minor, &pixmaps)) { // Shared memory
201d86ed7fbStbbdev             shmseginfo.shmid = shmget(IPC_PRIVATE, imgbytes, IPC_CREAT | 0777);
202d86ed7fbStbbdev             if (shmseginfo.shmid < 0) {
203d86ed7fbStbbdev                 fprintf(stderr, "Warning: Can't get shared memory: %s\n", strerror(errno));
204d86ed7fbStbbdev                 goto generic;
205d86ed7fbStbbdev             }
206d86ed7fbStbbdev             g_pImg = (unsigned int *)(shmseginfo.shmaddr = (char *)shmat(shmseginfo.shmid, 0, 0));
207d86ed7fbStbbdev             if (g_pImg == (unsigned int *)-1) {
208d86ed7fbStbbdev                 fprintf(stderr, "Warning: Can't attach to shared memory: %s\n", strerror(errno));
20957f524caSIlya Isaev                 shmctl(shmseginfo.shmid, IPC_RMID, nullptr);
210d86ed7fbStbbdev                 goto generic;
211d86ed7fbStbbdev             }
212d86ed7fbStbbdev             shmseginfo.readOnly = false;
213d86ed7fbStbbdev             if (!XShmAttach(dpy, &shmseginfo) || x_error) {
214d86ed7fbStbbdev                 char err[256];
215d86ed7fbStbbdev                 XGetErrorText(dpy, x_error, err, 255);
216d86ed7fbStbbdev                 fprintf(stderr,
217d86ed7fbStbbdev                         "Warning: Can't attach shared memory to display: %s (%d)\n",
218d86ed7fbStbbdev                         err,
219d86ed7fbStbbdev                         x_error);
220d86ed7fbStbbdev                 shmdt(shmseginfo.shmaddr);
22157f524caSIlya Isaev                 shmctl(shmseginfo.shmid, IPC_RMID, nullptr);
222d86ed7fbStbbdev                 goto generic;
223d86ed7fbStbbdev             }
224d86ed7fbStbbdev             already_called_X_ShmAttach = true;
225d86ed7fbStbbdev 
226d86ed7fbStbbdev #ifndef X_NOSHMPIX
227d86ed7fbStbbdev             if (pixmaps && XShmPixmapFormat(dpy) == ZPixmap) { // Pixmaps
228d86ed7fbStbbdev                 vidtype = 2;
229d86ed7fbStbbdev                 vidstr = "X11 shared memory pixmap";
230d86ed7fbStbbdev                 pixmap = XShmCreatePixmap(
231d86ed7fbStbbdev                     dpy, win, (char *)g_pImg, &shmseginfo, xsize, ysize, dispdepth);
232d86ed7fbStbbdev                 XSetWindowBackgroundPixmap(dpy, win, pixmap);
233d86ed7fbStbbdev             }
234d86ed7fbStbbdev             else
235d86ed7fbStbbdev #endif //!X_NOSHMPIX
236d86ed7fbStbbdev             { // Standard
237d86ed7fbStbbdev                 vidtype = 1;
238d86ed7fbStbbdev                 vidstr = "X11 shared memory";
239d86ed7fbStbbdev                 ximage =
240d86ed7fbStbbdev                     XShmCreateImage(dpy, vis, dispdepth, ZPixmap, 0, &shmseginfo, xsize, ysize);
241d86ed7fbStbbdev                 if (!ximage) {
242d86ed7fbStbbdev                     fprintf(stderr, "Can't create the shared image\n");
243d86ed7fbStbbdev                     goto fail;
244d86ed7fbStbbdev                 }
245d86ed7fbStbbdev                 assert(ximage->bytes_per_line == xsize * (dispdepth <= 16 ? 2 : 4));
246d86ed7fbStbbdev                 ximage->data = shmseginfo.shmaddr;
247d86ed7fbStbbdev             }
248d86ed7fbStbbdev         }
249d86ed7fbStbbdev         else
250d86ed7fbStbbdev #endif
251d86ed7fbStbbdev         {
252d86ed7fbStbbdev #ifndef X_NOSHMEM
253d86ed7fbStbbdev         generic:
254d86ed7fbStbbdev #endif
255d86ed7fbStbbdev             vidtype = 0;
256d86ed7fbStbbdev             vidstr = "generic X11";
257d86ed7fbStbbdev             g_pImg = new unsigned int[imgbytes / sizeof(int)];
258d86ed7fbStbbdev             ximage = XCreateImage(dpy,
259d86ed7fbStbbdev                                   vis,
260d86ed7fbStbbdev                                   dispdepth,
261d86ed7fbStbbdev                                   ZPixmap,
262d86ed7fbStbbdev                                   0,
263d86ed7fbStbbdev                                   (char *)g_pImg,
264d86ed7fbStbbdev                                   xsize,
265d86ed7fbStbbdev                                   ysize,
266d86ed7fbStbbdev                                   32,
267d86ed7fbStbbdev                                   imgbytes / ysize);
268d86ed7fbStbbdev             if (!ximage) {
269d86ed7fbStbbdev                 fprintf(stderr, "Can't create the image\n");
270d86ed7fbStbbdev                 goto fail;
271d86ed7fbStbbdev             }
272d86ed7fbStbbdev         }
273d86ed7fbStbbdev         if (ximage) {
274d86ed7fbStbbdev             // Note: It may be more efficient to adopt the server's byte order
275d86ed7fbStbbdev             //       and swap once per get_color() call instead of once per pixel.
276d86ed7fbStbbdev             const uint32_t probe = 0x03020100;
277d86ed7fbStbbdev             const bool big_endian = (((const char *)(&probe))[0] == 0x03);
278d86ed7fbStbbdev             ximage->byte_order = big_endian ? MSBFirst : LSBFirst;
279d86ed7fbStbbdev         }
280d86ed7fbStbbdev         printf("Note: using %s with %s visual for %d-bit color depth\n",
281d86ed7fbStbbdev                vidstr,
282d86ed7fbStbbdev                vis == DefaultVisual(dpy, theScreen) ? "default" : "non-default",
283d86ed7fbStbbdev                dispdepth);
284d86ed7fbStbbdev         running = true;
285d86ed7fbStbbdev         return true;
286d86ed7fbStbbdev     } // end of enclosing local variables
287d86ed7fbStbbdev fail:
288d86ed7fbStbbdev     terminate();
289d86ed7fbStbbdev     init_console();
290d86ed7fbStbbdev     return false;
291d86ed7fbStbbdev }
292d86ed7fbStbbdev 
init_console()293d86ed7fbStbbdev bool video::init_console() {
294d86ed7fbStbbdev     if (!g_pImg && g_sizex && g_sizey) {
295d86ed7fbStbbdev         dispdepth = 24;
296d86ed7fbStbbdev         red_shift = 16;
297d86ed7fbStbbdev         vidtype = 3; // fake video
298d86ed7fbStbbdev         g_pImg = new unsigned int[g_sizex * g_sizey];
299d86ed7fbStbbdev         running = true;
300d86ed7fbStbbdev     }
301d86ed7fbStbbdev     return true;
302d86ed7fbStbbdev }
303d86ed7fbStbbdev 
terminate()304d86ed7fbStbbdev void video::terminate() {
305d86ed7fbStbbdev     running = false;
306d86ed7fbStbbdev     if (dpy) {
307d86ed7fbStbbdev         vidtype = 3; // stop video
308d86ed7fbStbbdev         if (threaded) {
309d86ed7fbStbbdev             pthread_mutex_lock(&g_mutex);
310d86ed7fbStbbdev             pthread_mutex_unlock(&g_mutex);
311d86ed7fbStbbdev         }
312d86ed7fbStbbdev         if (ximage) {
313d86ed7fbStbbdev             XDestroyImage(ximage);
314d86ed7fbStbbdev             ximage = 0;
315d86ed7fbStbbdev             g_pImg = 0;
316d86ed7fbStbbdev         } // it frees g_pImg for vidtype == 0
317d86ed7fbStbbdev #ifndef X_NOSHMEM
318d86ed7fbStbbdev         if (pixmap)
319d86ed7fbStbbdev             XFreePixmap(dpy, pixmap);
320d86ed7fbStbbdev         if (shmseginfo.shmaddr) {
321d86ed7fbStbbdev             XShmDetach(dpy, &shmseginfo);
322d86ed7fbStbbdev             shmdt(shmseginfo.shmaddr);
323d86ed7fbStbbdev             g_pImg = 0;
324d86ed7fbStbbdev         }
325d86ed7fbStbbdev         if (shmseginfo.shmid >= 0)
32657f524caSIlya Isaev             shmctl(shmseginfo.shmid, IPC_RMID, nullptr);
327d86ed7fbStbbdev #endif
328d86ed7fbStbbdev         if (gc)
329d86ed7fbStbbdev             XFreeGC(dpy, gc);
330d86ed7fbStbbdev         if (win)
331d86ed7fbStbbdev             XDestroyWindow(dpy, win);
332d86ed7fbStbbdev         XCloseDisplay(dpy);
333d86ed7fbStbbdev         dpy = 0;
334d86ed7fbStbbdev     }
335d86ed7fbStbbdev     if (g_pImg) {
336d86ed7fbStbbdev         delete[] g_pImg;
337d86ed7fbStbbdev         g_pImg = 0;
338d86ed7fbStbbdev     } // if was allocated for console mode
339d86ed7fbStbbdev }
340d86ed7fbStbbdev 
~video()341d86ed7fbStbbdev video::~video() {
342d86ed7fbStbbdev     if (g_video)
343d86ed7fbStbbdev         terminate();
344d86ed7fbStbbdev     g_video = 0;
345d86ed7fbStbbdev }
346d86ed7fbStbbdev 
347d86ed7fbStbbdev //! Do standard event loop
main_loop()348d86ed7fbStbbdev void video::main_loop() {
349d86ed7fbStbbdev     struct timezone tz;
350d86ed7fbStbbdev     gettimeofday(&g_time, &tz);
351d86ed7fbStbbdev     on_process();
352d86ed7fbStbbdev }
353d86ed7fbStbbdev 
354d86ed7fbStbbdev //! Check for pending events once
next_frame()355d86ed7fbStbbdev bool video::next_frame() {
356d86ed7fbStbbdev     if (!running)
357d86ed7fbStbbdev         return false;
358d86ed7fbStbbdev     //! try acquire mutex if threaded code, returns on failure
359d86ed7fbStbbdev     if (vidtype == 3 || threaded && pthread_mutex_trylock(&g_mutex))
360d86ed7fbStbbdev         return running;
361d86ed7fbStbbdev     //! Refresh screen picture
362d86ed7fbStbbdev     g_fps++;
363d86ed7fbStbbdev #ifndef X_NOSHMPIX
364d86ed7fbStbbdev     if (vidtype == 2 && updating)
365d86ed7fbStbbdev         XClearWindow(dpy, win);
366d86ed7fbStbbdev #endif
367d86ed7fbStbbdev     while (XPending(dpy)) {
368d86ed7fbStbbdev         XEvent report;
369d86ed7fbStbbdev         XNextEvent(dpy, &report);
370d86ed7fbStbbdev         switch (report.type) {
371d86ed7fbStbbdev             case ClientMessage:
372d86ed7fbStbbdev                 if (report.xclient.format != 32 || report.xclient.data.l[0] != _XA_WM_DELETE_WINDOW)
373d86ed7fbStbbdev                     break;
374d86ed7fbStbbdev             case DestroyNotify: running = false;
375d86ed7fbStbbdev             case KeyPress: on_key(XLookupKeysym(&report.xkey, 0)); break;
376d86ed7fbStbbdev             case ButtonPress:
377d86ed7fbStbbdev                 on_mouse(report.xbutton.x, report.xbutton.y, report.xbutton.button);
378d86ed7fbStbbdev                 break;
379d86ed7fbStbbdev             case ButtonRelease:
380d86ed7fbStbbdev                 on_mouse(report.xbutton.x, report.xbutton.y, -report.xbutton.button);
381d86ed7fbStbbdev                 break;
382d86ed7fbStbbdev         }
383d86ed7fbStbbdev     }
384d86ed7fbStbbdev     struct timezone tz;
385d86ed7fbStbbdev     struct timeval now_time;
386d86ed7fbStbbdev     gettimeofday(&now_time, &tz);
387d86ed7fbStbbdev     double sec = (now_time.tv_sec + 1.0 * now_time.tv_usec / 1000000.0) -
388d86ed7fbStbbdev                  (g_time.tv_sec + 1.0 * g_time.tv_usec / 1000000.0);
389d86ed7fbStbbdev     if (sec > 1) {
390d86ed7fbStbbdev         memcpy(&g_time, &now_time, sizeof(g_time));
391d86ed7fbStbbdev         if (calc_fps) {
392d86ed7fbStbbdev             double fps = g_fps;
393d86ed7fbStbbdev             g_fps = 0;
394d86ed7fbStbbdev             char buffer[256];
395d86ed7fbStbbdev             snprintf(buffer,
396d86ed7fbStbbdev                      256,
397d86ed7fbStbbdev                      "%s%s: %d fps",
398d86ed7fbStbbdev                      title,
399d86ed7fbStbbdev                      updating ? "" : " (no updating)",
400d86ed7fbStbbdev                      int(fps / sec));
401d86ed7fbStbbdev             XStoreName(dpy, win, buffer);
402d86ed7fbStbbdev         }
403d86ed7fbStbbdev #ifndef X_FULLSYNC
404d86ed7fbStbbdev         XSync(dpy, false); // It is often better then using XSynchronize(dpy, true)
405d86ed7fbStbbdev #endif //X_FULLSYNC
406d86ed7fbStbbdev     }
407d86ed7fbStbbdev     if (threaded)
408d86ed7fbStbbdev         pthread_mutex_unlock(&g_mutex);
409d86ed7fbStbbdev     return true;
410d86ed7fbStbbdev }
411d86ed7fbStbbdev 
412d86ed7fbStbbdev //! Change window title
show_title()413d86ed7fbStbbdev void video::show_title() {
414d86ed7fbStbbdev     if (vidtype < 3)
415d86ed7fbStbbdev         XStoreName(dpy, win, title);
416d86ed7fbStbbdev }
417d86ed7fbStbbdev 
drawing_area(int x,int y,int sizex,int sizey)418d86ed7fbStbbdev drawing_area::drawing_area(int x, int y, int sizex, int sizey)
419d86ed7fbStbbdev         : base_index(y * g_sizex + x),
420d86ed7fbStbbdev           max_index(g_sizex * g_sizey),
421d86ed7fbStbbdev           index_stride(g_sizex),
422d86ed7fbStbbdev           pixel_depth(dispdepth),
423d86ed7fbStbbdev           ptr32(g_pImg),
424d86ed7fbStbbdev           start_x(x),
425d86ed7fbStbbdev           start_y(y),
426d86ed7fbStbbdev           size_x(sizex),
427d86ed7fbStbbdev           size_y(sizey) {
428d86ed7fbStbbdev     assert(x < g_sizex);
429d86ed7fbStbbdev     assert(y < g_sizey);
430d86ed7fbStbbdev     assert(x + sizex <= g_sizex);
431d86ed7fbStbbdev     assert(y + sizey <= g_sizey);
432d86ed7fbStbbdev 
433d86ed7fbStbbdev     index = base_index; // current index
434d86ed7fbStbbdev }
435d86ed7fbStbbdev 
update()436d86ed7fbStbbdev void drawing_area::update() {
437d86ed7fbStbbdev     if (!g_video->updating)
438d86ed7fbStbbdev         return;
439d86ed7fbStbbdev #ifndef X_NOSHMEM
440d86ed7fbStbbdev     switch (vidtype) {
441d86ed7fbStbbdev         case 0:
442d86ed7fbStbbdev #endif
443d86ed7fbStbbdev             pthread_mutex_lock(&g_mutex);
444d86ed7fbStbbdev             if (vidtype == 0)
445d86ed7fbStbbdev                 XPutImage(dpy, win, gc, ximage, start_x, start_y, start_x, start_y, size_x, size_y);
446d86ed7fbStbbdev             pthread_mutex_unlock(&g_mutex);
447d86ed7fbStbbdev #ifndef X_NOSHMEM
448d86ed7fbStbbdev             break;
449d86ed7fbStbbdev         case 1:
450d86ed7fbStbbdev             pthread_mutex_lock(&g_mutex);
451d86ed7fbStbbdev             if (vidtype == 1)
452d86ed7fbStbbdev                 XShmPutImage(dpy,
453d86ed7fbStbbdev                              win,
454d86ed7fbStbbdev                              gc,
455d86ed7fbStbbdev                              ximage,
456d86ed7fbStbbdev                              start_x,
457d86ed7fbStbbdev                              start_y,
458d86ed7fbStbbdev                              start_x,
459d86ed7fbStbbdev                              start_y,
460d86ed7fbStbbdev                              size_x,
461d86ed7fbStbbdev                              size_y,
462d86ed7fbStbbdev                              false);
463d86ed7fbStbbdev             pthread_mutex_unlock(&g_mutex);
464d86ed7fbStbbdev             break;
465d86ed7fbStbbdev             /*case 2: make it in next_frame(); break;*/
466d86ed7fbStbbdev     }
467d86ed7fbStbbdev #endif
468d86ed7fbStbbdev }
469