From a3197b8ad09c92c2af463d1a30ecf15c3ed98ed2 Mon Sep 17 00:00:00 2001
From: Ken Thomases <ken@codeweavers.com>
Date: Wed, 18 Sep 2013 13:00:37 -0500
Subject: [PATCH] winemac: At the start of a resize operation, get window
 min/max size info and pass it to Cocoa.

---
 dlls/winemac.drv/cocoa_window.h |   3 +
 dlls/winemac.drv/cocoa_window.m |  52 +++++++++---
 dlls/winemac.drv/event.c        |   4 +
 dlls/winemac.drv/macdrv.h       |   1 +
 dlls/winemac.drv/macdrv_cocoa.h |   2 +
 dlls/winemac.drv/window.c       | 136 ++++++++++++++++++++++++++++++++
 6 files changed, 188 insertions(+), 10 deletions(-)

diff --git a/dlls/winemac.drv/cocoa_window.h b/dlls/winemac.drv/cocoa_window.h
index 5cf47b434d5..86728125233 100644
--- a/dlls/winemac.drv/cocoa_window.h
+++ b/dlls/winemac.drv/cocoa_window.h
@@ -55,6 +55,9 @@ @interface WineWindow : NSPanel <NSWindowDelegate>
     void* imeData;
     BOOL commandDone;
 
+    NSSize savedContentMinSize;
+    NSSize savedContentMaxSize;
+
     BOOL causing_becomeKeyWindow;
     BOOL ignore_windowMiniaturize;
     BOOL ignore_windowDeminiaturize;
diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m
index 2ad406f608a..e8ac79c1c9b 100644
--- a/dlls/winemac.drv/cocoa_window.m
+++ b/dlls/winemac.drv/cocoa_window.m
@@ -500,6 +500,8 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w
         [window setDelegate:window];
         window.hwnd = hwnd;
         window.queue = queue;
+        window->savedContentMinSize = NSZeroSize;
+        window->savedContentMaxSize = NSMakeSize(FLT_MAX, FLT_MAX);
 
         [window registerForDraggedTypes:[NSArray arrayWithObjects:(NSString*)kUTTypeData,
                                                                   (NSString*)kUTTypeContent,
@@ -1131,14 +1133,14 @@ - (void) setDisabled:(BOOL)newValue
 
             if (disabled)
             {
-                NSSize size = [self frame].size;
-                [self setMinSize:size];
-                [self setMaxSize:size];
+                NSSize size = [self contentRectForFrameRect:[self frame]].size;
+                [self setContentMinSize:size];
+                [self setContentMaxSize:size];
             }
             else
             {
-                [self setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
-                [self setMinSize:NSZeroSize];
+                [self setContentMaxSize:savedContentMaxSize];
+                [self setContentMinSize:savedContentMinSize];
             }
         }
     }
@@ -1231,6 +1233,17 @@ - (void) postKeyEvent:(NSEvent *)theEvent
                 event:theEvent];
     }
 
+    - (void) setWineMinSize:(NSSize)minSize maxSize:(NSSize)maxSize
+    {
+        savedContentMinSize = minSize;
+        savedContentMaxSize = maxSize;
+        if (!self.disabled)
+        {
+            [self setContentMinSize:minSize];
+            [self setContentMaxSize:maxSize];
+        }
+    }
+
 
     /*
      * ---------- NSWindow method overrides ----------
@@ -1480,16 +1493,14 @@ - (void)windowDidResignKey:(NSNotification *)notification
     - (void)windowDidResize:(NSNotification *)notification
     {
         macdrv_event* event;
-        NSRect frame = [self frame];
+        NSRect frame = [self contentRectForFrameRect:[self frame]];
 
         if (self.disabled)
         {
-            NSSize size = frame.size;
-            [self setMinSize:size];
-            [self setMaxSize:size];
+            [self setContentMinSize:frame.size];
+            [self setContentMaxSize:frame.size];
         }
 
-        frame = [self contentRectForFrameRect:frame];
         [[WineApplicationController sharedController] flipRect:&frame];
 
         /* Coalesce events by discarding any previous ones still in the queue. */
@@ -1554,6 +1565,13 @@ - (void)windowWillMiniaturize:(NSNotification *)notification
 
     - (void) windowWillStartLiveResize:(NSNotification *)notification
     {
+        macdrv_query* query = macdrv_create_query();
+        query->type = QUERY_RESIZE_START;
+        query->window = (macdrv_window)[self retain];
+
+        [self.queue query:query timeout:0.3];
+        macdrv_release_query(query);
+
         // There's a strange restriction in window redrawing during Cocoa-
         // managed window resizing.  Only calls to -[NSView setNeedsDisplay...]
         // that happen synchronously when Cocoa tells us that our window size
@@ -2010,6 +2028,20 @@ void macdrv_give_cocoa_window_focus(macdrv_window w, int activate)
     });
 }
 
