weixin_39851977
2020-11-29 07:52 阅读 3

nana::screen::for_each multiple monitor enumeration throws exception

I have tested multiple display monitor support feature (nana/gui/screen.hpp) in ver 1.0.1 . And met the issue.

Currently, nana::screen implementation uses these Windows APIs. - EnumDisplayDevices - EnumDisplaySettings

In my testing environment, return value of screen::count method (which uses EnumDisplayDevices to check the number of monitors) is more than the number of attached monitors.

It seems like EnumDisplayDevices enumerate adapters instead of monitors. and in nana::real_display constructor, EnumDisplaySettings API returned 0(failed).

I could get the number of phyisical moniors with another APIs. Below are the sample code.

 c++
#include <nana>
#include <windows.h>

using namespace nana;

BOOL __stdcall MyInfoEnumProc(HMONITOR hMon, HDC hDC, LPRECT rect, LPARAM lParam)
{
    MONITORINFOEX mi;
    mi.cbSize = sizeof(MONITORINFOEX);
    if (GetMonitorInfo(hMon, &mi)) {
        int hoge = 0;
    }
    return TRUE;
}

int main()
{
    EnumDisplayMonitors(NULL, NULL, MyInfoEnumProc, 0);
    int num = GetSystemMetrics(SM_CMONITORS);

#if 0
    using namespace nana;
    auto s = screen();
    int count = s.count();
    int test = 0;
    s.for_each([&](display& d){
        int hoge = 0;
    });
#endif

}
</windows.h></nana>

Quote from http://stackoverflow.com/questions/18022612/enumerating-monitors-on-a-computer/18263412#18263412

Then, there is a difference between display adapters and monitors. EnumDisplayDevices shows you adapters and EnumDisplayMonitors shows you the monitors. The former is primarily to just enumerate the adapters but the latter allows you to provide a clipping rectangle and determine which monitors that clipping rectangle happens to land on. This becomes useful when you have multiple active monitors and someone decides to do something that causes a draw that will straddle multiple monitors. You get to specify a callback to EnumDisplayMonitors and that callback will be invoked with some parameters (if memory serves me correctly one of the parameters was a subset of the specified clipping rectangle that lands on the specified monitor).

该提问来源于开源项目:cnjinhao/nana

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

6条回答 默认 最新

  • weixin_39949954 weixin_39949954 2020-11-29 07:52

    Hi, beru. Thank you for your feedback and these helpful information, a fix has been checked into hotfixes branch, there are some changes to class screen. I'm not sure whether it works in your testing environment, wait for your feedback.

    点赞 评论 复制链接分享
  • weixin_39851977 weixin_39851977 2020-11-29 07:52

    Hi, jinhao. Thank you for the fix. I confirmed that it is working right now. Though I had to remove a compile error. please refer the comment. https://github.com/cnjinhao/nana/commit/e4382239e59a1da1e647a7e9424d765fa67ead23#commitcomment-10332201

    By the way, I noticed if I make a form with nana::display::workarea(). Size of the form is a bit bigger than the working area. Probablly window size calculation in nana::detail::native_interface::create_window() in nana/source/gui/detail/native_window_interface.cpp has to consider size of non-client area. But I guess it is out of scope of this issue...

    点赞 评论 复制链接分享
  • weixin_39949954 weixin_39949954 2020-11-29 07:52

    The compile error and the unexpected window size were fixed, the fix has been checked into the hotfixes branch. Thank you.

    点赞 评论 复制链接分享
  • weixin_39851977 weixin_39851977 2020-11-29 07:52

    Thank you for the fix but I think there is still the same problem. Please check below code.

     c++
    #include <nana>
    #include <nana>
    
    int main()
    {
        using namespace nana;
    
        auto s = screen();
        auto pa = s.get_primary().workarea();
        //form fm0({pa.x, pa.y, pa.width, pa.height});          // OK
        form fm0({pa.x, pa.y, pa.width - 1, pa.height - 1});    // Not OK
        fm0.caption(L"screen test");
        fm0.show();
    
        exec();
    }
    </nana></nana>
    点赞 评论 复制链接分享
  • weixin_39949954 weixin_39949954 2020-11-29 07:52

    The size parameters of widget's constructor and size() method indicates a window's client area size. Now, added a new outline_size method for root widget to change its window size(not client area size),

    
    form fm0(pa);
    fm0.outline_size({pa.width-1, pa.height-1});
    fm0.show();
    
    点赞 评论 复制链接分享
  • weixin_39851977 weixin_39851977 2020-11-29 07:52

    Thank you for adding the feature. Now it is working as I wished.

    Here is little sample code.

     c++
    #include <nana>
    #include <nana>
    
    int main()
    {
        using namespace nana;
    
        auto s = screen();
        auto pa = s.get_primary().workarea();
        form fm0, fm1, fm2, fm3;
    
        fm0.move(pa.x, pa.y);
        fm0.outline_size({pa.width / 2, pa.height / 2});
        fm0.caption(L"screen 0");
    
        fm1.move(pa.x + pa.width / 2, pa.y);
        fm1.outline_size({pa.width / 2, pa.height / 2});
        fm1.caption(L"screen 1");
    
        fm2.move(pa.x, pa.y + pa.height / 2);
        fm2.outline_size({pa.width / 2, pa.height / 2});
        fm2.caption(L"screen 2");
    
        fm3.move(pa.x + pa.width / 2, pa.y + pa.height / 2);
        fm3.outline_size({pa.width / 2, pa.height / 2});
        fm3.caption(L"screen 3");
    
        fm0.show();
        fm1.show();
        fm2.show();
        fm3.show();
    
        exec();
    }
    </nana></nana>
    点赞 评论 复制链接分享

相关推荐