[download]

local/bin/hud

   1 #!/bin/bash
   2 
   3 subnum=({0..100})
   4 declare -A pids labels
   5 busname=$(xprop -id $1 _GTK_UNIQUE_BUS_NAME     | cut -d \" -f 2)
   6 objpath=$(xprop -id $1 _GTK_MENUBAR_OBJECT_PATH | cut -d \" -f 2)
   7 
   8 while IFS=\| read id pos sid action label; do
   9     pid=${pids[$id]}
  10     label=${label//_/}
  11 
  12     [[ $pid ]] &&
  13     label="${labels[$id]} > $label"
  14 
  15     if [[ $2 == "$label" ]]; then
  16         busctl --user  -j call $busname $objpath \
  17         org.gtk.Actions Activate sava{sv} -- "${action#unity.}" 0 0
  18         exit
  19     fi
  20 
  21     if [[ $sid ]]; then
  22         pids[$sid]="$pid.$sid"
  23         labels[$sid]="$label"
  24     else
  25         echo "$pid.$id.$pos.$(( ++i )) $label"
  26     fi
  27 done < <( # {{{
  28     busctl --user  -j call $busname $objpath \
  29     org.gtk.Menus Start au -- ${#subnum[@]} ${subnum[@]} | jq -r '
  30         .data[] | .[] |
  31         .[0] as $id   |
  32         .[1] as $pos  |
  33     (.[2] | .[] | select(.label) | [$id, $pos, (.":submenu".data | .[0]), .action.data, .label.data] | @tsv)
  34     ' | tr \\t \|
  35 ) | # }}}
  36 sort -k 1,1V | cut -d ' ' -f 2-
  37 
  38 ################################################################################
  39 
  40 busaddr=$(busctl --user -j call \
  41 com.canonical.AppMenu.Registrar \
  42 /com/canonical/AppMenu/Registrar com.canonical.AppMenu.\
  43 Registrar GetMenuForWindow u $1 | jq -r '.data | join(" ")')
  44 
  45 while read id label; do
  46     if [[ $2 == "$label" ]]; then
  47         busctl --user -j call $busaddr \
  48         com.canonical.dbusmenu Event isvu -- $id clicked i 0 $(date +%s)
  49         exit
  50     fi
  51 
  52     echo "$label"
  53 done < <( # {{{
  54     busctl --user -j call $busaddr \
  55     com.canonical.dbusmenu GetLayout -- iias 0 -1 0 |
  56     jq -r  '.' --tab | awk '
  57         BEGIN {
  58             split("", tree)
  59         }
  60 
  61         /\s+[0-9]+/ {
  62             id = int($1)
  63             next
  64         }
  65 
  66         /"data": "submenu"/ {
  67             submenu = ""
  68             next
  69         }
  70 
  71         /"data": "radio"/     { next }
  72         /"data": "separator"/ { next }
  73         /"data": "checkmark"/ { next }
  74 
  75         /"data": "/ {
  76             gsub("_", "")
  77             sub(/"$/, "")
  78             sub(/"data": "/, "")
  79 
  80             if (!submenu){
  81                 submenu  = $0
  82 
  83                 last  = count
  84                 count = gsub(/\t/, "", submenu)
  85 
  86                 for (i in tree){
  87                     if (count < last && i >= last)
  88                         delete tree[i]
  89                 }
  90 
  91                 tree[count]=$0
  92                 next
  93             }
  94 
  95             menu = ""
  96             for (i in tree)
  97                 menu = (menu ? menu " > " : "") tree[i]
  98 
  99             sub(/^\s+/, "")
 100             gsub(/\t+/, "", menu)
 101 
 102             printf "%d %s > %s\n", id, menu, $0
 103             # menus[id]=id " " menu " > " $0
 104         }
 105     '
 106 ) # }}}