Tk Source Code

View Ticket
Login
Ticket UUID: c95d4691ff8723b47c820081ce50688cf04911f7
Title: winfo screenheight w/dual monitors returns the screen height of the primary display
Type: Bug Version: 8.6.3
Submitter: anonymous Created on: 2015-01-11 00:36:05
Subsystem: 68. Win Window Operations Assigned To: nobody
Priority: 5 Medium Severity: Minor
Status: Open Last Modified: 2016-08-22 13:54:08
Resolution: Wont Fix Closed By: nobody
    Closed on:
Description:
On windows, if a window is placed in the second monitor's display area, and [winfo screenheight .win2] is called, the screenheight returned is the first monitor's height, not the second monitor's.  Likewise for screenwidth.
User Comments: oehhar added on 2016-08-22 13:54:08:

For me, the current behavior is correct and I recomment to change the ticket state to "wont fix".

The ticket is for windows only.

On windows with multiple monitors, you get a big virtual screen over all monitors, which may be checked by the winfo v* commands. The current physical screen is lalways the primary monitor. One may use "wm geometry" to check the screen one is on.

There are ambiguities and room for enhancement, but this will break any compatibility. This would be an RFE requiring a TIP.

- Harald


fvogel added on 2016-08-15 10:20:41:

Discussion run in May/June 2016 on the Tcl Core List.

Stalled since June 06, 2016 where it was said that some stuff Tk feature should be dropped. This needs a TIP I can't write because I have no clear idea of what needs to be done/dropped. See last email of the thread.

Giving up.


fvogel added on 2016-07-30 18:48:24:

The issue this bug is dealing with was brought again on comp.lang.tcl.


fvogel added on 2016-05-31 18:54:55:

Interesting observation in [4face822b0].


fvogel added on 2016-05-25 19:27:11:
For me:

francois@TM:~$ xrandr --output eDP-1 --mode 1920x1080 --fb 3000x2000 --panning 2500x1500
francois@TM:~$ /home/francois/Documents/tcltk/fossil/tcltk/bin/wish8.6
% winfo screenwidth .
3000
% winfo screenheight .
2000
% winfo vrootwidth .
3000
% winfo vrootheight .
2000

So yes, the arguments from --fb are returned in both [winfo screenxxx ] and [winfo vrootxxx ] in this single panning screen case. I *think* this is correct  (extract from the Ubuntu documentation: https://wiki.ubuntu.com/X/Config/Resolution ): 

"If you want to have a panning viewport, i.e., a virtual screen that's bigger than your physical screen that moves when you move the mouse to the edge ("zoomed in" view) specify the desired physical resolution with --mode and the virtual screen size with --fb and panning area (typically same as virtual screen size) with --panning."

Anyway, if the above would be considered as a bug it should be the object of a distinct ticket I think.

anonymous (claiming to be [email protected]) added on 2016-05-24 00:15:40:
Sorry, all the ticket e-mails go to spam in a different e-mail account, and
I have to remember to check.

On Linux, I was not testing the usual case of two monitors -- that's probably correct -- it's just a bigger screen.

If you do (with changes for your setup):
   xrandr --output LVDS-0  --mode 1366x768 --fb 5464x3072 --panning 5464x3072
it creates a big virtual screen with a 1366x768 viewport (size of my laptop screen). 
This is a single monitor setup, _not_ two monitors.

This used to be much more common -- hardly anyone uses it anymore.

So the question is, in this situation, would you want the screen height/width
to return 5464x3072 (the size of the entire virtual screen), or 1366x768 (the
size of the viewport). 

I probably do not understand the original intention of the difference between a virtual root window vs. a screen.

I could see vroot w/h as 5464x3072 and screen w/h as 1366x768.
But returning the size of the entire virtual screen is probably also valid.

fvogel added on 2016-05-22 15:41:01:
BTW, this is the output of xrandr showing my display configuration on Debian 8:


Screen 0: minimum 320 x 200, current 3200 x 1080, maximum 8192 x 8192
eDP-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 344mm x 194mm
   1920x1080     59.99*+  59.96    40.03  
   1680x1050     59.95  
   1400x1050     59.98  
   1280x1024     59.89  
   1280x960      59.94  
   1152x864      59.96  
   1024x768      59.92  
   800x600       59.86  
   640x480       59.38  
   720x400       59.55  
   640x400       59.95  
   640x350       59.77  
VGA-1 connected 1280x1024+1920+0 (normal left inverted right x axis y axis) 338mm x 270mm
   1280x1024     60.02*+  75.02  
   1280x960      60.00  
   1280x800      74.93    59.81  
   1152x864      75.00  
   1280x768      74.89    59.87  
   1024x768      75.08    70.07    60.00  
   1024x576      59.97  
   832x624       74.55  
   800x600       72.19    75.00    60.32    56.25  
   848x480       60.00  
   640x480       75.00    72.81    66.67    60.00  
   720x400       70.08  
DP-1 disconnected (normal left inverted right x axis y axis)
DP-2 disconnected (normal left inverted right x axis y axis)


Now looking at if it's possible to create TWO screens, one on each output reported as conncected by xrandr

fvogel added on 2016-05-22 15:36:49:
Another way to check the display configuration on Linux is to issue:

  xdpyinfo

Among other info, this reports the number of screens of the display. Here is an extract of my output (Debian 8, primary physical monitor is the laptop one featuring 1920x180 pixels, secondary physical monitor is a VGA screen featuring 1280x1024 pixels) :

<snip>
default screen number:    0
number of screens:    1

screen #0:
  dimensions:    3200x1080 pixels (847x285 millimeters)
<snip>

So in my current configuration there really is a single screen made of two monitors ==> no bug on Linux

fvogel added on 2016-05-22 14:43:40:
Brad, about your comment below dated 2016-04-23 16:51:07:

I don't see this as wrong. With xrandr you set one *single* big screen, not two. The two monitors make up a single screen as far as the X server is concerned.

On Linux I have made a bit of research in the code, and it's quite simple: XOpenDisplay() does the entire job, checks for different screens presence and so on. You can check how many screens it finds by applying the following little patch:

Index: generic/tkWindow.c
==================================================================
--- generic/tkWindow.c
+++ generic/tkWindow.c
@@ -530,10 +530,11 @@
 	if ((strncmp(dispPtr->name, screenName, length) == 0)
 		&& (dispPtr->name[length] == '\0')) {
 	    break;
 	}
     }
