Author Topic: Better PlaceWindow implementation on Linux  (Read 1427 times)

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 12125
    • Travis build status
Better PlaceWindow implementation on Linux
« on: August 04, 2015, 09:40:34 pm »
I'm using a dual monitor setup on linux and the behaviour without this patch is pretty bad -> all new windows/dialogs are placed close to the middle of the whole two-monitor setup. With this patch they are placed in the middle of the screen where the cb main window/parent windows is. The same as on windows.

I'm running with the patch for the day and it seems that it works fine.
I'm posting the patch, so windows people can test it and they can verify that I've not broken something, because the implementation is now shared between windows and unix, and it uses wxDisplay APIs instead of the native APIs.

Code: Diff
  1. Index: src/sdk/globals.cpp
  2. ===================================================================
  3. --- src/sdk/globals.cpp    (revision 10379)
  4. +++ src/sdk/globals.cpp    (working copy)
  5. @@ -32,6 +32,7 @@
  6.  #include "tinyxml/tinyxml.h"
  7.  
  8.  #include <wx/dirdlg.h>
  9. +#include <wx/display.h>
  10.  #include <wx/filefn.h>
  11.  #include <wx/fontmap.h>
  12.  #include <wx/msgdlg.h>
  13. @@ -1065,18 +1066,8 @@ SettingsIconsStyle GetSettingsIconsStyle()
  14.      return SettingsIconsStyle(Manager::Get()->GetConfigManager(_T("app"))->ReadInt(_T("/environment/settings_size"), 0));
  15.  }
  16.  
  17. -#ifdef __WXMSW__
  18. -
  19. -typedef APIENTRY HMONITOR (*MonitorFromWindow_t)(HWND, DWORD);
  20. -typedef APIENTRY BOOL (*GetMonitorInfo_t)(HMONITOR, LPMONITORINFO);
  21. -
  22.  void PlaceWindow(wxTopLevelWindow *w, cbPlaceDialogMode mode, bool enforce)
  23.  {
  24. -    HMONITOR hMonitor;
  25. -    MONITORINFO mi;
  26. -    RECT        r;
  27. -
  28. -    int the_mode;
  29.  
  30.      if (!w)
  31.          cbThrow(_T("Passed NULL pointer to PlaceWindow."));
  32. @@ -1089,51 +1080,49 @@ void PlaceWindow(wxTopLevelWindow *w, cbPlaceDialogMode mode, bool enforce)
  33.      if (!referenceWindow)    // no application window available, so this is as good as we can get
  34.          referenceWindow = w;
  35.  
  36. -    wxRect windowRect = w->GetRect();
  37. -
  38. +    int the_mode;
  39.      if (mode == pdlBest)
  40.          the_mode = cfg->ReadInt(_T("/dialog_placement/dialog_position"), (int) pdlCentre);
  41.      else
  42.          the_mode = (int) mode;
  43.  
  44. +    wxRect monitorRect;
  45.  
  46. -    static MonitorFromWindow_t MonitorFromWindowProc = (MonitorFromWindow_t) GetProcAddress(GetModuleHandle(_T("user32.dll")), "MonitorFromWindow");
  47. -    static GetMonitorInfo_t    GetMonitorInfoProc    = (GetMonitorInfo_t)    GetProcAddress(GetModuleHandle(_T("user32.dll")), "GetMonitorInfoA");
  48. -    int monitorWidth;
  49. -    int monitorHeight;
  50. -
  51. -    if (GetMonitorInfoProc)
  52. +    if (wxDisplay::GetCount() > 0)
  53.      {
  54. -        hMonitor = MonitorFromWindowProc((HWND) referenceWindow->GetHandle(), MONITOR_DEFAULTTONEAREST);
  55. -
  56. -        mi.cbSize = sizeof(mi);
  57. -        GetMonitorInfoProc(hMonitor, &mi);
  58. -        r = mi.rcWork;
  59. -
  60. -        monitorWidth  = r.right - r.left;
  61. -        monitorHeight = r.bottom - r. top;
  62. +        int displayIdx = wxDisplay::GetFromWindow(referenceWindow);
  63. +        if (displayIdx == wxNOT_FOUND)
  64. +            displayIdx = 0;
  65. +        wxDisplay display(displayIdx);
  66. +        monitorRect = display.GetClientArea();
  67. +        // This is needed because on Linux the client area returned for the first monitor in a twin
  68. +        // monitor setup with nVidia card is spanning the two monitors.
  69. +        // The intersection function will return just the client for the specified monitor.
  70. +        monitorRect = display.GetGeometry().Intersect(monitorRect);
  71.      }
  72. -    else // Win95, NT4: support only single monitor
  73. +    else
  74.      {
  75. -        wxDisplaySize(&monitorWidth, &monitorHeight);
  76. -        r.left = r.top = 0;
  77. +        int width, height;
  78. +        wxDisplaySize(&width, &height);
  79. +        monitorRect = wxRect(0, 0, width, height);
  80.      }
  81.  
  82. +    wxRect windowRect = w->GetRect();
  83.  
  84.      switch(the_mode)
  85.      {
  86.          case pdlCentre:
  87.          {
  88. -            windowRect.x = r.left + (monitorWidth  - windowRect.width)/2;
  89. -            windowRect.y = r.top  + (monitorHeight - windowRect.height)/2;
  90. +            windowRect.x = monitorRect.x + (monitorRect.width  - windowRect.width)/2;
  91. +            windowRect.y = monitorRect.y  + (monitorRect.height - windowRect.height)/2;
  92.          }
  93.          break;
  94.  
  95.  
  96.          case pdlHead:
  97.          {
  98. -            windowRect.x = r.left + (monitorWidth  - windowRect.width)/2;
  99. -            windowRect.y = r.top  + (monitorHeight - windowRect.height)/3;
  100. +            windowRect.x = monitorRect.x + (monitorRect.width  - windowRect.width)/2;
  101. +            windowRect.y = monitorRect.y  + (monitorRect.height - windowRect.height)/3;
  102.          }
  103.          break;
  104.  
  105. @@ -1145,26 +1134,26 @@ void PlaceWindow(wxTopLevelWindow *w, cbPlaceDialogMode mode, bool enforce)
  106.              int y1 = windowRect.y;
  107.              int y2 = windowRect.y + windowRect.height;
  108.  
  109. -            if (windowRect.width > monitorWidth) // cannot place without clipping, so centre it
  110. +            if (windowRect.width > monitorRect.width) // cannot place without clipping, so centre it
  111.              {
  112. -                x1 = r.left + (monitorWidth  - windowRect.width)/2;
  113. +                x1 = monitorRect.x + (monitorRect.width  - windowRect.width)/2;
  114.                  x2 = x1 + windowRect.width;
  115.              }
  116.              else
  117.              {
  118. -                x2 = std::min((int) r.right, windowRect.GetRight());
  119. -                x1 = std::max(x2 - windowRect.width, (int) r.left);
  120. +                x2 = std::min(monitorRect.GetRight(), windowRect.GetRight());
  121. +                x1 = std::max(x2 - windowRect.width, monitorRect.x);
  122.                  x2 = x1 + windowRect.width;
  123.              }
  124. -            if (windowRect.height > monitorHeight) // cannot place without clipping, so centre it
  125. +            if (windowRect.height > monitorRect.height) // cannot place without clipping, so centre it
  126.              {
  127. -                y1 = r.top + (monitorHeight  - windowRect.height)/2;
  128. +                y1 = monitorRect.y + (monitorRect.height  - windowRect.height)/2;
  129.                  y2 = y1 + windowRect.height;
  130.              }
  131.              else
  132.              {
  133. -                y2 = std::min((int) r.bottom, windowRect.GetBottom());
  134. -                y1 = std::max(y2 - windowRect.height, (int) r.top);
  135. +                y2 = std::min(monitorRect.GetBottom(), windowRect.GetBottom());
  136. +                y1 = std::max(y2 - windowRect.height, monitorRect.y);
  137.                  y2 = y1 + windowRect.height;
  138.              }
  139.              windowRect = wxRect(x1, y1, x2-x1, y2-y1);
  140. @@ -1179,10 +1168,10 @@ void PlaceWindow(wxTopLevelWindow *w, cbPlaceDialogMode mode, bool enforce)
  141.              int y1 = windowRect.y;
  142.              int y2 = windowRect.y + windowRect.height;
  143.  
  144. -            x1 = std::max(x1, (int) r.left);
  145. -            x2 = std::min(x2, (int) r.right);
  146. -            y1 = std::max(y1, (int) r.top);
  147. -            y2 = std::min(y2, (int) r.bottom);
  148. +            x1 = std::max(x1, monitorRect.x);
  149. +            x2 = std::min(x2, monitorRect.GetRight());
  150. +            y1 = std::max(y1, monitorRect.y);
  151. +            y2 = std::min(y2, monitorRect.GetBottom());
  152.  
  153.              windowRect = wxRect(x1, y1, x2-x1, y2-y1);
  154.          }
  155. @@ -1192,61 +1181,6 @@ void PlaceWindow(wxTopLevelWindow *w, cbPlaceDialogMode mode, bool enforce)
  156.      w->SetSize(windowRect.x,  windowRect.y, windowRect.width, windowRect.height, wxSIZE_ALLOW_MINUS_ONE);
  157.  }
  158.  
  159. -
  160. -#else // ----- non-Windows ----------------------------------------------
  161. -
  162. -
  163. -void PlaceWindow(wxTopLevelWindow *w, cbPlaceDialogMode mode, bool enforce)
  164. -// TODO (thomas#1#): The non-Windows implementation is *pathetic*.
  165. -// However, I don't know how to do it well under GTK / X / Xinerama / whatever.
  166. -// Anyone?
  167. -{
  168. -    int the_mode;
  169. -
  170. -    wxWindow* referenceWindow = Manager::Get()->GetAppWindow();
  171. -    if (!referenceWindow) // let's not crash on shutdown
  172. -        return;
  173. -
  174. -    if (!w)
  175. -        cbThrow(_T("Passed NULL pointer to PlaceWindow."));
  176. -
  177. -
  178. -    ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("app"));
  179. -    if (!enforce && cfg->ReadBool(_T("/dialog_placement/do_place")) == false)
  180. -        return;
  181. -
  182. -    if (mode == pdlBest)
  183. -        the_mode = cfg->ReadInt(_T("/dialog_placement/dialog_position"), (int) pdlCentre);
  184. -    else
  185. -        the_mode = (int) mode;
  186. -
  187. -
  188. -    if (the_mode == pdlCentre || the_mode == pdlHead)
  189. -    {
  190. -        w->CentreOnScreen();
  191. -        return;
  192. -    }
  193. -    else
  194. -    {
  195. -        wxRect windowRect = w->GetRect();
  196. -        wxRect parentRect = referenceWindow->GetRect();   // poo again!
  197. -
  198. -        int x1 = windowRect.x;
  199. -        int x2 = windowRect.x + windowRect.width;
  200. -        int y1 = windowRect.y;
  201. -        int y2 = windowRect.y + windowRect.height;
  202. -
  203. -        x1 = std::max(x1, parentRect.x);
  204. -        x2 = std::min(x2, parentRect.GetRight());
  205. -        y1 = std::max(y1, parentRect.y);
  206. -        y2 = std::min(y2, parentRect.GetBottom());
  207. -
  208. -        w->SetSize(x1, y1, x2-x1, y2-y1, wxSIZE_ALLOW_MINUS_ONE);
  209. -    }
  210. -}
  211. -
  212. -#endif //platform-specific placement code
  213. -
  214.  DirAccessCheck cbDirAccessCheck(const wxString& dir)
  215.  {
  216.      wxString actualDir = dir;
  217.  

If there are no complaints I'll commit in some time, week or two.
« Last Edit: August 04, 2015, 10:31:07 pm by oBFusCATed »
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]

Offline oBFusCATed

  • Developer
  • Lives here!
  • *****
  • Posts: 12125
    • Travis build status
Re: Better PlaceWindow implementation on Linux
« Reply #1 on: August 15, 2015, 05:02:04 pm »
In svn.
(most of the time I ignore long posts)
[strangers don't send me private messages, I'll ignore them; post a topic in the forum, but first read the rules!]