Setting X11 properties in GTK4

Hi! I’m trying to create a panel-like application (like tint2 or xfce-panel) in GTK4 and libadwaita. I need to put it at the bottom edge of the screen and prevent maximized windows from overlapping it. I think I need to set X11 properties _NET_WM_STRUT and _NET_WM_STRUT_PARTIAL, but i don’t understand how to do it. The closest thing i could find is GdkX11. X11Surface. set_utf8_property, but it can’t do what i need. How can I do this?
Here is my program:

#!/bin/python
import gi, os
gi.require_version('Adw', '1')
from gi.repository import Adw, Gtk, Gdk, GdkX11, GLib

data = {
	'panel' : None
}

class Application(Adw.Application):
	def __init__(self):
		super().__init__()
		self.get_style_manager().set_color_scheme(Adw.ColorScheme.PREFER_DARK)
		self.run()

	def do_activate(self):
		Panel(app=self)

class Panel(Adw.ApplicationWindow):
	def __init__(self, app):
		super().__init__()
		data['panel'] = self
		self.props.application = app
		self.props.resizable = False
		self.props.default_height = 32
		self.props.default_width = self.get_monitor_size()[0]
		self.props.content = Box()
		self.present()
		self.move_panel_to_position()

	def get_monitor_size(self):
		out = os.popen("xrandr | grep '*'")
		width, height = out.read().split()[0].split('x')
		width = int(width)
		height = int(height)
		return width, height

	def move_panel_to_position(self):
		y_pos = self.get_monitor_size()[1] - self.props.default_height
		x_pos = 0

		xid = GdkX11.X11Surface.get_xid(self.get_surface())
		xscreen = GdkX11.X11Display.get_screen(self.get_display())

class Box(Gtk.Box):
	def __init__(self):
		super().__init__()
		self.props.homogeneous = True
		self.append(ApplicationLauncher())

class ApplicationLauncher(Gtk.Button):
	def __init__(self):
		super().__init__()
		self.props.halign = Gtk.Align.START
		self.props.icon_name = 'view-app-grid-symbolic'
	
	def do_clicked(self):
		data['panel'].destroy()

def main():
	Application()

if __name__ == '__main__':
	main()

you will have to go through xlib for that after you have got the the window’s xid through gdk4-x11.

i do something like this with python-xlib:

xid = GdkX11.X11Surface.get_xid(self.get_surface())
display = Xlib.display.Display()
window = display.create_resource_object('window', xid)
window.change_property(...)

My problem is “change_property” function. There is now good documentation on it. And I don’t understand it’s arguments. How can I write it?

The Xlib documentation may be helpful: XChangeProperty

1 Like

I got the solution!
To make it behave like a panel I did this (“configure_window” function):

class Panel(Adw.ApplicationWindow):
	def __init__(self, app):
		super().__init__()
		data['panel'] = self
		self.props.application = app
		self.props.resizable = False
		self.props.default_height = 32
		self.props.default_width = self.get_monitor_size()[0]
		self.props.content = Box()
		self.present()
		self.configure_window()

	def get_monitor_size(self):
		out = os.popen("xrandr | grep '*'")
		width, height = out.read().split()[0].split('x')
		width = int(width)
		height = int(height)
		return width, height

	def configure_window(self):
		# Get position
		height = self.props.default_height
		width = self.props.default_width
		y_pos = self.get_monitor_size()[1] - height
		x_pos = 0
		# Get window id
		xid = GdkX11.X11Surface.get_xid(self.get_surface())
		display = Xlib.display.Display()
		window = display.create_resource_object('window', xid)
		# Move window to position
		window.configure(x=x_pos, y=y_pos)
		# Add 'dock' property
		window.change_property(display.intern_atom('_NET_WM_WINDOW_TYPE'), display.intern_atom('ATOM'), 32, [display.intern_atom('_NET_WM_WINDOW_TYPE_DOCK')], X.PropModeReplace)
		# Reserve space for panel
		window.change_property(display.intern_atom('_NET_WM_STRUT_PARTIAL'), display.intern_atom('CARDINAL'), 32, [0, 0, 0, height, 0, 0, 0, 0, 0, 0, 0, width], X.PropModeReplace)
		# Sync changes
		display.sync()

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.