+printf("ScreenCount(dispPtr->display):   %d\n", ScreenCount(dispPtr->display));
     if (screenId >= ScreenCount(dispPtr->display)) {
 	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
 		"bad screen number \"%d\"", screenId));
 	Tcl_SetErrorCode(interp, "TK", "DISPLAY", "SCREEN_NUMBER", NULL);
 	return NULL;

I have now built a real (i.e. not in a VM) Linux Debian 8 configuration with two monitors just to investigate the present ticket, and like you I only have one screen reported by X.

I think that configuring X differently, so that instead of one big screen it sees two separate screens should be possible (how? tune xorg.conf?)
Then in Tk the behaviour should be already OK with no change in the Tk code. I do not think Tk has a bug (in the Linux implementation).

fvogel added on 2016-04-24 20:28:35:

Committed [671c976f] in branch "multiscreens":

- Tk now knows about all screens (monitors), not only about the primary one
- screenheight and screenwidth, and all values that depend on them, are now correct for each monitor as long as the windows are created with explicit -screen parameter
- resolution changes are now tracked correctly by Tk for each monitor

With this commit the following script is now working as expected:

package require Tk
winfo screenheight . ; # info from primary monitor
winfo screen . ; # :0.0
toplevel .t -screen :0.1
winfo screen .t ; # :0.1 (NEW!)
winfo screenheight .t ; # info from secondary monitor (NEW!)
<change secondary monitor resolution>
winfo screenheight .t ; # updated info from secondary monitor (NEW!)

<TODO>:

- Find a way to test all this without false alarms (when there is a single monitor attached)
- When moving a window from one screen to another, should its screen info "follow"?
- Fix this problem on Linux and MacOSX as well.


fvogel added on 2016-04-24 15:06:37:
Again with line breaks where they belong in the code extract:

  package require Tk
  winfo screenheight . ; # info from primary monitor
      <move the "." window to the second monitor>
  winfo screenheight . ; # info from second monitor
      <change second monitor resolution>
  winfo screenheight . ; # updated info from second monitor
  winfo screen .
  toplevel .t -screen :0.1
  winfo screen .t
  winfo screenheight .t

fvogel added on 2016-04-24 15:05:17:

Second thoughts on my side regarding how to fix the issue reported in the ticket.

