Bug 393076

Summary: Oxygen / Window Manager doesn't follow Qt window parent rule in terms of decoration
Product: [Plasma] Oxygen Reporter: Dan Sebald <daniel.sebald>
Component: styleAssignee: Hugo Pereira Da Costa <hugo.pereira.da.costa>
Status: RESOLVED WORKSFORME    
Severity: normal    
Priority: NOR    
Version: unspecified   
Target Milestone: ---   
Platform: unspecified   
OS: Linux   
Latest Commit: Version Fixed In:
Attachments: Widget Style & Behavior setting for which Oxygen has no decorations
Example of desired window decorations for Fusion, Breeze, Window 9x
Example of Oxygen decorations for similar setup

Description Dan Sebald 2018-04-12 21:58:10 UTC
Created attachment 111984 [details]
Widget Style & Behavior setting for which Oxygen has no decorations

I'm running Kubuntu (18.x) right now, but the same behavior applies to Mint KDE and Mageia latest versions.

We,ve been struggling with a bug in the Octave application in which the reparenting of the Qt window, a QDockWidget, to 0 does not create a top level window with decorations.  For background, details are here

https://savannah.gnu.org/bugs/?53276

but I think that link discussion is too much to absorb, so I will try to summarize here.

According to Qt documentation

http://doc.qt.io/qt-5/qwidget.html#details
http://doc.qt.io/qt-5/qwidget.html#top-level-and-child-widgets
http://doc.qt.io/qt-5/qdockwidget.html#setTitleBarWidget

a toplevel window for which

    setParent (0, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
               Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);

or even

    setWindowFlags (Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
                    Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);

should display a full array of decorations, buttons, borders, drag-movement.  For Oxygen theme, we've found that no decorations appear.  I'll summarize: A QDockWidget in a docked state that is floated and assigned the above window attributes is not acquiring window decorations in Oxygen.

One might argue that semantically Qt doesn't exactly say such a thing, but there is enough inference.  Also, I've tested the above Qt behavior in all the non-Oxygen KDE frameworks on Kubuntu 18.x and those show decorations nicely.  To be more specific, I'm attaching a screenshot of the exact KDE setting that matters,  Widget Style & Behavior.  Furthermore, the decorations rule Qt describes also works for non-KDE frameworks.

I was perplexed by how this could come about, but having looked at some KDE code from the git repository, I think I have a better understanding.  Oxygen is unique in that it, along with the KDE Window Manager, is written in Qt.  The decorations are written in Qt, the buttons, signals/slots, etc.  All fine.  Of course, Oxygen / Window Manager can't, say, call member functions associated with Qt QDockWidget and so on, without being very careful.  So, it looks to me, where QDockWidget is used by Oxygen, it is more for the sake of settings and not calling member functions.  Again, all fine, but I'm wondering if those who developed Oxygen may have not considered the above "rules", because it isn't obvious that one should check such things when they're in fact using the Qt framework.  In some sense, Oxygen is rolling its own implementation of Qt, using Qt, if you follow.

In any case, I've looked around in the source code without identifying exactly where the problem is, but I have a hunch that I think narrows things down slightly.  The important parameter in the KDE Window Manager client appears to be the setting "noborder".  That is, from kwin/client.cp:

bool Client::noBorder() const
{
    return decorationPlugin()->isDisabled() || noborder || isFullScreen();
}

I take it the plugin is enabled (in this case Qxygen), as there are plenty of elements of the Octave graphical application that have full decorations: dialog boxes, the main app, etc.  It's not full-screen, but it makes sense that isFullScreen() appears above.  So "noborder" is it.

Now, noBorder() member function is used in the following routine:

void Client::updateDecoration(bool check_workspace_pos, bool force)
{
    if (!force &&
            ((decoration == NULL && noBorder()) || (decoration != NULL && !noBorder())))
        return;
    QRect oldgeom = geometry();
    blockGeometryUpdates(true);
    if (force)
        destroyDecoration();
    if (!noBorder()) {
        createDecoration(oldgeom);
    } else
        destroyDecoration();
    if (check_workspace_pos)
        checkWorkspacePosition(oldgeom);
    updateInputWindow();
    blockGeometryUpdates(false);
    if (!noBorder())
        decoration->show();
    updateFrameExtents();
}

and it is clear if noBorder() is true, then the window decoration->show() doesn't happen.

Lastly, the following is where "noborder" is set:

void Client::detectNoBorder()
{
    if (shape()) {
        noborder = true;
        app_noborder = true;
        return;
    }
    switch(windowType()) {
    case NET::Desktop :
    case NET::Dock :
    case NET::TopMenu :
    case NET::Splash :
    case NET::Notification :
        noborder = true;
        app_noborder = true;
        break;
    case NET::Unknown :
    case NET::Normal :
    case NET::Toolbar :
    case NET::Menu :
    case NET::Dialog :
    case NET::Utility :
        noborder = false;
        break;
    default:
        abort();
    }
    // NET::Override is some strange beast without clear definition, usually
    // just meaning "noborder", so let's treat it only as such flag, and ignore it as
    // a window type otherwise (SUPPORTED_WINDOW_TYPES_MASK doesn't include it)
    if (info->windowType(SUPPORTED_MANAGED_WINDOW_TYPES_MASK | NET::OverrideMask) == NET::Override) {
        noborder = true;
        app_noborder = true;
    }
}

