2

When I switch between windows of the same application, it it doesn't work with all applications:

  • gnome terminal: OK
  • gedit: OK
  • chrome: KO
  • emacs: KO

More specifically, for chrome and emacs it sees only one window while two are open.

At the same time, the window grouping feature works very well in the bottom bar that shows all open windows.

In "preferences" -> "Keyboard Shortcuts", I customized "Switch windows of an application" with "Super+Tab" and disabled "Switch Applications".

Text

Is this a known problem?

I'm on Ubuntu 20.04 running Gnome 3.36.8 flashback (metacity).

Thanks!

Ricky Robinson
  • 1,457
  • 6
  • 20
  • 30
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackexchange.com/rooms/129129/discussion-on-question-by-ricky-robinson-switching-between-windows-of-the-same-a). – Thomas Ward Aug 31 '21 at 15:32

2 Answers2

1

I tried on Ubuntu (Budgie) 20.04 with the same result, be it that the shortcut, if it worked, switched (only) between the two most recent windows of the active application. Like you, with a.o. Chrome, no switching took place at all.

We can think of several reasons why specific applications do not switch windows, but we'd need to look into the code to know what is exactly happening. Even then, it would not quite fix your issue.

The script below, run as a daemon, in combination with an edited shortcut, does the job though. It's tested on 20.04 and (at least) with Chrome with no issue. I am pretty sure it works fine with all applications with windows of type NORMAL.

What it does

The daemon is triggered by a trigger file, created in /tmp by a/the shortcut. Subsequently it looks up all valid windows of the active application, on the current workspace, in stack, so we know the z-order. The daemon then activates the first window in stack, thus cycling through the windows.

As an extra

...You can set a shortcut to switch between the two most recent application windows, which was the default behavior on my 20.04.

How to setup

  • Copy the script below into an empty file, save it as cycle_alternative, (or any other name you like). The extension .py is not needed.
  • Make the script executable
  • Run it (keep it running) by the command /path/to/cycle_alternative.
  • Now make your shortcut execute the command touch /tmp/forward_trigger to make it cycle through all windows of the active application. To switch between the two most recent windows, set the shortcut to execute touch /tmp/switchactive_trigger

If all works fine, add the daemon to your startup applications.

Why a daemon?

You could add the same functionality to a script, called by a shortcut, but the cold start + loading the libs per occasion would make it work less responsive. Running the daemon is nothing when it comes to additional burden.

The script/daemon

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

class watchout:
    def __init__(self):
        self.wnckscr = Wnck.Screen.get_default()
        # we'll activate the daemon's function by trigger files
        self.triggers = [
            "/tmp/forward_trigger",
            "/tmp/switchactive_trigger"
        ]
        # so, let's keep an eye on these two files
        forward_mon = Gio.File.new_for_path(self.triggers[0]).monitor(
            Gio.FileMonitorFlags.NONE , None
        )
        switchactive_mon = Gio.File.new_for_path(self.triggers[1]).monitor(
            Gio.FileMonitorFlags.NONE , None
        )
        # ...and make them trigger something
        for mon in [
            forward_mon, switchactive_mon
        ]:
            mon.connect("changed", self.switchwindow)
        Gtk.main()

    def switchwindow(self, arg1, file, arg3, event):
        # let's see what trigger is fired, get the active window's group name
        fname = file.get_path()
        activewin = self.wnckscr.get_active_window()
        checkwinisnormal = False
        try:
            active_class = activewin.get_class_group_name()
            checkwinisnormal = activewin.get_window_type() == Wnck.WindowType.NORMAL
        except AttributeError:
            pass
        # let's check if the event is right, and if the window is valid
        if all([
            event == Gio.FileMonitorEvent.CREATED,
            checkwinisnormal
        ]):
            # we'll get the active application's windows and the current workspace
            # look for windows only on this workspace
            currclass_xids = []
            curr_ws = self.wnckscr.get_active_workspace().get_number()
            for w in self.wnckscr.get_windows_stacked():
                try:
                    onthis = w.get_workspace().get_number() == curr_ws
                except AttributeError:
                    pass
                else:
                    if all([
                        w.get_window_type() == Wnck.WindowType.NORMAL,
                        active_class == w.get_class_group_name(),
                        onthis
                    ]):
                        currclass_xids.append(w.get_xid())
            target_xid = [0, -2][self.triggers.index(fname)]
            for w in self.wnckscr.get_windows_stacked():
                try:
                    if w.get_xid() == currclass_xids[target_xid]:
                        now = GdkX11.x11_get_server_time(
                            GdkX11.X11Window.lookup_for_display(
                                Gdk.Display.get_default(),
                                GdkX11.x11_get_default_root_xwindow()
                            )
                        )
                        w.activate(now)
                except IndexError:
                    pass
        try:
            os.remove(fname)
        except FileNotFoundError:
            pass

        
watchout()

N.B.

P.S. Possibly, you might need to install one or two additional libs, but let's find out if there is any output in terminal.

Jacob Vlijm
  • 82,471
  • 12
  • 195
  • 299
  • Thanks a lot for the script! It seems a bit of an overkill, though. :) You definitely deserve the bounty, let me just figure out if I can fix this by upgrading my setup. – Ricky Robinson Aug 30 '21 at 14:53
  • @RickyRobinson you mean overkill to make a script for it, or overkill to -use- a script for it? If the first: don't worry, it's an edited/simplified python-version of an out-take of code I use elsewhere. To use it isn't really complicated, and it fixes the problem. Another option is of course to update to a later version of Ubuntu, where it appears to be fixed (at least in 21.10 dev. version). That is much more work however :) – Jacob Vlijm Aug 30 '21 at 15:57
0

Try to overwrite the values.

  1. Set up a new value for Switch applications.
  2. Overwrite the value for Switch windows.
Unix
  • 197
  • 9
  • I see. But on another machine, I have debian + xfce and switching between windows of the same application works very well. At least in that setup, there doesn't seem be any differences in behaviour from one application to another. – Ricky Robinson Aug 18 '21 at 08:36
  • Ah man, I was "reading" (wrong) 'tabs' instead of 'windows'... Let me fix my answer. – Unix Aug 18 '21 at 09:17
  • Sure! But... "switch applications" comes down to "switch windows" on my setup. It seems to do the exact same thing on both my workspaces. My problem is that switching between windows of the same application is buggy... – Ricky Robinson Aug 18 '21 at 09:57
  • If overwriting the values (just to test it) does not fix the problem, then the next step is to check dconf tool. Take a look at this answer: https://superuser.com/a/860001/396041 – Unix Aug 18 '21 at 10:27
  • All right, but that didn't lead anywhere, unfortunately. The problem is not that it doesn't ever work. The problem is that for some applications it works, but for others it sees only one window, while there are many. – Ricky Robinson Aug 19 '21 at 11:12