The root problem raised by the present ticket is much more general than just a wrong returned value from [winfo].

My fix [38168e2176] is not really correct/complete. It makes Tk request the width and height of the correct monitor so that the returned values for [winfo screenwidth/screenheight ...] is the right one. But the problem is that is does not update the screens sizes cached internally in Tk in the Tk_Display structure. As a consequence, all what is based on these sizes in Tk is still broken.

I have started thinking afresh regarding this ticket and am currently working on a different approach: Tk already has (more or less) support for multiple screens, but the number of such screens is set once and for all to 1 when opening the display. The idea is then to make Tk fully support several screens (aka monitors) by allowing display->nscreens to be larger than 1, and add the required for loops on screens whenever needed. This could sound hard but in fact it is not so difficult. Then the screen identifier attached to any window needs to be updated whenever this window changes screen. Also feasible. And screen characteristics shall be updated whenever the monitor resolution, colors... changes. Fine.

The net result is that we will then get correct results for incantations like:

package require Tk winfo screenheight . ; # info from primary monitor <move the "." window to the second monitor> winfo screenheight . ; # info from second monitor <change second monitor resolution> winfo screenheight . ; # updated info from second monitor winfo screen . toplevel .t -screen :0.1 winfo screen .t winfo screenheight .t

Addressing this ticket this way will fix the general issue, which is that Tk is just not aware of multiple monitors.

Then, all the other places where a potentially wrong monitor size is used in Tk (see one of my previous posts in the present ticket) will be automatically fixed because the correct size of each monitor will now be cached in the (several, no longer just one) screens element of Tk_Display.

All the above I'm working on considers Win for the moment. I didn't look at other platforms implementation so far.


anonymous (claiming to be [email protected]) added on 2016-04-23 17:06:42:
Windows with the primary as a smaller screen:


F:\>tclsh z.tcl
vrootwidth:1824   monitor 1
vrootheight:778
screenwidth:800
screenheight:600

vrootwidth:1824   monitor 2
vrootheight:778
screenwidth:800
screenheight:600

anonymous (claiming to be [email protected]) added on 2016-04-23 16:51:07:
Ok, Linux is definitely broken.
Single monitor, big virtual screen.

bll-tecra:bll$ xrandr --output LVDS-0  --mode 1366x768 --fb 5464x3072 --panning 5464x3072
bll-tecra:bll$ cd
bll-tecra:bll$ tclsh $HOME/vbox*/z.tcl
vrootwidth:5464
vrootheight:3072
screenwidth:5464
screenheight:3072

screen width and height should be 1366x768!
The output does not match the documentation.

anonymous (claiming to be [email protected]) added on 2016-04-23 16:29:59:
Sorry, I just ran the windows test with whatever sizes from the VM.
Here it is with normal monitor sizes, 1024x768 and 800x600.

I am not using any code from the fossil repo.

F:\>tclsh z.tcl   First monitor
vrootwidth:1824
vrootheight:768
screenwidth:1024
screenheight:768

vrootwidth:1824   Moved the window to the second monitor
vrootheight:768
screenwidth:1024
screenheight:768

Linux acts just like FreeBSD as I expected.

I am just worried about breaking something.

Otherwise I completely agree with you -- I would like to have "screen" imply the
current monitor.

fvogel added on 2016-04-23 12:41:33:
Many thanks for your feedback!


FreeBSD and Linux:

Your test on FreeBSD is clear to me. FreeBSD also has the same issue as Windows regarding screenwidth/height. Linux is probably not different but if you can check that would be appreciated, thanks.
OK, I will (maybe) look at this for Linux later.


Windows:

Regarding Windows, I don't understand your results. Was your check with the same monitors as for FreeBSD? You do not give the resolution of each monitor, and their relative arrangement in space.

Besides, I hope your test didn't run from the bug fix branch "bug-c95d4691ff"? Because (I believe) I have fixed screenwidth/height for Windows in that branch and you should get the correct screenwidth/height depending on what monitor the window you pass is displayed. Or does my fix not work for you perhaps?


Finally, about "wonder if "fixing" windows would break everybody's code":

I don't think so. It's the opposite: people's code is broken now and fixing [winfo screenwidth/height ...] would fix their code.

