'How to stop the execution of a running code in x11

I have a program that draws on a x11 window and I'd like to quit it as soon as I press any key.

With the code I have, I cannot stop the program with a keypress until the for loop has finished drawing on the window (moving a red oval from left to right). I'd like to quit the for loop as soon as a key is pressed regardless of the state of the drawing (finished or not) even if the for loop hasn't finished executing its part.

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <unistd.h>

Display *dis;
Window win;

unsigned long GetColor(char *color_name)
{
  Colormap cmap;
  XColor near_color, true_color;
  cmap = DefaultColormap(dis, 0);
  XAllocNamedColor(dis, cmap, color_name, &near_color, &true_color);
  return(near_color.pixel);
}

int main(int argc, char **argv)
{
  if ((dis = XOpenDisplay(NULL)) == NULL) { printf("Error XOpenDisplay\n"); return 1; }

  win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 256, 256, 0, BlackPixel(dis, 0), BlackPixel(dis, 0));

  XSelectInput(dis, win, ExposureMask | KeyPressMask | KeyReleaseMask);

  XMapWindow(dis, win);
  XFlush(dis);

  XEvent ev;
  do {
    XNextEvent(dis, &ev);
  } while (ev.type != Expose);

  GC gc;
  gc = XCreateGC(dis, DefaultRootWindow(dis), 0, 0);
  XSetFunction(dis, gc, GXxor);

  while (!(XCheckWindowEvent(dis, win, KeyPressMask, &ev) || XCheckTypedWindowEvent(dis, win, ClientMessage, &ev))) {

    XNextEvent(dis, &ev);

    // quit program as soon as a key is pressed
    if (ev.type == KeyPress && XEventsQueued(dis, QueuedAfterReading)) {
      goto finish;
    }
    // I'd like to quit from this for loop as soon as a key is pressed
    for (int t = 0; t < 150; t++) {

      // quit program as soon as a key is pressed
      if (ev.type == KeyPress && XEventsQueued(dis, QueuedAfterReading)) {
        goto finish;
      } else {
        // draw a red oval and move it from left to right
        XSetForeground(dis, gc, BlackPixel(dis, 0) ^ GetColor("red"));
        XFillArc(dis, win, gc, t * 5 + 10, t * 3 + 40, 80, 40, 0, 360 * 64);
        XSetForeground(dis, gc, BlackPixel(dis, 0) ^ GetColor("red"));
        usleep(20000);
        XFillArc(dis, win, gc, t * 5 + 10, t * 3 + 40, 80, 40, 0, 360 * 64);
        //XSync(dis, True);
      }
    }
  }

finish:
  XFreeGC(dis, gc);
  XDestroyWindow(dis, win);
  XCloseDisplay(dis);
  return(0);
}

I execute it with: gcc draw.c -lX11 && ./a.out



Solution 1:[1]

The issue you are facing has to do with usleep.

Basically, usleep will suspend the thread that the program runs on until the set interval will finish. You can interrupt it by sending a signal (e.g. SIGKILL or SIGQUIT) to it, but this is something that can be done only outside of the program, not from within.

You may want to see this page to understand how usleep works.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 datcuandrei