Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

Flashing window on taskbar

I got very interested, for probably no real reason, in knowing how to make my window titles blink or flash in the taskbar (iconbar in Fluxbox). I wanted to know if Fluxbox supports it, and it does. It's called urgency or _NET_WM_STATE_DEMANDS_ATTENTION.

A great little tool named xurgent exists and is trivial to compile. You tell it what window id (from xwininfo) to make urgent. You can accomplish the same with xdotool (upstream website) as well:

xdotool set_window --urgency 1 $( xwininfo | awk '/ id/{print $4}' )

This command lets the user use the crosshairs cursor to select a window, which will then set its window hint for urgency. Flubox and other reasonable window managers then interpret this as the need to flash the taskbar entry for that window.

If you want to have a very simple python program that can set its own urgency:

#!/usr/bin/env python3
# Reference:
#    logout-manager for basic python3 gtk3 app
#    https://stackoverflow.com/questions/3433615/python-window-focus/3433968#3433968
#    timeout_add https://www.programcreek.com/python/?code=berarma%2Foversteer%2Foversteer-master%2Foversteer%2Fgtk_ui.py
import gi, time
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
class MainWindow(Gtk.Window):
   def __init__(self):
      Gtk.Window.__init__(self, title="Normal program")
      self.connect("notify::is-active", self.is_active_changed)
      self.grid = Gtk.Grid()
      self.add(self.grid)
      button0 = Gtk.Button(label="_Make urgent")
      button0.connect("button-press-event", self.on_button0_press_event)
      button0.connect("activate", self.on_button0_press_event) # activate covers ALT action if used and spacebar when selected
      button0.set_use_underline(True)
      self.grid.add(button0)
   def is_active_changed(self, window, param):
      if self.props.is_active:
         self.set_urgent(False)
   def on_button0_press_event(self, *args):
      print("counting to 3")
      GLib.timeout_add(3000, self.set_urgent, True)
   def set_urgent(self, *args):
      # should call with True or False
      if len(args) >= 1 and args[0]:
         self.set_title("Urgent notification!")
         self.set_urgency_hint(True)
      else:
         self.set_title("Normal program")
         self.set_urgency_hint(False)
# MAIN LOOP
win = MainWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

Comments