wangwenx190 / framelesshelper

Project moved to: https://github.com/stdware/qwindowkit Cross-platform window customization framework for Qt Widgets and Qt Quick. Supports Windows, Linux and macOS.
MIT License
846 stars 202 forks source link

[ATTENTION] The next major release - 2.0 early feedback #104

Closed wangwenx190 closed 2 years ago

wangwenx190 commented 2 years ago

Please don't hesitate to tell me your feature requests and any bugs you have found! Thanks!

wangwenx190 commented 2 years ago

There's qrc file inside the src/core folder, you should add it to your RESOURCES as well

JulienMaille commented 2 years ago

But that's for your own images, I don't need them

wangwenx190 commented 2 years ago

OK, then you could search and remove all the occurances of Q_INIT_RESOURCE in framelesshelper.

JulienMaille commented 2 years ago

Ok, i'm almost there. I had to call setMenuWidget(widget); to get something correct

wangwenx190 commented 2 years ago

I had to call setMenuWidget(widget); to get something correct

Sorry I don't quite get the point. What issue did you find?

JulienMaille commented 2 years ago

I was just mentioning your comment below. It's not clear what setMenuWidget does, in my case it was required

    // This call to the setMenuWidget() function is only needed by this example
    // application to achieve some special effects, don't use it in your own
    // code if you don't know what's it for!
    setMenuWidget(titleBarWidget);
wangwenx190 commented 2 years ago

OK. I added that comment because some days ago one user tell me the window layout is messed up by framelesshelper and in the end I find he copied setMenuWidget(titleBarWidget) to his project as well because the demo project has this line. So it's better to inform people not to use this line unless they know what they are doing.

JulienMaille commented 2 years ago

I have one last question, it now works without calling any setHitTestVisible() but I see you still do in your example. Is that needed?

wangwenx190 commented 2 years ago

I have one last question, it now works without calling any setHitTestVisible() but I see you still do in your example. Is that needed?

That's still needed. If you use the standard title bar provided by FramelessHelper, it will call this function internally so you don't have to do this explicitly in your own code. But if you are using your own homemade title bar, you still need to use that function to make any widget in your title bar visible to hit test.

JulienMaille commented 2 years ago

i'm using my own titlebar and I don't need it. But it might work because of setMenuWidget?

wangwenx190 commented 2 years ago

i'm using my own titlebar and I don't need it. But it might work because of setMenuWidget?

That's very strange. Anyway, you'd better call setHitTestVisible if you are using your own titlebar, in case the current situation changes without notice and your titlebar stops functional.

JulienMaille commented 2 years ago

Noted. So I'm going to further test, but it seems to now work very well (except for bug 92)! Thanks a lot for your assistance!

wangwenx190 commented 2 years ago

92 is back sadly, I know that, but now it seems that bug becomes harder to fix. The previous workaround is not appliable because we now don't reply on WM_NCHITTEST to return HTCAPTION now. I might need your help again on this bug.

JulienMaille commented 2 years ago

Argh

JulienMaille commented 2 years ago

One additional question, on win7 there's no frame at all, I've seen this comment so I suppose this is a feature? https://github.com/wangwenx190/framelesshelper/blob/d4e711d679acee0605e72b6e545a8a2e4b816d7e/src/core/utils_win.cpp#L978-L981

wangwenx190 commented 2 years ago

You can set the environment variable FRAMELESSHELPER_FORCE_SHOW_FRAME_BORDER to a non-zero value to force show the window frame even on Windows 7, but that will make your window look very bad, so I only enable this feature on Windows 10 and Windows 11. On Windows 7 the code still goes through the old 1.x behavior, for example, resize inside the window, no frame border, etc.

JulienMaille commented 2 years ago

When forcing kForceShowFrameBorderFlag it could look nice except that the top frame is not drawn. Otherwise it would be acceptable. Can I do something to get the full frame?

wangwenx190 commented 2 years ago

When forcing kForceShowFrameBorderFlag it could look nice except that the top frame is not drawn. Otherwise it would be acceptable. Can I do something to get the full frame?

Can you show me a screenshot that you think looks nice? In my test the window looks very strange.

JulienMaille commented 2 years ago

image

JulienMaille commented 2 years ago

Maybe just a one pixel frame like we had before would look better

wangwenx190 commented 2 years ago

well I don't think it looks very nice because the frame border is quite wide, it's 8px when DPI is 96, while it's only 1px on Windows 10.

JulienMaille commented 2 years ago

well I don't think it looks very nice because the frame border is quite wide, it's 8px when DPI is 96, while it's only 1px on Windows 10.

on Win7 such a wide frame border is normal, so that's why I said it could be acceptable

wangwenx190 commented 2 years ago

Maybe just a one pixel frame like we had before would look better

Then why not hide the whole frame and draw a 1px frame border ourself? If we preserve the system border to make it 1px wide, it is doable indeed, but the resize area will be too small so to make the resize area wider we will have to make the area expand to the client area, that will make the whole processing much more complicated because we now have two resize area, one is the original system border, the other is inside the window which is made by ourselves.

