ScreenDC - How to reference an extended screen ?

I’ve been wallowing around in the wxWidgets code and haven’t been able to identify the code that selects the particular physical screen. Perhaps it’s in a platform-specific source include file for MS Windows ? Or maybe a pre-compiled DLL that gets linked ?

wx.ScreenDC takes no parameters, so it always works on the primary display screen. Giving proper position offsets outside the primary is illegal. Can an extended screen be selected and so it can be referenced from an origin of (0, 0) ?

Thanks,
Ray Pasco

Hi Ray,

Thanks for the response. While I partially understand your response, I am new to the Windows UI stuff, can you please explain last part of your response about extended screen?

Thanks in advnace,

Gowtham

···

On Fri, Jun 10, 2011 at 2:23 PM, Ray Pasco pascor22234@gmail.com wrote:

I’ve been wallowing around in the wxWidgets code and haven’t been able to identify the code that selects the particular physical screen. Perhaps it’s in a platform-specific source include file for MS Windows ? Or maybe a pre-compiled DLL that gets linked ?

wx.ScreenDC takes no parameters, so it always works on the primary display screen. Giving proper position offsets outside the primary is illegal. Can an extended screen be selected and so it can be referenced from an origin of (0, 0) ?

Thanks,
Ray Pasco

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en

What response ? I started this thread by asking a question.

Systems are allowed to have more physical monitors than the main one. They can be used to extend the OS’s Desktop which results in a “extended Desktop”. Though split between separate monitors, what is seen acts like a single big Desktop. Wx controls can be placed anywhere an the virtual Desktop by giving its position relative to the main display’s origin which is always (0, 0), by definition. Negative valued ordinates may have to be used.

Ray

On Windows GetDC(NULL) is used to get the handle for the screen DC, and MSDN states that in that case it is "the DC for the entire screen." There isn't anything in the documentation implying that it is limited to the primary display, and I don't see anything about getting the dc for other displays, so I would expect it to cover the entire virtual display. What errors are you getting?

Creating a ticket for this in Trac will be helpful so the right people on the wx core team will see it.

···

On 6/10/11 2:23 PM, Ray Pasco wrote:

I've been wallowing around in the wxWidgets code and haven't been able
to identify the code that selects the particular physical screen.
Perhaps it's in a platform-specific source include file for MS Windows
? Or maybe a pre-compiled DLL that gets linked ?

wx.ScreenDC takes no parameters, so it always works on the primary
display screen. Giving proper position offsets outside the primary is
illegal. Can an extended screen be selected and so it can be referenced
from an origin of (0, 0) ?

--
Robin Dunn
Software Craftsman

Only the primary screen image is returned, not the entire extended Desktop. Currently, this is no way to get everything at once, much less the extended screen portion by itself.

In the mean time I’ll give the win32 DLL calls in the user32 and gdi32 DLL’s a try.

Pressing the keyboard button actually does save the entire bitmap into the clipboard. Right now I wish I knew the DLL entry point for the key handler !

I’ll submit a ticket.

Thanks
Ray

···

On Sat, Jun 11, 2011 at 2:40 PM, Robin Dunn robin@alldunn.com wrote:

On 6/10/11 2:23 PM, Ray Pasco wrote:

I’ve been wallowing around in the wxWidgets code and haven’t been able

to identify the code that selects the particular physical screen.

Perhaps it’s in a platform-specific source include file for MS Windows

? Or maybe a pre-compiled DLL that gets linked ?

wx.ScreenDC takes no parameters, so it always works on the primary

display screen. Giving proper position offsets outside the primary is

illegal. Can an extended screen be selected and so it can be referenced

from an origin of (0, 0) ?

On Windows GetDC(NULL) is used to get the handle for the screen DC, and MSDN states that in that case it is “the DC for the entire screen.” There isn’t anything in the documentation implying that it is limited to the primary display, and I don’t see anything about getting the dc for other displays, so I would expect it to cover the entire virtual display. What errors are you getting?

Creating a ticket for this in Trac will be helpful so the right people on the wx core team will see it.

