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