It's pretty clear what the above routine is doing.  Those windows which are dialogs, menus, normal, etc can have decorations, while things like splash-screens and notifications can't have decorations.  I suspect the important entry in the latter category is the NET::Dock.  I'll make a guess that Oxygen logically sets up a QDockWidget to be in the NET::Dock category and *perhaps* Oxygen is not setting the class to be something like NET::Normal when the QDockWidget becomes floated... something along that category I suspect.  Whereas, the Breeze, Fusion and Windows 9x themes have likely been following such rules for a long time with legacy KDE Window Manager and Qt-based KDE Window Manager

Octave is a big program, and probably too much for KDE developers to test, but if you'd like me to, I could probably use qtcreator to build some simple QMainWindow application that will immediately float a QDockWidget and turn it into a top-level window.
Comment 1 Dan Sebald 2018-04-12 22:03:40 UTC
Oh, just a follow-up observation and comment.  The other detail about the Qt top-level rule in terms of KDE is that making this transition

    setParent (0, Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
               Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);

does create a taskbar entry for the floated window.  Per the Qt rule, if I add some arbitrary title to the QDockWidget and float, there are no decorations *and* no taskbar icon--all themes and frameworks.  So, Oxygen's taskbar icon is working correctly, but not its window decorations.
Comment 2 Christoph Feck 2018-04-12 22:49:40 UTC
Wait, is it about KWin window decorations or QWidget styles? Could you test other combinations, e.g. Breeze decoration, or Fusion widget style?
Comment 3 Dan Sebald 2018-04-12 23:25:09 UTC
What combinations should I try?  In this screenshot

https://bugs.kde.org/attachment.cgi?id=111984

is the setting for which, if I select Oxygen no decorations (maximize, minimize, close buttons, etc.) appears while the other three choices in the combo-box produce floated windows in wihch borders appear.  So I should, say, select some other theme (say it is Breeze and I select Fusion) then come back to the Widget Style & Behavior system setting and try all four styles to confirm Oxygen stands alone as the one for which decorations doesn't appear?  (I'm using the word "decoration" in the specific sense that Qt uses it and the KDE kwin/client.cp uses it: the buttons and border.)
Comment 4 Christoph Feck 2018-04-12 23:35:46 UTC
I am still confused, but maybe Hugo understands the issue.
Comment 5 Dan Sebald 2018-04-13 00:14:16 UTC
Created attachment 111986 [details]
Example of desired window decorations for Fusion, Breeze, Window 9x

This is KDE display after selecting the "Fusion" setting in the Widget Style and Behavior system setting as shown in the first screen capture 111984.  There are conventional system decorations, buttons, title bar, etc. and can be resized and move with conventional mouse actions.
Comment 6 Dan Sebald 2018-04-13 00:24:53 UTC
Created attachment 111987 [details]
Example of Oxygen decorations for similar setup

And attached here is what happens when I select "Oxygen" in the combo-box displayed in the Widget Style and Behavior setting show in the screen shot 111984.  Notice that no longer are there any system decorations and the window can't be moved and resized in a conventional way.  There is a title bar of sorts, but that is the default Qt QDockWidget title bar, non-custom.  The buttons on that title bar are used to re-dock to the main window (which can't be done in the Qt sense when the window becomes toplevel).  That secondary title bar is also present in the Fusion example, 111986.

I've also shown in this attachment the taskbar icon to illustrate that the two windows I floated appear in the taskbar--which is correct, that is what should happen.  If these were normal Qt QDockWidget behavior, the child windows wouldn't have an associated taskbar icon.

I'll also note that when I select "Oxygen" from the list, the system window decorations remain.  It is when I dock then refloat the QDockWidgets that the decorations go away.  That is why I suggest that Oxygen realizes that the QDockWidgets become "NET::Dock", but in the transition to a normal window, Oxygen is not realized the QDockWidgets should become "NET::Normal" or some other category for which "noborder" turns out to be "false" once run through that case statement.
Comment 7 Justin Zobel 2022-11-18 04:30:18 UTC
Thank you for reporting this issue in KDE software. As it has been a while since this issue was reported, can we please ask you to see if you can reproduce the issue with a recent software version?

If you can reproduce the issue, please change the status to "REPORTED" when replying. Thank you!
Comment 8 Bug Janitor Service 2022-12-03 05:18:43 UTC
Dear Bug Submitter,

This bug has been in NEEDSINFO status with no change for at least
15 days. Please provide the requested information as soon as
possible and set the bug status as REPORTED. Due to regular bug
tracker maintenance, if the bug is still in NEEDSINFO status with
no change in 30 days the bug will be closed as RESOLVED > WORKSFORME
due to lack of needed information.

For more information about our bug triaging procedures please read the
wiki located here:
https://community.kde.org/Guidelines_and_HOWTOs/Bug_triaging

If you have already provided the requested information, please
mark the bug as REPORTED so that the KDE team knows that the bug is
ready to be confirmed.

Thank you for helping us make KDE software even better for everyone!
Comment 9 Bug Janitor Service 2022-12-18 05:16:47 UTC
This bug has been in NEEDSINFO status with no change for at least
30 days. The bug is now closed as RESOLVED > WORKSFORME
due to lack of needed information.

For more information about our bug triaging procedures please read the
wiki located here:
https://community.kde.org/Guidelines_and_HOWTOs/Bug_triaging

Thank you for helping us make KDE software even better for everyone!