Transparent canvas (on transparent window)?

BlitzPlus Forums/BlitzPlus Programming/Transparent canvas (on transparent window)?

David Boudreau(Posted 2008) [#1]
I don't know if this is possible or feasible, but I want to basically have an image or two appear, but without seeing the image's canvas it's drawn on, (the panel the canvas might be on,) nor the window's borders/menus/background, unless the mouse pointer is over my app's window, in which case you do see the window and everything else inside it (to be able to close it, use menu, etc).

I searched and found some interesting things on "skinning windows" and maybe that's what I mean but not sure. The window doesn't have to be 100% transparent, but as long as you can see what's basically happening in the window underneath it. I found public code in the archives to get my window to be AlwaysOnTop (much thanks to Syntax Error/Jim Brown! http://www.blitzbasic.com/Community/posts.php?topic=22583#237663 ), so this would be implemented in an application that runs lightly over another game entirely--

"runs lightly" meaning not RAM/cpu/resource hungry... I just want to draw the images ONLY while another game visibly runs underneath it, w/out my canvas/window backgrounds appearing to cover up the game underneath (only the images).

This looks really cool, something like this might be ok but have images moving around in it too while some other game/program/Desktop runs underneath that you can see too because of the transparency:
http://www.blitzbasic.com/codearcs/codearcs.php?code=1403
but I think that is skinning- is that the only way to do what I want? That works on my Windows 2000 PC so if it worked on win2k, XP as well as Vista that's desired.

Sorry if any of this is unclear but that's what I mean by "transparency" of a canvas. I just want to have a way to show only the images, not their background. My guess is that having to grab a window's size worth of Desktop on each loop and updating that would make my app a lot more resource-intensive which I'd like to avoid if possible.


TAS(Posted 2008) [#2]
I would be suprised if there's a way to have windows ar blitz do this for you but you could probably implement yourself by copying the desktop into a full screen window and then drawing the game window and the transparent window where desired.


David Boudreau(Posted 2008) [#3]
Thanks for the reply! I have tried a few things like that I think, but could you be a little more specific? I mean is copying the entire full screen window necessary? I only want to see the area directly under my window, and copy that (from x,y of window's top left to window's width,height) and draw that image, then draw my own small image, and flipcanvas.

Blitz comes with code by Ma[r?]k that sort of acts like the Windows Magnify program, and today I was experimenting with that to get what I want by:
1) record wx,wy as window's x,y
2) get the window (with canvas on it) off the screen using SetGadgetShape
3) CopyImage from wx,wy to window's width/height into an imagebuffer
4) use SetGadgetShape again to "restore" the window back into place
5) draw my own stuff over it (using DrawImage and my own code)

Here's an excerpt of that code:

timer = CreateTimer(60)
frameSet1 = CreateImage(width,height,1,2) ; width/height both 192 ea
;... then later in the While/Wend loop:
;1) record wx,wy as window's x,y
wx= GadgetX(window)
wy= GadgetY(window)
;2) get the window (with canvas on it) off the screen using SetGadgetShape
SetGadgetShape(window,-500,-500,192,192)
;3) CopyImage from wx,wy to window's width/height into an imagebuffer
CopyRect(wx,wy,width,height,0,0,DesktopBuffer(),ImageBuffer(frameSet1));<---does it get under?
;4) use SetGadgetShape again to "restore" the window back into place
SetGadgetShape(window,wx,wy,width,height)
DrawImage(frameSet1,0,0)

;5) my own images "over" the desktop.
If JoyY() = -1 Then DrawImage myPic,20,20 ; etc.

;close out the $4001/wend loops


(I put that in a condition If WaitEvent() = $4001 for timer ticks...)

Yes faking it this way would be fine, again as long as it's not wasting system resources. But I get a flicker, and it does not update so well. like when I get my own pic to be drawn, it doesn't disappear as soon as I let go of the up direction. I've made the window style 0 which is a close match to it's background, as well as other styles like default 15. Anyway I don't imagine I need to grab a fullscreen's worth of Desktop() but would that be faster?