Robin Dunn

Software Craftsman

http://wxPython.org

I’ve submitted a TRAC ticket (#13279)

I’ve got the hard part figured out. WX’s wx.ScreenDC is created with the wrong size - it’s only the main screen’s size. The underlying win32ui.CreateDCFromHandle() creates a DC whose size is the bounding rectangle for the combined extended Desktop.

Attached is a demo app and the resulting screenshot from my system.

Ray Pasco

DesktopGrab.PY (2.04 KB)

···

On Sun, Jun 12, 2011 at 12:43 PM, Ray Pasco pascor22234@gmail.com wrote:

On Sat, Jun 11, 2011 at 2:40 PM, Robin Dunn robin@alldunn.com wrote:

On 6/10/11 2:23 PM, Ray Pasco wrote:

I’ve been wallowing around in the wxWidgets code and haven’t been able

to identify the code that selects the particular physical screen.

Perhaps it’s in a platform-specific source include file for MS Windows

? Or maybe a pre-compiled DLL that gets linked ?

wx.ScreenDC takes no parameters, so it always works on the primary

display screen. Giving proper position offsets outside the primary is

illegal. Can an extended screen be selected and so it can be referenced

from an origin of (0, 0) ?

On Windows GetDC(NULL) is used to get the handle for the screen DC, and MSDN states that in that case it is “the DC for the entire screen.” There isn’t anything in the documentation implying that it is limited to the primary display, and I don’t see anything about getting the dc for other displays, so I would expect it to cover the entire virtual display. What errors are you getting?

Creating a ticket for this in Trac will be helpful so the right people on the wx core team will see it.

Robin Dunn

Software Craftsman

http://wxPython.org

Only the primary screen image is returned, not the entire extended Desktop. Currently, this is no way to get everything at once, much less the extended screen portion by itself.

In the mean time I’ll give the win32 DLL calls in the user32 and gdi32 DLL’s a try.

Pressing the keyboard button actually does save the entire bitmap into the clipboard. Right now I wish I knew the DLL entry point for the key handler !

I’ll submit a ticket.

Thanks
Ray

I've submitted a TRAC ticket (#13279)

Thanks. BTW to attach a file to a new ticket you just need to click the box labeled "I have files to attach to this ticket" and then it will let you do it on the next page. And you can always attach files to already submitted tickets as well.

I've got the hard part figured out. WX's wx.ScreenDC is created with
the wrong size - it's only the main screen's size. The underlying
win32ui.CreateDCFromHandle() creates a DC whose size is the bounding
rectangle for the combined extended Desktop.

It's probably due to using the handle returned from GetDesktopWindow instead of passing NULL to GetDC, (although the docs imply that using NULL should do the same thing...) You should update your ticket with this information so whoever handles the ticket will not have to duplicate the discovery work.

···

On 6/12/11 8:32 PM, Ray Pasco wrote:

--
Robin Dunn
Software Craftsman

I’ve submitted a TRAC ticket (#13279)

Thanks. BTW to attach a file to a new ticket you just need to click the box labeled “I have files to attach to this ticket” and then it will let you do it on the next page. And you can always attach files to already submitted tickets as well.

I’ve got the hard part figured out. WX’s wx.ScreenDC is created with

the wrong size - it’s only the main screen’s size. The underlying

win32ui.CreateDCFromHandle() creates a DC whose size is the bounding

rectangle for the combined extended Desktop.

It’s probably due to using the handle returned from GetDesktopWindow instead of passing NULL to GetDC, (although the docs imply that using NULL should do the same thing…) You should update your ticket with this information so whoever handles the ticket will not have to duplicate the discovery work.

Robin Dunn

Software Craftsman

http://wxPython.org

From TRAC ticket #13279:

  • summary
    changed from Win7 wx.ScreenDC() doesn’t include extended screens’ bitmaps to wxScreenDC::Blit() doesn’t work with negative source origin
    So the problem is that if you pass a negative source origin to wxScreenDC::Blit() it doesn’t work? Or is there anything else/more to it?

That’s it.To be honest I don’t really see what could we be doing wrong as we simply pass the source coordinates to the the native BitBlt() .
It would be interesting to know if you see any blit-related errors on Windows debug output (i.e. what you see using a tool like debug view) when using debug build of wxWidgets).

My response:

That’s the problem in a nutshell. My sample app passes negative start values in the call:

``
dtDestDC.BitBlt( bltWriteToStartCoord, bltSize, # Destination args
dtSourceDC, bltReadFromStartCoord, win32con.SRCCOPY ) # Source args.

The values in [ bltReadFromStartCoord ] are negative in this PyWin32 call and it works as expected.

From what you just said, I suspect the bug may be in wxPython and not wxWidgets.

Somewhere along the line the DC.Blit source start ordinates mistakenly cause an exception if either one is negative.

Ray Pasco

GetDesktopWindow.py (8.01 KB)

···

On Mon, Jun 13, 2011 at 10:20 PM, Robin Dunn robin@alldunn.com wrote:

On 6/12/11 8:32 PM, Ray Pasco wrote:

I must be getting Alzheimer’s… My original pure wxPython app causes no exceptions - it merely doesn’t work as expected. 1) Calls to wx.ScreenDC() simply return a DC that reports a size of (0, 0). The app checks for this error condition and then tries an alternate method that uses a MemoryDC and Blits the entire ScreenDC to the MemoryDC. However, 2) only 1 screen’s worth of bitmap gets Blitted instead of the entire extended Desktop. Using the correct negative-valued source origin results in just the extended screen that origin refers to.

