!7

cmodule2 LinuxWindowList > DynObjectTable<wmctrl_Entry> {
  switchable bool inZOrder = false;
  
  start {
    if (!isLinux())
      ret with setModuleName("Sorry, wrong OS - LINUX Window List");
      
    dontPersist();
    set fieldsInOrder;
    defaultAction = voidfunc(wmctrl_Entry e) { wmctrl_activateWindow(e) };
    doEvery(0.0, 10.0, r updateMe);
    dm_vmBus_answerToMessage currentWindowTitle(() -> currentWindowTitle());
  }
  
  afterVisualize {
    popupMenuItem_top("Close window", r { wmctrl_closeWindow(selected()) });
    popupMenuItem_top("Switch to window", defaultAction);
    popupMenuItem_top("Shoot window", rThread { showImage(shootSystemWindow(selected())) });
  }
  
  void update {
    S output = backtick("wmctrl -lpG");
    L<wmctrl_Entry> l = linux_parse_wmctrl_lpG_output(output);
    if (inZOrder) {
      LS order = map last7chars(regexpExtractAll("0x[a-f0-9]+", backtick("xprop -root _NET_CLIENT_LIST_STACKING")));
      final Map<S, Int> map = mapItemsToListIndex(order);
      l = sortedByCalculatedFieldDesc(l, func(wmctrl_Entry e) {
        map.get(last7chars(e.windowIdentity))
      });
    }
    setData(l);
  }
  
  // API
  
  // id = "0x..."
  S titleForWindowID(S windowIdentity) {
    while (l(windowIdentity) < 10) windowIdentity = spliceString(windowIdentity, 2, 2, "0");
    //print("Searching window: " + windowIdentity);
    ret getString windowTitle(objectWhere(data(), +windowIdentity));
  }
  
  // may be costly (one invocation of xprop)
  // information is accurate if window is older than 10 secs
  S currentWindowTitle() enter {
    ret titleForWindowID(linux_activeWindowID());
  }
}