[M3devel] pixmap problem (some success)

Jay jayk123 at hotmail.com
Fri Aug 8 03:35:10 CEST 2008


Computing the values is probably easy. It appears we already have the code to do that -- the program I had you run and report the numbers.

It is true there is a *small* problem of computing them early enough, but..yeah, I expect that's just done in the module initializer. I really don't like "global initialization" code ala C++ global constructors/destructors, but Modula-3 is rife with them and they aren't going away, so I'll just pile in a few more bits.

I don't know if is legal Modula-3 code, but if fields can be initialized from globals, that's about all it takes.

SOMETHING LIKE (don't castigate me where I am wrong)
In the platform-independent code, add two private globals:
DefaultXRes : INTEGER;
DefaultYRes : INTEGER;

heck, default them to 75, for the Posix case.

In the platform independent interface, functions to set them:
PROCEDURE SetDefaultXRes(a: INTEGER);
PROCEDURE SetDefaultYRes(a: INTEGER);

Nothing else on Posix, for now.

On Windows, add another module WinImage.m3 that imports Image and just has a module initializer:

BEGIN
  Image.SetDefaultXRes(ComputedSomehowNotDifficult());
  Image.SetDefaultYRes(ComputedSomehowNotDifficult());
END.

If fields cannot be initialized from globals (or function calls..heh, that has a niceness!), then you have to search out all the uses and change them to function calls, possibly a lot, possibly tedious, definitely a "breaking change", but probably just fine, really.

And then, if fields can be initialized from functions, that'd be better -- that way no module initializer.


Module initializers are "bad" in that they cause a startup cost for "everyone", even if they aren't needed for a particular scenario. It is "best" imho to have constant initialization as much as possible, and where values must be computed, use an explicit function call when needed. You can still cache the values upon first computation.


> would seem that most code must not be computing these, but relying on the default values to be correct.

Or that "most code" doesn't care what the values are, doesn't use them at all.
Like, maybe they are only used for pixmaps and not text or lines?

Anyway, I can't look into this now, but hopefully "soon".
If your customer is antsy, "the problem is mostly understood and a fix will definitely be available soon".
I think "patch Tuesday" is coming up. Let's make it by then? :)


Really, I can't believe they'd call for a rewrite over this small issue.
Presumably they really want the rewrite and are looking for any excuse they can find.
Also, if you removed the "advertising" from the splash screen, they might not have even noticed?
Or, I guess if this is Windows only, the odd look could not be noticed.
But if they also want it on X and you showed it there, and it looked the same on Windows, well...
(Really this is just a general dilemna -- app looks the same as app on all platforms, or app looks like the platform on all platforms.)


 - Jay

________________________________

Date: Thu, 7 Aug 2008 20:26:13 -0400
From: rcoleburn at scires.com
To: m3devel at elegosoft.com; jayk123 at hotmail.com; dabenavidesd at yahoo.es
Subject: RE: [M3devel] pixmap problem (some success)



Well, I hope to soon share your optimism for "easy".



Since these numbers wind up being default values for the xres/yres and since changing the defaults has made a big difference in the results, it would seem that most code must not be computing these, but relying on the default values to be correct.



Since these numbers may be different for every program run on a different monitor (potentially), the question becomes how to effect a change that will work in all cases without having to recompile vbtkit.



Does this mean we have to track down each use of Image.Raw and put in code to compute the dpi?  Or is there some way we can do this during an initialization sequence? but alas, how to deal with the defaults supplied in the declaration?



Regards,

Randy

>>> Jay  8/7/2008 8:16 PM>>>

Awesome. I expect it is easy from here. Thanks David!

I *assume* the 75 should have been 86 in the one case,
but close enough that nobody noticed.
So these numbers come pretty directly from the GetDeviceCaps / GetSystemMetrics.

And then X Windows too.
Does anyone have a high DPI monitor running X Windows?
Probably easy enough to do this blind.

I'm trying to ignore the fact that systems have multiple
monitors, with varying dpi. You are supposed to loop your
drawing over monitors and compute what it looks like per-monitor.
I'm just making that up, right? :)

- Jay

________________________________

Date: Thu, 7 Aug 2008 19:42:33 -0400
From: rcoleburn at scires.com
To: m3devel at elegosoft.com; jayk123 at hotmail.com; dabenavidesd at yahoo.es
Subject: Re: [M3devel] pixmap problem (some success)



Ok, I solved the Microsoft problem.



Here are the results on Dell M4300 at 1920x1200:



horizonal pixels 1920
veritical pixels SM_CYSCREEN 1200
horizontal millimeters 330
veritical millimeters 206
horizontal pixels per millimeter 5.818182
vertical pixels per millimeter 5.825243
horizontal pixels per inch 147.781818
vertical pixels per inch 147.961165

Wow!  these numbers are radically different than the IBM T60 at 1280x1024:



horizonal pixels 1280
veritical pixels SM_CYSCREEN 1024
horizontal millimeters 375
veritical millimeters 300
horizontal pixels per millimeter 3.413333
vertical pixels per millimeter 3.413333
horizontal pixels per inch 86.698667
vertical pixels per inch 86.698667

Now, if you look at the Windows dpi setting for the 1920x1200 machine, it says 96dpi, but this is in the General tab of the Display properties Advanced settings.  I suspect this is just the dpi setting applied to fonts.



I tried plugging the numbers into Image.i3 as suggested by Daniel:

TYPE
  Raw = OBJECT
      width, height: INTEGER;
      xres: REAL := 147.781818; (* in pixels per inch *)
      yres: REAL := 147.961165; (* in pixels per inch *)
    METHODS
      get (h, v: INTEGER): Pixel;
      set (h, v: INTEGER; pixel: Pixel);
    END;

When I do this, my pixmaps look correct on the 1920x1200 display!!!!!



Now, the problem I am faced with is how to come up with a way that the code will work on any type of monitor.  I can't edit Image.i3 for every resolution and produce a different binary.  Any ideas?



Regards,

Randy


>>> Jay  8/5/2008 9:01 AM>>>


Randy, I'm pretty clueless here.
I don't do gui or graphics.
If anyone has a clue, please stand up.
If you can get us code to run, please do.
But I think I need multiple particularly configured machines too.

I'm curious what this code prints on the systems:

#include
#include

int main()
{
int pix_ver = { 0 };
int pix_hor = { 0 };
int mm_hor = { 0 };
int mm_ver = { 0 };
HWND hwnd = { 0 };
HDC hdc = { 0 };

hwnd = GetDesktopWindow();
hdc = GetDC(hwnd);
mm_hor = GetDeviceCaps(hdc, HORZSIZE);
mm_ver = GetDeviceCaps(hdc, VERTSIZE);
pix_hor = GetSystemMetrics(SM_CXSCREEN);
pix_ver = GetSystemMetrics(SM_CYSCREEN);

printf("horizonal pixels %d\n", pix_hor);
printf("veritical pixels SM_CYSCREEN %d\n", pix_ver);
printf("horizontal millimeters %d\n", mm_hor);
printf("veritical millimeters %d\n", mm_ver);

printf("horizontal pixels per millimeter %f\n", (((float) pix_hor) / ((float) mm_hor)));
printf("vertical pixels per millimeter %f\n", (((float) pix_ver) / ((float) mm_ver)));

printf("horizontal pixels per inch %f\n", (((float) pix_hor) / ((float) mm_hor) * 10.0 * 2.54));
printf("vertical pixels per inch %f\n", (((float) pix_ver) / ((float) mm_ver) * 10.0 * 2.54));

return 0;
}


for me:

$ gcc dpi.c -luser32 -lgdi32

jay at jay-win9 /dev2/j/dpi
$ ./a
horizonal pixels 1280
veritical pixels SM_CYSCREEN 800
horizontal millimeters 384
veritical millimeters 240
horizontal pixels per millimeter 3.333333
vertical pixels per millimeter 3.333333
horizontal pixels per inch 84.666667
vertical pixels per inch 84.666667

(Visual C++ is fine:
cl dpi.c user32.lib gdi32.lib
.\dpi
)

I wonder if lying in this code:

Searching for 'GetDeviceCaps'...
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScreenType.m3(25): VAR res := NEW(T); n_colors := GetDeviceCaps (WinGDI.NUMCOLORS);
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScreenType.m3(32): res.depth := GetDeviceCaps(WinGDI.BITSPIXEL); (* John Karnak 8/3/98 *)
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScreenType.m3(68): mm_hor = GetDeviceCaps (WinGDI.HORZSIZE),
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScreenType.m3(69): mm_ver = GetDeviceCaps (WinGDI.VERTSIZE) DO

Searching for 'res.res[Axis.T.'...
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScreenType.m3(71): res.res[Axis.T.Hor] := FLOAT(pix_hor) / FLOAT(mm_hor);
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScreenType.m3(72): res.res[Axis.T.Ver] := FLOAT(pix_ver) / FLOAT(mm_ver);


D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScreenType.m3(89):PROCEDURE GetDeviceCaps (cap: Ctypes.int): INTEGER =
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScreenType.m3(93): res := WinGDI.GetDeviceCaps (hdc, cap);
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScreenType.m3(98): END GetDeviceCaps;
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScrnColorMap.m3(268): cnt := WinGDI.GetDeviceCaps (hdc, WinGDI.NUMCOLORS);
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScrnFont.m3(316): LogicalPixelsPerVertInch := WinGDI.GetDeviceCaps(er.hdc, WinGDI.LOGPIXELSY);
9 occurrence(s) have been found.


Searching for '1000.0'...
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScrnPixmap.m3(463): bmih.biXPelsPerMeter := ROUND (st.res[Axis.T.Hor] * 1000.0);
D:\dev2\cm3.2\m3-ui\ui\src\winvbt\WinScrnPixmap.m3(464): bmih.biYPelsPerMeter := ROUND (st.res[Axis.T.Ver] * 1000.0);


and just claiming 96dpi is the way to go.
Can you try that??


Specifically try setting res.res[Axis.T.Hor] and .Ver to 3.779527559055118.
Or heck to 3.3333 like my laptop has.


Or maybe claiming ignorance and setting biXPelsPerMeter and biYPelsPerMeter to 0???
Claiming ignorance feels better than lying of course. :)

Hm, so throw in also:

printf("LogicalPixelsX %u\n", GetDeviceCaps(hdc, LOGPIXELSX));
printf("LogicalPixelsY %u\n", GetDeviceCaps(hdc, LOGPIXELSY));

I get the magic number 96.

- Jay




More information about the M3devel mailing list