So, there’s actually 2 bugs.

The “alternate method” for getting the ScreenDC is simply a hack to help get around bug 1) . This hack doesn’t work properly for extended desktop screens. Yet, I believe it should, too.

Ray Pasco

···

On Mon, Jun 13, 2011 at 10:20 PM, Robin Dunn robin@alldunn.com wrote:

On 6/12/11 8:32 PM, Ray Pasco wrote:

I’ve submitted a TRAC ticket (#13279)

Thanks. BTW to attach a file to a new ticket you just need to click the box labeled “I have files to attach to this ticket” and then it will let you do it on the next page. And you can always attach files to already submitted tickets as well.

I’ve got the hard part figured out. WX’s wx.ScreenDC is created with

the wrong size - it’s only the main screen’s size. The underlying

win32ui.CreateDCFromHandle() creates a DC whose size is the bounding

rectangle for the combined extended Desktop.

It’s probably due to using the handle returned from GetDesktopWindow instead of passing NULL to GetDC, (although the docs imply that using NULL should do the same thing…) You should update your ticket with this information so whoever handles the ticket will not have to duplicate the discovery work.

Robin Dunn

Software Craftsman

http://wxPython.org

I’ve submitted a TRAC ticket (#13279)

Thanks. BTW to attach a file to a new ticket you just need to click the box labeled “I have files to attach to this ticket” and then it will let you do it on the next page. And you can always attach files to already submitted tickets as well.

I’ve got the hard part figured out. WX’s wx.ScreenDC is created with

the wrong size - it’s only the main screen’s size. The underlying

win32ui.CreateDCFromHandle() creates a DC whose size is the bounding

rectangle for the combined extended Desktop.

It’s probably due to using the handle returned from GetDesktopWindow instead of passing NULL to GetDC, (although the docs imply that using NULL should do the same thing…) You should update your ticket with this information so whoever handles the ticket will not have to duplicate the discovery work.

Robin Dunn

Software Craftsman

http://wxPython.org

I must be getting Alzheimer’s… My original pure wxPython app causes no exceptions - it merely doesn’t work as expected. 1) Calls to wx.ScreenDC() simply return a DC that reports a size of (0, 0). The app checks for this error condition and then tries an alternate method that uses a MemoryDC and Blits the entire ScreenDC to the MemoryDC. However, 2) only 1 screen’s worth of bitmap gets Blitted instead of the entire extended Desktop. Using the correct negative-valued source origin results in just the extended screen that origin refers to.