JulienMaille commented 2 years ago

Understood. A simpler solution would be to accept a 1px resize area and draw a 1px frame. this could be done by tweaking updateContentsMargins() and shouldDrawFrameBorder() correct?

wangwenx190 commented 2 years ago

Currently the top frame border is also self painted by FramelessHelper, but that's not difficult due to on Windows 10 and 11 the frame border only has solid color, not semi-transparent. But on Windows 7, things become quite complicated, the DWM composition may be disabled (that's also showed from your screenshot), in such cases the frame border color is something like gradient color, and when DWM composition is enabled, the frame border looks like semi-transparent and blended with some theme color, if we want to totally draw the top border ourself, it will be very difficult. They are really not easy to simulate. But I did recall some window have the four borders on Windows 7, it looks normal indeed, but that window doesn't have a titlebar, I guess it was some kind of dialog style window, need more investigation though.

wangwenx190 commented 2 years ago

this could be done by tweaking updateContentsMargins() and shouldDrawFrameBorder() correct?

Yes you are right, for now you can tweak these two functions to add this feature temporarily, but I think I should add a separate option or switch to do this, and this feature of course can be used on Windows 10/11 as well.

JulienMaille commented 2 years ago

Almost ok, some pixels are missing?! image

wangwenx190 commented 2 years ago

because the top frame is round corner, different with the bottom frame.

wangwenx190 commented 2 years ago

This issue can be fixed by enabling Aero

JulienMaille commented 2 years ago

Yep thanks again. Are your sure about this line I suppose I also need to return true in isWindowFrameBorderVisible() if we draw them ourself?

wangwenx190 commented 2 years ago

I suppose I also need to return true in isWindowFrameBorderVisible() if we draw them ourself?

Yes. These functions mostly check whether the application is running on win10 or onwards or not. They are wrapped in separate functions just because I want to use multiple ways to control this behavior so write a separate function is convenient.

JulienMaille commented 2 years ago

Should I add a new FRAMELESSHELPER_FORCE_SHOW_FRAME_WIN7?

JulienMaille commented 2 years ago

I suppose I also need to return true in isWindowFrameBorderVisible() if we draw them ourself?

Yes. These functions mostly check whether the application is running on win10 or onwards or not. They are wrapped in separate functions just because I want to use multiple ways to control this behavior so write a separate function is convenient.

hum returning true will activate win7 "ugly" frames

wangwenx190 commented 2 years ago

Should I add a new FRAMELESSHELPER_FORCE_SHOW_FRAME_WIN7?

You can, and if you want to make this a pr, we can discuss the details later in the pr instead.

JulienMaille commented 2 years ago

I'm trying to understand where the bug #92 could come from. I'm wondering if it has to do with void QWidgetWindow::handleEnterLeaveEvent(QEvent *event) https://github.com/qt/qtbase/blob/dev/src/widgets/kernel/qwidgetwindow.cpp#L378 My theory is that the QMainWindow receives a LeaveEvent when opening a QMenu/QComboBox but doesn't receive an EnterEvent when we click in the titlebar

Unfortunately setting breakpoints always hides the bug so I would need to try recompiling Qt with some traces

EDIT: I found a new way to trigger the issue, without using a QMenu/QComboBox Just click the titlebar! And now it gets even weirder: If you hold the click for one second, the bug doesn't appear?!

JulienMaille commented 2 years ago

Ok I think I found it: calling startSystemMove2() should not be done in MousePress but in MouseMove. You can test my PR #105

wangwenx190 commented 2 years ago

I think the implementation on Windows is feature complete now, maybe there still are some uncovered minor bugs but that could wait for the final cleanup of 2.0. I think I'll focus on adding Linux implementation for the next few weeks, but I guess it won't take too long because Linux implementation is expected to be a lot more simple than Windows. macOS support will be the last one to implement due to I myself is not familiar with developing on macOS.

wangwenx190 commented 2 years ago

@Detector-I I found that the native system menu will always appear in light theme regardless of the system theme in both Windows 10 and Windows 11. So the dark menu you observed should be an application specific extension. Although it may be better to use dark theme in as many places as we can, make the system menu dark is not the native behavior of Windows and most applications don't do this either. I think we should sync with the OS and what most applications do. What do you think?

Detector-I commented 2 years ago

@Detector-I I found that the native system menu will always appear in light theme regardless of the system theme in both Windows 10 and Windows 11. So the dark menu you observed should be an application specific extension. Although it may be better to use dark theme in as many places as we can, make the system menu dark is not the native behavior of Windows and most applications don't do this either. I think we should sync with the OS and what most applications do. What do you think?

Thank you for checking it. It was indeed a good thing to have them all with same theme... But as you said it's better to keep using the available native features instead of creating custom ones... So I think program like np++ and sublime Text also custom creating it?

