Skip to content

Commit

Permalink
Implementation of GC to enable multi zoom level support for win32 whi…
Browse files Browse the repository at this point in the history
…ch can be

extended by other resources and widgets.

Contributes to
#62 and #131
  • Loading branch information
amartya4256 committed May 17, 2024
1 parent 600418a commit 67e2821
Show file tree
Hide file tree
Showing 13 changed files with 263 additions and 120 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public final class GCData {
public float[] lineDashes;
public float lineMiterLimit = 10;
public int alpha = 0xFF;
public int nativeDeviceZoom;

public Image image;
public PAINTSTRUCT ps;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,7 @@ public long internal_new_GC (GCData data) {
data.style |= SWT.LEFT_TO_RIGHT;
}
data.device = device;
data.nativeDeviceZoom = currentNativeZoom;
data.image = this;
data.font = Font.win32_new(device.getSystemFont(), DPIUtil.getNativeDeviceZoom());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1375,7 +1375,7 @@ LRESULT wmNotifyChild (NMHDR hdr, long wParam, long lParam) {
if (image != null) {
GCData data = new GCData();
data.device = display;
GC gc = GC.win32_new (nmcd.hdc, data);
GC gc = getNewGC(nmcd.hdc, data);

int margin = computeLeftMargin();
Rectangle imageBounds = DPIUtil.autoScaleBounds(image.getBounds(), this.getZoom(), 100);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1533,7 +1533,7 @@ LRESULT WM_PAINT (long wParam, long lParam) {
OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
drawBackground (phdc [0], rect);
}
GC gc = GC.win32_new (phdc [0], data);
GC gc = getNewGC(phdc [0], data);
Event event = new Event ();
event.gc = gc;
event.setBoundsInPixels(new Rectangle(ps.left, ps.top, width, height));
Expand Down Expand Up @@ -1697,7 +1697,7 @@ LRESULT WM_PRINTCLIENT (long wParam, long lParam) {
data.background = control.getBackgroundPixel ();
data.font = Font.win32_new(display, OS.SendMessage (handle, OS.WM_GETFONT, 0, 0));
data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
GC gc = GC.win32_new (wParam, data);
GC gc = getNewGC(wParam, data);
Event event = new Event ();
event.gc = gc;
event.setBoundsInPixels(new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,7 @@ public long internal_new_GC (GCData data) {
}
}
data.device = display;
data.nativeDeviceZoom = getNativeZoom();
int foreground = getForegroundPixel ();
if (foreground != OS.GetTextColor (hDC)) data.foreground = foreground;
Control control = findBackgroundControl ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ LRESULT WM_PRINTCLIENT (long wParam, long lParam) {
GCData data = new GCData ();
data.device = display;
data.foreground = getForegroundPixel ();
GC gc = GC.win32_new (wParam, data);
GC gc = getNewGC(wParam, data);
drawWidget (gc, rect);
gc.dispose ();
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -563,8 +563,9 @@ void wmDrawChildImage(DRAWITEMSTRUCT struct) {
}

GCData data = new GCData();
data.nativeDeviceZoom = getNativeZoom();
data.device = display;
GC gc = GC.win32_new (struct.hDC, data);
GC gc = getNewGC(struct.hDC, data);
Image image = getEnabled () ? this.image : new Image (display, this.image, SWT.IMAGE_DISABLE);
gc.drawImage (image, DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(Math.max (0, (height - imageRect.height) / 2)));
if (image != this.image) image.dispose ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,7 @@ LRESULT wmDrawChild (long wParam, long lParam) {
if (image != null) {
GCData data = new GCData();
data.device = display;
GC gc = GC.win32_new (struct.hDC, data);
GC gc = getNewGC(struct.hDC, data);
/*
* Bug in Windows. When a bitmap is included in the
* menu bar, the HDC seems to already include the left
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3464,7 +3464,7 @@ void sendEraseItemEvent (TableItem item, NMLVCUSTOMDRAW nmcd, long lParam, Event
data.font = item.getFont (nmcd.iSubItem);
data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
int nSavedDC = OS.SaveDC (hDC);
GC gc = GC.win32_new (hDC, data);
GC gc = getNewGC(hDC, data);
RECT cellRect = item.getBounds ((int)nmcd.dwItemSpec, nmcd.iSubItem, true, true, true, true, hDC);
Event event = new Event ();
event.item = item;
Expand Down Expand Up @@ -3599,7 +3599,7 @@ Event sendEraseItemEvent (TableItem item, NMTTCUSTOMDRAW nmcd, int column, RECT
data.background = OS.GetBkColor (nmcd.hdc);
data.font = item.getFont (column);
data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
GC gc = GC.win32_new (nmcd.hdc, data);
GC gc = getNewGC(nmcd.hdc, data);
Event event = new Event ();
event.item = item;
event.index = column;
Expand All @@ -3620,7 +3620,7 @@ Event sendMeasureItemEvent (TableItem item, int row, int column, long hDC) {
data.device = display;
data.font = item.getFont (column);
int nSavedDC = OS.SaveDC (hDC);
GC gc = GC.win32_new (hDC, data);
GC gc = getNewGC(hDC, data);
RECT itemRect = item.getBounds (row, column, true, true, false, false, hDC);
Event event = new Event ();
event.item = item;
Expand Down Expand Up @@ -3907,7 +3907,7 @@ void sendPaintItemEvent (TableItem item, NMLVCUSTOMDRAW nmcd) {
}
data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
int nSavedDC = OS.SaveDC (hDC);
GC gc = GC.win32_new (hDC, data);
GC gc = getNewGC(hDC, data);
RECT itemRect = item.getBounds ((int)nmcd.dwItemSpec, nmcd.iSubItem, true, true, false, false, hDC);
Event event = new Event ();
event.item = item;
Expand Down Expand Up @@ -3948,7 +3948,7 @@ Event sendPaintItemEvent (TableItem item, NMTTCUSTOMDRAW nmcd, int column, RECT
data.foreground = OS.GetTextColor (nmcd.hdc);
data.background = OS.GetBkColor (nmcd.hdc);
data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
GC gc = GC.win32_new (nmcd.hdc, data);
GC gc = getNewGC(nmcd.hdc, data);
Event event = new Event ();
event.item = item;
event.index = column;
Expand Down Expand Up @@ -6964,7 +6964,7 @@ LRESULT wmNotifyHeader (NMHDR hdr, long wParam, long lParam) {
if (columns[i].image != null) {
GCData data = new GCData();
data.device = display;
GC gc = GC.win32_new (nmcd.hdc, data);
GC gc = getNewGC(nmcd.hdc, data);
int y = Math.max (0, (nmcd.bottom - columns[i].image.getBoundsInPixels().height) / 2);
gc.drawImage (columns[i].image, DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(y));
x += columns[i].image.getBoundsInPixels().width + 12;
Expand Down Expand Up @@ -7286,7 +7286,7 @@ LRESULT wmNotifyToolTip (NMTTCUSTOMDRAW nmcd, long lParam) {
data.foreground = OS.GetTextColor (nmcd.hdc);
data.background = OS.GetBkColor (nmcd.hdc);
data.font = Font.win32_new (display, hFont);
GC gc = GC.win32_new (nmcd.hdc, data);
GC gc = getNewGC(nmcd.hdc, data);
int x = cellRect.left;
if (pinfo.iSubItem != 0) x -= gridWidth;
Image image = item.getImage (pinfo.iSubItem);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ LRESULT CDDS_ITEMPOSTPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
if (!ignoreDrawForeground) {
GCData data = new GCData();
data.device = display;
GC gc = GC.win32_new (hDC, data);
GC gc = getNewGC(hDC, data);
RECT iconRect = item.getBounds (index, false, true, false, false, true, hDC); // Pixels
gc.setClipping (DPIUtil.autoScaleDown(new Rectangle(iconRect.left, iconRect.top, iconRect.right - iconRect.left, iconRect.bottom - iconRect.top)));
gc.drawImage (image, 0, 0, bounds.width, bounds.height, DPIUtil.autoScaleDown(iconRect.left), DPIUtil.autoScaleDown(iconRect.top), size.x, size.y);
Expand Down Expand Up @@ -625,7 +625,7 @@ LRESULT CDDS_ITEMPOSTPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
}
data.font = item.getFont (index);
data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
GC gc = GC.win32_new (hDC, data);
GC gc = getNewGC(hDC, data);
Event event = new Event ();
event.item = item;
event.index = index;
Expand Down Expand Up @@ -768,7 +768,7 @@ LRESULT CDDS_ITEMPOSTPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
int x1 = Math.max (rect.left, rect.left - inset + 1);
GCData data = new GCData();
data.device = display;
GC gc = GC.win32_new (hDC, data);
GC gc = getNewGC(hDC, data);
gc.setClipping (DPIUtil.autoScaleDown(new Rectangle(x1, rect.top, rect.right - x1, rect.bottom - rect.top)));
gc.drawImage (image, 0, 0, bounds.width, bounds.height, DPIUtil.autoScaleDown(x1), DPIUtil.autoScaleDown(y1), size.x, size.y);
OS.SelectClipRgn (hDC, 0);
Expand Down Expand Up @@ -841,7 +841,7 @@ LRESULT CDDS_ITEMPOSTPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
if (clrTextBk != -1) data.background = clrTextBk;
}
data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
GC gc = GC.win32_new (hDC, data);
GC gc = getNewGC(hDC, data);
Event event = new Event ();
event.item = item;
event.index = index;
Expand Down Expand Up @@ -1063,7 +1063,7 @@ LRESULT CDDS_ITEMPREPAINT (NMTVCUSTOMDRAW nmcd, long wParam, long lParam) {
}
data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
data.font = item.getFont (index);
GC gc = GC.win32_new (hDC, data);
GC gc = getNewGC(hDC, data);
Event event = new Event ();
event.index = index;
event.item = item;
Expand Down Expand Up @@ -4523,7 +4523,7 @@ Event sendEraseItemEvent (TreeItem item, NMTTCUSTOMDRAW nmcd, int column, RECT c
data.background = OS.GetBkColor (nmcd.hdc);
data.font = item.getFont (column);
data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
GC gc = GC.win32_new (nmcd.hdc, data);
GC gc = getNewGC(nmcd.hdc, data);
Event event = new Event ();
event.item = item;
event.index = column;
Expand All @@ -4545,7 +4545,7 @@ Event sendMeasureItemEvent (TreeItem item, int index, long hDC, int detail) {
GCData data = new GCData ();
data.device = display;
data.font = item.getFont (index);
GC gc = GC.win32_new (hDC, data);
GC gc = getNewGC(hDC, data);
Event event = new Event ();
event.item = item;
event.gc = gc;
Expand Down Expand Up @@ -4579,7 +4579,7 @@ Event sendPaintItemEvent (TreeItem item, NMTTCUSTOMDRAW nmcd, int column, RECT i
data.foreground = OS.GetTextColor (nmcd.hdc);
data.background = OS.GetBkColor (nmcd.hdc);
data.uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
GC gc = GC.win32_new (nmcd.hdc, data);
GC gc = getNewGC(nmcd.hdc, data);
Event event = new Event ();
event.item = item;
event.index = column;
Expand Down Expand Up @@ -7925,7 +7925,7 @@ LRESULT wmNotifyHeader (NMHDR hdr, long wParam, long lParam) {
if (columns[i].image != null) {
GCData data = new GCData();
data.device = display;
GC gc = GC.win32_new (nmcd.hdc, data);
GC gc = getNewGC(nmcd.hdc, data);
Rectangle imageBounds = DPIUtil.autoScaleBounds(columns[i].image.getBounds(), this.getZoom(), 100);
int y = Math.max (0, (nmcd.bottom - imageBounds.height) / 2);
gc.drawImage (columns[i].image, DPIUtil.autoScaleDown(x), DPIUtil.autoScaleDown(y));
Expand Down Expand Up @@ -8214,7 +8214,7 @@ LRESULT wmNotifyToolTip (NMTTCUSTOMDRAW nmcd, long lParam) {
data.foreground = OS.GetTextColor (nmcd.hdc);
data.background = OS.GetBkColor (nmcd.hdc);
data.font = Font.win32_new (display, hFont);
GC gc = GC.win32_new (nmcd.hdc, data);
GC gc = getNewGC(nmcd.hdc, data);
int x = cellRect [0].left + INSET;
if (index [0] != 0) x -= gridWidth;
Image image = item [0].getImage (index [0]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2635,6 +2635,11 @@ void notifyDisposalTracker() {
}
}

GC getNewGC(long hDC, GCData data) {
data.nativeDeviceZoom = getNativeZoom();
return GC.win32_new(hDC, data);
}


/**
* The current native zoom level of the monitor, the widget is scaled with respect to
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*******************************************************************************
* Copyright (c) 2024 Yatta Solutions
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Yatta Solutions - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.graphics;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.lang.reflect.Field;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;

import org.eclipse.swt.SWT;
import org.eclipse.swt.internal.DPIUtil;
import org.eclipse.swt.internal.SWTFontProvider;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class GCWin32Tests {
private Display display;

@Before
public void setUp() {
changeAutoScaleOnRuntime(true);
display = Display.getDefault();
}

@After
public void tearDown() {
changeAutoScaleOnRuntime(false);
}

@Test
public void gcZoomLevelMustChangeOnShellZoomChange() {
CompletableFuture<Integer> gcNativeZoom = new CompletableFuture<>();
CompletableFuture<Integer> scaledGcNativeZoom = new CompletableFuture<>();
int zoom = DPIUtil.getDeviceZoom();
AtomicBoolean isScaled = new AtomicBoolean(false);
Shell shell = new Shell(display);
shell.addListener(SWT.Paint, event -> {
if (isScaled.get()) {
scaledGcNativeZoom.complete(event.gc.getGCData().nativeDeviceZoom);
} else {
gcNativeZoom.complete(event.gc.getGCData().nativeDeviceZoom);
}
});

shell.open();
assertEquals("GCData must have a zoom level equal to the actual zoom level of the widget/shell", DPIUtil.getNativeDeviceZoom(), (int) gcNativeZoom.join());

int newSWTZoom = zoom * 2;
Event swtEvent = new Event();
swtEvent.type = SWT.ZoomChanged;
swtEvent.widget = shell;
swtEvent.detail = newSWTZoom;
shell.notifyListeners(SWT.ZoomChanged, swtEvent);
isScaled.set(true);
shell.setVisible(false);
shell.setVisible(true);

assertEquals("GCData must have a zoom level equal to the actual zoom level of the widget/shell on zoomChanged event", newSWTZoom, (int) scaledGcNativeZoom.join());
}

@Test
public void drawnElementsShouldScaleUpToTheRightZoomLevel() {
int zoom = DPIUtil.getDeviceZoom();
int scalingFactor = 2;
Shell shell = new Shell(display);
GC gc = GC.win32_new(shell, new GCData());
gc.getGCData().nativeDeviceZoom = zoom * scalingFactor;
gc.getGCData().lineWidth = 10;
assertEquals("DPIUtil calls with getDeviceZoom should scale to the right value", gc.getGCData().lineWidth, gc.getLineWidth() * scalingFactor, 0);
}

void changeAutoScaleOnRuntime(boolean value) {
try {
Field autoScaleOnRuntimeField = DPIUtil.class.getDeclaredField("autoScaleOnRuntime");
autoScaleOnRuntimeField.setAccessible(true);
autoScaleOnRuntimeField.setBoolean(null, value);
autoScaleOnRuntimeField.setAccessible(false);
// dispose a probably existing font registry for the default display
SWTFontProvider.disposeFontRegistry(display);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
fail("Value for DPI::autoScaleOnRuntime could not be changed");
}
}
}

0 comments on commit 67e2821

Please sign in to comment.