In my opinion, [winfo screenwidth/height ...] should return the size of the monitor on which the given window is displayed (there exist fallbacks in the API to deal with the case when the window is partially displayed on several monitors). Note that I'm not discussing the introduction of new commands to get the monitors resolution, because that is precisely the job of the existing [winfo screenwidth/height ...], which get it wrong except when considering the primary monitor.

Currently it appears that people use [winfo screenwidth/height ...] to get numbers that are correct when they mean the primary monitor, or probably wrong when using another monitor.
In the latter case, it only matters when the second monitor has different resolution than the primary one. This is not always the case.
And when it has different resolution, it is usually not *very* different because people get monitors more or less at the pace of technology changes. Nobody I think has a virtual screen composed of a 1920x1080 full HD monitor and aside of it a 640x480 VGA oldie.

Therefore people's applications using [winfo screenwidth/height ...] currently just work based on:
  - chance: all monitors have the same resolution
  - approximation: wrong results are only slightly wrong

anonymous (claiming to be [email protected]) added on 2016-04-23 01:30:10:
With a 1024x768 and a 800x600 monitor (FreeBSD 10.1 in a VM, mate desktop):

freebsd101:bll$ ./z.tcl   # same on both monitors
vrootwidth:1824
vrootheight:768
screenwidth:1824
screenheight:768


vroot/screen both indicate the full size of the "screen", not the current monitor.
And with the mixed sizes, the 768 is correct.

It would probably be nice if there was an additional function to get the
size of the current monitor, but there are workarounds for that.

Windows, both monitor 1 and monitor 2:
F:\>tclsh z.tcl  
vrootwidth:2001
vrootheight:675
screenwidth:1086
screenheight:665

I wonder if "fixing" windows would break everybody's code.
Though it is not nice that windows and other OSs act differently.

If you want, I can verify Linux at a later time when I have access to my other VMs or other monitor.

fvogel added on 2016-04-22 22:17:59:

I think there are further places where the size of a potentially wrong monitor is used in Tk:

tk scaling

Full screen on Windows, see bug [4face822b0b3d0cb8383c5cf46ff2099715846fa]

Full screen on MacOSX (perhaps?)

canvas

and so on...

Basically, everywhere WidthOfScreen() and HeightOfScreen() are used.

Regarding WidthMMOfScreen() and HeightMMOfScreen() I'm wondering.

Fixing all this needs careful analysis because, on Windows at least there seems to be a single *display* featuring a single *screen*, but this screen may be shown on several *monitors*.


fvogel added on 2016-04-21 16:37:08:

Fix proposed here: [38168e2176] (changes for Windows only since the present ticket was opened for Win).

Review requested please, regarding code organization in the different modules. For instance, is the MODULE_SCOPE trick best for platform-specific Tkp... functions?

And a question: do we have the same problem for Linux and/or for OSX? I cannot check this myself, for both platforms.


fvogel added on 2016-04-20 20:14:54:

On Windows, [winfo screenwidth/screenheight ...] receive values in TkWinDisplayChanged().

These values are obtained through GetDeviceCaps.

MSDN documents it: "On a multiple monitor system, if hdc is the desktop, GetDeviceCaps returns the capabilities of the primary monitor. If you want info for other monitors, you must use the multi-monitor APIs or CreateDC to get a HDC for the device context (DC) of a specific monitor."


oehhar added on 2015-02-25 16:53:40:
I can confirm that the screenwidth/height are always those of the primary screen.

With WIn 8.1 64bit, TCL8.6.3 on:
Laptop screen: 1280x720
Attached LCD: 1920x1080

I get:
Virtual Screen: 3840x1080
and as screenwidth/height the size of the first screen defined in windows.
This is independent on the physical window position.

anonymous (claiming to be [email protected]) added on 2015-01-11 04:26:19:
#!/usr/bin/tclsh

package require Tk

variable vars
variable d
set d {
  vrw vrootwidth
  vrh vrootheight
  vrx vrootx
  vry vrooty
  sw  screenwidth
  sh  screenheight
}

proc getstuff { } {
  variable vars
  variable d

  dict for {k v} $d {
    set dv [winfo $v .]
    set vars($k) $dv
  }
}

dict for {k v} $d {
  set vars($k) {}
  ttk::label .l$k -text $v
  ttk::label .$k -textvariable vars($k)
  grid .l$k .$k
  grid configure .l$k -sticky e
  grid configure .$k -sticky e
}
ttk::button .b -text {Click Me!} -command getstuff
grid .b -columnspan 2 -sticky e