+/***********************************************************************
+ *              macdrv_set_window_min_max_sizes
+ *
+ * Sets the window's minimum and maximum content sizes.
+ */
+void macdrv_set_window_min_max_sizes(macdrv_window w, CGSize min_size, CGSize max_size)
+{
+    WineWindow* window = (WineWindow*)w;
+
+    OnMainThread(^{
+        [window setWineMinSize:NSSizeFromCGSize(min_size) maxSize:NSSizeFromCGSize(max_size)];
+    });
+}
+
 /***********************************************************************
  *              macdrv_create_view
  *
diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c
index 8a8acf36b53..97f1e3b38a8 100644
--- a/dlls/winemac.drv/event.c
+++ b/dlls/winemac.drv/event.c
@@ -146,6 +146,10 @@ static void macdrv_query_event(HWND hwnd, const macdrv_event *event)
             TRACE("QUERY_PASTEBOARD_DATA\n");
             success = query_pasteboard_data(hwnd, query->pasteboard_data.type);
             break;
+        case QUERY_RESIZE_START:
+            TRACE("QUERY_RESIZE_START\n");
+            success = query_resize_start(hwnd);
+            break;
         default:
             FIXME("unrecognized query type %d\n", query->type);
             break;
diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h
index 0e7d364be71..d308e690f49 100644
--- a/dlls/winemac.drv/macdrv.h
+++ b/dlls/winemac.drv/macdrv.h
@@ -161,6 +161,7 @@ static inline RECT rect_from_cgrect(CGRect cgrect)
 extern void macdrv_app_quit_requested(const macdrv_event *event) DECLSPEC_HIDDEN;
 extern void macdrv_window_did_minimize(HWND hwnd) DECLSPEC_HIDDEN;
 extern void macdrv_window_did_unminimize(HWND hwnd) DECLSPEC_HIDDEN;
+extern BOOL query_resize_start(HWND hwnd) DECLSPEC_HIDDEN;
 
 extern void macdrv_mouse_button(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDDEN;
 extern void macdrv_mouse_moved(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDDEN;
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h
index 1f68b615244..71d8c9f1513 100644
--- a/dlls/winemac.drv/macdrv_cocoa.h
+++ b/dlls/winemac.drv/macdrv_cocoa.h
@@ -272,6 +272,7 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display,
     QUERY_DRAG_OPERATION,
     QUERY_IME_CHAR_RECT,
     QUERY_PASTEBOARD_DATA,
+    QUERY_RESIZE_START,
     NUM_QUERY_TYPES
 };
 
@@ -373,6 +374,7 @@ extern void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat
 extern void macdrv_clear_window_color_key(macdrv_window w) DECLSPEC_HIDDEN;
 extern void macdrv_window_use_per_pixel_alpha(macdrv_window w, int use_per_pixel_alpha) DECLSPEC_HIDDEN;
 extern void macdrv_give_cocoa_window_focus(macdrv_window w, int activate) DECLSPEC_HIDDEN;
+extern void macdrv_set_window_min_max_sizes(macdrv_window w, CGSize min_size, CGSize max_size) DECLSPEC_HIDDEN;
 extern macdrv_view macdrv_create_view(macdrv_window w, CGRect rect) DECLSPEC_HIDDEN;
 extern void macdrv_dispose_view(macdrv_view v) DECLSPEC_HIDDEN;
 extern void macdrv_set_view_window_and_frame(macdrv_view v, macdrv_window w, CGRect rect) DECLSPEC_HIDDEN;
diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c
index 59912909ddb..411270c4838 100644
--- a/dlls/winemac.drv/window.c
+++ b/dlls/winemac.drv/window.c
@@ -464,6 +464,129 @@ static void sync_window_opacity(struct macdrv_win_data *data, COLORREF key, BYTE
 }
 
 
+/***********************************************************************
+ *              sync_window_min_max_info
+ */
+static void sync_window_min_max_info(HWND hwnd)
+{
+    LONG style = GetWindowLongW(hwnd, GWL_STYLE);
+    LONG exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
+    RECT win_rect, primary_monitor_rect;
+    MINMAXINFO minmax;
+    LONG adjustedStyle;
+    INT xinc, yinc;
+    WINDOWPLACEMENT wpl;
+    HMONITOR monitor;
+    struct macdrv_win_data *data;
+    RECT min_rect, max_rect;
+    CGSize min_size, max_size;
+
+    TRACE("win %p\n", hwnd);
+
+    if (!macdrv_get_cocoa_window(hwnd, FALSE)) return;
+
+    GetWindowRect(hwnd, &win_rect);
+    minmax.ptReserved.x = win_rect.left;
+    minmax.ptReserved.y = win_rect.top;
+
+    if ((style & WS_CAPTION) == WS_CAPTION)
+        adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
+    else
+        adjustedStyle = style;
+
+    primary_monitor_rect.left = primary_monitor_rect.top = 0;
+    primary_monitor_rect.right = GetSystemMetrics(SM_CXSCREEN);
+    primary_monitor_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
+    AdjustWindowRectEx(&primary_monitor_rect, adjustedStyle, ((style & WS_POPUP) && GetMenu(hwnd)), exstyle);
+
+    xinc = -primary_monitor_rect.left;
+    yinc = -primary_monitor_rect.top;
+
+    minmax.ptMaxSize.x = primary_monitor_rect.right - primary_monitor_rect.left;
+    minmax.ptMaxSize.y = primary_monitor_rect.bottom - primary_monitor_rect.top;
+    minmax.ptMaxPosition.x = -xinc;
+    minmax.ptMaxPosition.y = -yinc;
+    if (style & (WS_DLGFRAME | WS_BORDER))
+    {
+        minmax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
+        minmax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
+    }
+    else
+    {
+        minmax.ptMinTrackSize.x = 2 * xinc;
+        minmax.ptMinTrackSize.y = 2 * yinc;
+    }
+    minmax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXMAXTRACK);
+    minmax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYMAXTRACK);
+
+    wpl.length = sizeof(wpl);
+    if (GetWindowPlacement(hwnd, &wpl) && (wpl.ptMaxPosition.x != -1 || wpl.ptMaxPosition.y != -1))
+    {
+        minmax.ptMaxPosition = wpl.ptMaxPosition;
+
+        /* Convert from GetWindowPlacement's workspace coordinates to screen coordinates. */
+        minmax.ptMaxPosition.x -= wpl.rcNormalPosition.left - win_rect.left;
+        minmax.ptMaxPosition.y -= wpl.rcNormalPosition.top - win_rect.top;
+    }
+
+    TRACE("initial ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
+          wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
+
+    SendMessageW(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&minmax);
+
+    TRACE("app's ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
+          wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
+
+    /* if the app didn't change the values, adapt them for the window's monitor */
+    if ((monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)))
+    {
+        MONITORINFO mon_info;
+        RECT monitor_rect;
+
+        mon_info.cbSize = sizeof(mon_info);
+        GetMonitorInfoW(monitor, &mon_info);
+
+        if ((style & WS_MAXIMIZEBOX) && ((style & WS_CAPTION) == WS_CAPTION || !(style & WS_POPUP)))
+            monitor_rect = mon_info.rcWork;
+        else
+            monitor_rect = mon_info.rcMonitor;
+
+        if (minmax.ptMaxSize.x == primary_monitor_rect.right - primary_monitor_rect.left &&
+            minmax.ptMaxSize.y == primary_monitor_rect.bottom - primary_monitor_rect.top)
+        {
+            minmax.ptMaxSize.x = (monitor_rect.right - monitor_rect.left) + 2 * xinc;
+            minmax.ptMaxSize.y = (monitor_rect.bottom - monitor_rect.top) + 2 * yinc;
+        }
+        if (minmax.ptMaxPosition.x == -xinc && minmax.ptMaxPosition.y == -yinc)
+        {
+            minmax.ptMaxPosition.x = monitor_rect.left - xinc;
+            minmax.ptMaxPosition.y = monitor_rect.top - yinc;
+        }
+    }
+
+    minmax.ptMaxTrackSize.x = max(minmax.ptMaxTrackSize.x, minmax.ptMinTrackSize.x);
+    minmax.ptMaxTrackSize.y = max(minmax.ptMaxTrackSize.y, minmax.ptMinTrackSize.y);
+
+    TRACE("adjusted ptMaxSize %s ptMaxPosition %s ptMinTrackSize %s ptMaxTrackSize %s\n", wine_dbgstr_point(&minmax.ptMaxSize),
+          wine_dbgstr_point(&minmax.ptMaxPosition), wine_dbgstr_point(&minmax.ptMinTrackSize), wine_dbgstr_point(&minmax.ptMaxTrackSize));
+
+    if ((data = get_win_data(hwnd)) && data->cocoa_window)
+    {
+        SetRect(&min_rect, 0, 0, minmax.ptMinTrackSize.x, minmax.ptMinTrackSize.y);
+        SetRect(&max_rect, 0, 0, minmax.ptMaxTrackSize.x, minmax.ptMaxTrackSize.y);
+        macdrv_window_to_mac_rect(data, style, &min_rect);
+        macdrv_window_to_mac_rect(data, style, &max_rect);
+        min_size = CGSizeMake(min_rect.right - min_rect.left, min_rect.bottom - min_rect.top);
+        max_size = CGSizeMake(max_rect.right - max_rect.left, max_rect.bottom - max_rect.top);
+
+        TRACE("min_size (%g,%g) max_size (%g,%g)\n", min_size.width, min_size.height, max_size.width, max_size.height);
+        macdrv_set_window_min_max_sizes(data->cocoa_window, min_size, max_size);
+    }
+
+    release_win_data(data);
+}
+
+
 /**********************************************************************
  *              create_cocoa_window
  *
@@ -1858,3 +1981,16 @@ fail:
     }
     macdrv_quit_reply(FALSE);
 }
+
+
+/***********************************************************************
+ *              query_resize_start
+ *
+ * Handler for QUERY_RESIZE_START query.
+ */
+BOOL query_resize_start(HWND hwnd)
+{
+    TRACE("hwnd %p\n", hwnd);
+    sync_window_min_max_info(hwnd);
+    return TRUE;
+}