0

I need to implement a visual bell for Konsole, because it doesn't honour the accessibility settings on my Ubuntu/KDE set-up.

I've cobbled together a utility to invert the currently focused X11 window, and have it triggered by Konsole, but I can't work out how to get it to re-invert the window without simply calling the invert program twice from a shell script (which works, but is ugly).

#include <X11/Xlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    Display *dpy;
    Window focused=0;
    Window rr;
    int revert_to=0;
    GC gc;
    XGCValues gcv;
    int xr, yr;
    unsigned int wr, hr, bwr, dr;

    struct timespec tp1;
    struct timespec tp2;

    dpy = XOpenDisplay(":0.0");
    XGetInputFocus(dpy, &focused, &revert_to);
    XGetGeometry(dpy, focused, &rr, &xr, &yr, &wr, &hr, &bwr, &dr);

    gc = XCreateGC(dpy, focused, 0, NULL);
    XSetSubwindowMode(dpy, gc, IncludeInferiors);

    gcv.function = GXcopyInverted;
    XChangeGC(dpy, gc, GCFunction, &gcv);
    XFlushGC(dpy, gc);
    XCopyArea(dpy, focused, focused, gc, xr, yr, wr, hr, 0, 0);

    clock_gettime(CLOCK_REALTIME, &tp1);

    for(;;) {
      XEvent e;
      while (XPending(dpy)) XNextEvent(dpy, &e);

      usleep(5000);

      clock_gettime(CLOCK_REALTIME, &tp2);
      if (((tp2.tv_nsec - tp1.tv_nsec)/1000000 + 1000 * (tp2.tv_sec - tp1.tv_sec)) > 15)
        break;
    }

    exit(0);
}

I tried to add a second copy operation - inverting or non-inverting - as follows:

int invert=0;
long slept=0;

for(;;) {
  XEvent e;
  while (XPending(dpy)) XNextEvent(dpy, &e);

  if (invert == 0 || slept > 29) {
    switch (invert++) {
      case 1:
        gcv.function = GXcopyInverted;
        break;
      case 2:
        gcv.function = GXcopyInverted;
        // gcv.function = GXcopy;
        break;
      case 3:
        exit(0);
    }
    XChangeGC(dpy, gc, GCFunction, &gcv);
    XFlushGC(dpy, gc);
    XCopyArea(dpy, focused, focused, gc, xr, yr, wr, hr, 0, 0);

    clock_gettime(CLOCK_REALTIME, &tp1);
    slept=0;
  }

  usleep(5000);

  clock_gettime(CLOCK_REALTIME, &tp2);
  slept = ((tp2.tv_nsec - tp1.tv_nsec)/1000000 + 1000 * (tp2.tv_sec - tp1.tv_sec));
}

Sometimes it works, sometimes it just blanks the window, sometimes it doesn't do anything. The console refreshes the blanked or inverted data readily enough, but it's confusing.

I presume I have to return control to X11 somehow between inversion operations, to synchronise, but I don't really know what I'm doing. :)

The code I stole the basis of this from created a bitmap (to display in another window), so I suppose I could copy the original into a bitmap and then copy it back, but I'm enticed by the first listing above not needing that.

Help?

Tim Baverstock
  • 415
  • 4
  • 11
  • Does adding `XFlush(dpy)` before your `usleep` help? – Uli Schlachter Oct 26 '19 at 05:25
  • @UliSchlachter Sadly, no, though it does seem to make it more reliably wipe out the window data, which is progress of a sort! :D I suspect copying the data and flashing that, rather than relying on catching the on-screen data, will be less race-conditiony. Thanks! – Tim Baverstock Nov 15 '19 at 14:53
  • 1
    I'd have expected `GXxor` instead of `GXcopyInverted`. – AProgrammer Nov 15 '19 at 15:06
  • @AProgrammer GXxor is src xor dst - I'm copying from and to the same place, so that would just cause it to go blank, wouldn't it? I want it to briefly switch black and white, then back again, without losing the on-screen data. – Tim Baverstock Nov 20 '19 at 10:51

0 Answers0