The other way that I referenced in my first post, that uses Hipteen's code of a skinned transparent panel to see under it is great, except for one thing- if I use a canvas instead of a panel like he did, it leaves a solid black rectangle under the window.

What I mean by that is, if I move the window by dragging it around, I see all these black boxes (and any image frames that were drawn) all over the screen where it was along the trail I dragged it (these boxes are left all over the desktop, ie not my present app's area-- it's like if I set the canvas size to 5x5 pixels, I am "painting" with the mouse in black color all over my desktop when I drag its window around). Even if I don't move the app around the desktop screen, it still does this: when I exit and close my app, the black box(es) where the canvas was (ALL the places it was) are still remaining on my screen. I.e. the desktop itself didn't get refreshed. It's like my app prevented a Cls call before windows refreshed/flipped itself (my app is closed). To get rid of the black boxes, I have to bring another window/tab into focus. I've tried this on multiple machines with the same result (each running win2k, incl. two PCs and a laptop).


TAS(Posted 2008) [#4]
I think a truely transparent window is impossible because each screen pixel must be under the control of only one window. If you own both windows you can fake it by

1) have the 'transparent window make a copy of the part of the desktop its going to cover to its canvas.
2) Draw itself in transparent mode (aka alpha blending"
3) pass the overlaping rectangle with its transparent image to the main program that than incorporates into its own canvas.

Should be too painful if the transparent window is static. If not, I would incorporate the transparent window into the main window.


David Boudreau(Posted 2008) [#5]
1) For 1), I have been trying this approach recently but it seems you must first get your app _off_ of the desktop somehow before you get to see and copy the part under it. I even tried minimizing and restoring my app before flipping, but that just actually minimized it to the Windows traybar and literally showed that short animation, and restoring itself over and over. So instead, I moved my app offscreen to copy under it, as with the code in my post above, however it flickers and does not update so fast as I mentioned before (any suggestions to get it to work better? anyone?)....

2) For 2), Hipteen's code does it really well, he explains how to do it here: http://www.blitzbasic.com/codearcs/codearcs.php?code=1403
but he uses a panel on the window and a textfield in that panel. I tried putting a canvas on the panel, and just a canvas on the window (no panel) but both times got the problem described above where the desktop itself gets crapped on all over with canvas remnant trails, even after the app exits. If it didn't do that, I could even live with the canvas and image inside it not being transparent-- just having my app's window/borders be transparent would be acceptable enough for what I want.

btw: For a gadget like a button to get this kind of functionality (as you mentioned in your other thread), did you take a look at Hipteen's code and try it out? I imagine it would be more helpful for you. I have questions about his code though, eg why does his skin function recreate the panel... also I have searched MSDN for more info on the parameters in these 3 lines but can't understand exactly what they mean:
hwnd = QueryObject (window_handle, 1)
SetWindowLong(hwnd, -20,  $80000)
SetLayeredWindowAttributes(hwnd, colorkey, alpha, colororalpha)

Can anyone tell me how to determine what -20 and the $80000 parameters mean? (I think MSDN website can help me but could not find any info in the docs on these parameters in SetLayeredWindowAttributes nor SetWindowLong functions.) I already experimented with fiddling around with the arguments for the last line but I'm not even sure about the QueryObject's argument 1 and what it does. All 3 lines above appear to be required for any transparency.

3) I could not get this approach to work. There are some code in the archives or this forum that try 2D Alpha Blending but are either too slow or don't work to show a little of what is under the window. I don't need the window fully 100% transparent, and my canvas/images can be opaque, but the window should be just transparent enough to see what is happening under it (there will be another window with its own game, e.g. an emulator running a game, nothing I have control over). So I focused on 1) and 2) instead with Mark's and Hipteen's code.

With these approaches and what people have already done, and without a definitive answer yet that it cannot be done in BlitzPlus, I have hope but need some help to get there. Thanks again for your response.