3

I am developing a module with Python, and I would like to figure out a way to get the monitor resolution minus the taskbar without any user interaction and preferably in a way that doesn't interfere with the visual interface. If I can just get the taskbar size and position, I can simply subtract it from the monitor resolution easily. However, I cannot seem to find a way.

In Windows, I am able to use the win32api module and use GetMonitorInfo to get the monitor resolution. However, I have yet to figure out some way to do this in Ubuntu, or Linux in general. If you also have a way to do this in macOS, that would be nice to know as well, but is not necessary for this question.

I would like to support as many desktop environments as possible, but I realize how difficult it would be to do so, since each one may have their own solution. Considering this, I would prefer to start with these desktop environments:

  • KDE
  • XFCE
  • Gnome
  • Cinnamon

If this requires some external programs to get it, I would prefer to use something that comes with the desktop environment or operating system.

  • 2
    Monitor resolution is easy to obtain, both via shell utilities or API. We can also use a few manual ways. But as dessert mentioned, taskbar size might be something specific to desktop environment , that is if you intend to calculate that without user's interaction. Really depends on what are your requirements for the application. – Sergiy Kolodyazhnyy Mar 8 at 22:25
  • 2
    This is actually a tricky thing. Most reliable seems to get the claimed space (strut) values from xprop, looking like: _NET_WM_STRUT(CARDINAL) = 0, 0, 0, 52 or _NET_WM_STRUT_PARTIAL(CARDINAL) = 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 1919 , but specifically in a multi monitor setup, not all panels return correct values in the spanning screen layout: bugs.launchpad.net/plank/+bug/1755731 – Jacob Vlijm Mar 8 at 22:27
  • @SergiyKolodyazhnyy I have edited my question to clarify. – Christian Sirolli Mar 11 at 3:19
  • @ChristianSirolli I've seen that yesterday. I'll loop into it, will see what can be done. – Sergiy Kolodyazhnyy Mar 11 at 3:21
  • 1
    Hello, @ChristianSirolli I've posted an answer with a couple examples and discussion of potential issues. I hope to get it updated later sometime and maybe figure out other ways to achieve the desired result. Let me know if you have any other questions and suggestions to improve the answer. – Sergiy Kolodyazhnyy Mar 15 at 8:24
2

I would like to figure out a way to get the monitor resolution minus the taskbar without any user interaction and preferably in a way that doesn't interfere with the visual interface.

This is what has been asked and I will be focusing on that through out this answer based on what I've found. Getting taskbar size and position was an original idea, but as has been discussed in the comments, this will be difficult to implement without knowing lots of information - which panel or dock is running, do they have _NET_WM_STRUT property set, do they expose that information via GSettings database or other methods. I am certain it is not impossible, but is rather difficult.

NET_WORKAREA property

According to specifications for the root window, _NET_WORKAREA is defined as so:

_NET_WORKAREA, x, y, width, height CARDINAL/32

This property MUST be set by the Window Manager upon calculating the work area for each desktop. Contains a geometry for each desktop. These geometries are specified relative to the viewport on each desktop and specify an area that is completely contained within the viewport. Work area SHOULD be used by desktop applications to place desktop icons appropriately.

The Window Manager SHOULD calculate this space by taking the current page minus space occupied by dock and panel windows, as indicated by the _NET_WM_STRUT or _NET_WM_STRUT_PARTIAL properties set on client windows.