wangwenx190 commented 2 years ago

So I think program like np++ and sublime Text also custom creating it?

To make the menu background dark, we have to apply a dark theme provided by the system theme resource. This is the standard way to change some control's theme as it will always sync with the system's latest native looking-and-feel. But after some studying these days, I found there's no such theme for the menus, at least I can't find a public official way to apply dark theme to win32 menus. Previously I said I could change the menu color because we can change the menu item color through win32 apis indeed, but later I found it's a totally different thing with applying a different theme. But if we draw the menu ourself, we can of course control the theme of it, but it's not the native system menu anymore, although it can have exactly the same functionalities with the system menu. It will need much more code to draw and maintain the system menu ourself, and I think this repository's main focus is to remove the system window frame and customize the window, although customize the system menu is kind of relevant to our main focus, it's quite far from our core functionality, and it will increase the complexity and potential bugs of this repository, so I think we'd better postpond it until we can find a better solution which doesn't need to draw the menu ourself.

JulienMaille commented 2 years ago

Hello again. I have one feature request since you are asking for it. I draw my own min/max/close buttons but would very much the win11 behavior to work. I have tried adding a setter function on button pointers:

    m_settings.minimizeButton = minimizeButton;
    m_settings.maximizeButton = maximizeButton;
    m_settings.closeButton = closeButton;

and then setting the Option::MaximizeButtonDocking flag. I can see the maximize menu but also many artifacts (like old winXP buttons popping up) so I believe that's not the way to go

wangwenx190 commented 2 years ago

I can see the maximize menu but also many artifacts (like old winXP buttons popping up) so I believe that's not the way to go

The code is correct but not complete, so some artifacts may occur. For now it's better not to use this cool feature temporarily. I'll finish the implementation at some later point.

wangwenx190 commented 2 years ago

@JulienMaille Once it's fully implemented, I'll enable it by default for the demo applications.

wangwenx190 commented 2 years ago

It seems among all the system applications only the file explorer has a dark themed system menu. I know how it's done but that's the first awkward situation I have mentioned before: the dark theme will be applied to the whole window, so some of the native looking widgets will also become dark, while others remain in the light theme, and thus make the whole user interface look bad. However, Qt Quick applications won't be affected, so it may still be an option for me.

Detector-I commented 2 years ago

So I think program like np++ and sublime Text also custom creating it?

To make the menu background dark, we have to apply a dark theme provided by the system theme resource. This is the standard way to change some control's theme as it will always sync with the system's latest native looking-and-feel. But after some studying these days, I found there's no such theme for the menus, at least I can't find a public official way to apply dark theme to win32 menus. Previously I said I could change the menu color because we can change the menu item color through win32 apis indeed, but later I found it's a totally different thing with applying a different theme. But if we draw the menu ourself, we can of course control the theme of it, but it's not the native system menu anymore, although it can have exactly the same functionalities with the system menu. It will need much more code to draw and maintain the system menu ourself, and I think this repository's main focus is to remove the system window frame and customize the window, although customize the system menu is kind of relevant to our main focus, it's quite far from our core functionality, and it will increase the complexity and potential bugs of this repository, so I think we'd better postpond it until we can find a better solution which doesn't need to draw the menu ourself.

Well I think the best solution would be have them both available, like force program to use native system menu with some kind of flags... (I think the custom created one would be nice too, because it should be easier to make it cross platform...) But as you said, it shouldn't be the priority for now, it should be more of a side feature after the core library finished.

xland commented 2 years ago

在一个Qt新项目中使用这个新分支的代码是一个大问题

wangwenx190 commented 2 years ago

The Linux implementation is mostly done now. Tested on Ubuntu 20.04 and it's totally usable now. I'll try to finish the macOS implementation in the next few weeks.

xland commented 2 years ago

@wangwenx190 ,

想在VS2022环境下使用这个库的这个分支,可不知道怎么引入,有没有相应的文档呀

wangwenx190 commented 2 years ago

@wangwenx190 ,

想在VS2022环境下使用这个库的这个分支,可不知道怎么引入,有没有相应的文档呀

vs的话可以直接用cmake生成工程文件吧,然后引入你自己的项目就可以了。或者先把.lib都编译出来,然后在vs里添加到附加库或者用#pragma comment(lib, xxx.lib)就行。遇到什么问题再来反馈就可以了。

wangwenx190 commented 2 years ago

The Linux implementation is mostly done now. Tested on Ubuntu 20.04 and it's totally usable now. I'll try to finish the macOS implementation in the next few weeks.

The macOS implementation is also in place. But the Linux and macOS implementation are not perfect yet, compared to the Windows implemetation. I hope I can fix all the major issues during this week and if there's no serious issues on the three platform implementations, I'll release the initial 2.0 version of FramelessHelper. We can fix the minor issues (such as system button color in different themes) in the following .1 .2 .3 etc versions. And I'll also try to implement the features that are requested in this ticket.