Below I mention quite a few focus issues. Some may be related and
some may not, but my thinking is it is less noisy to present them
all in the same place as opposed to splitting up issues with the
potential same cause.

With a recent update of the Opera browser, its window has started
automatically raising itself whenever the mouse enters it (causing
it to receive focus). I have found that the ctwm variable
NoRaiseOnWarp mitigates the issue a bit by making Opera no longer
raise itself. Is this indicating that the cursor is warped (in-place;
it does not move) whenever it enters the window? Unfortunately
this is a bit too unrestrictive since I have become accustomed to
some raise-on-warp behaviour, not to mention NoRaiseOnWarp is not
restricted to specific windows (I have not looked into the viability
of patching that in) e.g. only to Opera.

Opera has some other strange behaviour in conjunction with MakeTitle.
If I hover over the ctwm-title of Opera (it normally does not create
a titlebar) the titlebar will sometimes flicker rapidly. This happens
even without setting NoRaiseOnWarp, though I do not recall if this
started happening along with the raise-on-mouseover focus or if it
also happened earlier and I just lived with it. I can more or less
reproduce it by having Opera and another window side by side, and
lowing the Opera window with the mouse over the titlebar while moving
it over to the titlebar of the second window and back.
The flashing is also not indefinite, and dies down after a short
(sometimes immediately) while, though it might be worth noting that
the cursor will sometimes flicker over to and back from the big
twm/xorg X (X_cursor?) while the flickering is going on.

No other variable I have tried seemed to have any effect on either of
these two issues, including (I did not expect some of these to have
an effect, but to be fair I did not expect NoRaiseOnWarp to either):
NoStackMode { "Opera" }
EWMHIgnore { all flags }
NoRaiseOn[Deiconify,Move,Resize]
ForceFocus

One of the unfortunate side effects of the NoRaiseOnWarp variable is
in conjunction with modals. Setting NoRaiseOnWarp causes modals of
a certain size to stop being on top. It appears this is related to
the option `TransientOnTop int%` -- if I set it to a high value,
modals (transients) again remain on top even with NoRaiseOnWarp set.

Minor note: With NoRaiseOnWarp set, `TransientOnTop 4294%` causes
transients to be on top, while increasing the percentage to
`TransientOnTop 4295%` suddenly breaks the behaviour again (even for
modals of size 1x1 + titlebar). The %-sign also seems necessary,
which was not clear to me from reading the manual. 

>From looking at the source, the default value looks to be 30%, and
that it includes the titlebar and border. This is supported by my
example script where a parent of size (800,700) and a modal of size
(750, 187) causes the not-always-on-top issue to happen, while a
modal of size (187, 750) does not -- most likely due to a wider
titlebar (the percentage of the area of both modals to their parent
is 0.2921875, which probably becomes >30 with longer titlebars).
In retrospect this makes sense, but it made for some confusion when
trying to figure out why it was happening. 

Nonetheless, I was not able to cause the modal to lose its on-top
behaviour with both NoRaiseOnWarp and TransientsOnTop unset, despite
having a modal area way larger than the parent window area -- so
NoRaiseOnWarp appears to introduce the issue.

There is two more focus issues I have no idea if can be worked
around with setting some variables. The first occurs with the
PyQt5 example  program I have attached at the end. If I run the
program (without any wonky variables like NoRaiseOnWarp set) and
press Esc while my mouse is above the purple modal (on top of the
parent), the modal will close and the parent gains focus. I can
now press Ctrl+Q in the orange parent window, and the program quits.

If I on the other hand run the program and move my mouse out of the
modal and over the parent and then press Esc, the modal will close
and it will look like the parent gains focus (its border highlights).
If I then press Ctrl+Q, the program does not close. I have to click
once inside the parent (or alternatively move my mouse out of the
orange parent and back inside it) in order to make the program quit.

The second issue is probably maybe not as related and involves a
not-so-great application running in Wine (the game-portion of
League of Legends (TM)). I have set it to start iconified, and it
does, but after it loads it will change my cursor (while iconified),
as well as steal focus. A combination of uniconifying the window a
few times and clicking inside it (1-2 iconifies usually does it, but
sometimes a nimble combination of keybinds (ctwm-restart follow by a
fast uniconify while hovering over the icon) is required to steal
back the cursor). I have tried a lot of the variables I mentioned
earlier (also included in the .twmrc below), though nothing I tried
has had an effect on this behaviour. 
Since programs run in Wine can have a tendency to not be very nice or
well-behaved, I would say this last issue probably is not worth
focusing[ c: ] on here, though I thought I could mention it.

Bonus issue I just remembered -- Firefox tooltips in conjunciton with
opening the gtkfilechooser will sometimes linger on top of the
filechooser window, and will not disappear until the filechooser is
closed. It may be related to the tooltips having a tiny delay before
showing, and the gtkfilechooser also being a bit slow to open, so
that they appear at around the same time. This is just speculation
from my side though.

Version information:
git:c6e3a713ff3bf54e7266faffcafdecda75984b5e
version 4.0.3-post
I18N, JPEG, USEM4, EWMH, XRANDR

My more or less minimal .twmrc for trying out various combinations
of possibly-related options has these lines of interest, followed
by about 100 lines of basic workspace/font/menu/ keybinds that I
have not included:
#BEGIN
#ForceFocus
#AutoFocusToTransients
#NoStackMode

#NoRaiseOnDeiconify
#NoRaiseOnMove
#NoRaiseOnResize

# one more percentage and it falls below (at least on my machine)
#TransientOnTop 4294%
NoRaiseOnWarp
#DontSetInactive { "minimal.py" }
#IgnoreTransient { "minimal.py" }

# I have left out EWMHIgnore here as it does not seem to do much
# for the above issues.

# The below is basic navigation settings

StartInButtonState
RandomPlacement
DontMoveOff
MoveOffResistance 40
RestartPreviousState
ConstrainedMoveTime 0
# ... (keybinds, workspaces, menus, fonts)
#END


I use this small PyQt5 program to creat a parent window with a modal,
and close the modal with Esc (default Qt behaviour) or the program
with Ctrl+Q.


import sys
from PyQt5.QtCore import QSize
from PyQt5.QtWidgets import QApplication, QWidget, QShortcut, QDialog

parentsize = (800,600)
modalsize = (600,400)
#modalsize = (1,1)

class Dialog(QDialog):
    def __init__(self, parent, resize):
        super().__init__(parent)
        self.setModal(True)

        self.setWindowTitle("modal")
        self.setStyleSheet("QDialog {background: purple}")
        self.resize(QSize(*modalsize))

        shortcut = QShortcut("Ctrl+Q", self)
        shortcut.activated.connect(sys.exit)
        # calculate area of modal to parent
        modal_area = modalsize[0]*modalsize[1]
        parent_area = parentsize[0]*parentsize[1]
        print(modal_area/parent_area)

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Parent window")
        self.setStyleSheet("MainWindow {background: orange}")

        shortcut = QShortcut("Ctrl+Q", self)
        shortcut.activated.connect(self.close)

        # consistent parent position and size
        self.move(100,100)
        self.resize(QSize(*parentsize))
        self.show_dialog()
        self.show()

    def show_dialog(self):
        dialog = Dialog(self, False)
        dialog.show()
        # automatically attempt to raise parent window on top
        # this could be done manually as well
        self.raise_()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainwindow = MainWindow()
    sys.exit(app.exec_())

Reply via email to