There's a few points to note:

  • A window manager that is compliant with these specifications must set this property, so on desktop environments like XFCE, Budgie, Unity, GNOME, KDE - that is in any official Ubuntu flavor that doesn't use any experimental window manager will have this property set; in other words, this will work on supported desktops
  • This calculates available width and height, but also where offsets begin relative to leftmost corner of the whole display (in case of dual screen, your left-most screen's top left corner will be the the starting point)
  • The _NET_WM_STRUT or _NET_WM_STRUT_PARTIAL are properties that are set by docks and panels. This means, that if the panel or dock don't set it, they will basically behave like a normal window that just sits above all the others ( and making the users potentially annoyed1 ). That said, this is good enough for us. I've tested this property on Cinnamon, LXQt, and XFCE on top of Ubuntu 18.04. In all instances, the docks and panels properly informed the window manager of their strut area. That means, _NET_WORKAREA will work for you in 99% of the cases.

This property can be queried in shell via xprop utility over the root window.

$ xprop -root _NET_WORKAREA
_NET_WORKAREA(CARDINAL) = 0, 32, 3120, 974, 0, 32, 3120, 974

That's the output with my dual monitor setup, with two monitors aligned along the top, a dock and top panel. If you notice only the first four values are significant, and the other four are repeated. Of particular interest is 3120 and 974. That's the value we're interested in. The first two tell us where the desktop's left most corner starts. My top panel takes up 32 points, hence desktop's left most corner starts all the way on the left, with offset downward 32 points. Offset from the bottom usually doesn't matter for windows - they'll fill the workarea that's available.

If I put the dock on the right side of the primary monitor, you will notice that width has decreased, but height has:

$ xprop -root _NET_WORKAREA
_NET_WORKAREA(CARDINAL) = 0, 32, 3059, 1018, 0, 32, 3059, 1018

The change in height is 44 points. Add another 32 (the size of top panel window) to that, and you'll get 1050 exactly the geometry of my desktop (note the 3120 from before when there was no dock to the size, so full desktop width was being used ):

$ xprop -root _NET_DESKTOP_GEOMETRY
_NET_DESKTOP_GEOMETRY(CARDINAL) = 3120, 1050

Python and xprop

The xprop command above comes with most desktops, and belongs to x11-utils package, so if you're targeting major Debian-based systems, you should have it available at most times. What I would do is use Python's subprocess, and utilize either subprocess.check_output() or subprocess.run() command and parse the output via re module.

>>> import re,subprocess
>>> out = subprocess.check_output(['xprop','-root','_NET_WORKAREA'])
>>> workarea_tokens = re.split('=|,',out.decode())
>>> workarea_tokens[1:5]
[' 0', ' 32', ' 3059', ' 1018']

Python and Gdk

Alternative ( and usually my preferred way ) would be to utilize Gdk library which is closely related to other GNOME project libraries. If you are developing a desktop application using Gtk, you already have the necessary tools available, so why not use them ? The tricky part is that you have to calculate workarea for each individual monitor.

#!/usr/bin/env python3
import gi
gi.require_version('Gtk','3.0')
gi.require_version('Gdk','3.0')
from gi.repository import Gdk,Gtk,GdkX11

display = Gdk.Display().get_default()
for i in range(display.get_n_monitors()):
    monitor = display.get_monitor(i)
    w_area  = monitor.get_workarea()
    print(w_area.x, w_area.y,
          w_area.width, w_area.height)

The result of this program:

$ python3  display_area.py
1440 32 1619 1018
0 0 1440 900
# width of two monitors with dock on right adds up to _NET_WORKAREA
$ echo $((1619+1440))
3059
$ xprop -root _NET_WORKAREA
_NET_WORKAREA(CARDINAL) = 0, 32, 3059, 1018, 0, 32, 3059, 1018

Issues

Now, remember I've mentioned I have dual monitors ? Such setup opens whole lot of possibilities, but also reveals certain odd behaviors.

# added xfce4-panel at the bottom of second screen, no change in height - 900
$ python3 display_area.py ; xprop -root _NET_WORKAREA
1440 32 1619 1018
0 0 1440 900
_NET_WORKAREA(CARDINAL) = 526, 32, 2533, 1018, 526, 32, 2533, 1018
# stopped xfce4-panel process, same height - 900
$ python3 display_area.py ; xprop -root _NET_WORKAREA
1440 32 1619 1018
0 0 1440 900
_NET_WORKAREA(CARDINAL) = 0, 32, 3059, 1018, 0, 32, 3059, 1018
# added xfce4-panel to the top of second monitor
$ python3 display_area.py ; xprop -root _NET_WORKAREA
1440 49 1619 1001
0 0 1440 900
_NET_WORKAREA(CARDINAL) = 0, 49, 3059, 1001, 0, 49, 3059, 1001

Remember that I have a panel and a dock on one screen, and added for tests xfce4-panel on the other screen. The buggy results with Gdk is that second monitor work area did not get changed. xprop also reported erroneous numbers - in the first output 526 points of offset from the left were simply not true. In the last output, however, the vertical offset increased, which was the good thing - the extra width added by xfce4-panel should be added to the total, and probably what helps is that my two monitors are aligned at the top.

In other words, if your application is planning on determining the area without docks and panels, these methods will work best with single monitor setup. In dual monitor setup - results could potentially be inconsistent. Note that I am using Metacity Window Manager, and the bugginess could be attributed to that. However, I don't have a way to test other WM with dual monitor setup at the moment,so I'll leave this section as inconclusive.

TODO ( someday )

  • libx11 example in C or Python

  • dual monitor testing with alternative window manager

  • find dock and panel locations


Footnotes

1 Feature not documented, depends on user's amount of patience.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.