Last active
February 17, 2025 05:56
-
-
Save johnlane/351adff97df196add08a to your computer and use it in GitHub Desktop.
Example GTK to create a dock-like bar and strut
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 () |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 () |
Thanks! You're an absolute legend!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.