So, there’s actually 2 bugs.

The “alternate method” for getting the ScreenDC is simply a hack to help get around bug 1) . This hack doesn’t work properly for extended desktop screens. Yet, I believe it should, too.

Ray Pasco

···

On Wed, Jun 15, 2011 at 10:32 AM, Ray Pasco pascor22234@gmail.com wrote:

On Mon, Jun 13, 2011 at 10:20 PM, Robin Dunn robin@alldunn.com wrote:

On 6/12/11 8:32 PM, Ray Pasco wrote:


On 6/15/2011 3:57 PM, wxTrac wrote:

Ticket URL: <[http://trac.wxwidgets.org/ticket/13279#comment:7](http://trac.wxwidgets.org/ticket/13279#comment:7)>

#13279: wxScreenDC::Blit() doesn't work with negative source origin

--------------------+-------------------------------------------------------
 Reporter: pascor | Owner:
     Type: defect | Status: new
 Priority: normal | Milestone:
Component: wxMSW | Version: 2.8.11

 Keywords: | Blockedby:
    Patch: 0 | Blocking:
--------------------+-------------------------------------------------------

Comment(by robind):

 Oops the image file is larger than our limit set in Trac. I put the file

 in my dropbox instead: [http://dl.dropbox.com/u/727255/sdctest-GetDC.png](http://dl.dropbox.com/u/727255/sdctest-GetDC.png)


--
Ticket URL: <[http://trac.wxwidgets.org/ticket/13279#comment:7](http://trac.wxwidgets.org/ticket/13279#comment:7)>

I finally got to the bottom of the problem. (Yeay!) My desktop is arranged with an extended 1280x800 screen on top and the primary 1280x800 screen on the bottom. When these 2 statements are run:

    scrDC     = wx.ScreenDC()

    scrDcSize = scrDC.Size

the resulting bitmap is sized correctly as 1280x1600 while querying wx.ScreenDC.Size returns the incorrect value of 1280x800.

Also, the origin convention for placing controls on the desktop are different values than that for blitting from or to the screenDC bitmap. Meaning, for controls placement purposes the upper-left corner coordinate of the desktop is valued (0, -800) while for blitting the U-L coordinate is (0,
0).

II hope this clears up the problems:

  1. wxPython function wx.ScreenDC.Size returns the wrong size when the desktop uses extended screens;

  2. The wxPython desktop origin convention for both controls placement and desktop drawing (correct) is different than for bitblitting (incorrect);

  3. Bitbliiting in wxPython needs to allow negative ordinate values: on MSW the
    function BitBlt() properly does. Negative valued ordinates given for blitting now cause exceptions.


Ray Pasco

I just realized that there needs to be a new function called wx.DesktopDC

Since all bitmaps’ upper-left coordinate is always (0, 0) there also needs to be an easy way to apply the “screenToBitmap” offset. If there was available the desktop’s rect tuple then this offset would be defined as:
screenToBitmapOffset = (desktopRect[0], desktopRect[1])
and
desktopOrigin = (desktopRect[2], desktopRect[3])

Since DC bitmap ordinate values can only be positive, but the MSW function allows negative position ordinates for blit source DC ordinates such as :

---- desktopScreenRectList (originX, originY, sizeX, sizeY) =
(0, 0, 1280, 800)
(0, -800, 1280, 0)

---- Desktop Rect = (originX, originY, sizeX, sizeY) =
(0, -800, 1280, 800)

    blitWriteToStartCoord = (0, 0)   # Origin (upper-left corner) of the destination bitmap.
    bltSize = (sizeX, sizeY)

---- BitBlt() args :
blitWriteToStartCoord (0, 0)
bltSize (1280, 1600)
blitReadFromStartCoord (0, -800) # <----------------------------------------------

    desktopBmapDC.BitBlt( blitWriteToStartCoord, bltSize,                       # Dest'n args
                          desktopDC, blitReadFromStartCoord, win32con.SRCCOPY ) # Source args.

Ray Pasco