Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@johnlane
Last active October 24, 2023 21:43
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save johnlane/351adff97df196add08a to your computer and use it in GitHub Desktop.
Save johnlane/351adff97df196add08a to your computer and use it in GitHub Desktop.
Example GTK to create a dock-like bar and strut
#!/usr/bin/env python2
#
# dockbar.py
#
# Example program places a coloured bar across the top of the
# current monitor
#
# demonstrates
#
# (a) creating the bar as an undecorated "dock" window
# (b) setting its colour
# (c) getting the number of monitors and their sizes
#
# JL 20140512
import gtk
# Colour style for (b)
colour_rc= """
style "bar-colour" {
bg[NORMAL] = "Dark Red"
} widget "*bar" style "bar-colour"
"""
# the size of the bar (its height), in pixels
bar_size = 10
def main ():
# (a) Create an undecorated dock
window = gtk.Window()
window.set_name("bar")
window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK)
window.set_decorated(False)
window.connect("destroy", gtk.main_quit)
# (b) Style it
gtk.rc_parse_string(colour_rc)
# the screen contains all monitors
screen = window.get_screen()
width = gtk.gdk.screen_width()
print "width: %d" % width
# (c) collect data about each monitor
monitors = []
nmons = screen.get_n_monitors()
print "there are %d monitors" % nmons
for m in range(nmons):
mg = screen.get_monitor_geometry(m)
width = mg.width
print "monitor %d: %d x %d" % (m,mg.width,mg.height)
monitors.append(mg)
# current monitor
curmon = screen.get_monitor_at_window(screen.get_active_window())
x, y, width, height = monitors[curmon]
print "monitor %d: %d x %d (current)" % (curmon,width,height)
print "bar: start=%d end=%d" % (x,x+width-1)
# display bar along the top of the current monitor
window.move(x,y)
window.resize(width,bar_size)
# it must be shown before changing properties
window.show_all()
# (d) reserve space (a "strut") for the bar so it does not become obscured
# when other windows are maximized, etc
topw = window.get_toplevel().window
topw.property_change("_NET_WM_STRUT","CARDINAL",32,gtk.gdk.PROP_MODE_REPLACE,
[0, 0, bar_size, 0])
topw.property_change("_NET_WM_STRUT_PARTIAL","CARDINAL",32,gtk.gdk.PROP_MODE_REPLACE,
[0, 0, bar_size, 0, 0, 0, 0, 0, x, x+width-1, 0, 0])
# we set _NET_WM_STRUT, the older mechanism as well as _NET_WM_STRUT_PARTIAL
# but window managers ignore the former if they support the latter.
#
# the numbers in the array are as follows:
#
# 0, 0, bar_size, 0 are the number of pixels to reserve along each edge of the
# screen given in the order left, right, top, bottom. Here the size of the bar
# is reserved at the top of the screen and the other edges are left alone.
#
# _NET_WM_STRUT_PARTIAL also supplies a further four pairs, each being a
# start and end position for the strut (they don't need to occupy the entire
# edge).
#
# In the example, we set the top start to the current monitor's x co-ordinate
# and the top-end to the same value plus that monitor's width, deducting 1,
# because the xo-ordinate system starts at 0 rather than 1. The net result
# is that space is reserved only on the current monitor.
#
# co-ordinates are specified relative to the screen (i.e. all monitors together).
#
# main event loop
gtk.main()
if __name__ == "__main__":
main ()
#!/usr/bin/env python
#
# dockbar.py
#
# Example program places a coloured bar across the top of the
# current monitor
#
# demonstrates
#
# (a) creating the bar as an undecorated "dock" window
# (b) setting its colour
# (c) getting the number of monitors and their sizes
#
# JL 20140512, 20170220
import gi
gi.require_version('Gtk','3.0')
from gi.repository import Gtk, Gdk
import Xlib
from Xlib.display import Display
from Xlib import X
# Colour style for (b)
stylesheet=b"""
window#bar {
background-color: darkred;
}
"""
# the size of the bar (its height), in pixels
bar_size = 10
def main ():
# Version information
print("Gtk %d.%d.%d" % (Gtk.get_major_version(),
Gtk.get_minor_version(),
Gtk.get_micro_version()))
# (a) Create an undecorated dock
window = Gtk.Window()
window.set_name("bar")
window.set_type_hint(Gdk.WindowTypeHint.DOCK)
window.set_decorated(False)
window.connect("delete-event", Gtk.main_quit)
# (b) Style it
style_provider = Gtk.CssProvider()
style_provider.load_from_data(stylesheet)
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
# the screen contains all monitors
screen = window.get_screen()
width = screen.width() #width = Gdk.Screen.width()
print("width: %d" % width)
# (c) collect data about each monitor
monitors = []
nmons = screen.get_display().get_n_monitors()
print("there are %d monitors" % nmons)
for m in range(nmons):
mg = screen.get_monitor_geometry(m)
print("monitor %d: %d x %d" % (m,mg.width,mg.height))
monitors.append(mg)
# current monitor
curmon = screen.get_monitor_at_window(screen.get_active_window())
x = monitors[curmon].x
y = monitors[curmon].y
width = monitors[curmon].width
height = monitors[curmon].height
print("monitor %d: %d x %d (current, offset %d)" % (curmon,width,height,x))
print("bar: start=%d end=%d" % (x,x+width-1))
# display bar along the top of the current monitor
window.move(x,y)
window.resize(width,bar_size)
# it must be shown before changing properties
window.show_all()
# (d) reserve space (a "strut") for the bar so it does not become obscured
# when other windows are maximized, etc
# http://stackoverflow.com/questions/33719686 property_change not in gtk3.0
# https://sourceforge.net/p/python-xlib/mailman/message/27574603
display = Display()
topw = display.create_resource_object('window',
window.get_toplevel().get_window().get_xid())
# http://python-xlib.sourceforge.net/doc/html/python-xlib_21.html#SEC20
topw.change_property(display.intern_atom('_NET_WM_STRUT'),
display.intern_atom('CARDINAL'), 32,
[0, 0, bar_size, 0 ],
X.PropModeReplace)
topw.change_property(display.intern_atom('_NET_WM_STRUT_PARTIAL'),
display.intern_atom('CARDINAL'), 32,
[0, 0, bar_size, 0, 0, 0, 0, 0, x, x+width-1, 0, 0],
X.PropModeReplace)
# we set _NET_WM_STRUT, the older mechanism as well as _NET_WM_STRUT_PARTIAL
# but window managers ignore the former if they support the latter.
#
# the numbers in the array are as follows:
#
# 0, 0, bar_size, 0 are the number of pixels to reserve along each edge of the
# screen given in the order left, right, top, bottom. Here the size of the bar
# is reserved at the top of the screen and the other edges are left alone.
#
# _NET_WM_STRUT_PARTIAL also supplies a further four pairs, each being a
# start and end position for the strut (they don't need to occupy the entire
# edge).
#
# In the example, we set the top start to the current monitor's x co-ordinate
# and the top-end to the same value plus that monitor's width, deducting one.
# because the co-ordinate system starts at zero rather than 1. The net result
# is that space is reserved only on the current monitor.
#
# co-ordinates are specified relative to the screen (i.e. all monitors together).
#
# main event loop
# Gtk.main()
# Control-C termination broken in GTK3 http://stackoverflow.com/a/33834721
# https://bugzilla.gnome.org/show_bug.cgi?id=622084
from gi.repository import GLib
GLib.MainLoop().run()
if __name__ == "__main__":
main ()
@RossComputerGuy
Copy link

How would I calculate out the partial strut out of an array of booleans that enable anchors, integer margins values, position of the window, and size of the window? I'm doing this all in C.

@RobinBoers
Copy link

Thanks! You're an absolute legend!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment