Trying to stubs-enable Tkogl

3 views
Skip to first unread message

Jean-Claude Wippler

unread,
Feb 10, 2004, 6:09:44 AM2/10/04
to
While trying to add stubs support to Tkogl (OpenGL from Tcl), I hit a
snag on Windows:

Tkogl uses a WndProc to capture WM_WINDOWPOSCHANGED and WM_MOVE
events. For those, it wants to call TkWinChildProc - which is not in
the stubs table.

I've commented it out, and though a few demo's appear to work, many
don't - the refresh never happens.

Is there a reason (technical or otherwise) why TkWinChildProc has not
been added to the stubs table?

Is there a way around it? I only need Win32 for now, and have been
thinking of writing a small extension which locates that call through
the LoadLibrary (handle of main app), and FindSymbol system calls. Or
perhaps there is a way to extract that windowproc's address by
inspecting another window and hijacking the pointer?

All tips/tricks/hacks appreciated.

-jcw

Iain Findleton

unread,
Feb 10, 2004, 12:11:11 PM2/10/04
to

One way to get around this is to "sub-class' the Tk window, and use it
as a wrapper around the window that you are actually using (I presume a
GL window) to draw stuff. The "sub-classed" (A Microsoft term) window
will then get all events, which you can forward to your drawing window,
handle them as you see fit, then call the DefWindProc of the wrapper
through its alias. This gobbledygook required a bit of bending of the
brain to get the concept, but it works quite well. I would send you some
code, but the last time I did it was using borland OWL 4.5 or some such
thing, and it would probably be quite useless to you. The WinHelp
database for Win3.1 and Win32, if yoy can find such a thing, had many
obscure and arcane references on how to do it.

The essential idea is:

1) grab the pointer to the Tk window's WndProc and save it somewhere
2) Install a pointer to your alias WndProc where you grabbed the pointer
from.
3) Your aliased WndProc simply forwards the events you are interested in
to the GL window's WndProc. You return a return code that tells the
alias what to do about the DefWndProc (i.e. Call it or not)
4) Do your own thing in the GL window.

Don't forget to clean up on WM_CLOSE, or Tk may go nuts, leaving
dangling windows on your Windows desktop.

This allows you to do your think without ever knowing about Tk's window
handler functions. Both my animate and (now infamous) TkPrint extensions
use this technique. The original Tkprint from i forget where used the
kind of technique that you are describing for the togl thing.


Enjoy!


Jean-Claude Wippler

unread,
Feb 10, 2004, 6:11:46 PM2/10/04
to
Iain Findleton <ifind...@yahoo.com> wrote...

> > Tkogl uses a WndProc to capture WM_WINDOWPOSCHANGED and WM_MOVE
> > events. For those, it wants to call TkWinChildProc - which is not in
> > the stubs table.
> >
> > I've commented it out, and though a few demo's appear to work, many
> > don't - the refresh never happens.
[...]

> 1) grab the pointer to the Tk window's WndProc and save it somewhere
> 2) Install a pointer to your alias WndProc where you grabbed the pointer
> from.
> 3) Your aliased WndProc simply forwards the events you are interested in
> to the GL window's WndProc. You return a return code that tells the
> alias what to do about the DefWndProc (i.e. Call it or not)
> 4) Do your own thing in the GL window.

Thanks for your help.

Wait... you're describing event overrides, right?

I think Tkogl does that (drat, I've forgotten all Petzold ever told me
about Win32...).

The problem is not catching events. The problem is passing a them to
Tk by calling TkWinChildProc() - I don't have an address for that
internal Tk proc, there is no stub for it.

> This allows you to do your think without ever knowing about Tk's window
> handler functions. Both my animate and (now infamous) TkPrint extensions
> use this technique. The original Tkprint from i forget where used the
> kind of technique that you are describing for the togl thing.

I couldn't find any source for the packages you mention - do you have
an URL handy?

Here's the relevant code from Tkogl, btw (edited for brevity):

static LONG WINAPI WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM
lParam)
{
LONG result;
switch (msg) {
case WM_WINDOWPOSCHANGED:
case WM_MOVE:
result = DefWindowProc(hwnd, msg, wParam, lParam);
Tcl_ServiceAll();
break;
default:
result = TkWinChildProc (hwnd, msg, wParam, lParam);
}
return result;
}

This captures all but WM_WINDOWPOSCHANGED and WM_MOVE, right?

I don't understand what this is doing. Both of these call back into
Tcl and Tk. So Tkogl isn't actually capturing any events. When I
look in Tk's tkWinWm.c, I see a TopLevelProc which is quite similar,
used as window proc. It does look like Tkogl creates its own window
class.

FWIW, I'm using Tkogl 1.1 (not 3.0, which appears to be a major
overhaul...) - home page at http://ganimede.lcg.ufrj.br/Projetos/tkogl
- the code works in wish8.4, I'm merely trying to stubs-enable it so
it can be used in a starkit and called from tclkit.

-jcw

David Gravereaux

unread,
Feb 10, 2004, 6:25:54 PM2/10/04
to
j...@equi4.com (Jean-Claude Wippler) wrote:

>I think Tkogl does that (drat, I've forgotten all Petzold ever told me
>about Win32...).

LOL... Got 2 of his books on my shelf..

>The problem is not catching events. The problem is passing a them to
>Tk by calling TkWinChildProc() - I don't have an address for that
>internal Tk proc, there is no stub for it.

You could do it the hard way.. Thankfully, the EXTERN macro is still
broken ;)

D:\tcl_workspace\tk_head\win>dumpbin /exports release/tk85.dll | findstr
"TkWinChildProc"
266 320 00021E71 _TkWinChildProc@16

It's got a funny name in the export table, but that's just __stdcall
convention. You should be able to grab it with GetProcAddress() and use
GetModuleHandle() to get the HMODULE of the loaded Tk.
--
David Gravereaux <davy...@pobox.com>
[species: human; planet: earth,milkyway(western spiral arm),alpha sector]

David Gravereaux

unread,
Feb 10, 2004, 6:32:33 PM2/10/04
to
David Gravereaux <davy...@pobox.com> wrote:

>j...@equi4.com (Jean-Claude Wippler) wrote:
>
>>I think Tkogl does that (drat, I've forgotten all Petzold ever told me
>>about Win32...).
>
>LOL... Got 2 of his books on my shelf..
>
>>The problem is not catching events. The problem is passing a them to
>>Tk by calling TkWinChildProc() - I don't have an address for that
>>internal Tk proc, there is no stub for it.
>
>You could do it the hard way.. Thankfully, the EXTERN macro is still
>broken ;)
>
>D:\tcl_workspace\tk_head\win>dumpbin /exports release/tk85.dll | findstr
>"TkWinChildProc"
> 266 320 00021E71 _TkWinChildProc@16
>
>It's got a funny name in the export table, but that's just __stdcall
>convention. You should be able to grab it with GetProcAddress() and use
>GetModuleHandle() to get the HMODULE of the loaded Tk.


Or another way would be to ask a window you know has TkWinChildProc as the
window proc for its address from the HWND with GetWindowLong ??

Iain B. Findleton

unread,
Feb 10, 2004, 8:55:26 PM2/10/04
to
Jean-Claude Wippler wrote:
> Iain Findleton <ifind...@yahoo.com> wrote...
>
>>>Tkogl uses a WndProc to capture WM_WINDOWPOSCHANGED and WM_MOVE
>>>events. For those, it wants to call TkWinChildProc - which is not in
>>>the stubs table.
>>>
>>>I've commented it out, and though a few demo's appear to work, many
>>>don't - the refresh never happens.
>
> [...]
>
>>1) grab the pointer to the Tk window's WndProc and save it somewhere
>>2) Install a pointer to your alias WndProc where you grabbed the pointer
>>from.
>>3) Your aliased WndProc simply forwards the events you are interested in
>>to the GL window's WndProc. You return a return code that tells the
>>alias what to do about the DefWndProc (i.e. Call it or not)
>>4) Do your own thing in the GL window.
>
>
> Thanks for your help.
>
> Wait... you're describing event overrides, right?

The "problem" with using something like GL is related to event loops. I
have not studied the code used by the Tkogl code, but the issue is that
Tk has an event loop under windows that dispatches events to windows
that it knows about. If you have another GUI that has its own event
router (i.e. and event loop), you need to arrange so that both event
routers get called.

There are a number of ways to do this. Tcl/Tk for instance, provides a
mechanism to hook into the event loop it runs, presumably for this
purpose. My Fltk extension uses this mechanism. When the Tcl/Tk event
loop runs, it invokes a hook that I insert which calls the Fltk event
loop. This works fine. I have also, in the past, used this mechanism to
call the OpenGL event loop, for example.

If you don't go this way, then you have to trap and route the events
from those routed by Tcl/Tk to your handler. Well, there are two obvious
ways to do it: Stuff a pointer to your window procedure somewhere so
that it gets the events from the event loop, and arrange to forward them
the the Tcl/Tk loop, or, create a wrapper window that Tk knows about,
such as a frame widget, alias its window procedure, and forward the
events caught by the alias to your window proc.

I am proposing the second approach. I suspect that the current Tkogl
code is using the first approach. I suspect this because your code says
that it gets the event, then sends it to the appropriate Tk window proc,
then calls the Tcl event loop initiator.

>
> I think Tkogl does that (drat, I've forgotten all Petzold ever told me
> about Win32...).
>
> The problem is not catching events. The problem is passing a them to
> Tk by calling TkWinChildProc() - I don't have an address for that
> internal Tk proc, there is no stub for it.
>
>
>>This allows you to do your think without ever knowing about Tk's window
>>handler functions. Both my animate and (now infamous) TkPrint extensions
>>use this technique. The original Tkprint from i forget where used the
>>kind of technique that you are describing for the togl thing.
>
>
> I couldn't find any source for the packages you mention - do you have
> an URL handy?
>

As I indicated to you in my earlier note, the code is written using
Borland OWL 4.5 in my extensions. Can you grok that? If yes, I can mail
you a tarball. If, as I suspect, this is useless to you, then I can't
see the point.


> Here's the relevant code from Tkogl, btw (edited for brevity):
>
> static LONG WINAPI WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM
> lParam)
> {
> LONG result;
> switch (msg) {
> case WM_WINDOWPOSCHANGED:
> case WM_MOVE:
> result = DefWindowProc(hwnd, msg, wParam, lParam);
> Tcl_ServiceAll();
> break;
> default:
> result = TkWinChildProc (hwnd, msg, wParam, lParam);
> }
> return result;
> }
>
> This captures all but WM_WINDOWPOSCHANGED and WM_MOVE, right?
>
> I don't understand what this is doing. Both of these call back into
> Tcl and Tk. So Tkogl isn't actually capturing any events. When I
> look in Tk's tkWinWm.c, I see a TopLevelProc which is quite similar,
> used as window proc. It does look like Tkogl creates its own window
> class.

This code is, to me, not the correct way to do things. But then, I am
not a programmer!

>
> FWIW, I'm using Tkogl 1.1 (not 3.0, which appears to be a major
> overhaul...) - home page at http://ganimede.lcg.ufrj.br/Projetos/tkogl
> - the code works in wish8.4, I'm merely trying to stubs-enable it so
> it can be used in a starkit and called from tclkit.
>

I understand wanting to make it stubs enabled. I can't really get into
an analysis of the code you are using. I can say, however, that
modifying the stubs interface to support the kind of thing the above
code is doing is probably a very bad idea. But again,...I am not a....

> -jcw

Jean-Claude Wippler

unread,
Feb 13, 2004, 5:50:38 AM2/13/04
to
David Gravereaux <davy...@pobox.com> wrote...

> >>The problem is not catching events. The problem is passing a them to
> >>Tk by calling TkWinChildProc() - I don't have an address for that
> >>internal Tk proc, there is no stub for it.
> >
> >You could do it the hard way.. Thankfully, the EXTERN macro is still
> >broken ;)

Tried that, but it looks like tclkit.exe does not export it.

> Or another way would be to ask a window you know has TkWinChildProc as the
> window proc for its address from the HWND with GetWindowLong ??

Bingo, that works!

Relevant code is:
HANDLE h = FindWindow("TkTopLevel",NULL);
if (h) h = FindWindowEx(h, NULL, "TkChild", NULL);
if (h) tkwcp = (WNDPROC) GetClassLong(h, GCL_WNDPROC);

The one requirement is that Tk is loaded and "update" has been called
before Tkogl is loaded, so at least one window is showing to grab the
windowproc from.

A stubs-enabled version of tkogl 1.1 for Windows is now at:
http://www.equi4.com/pub/etc/Tkogl.dll
I've also added a comment to http://wiki.tcl.tk/opengl

Thanks David and Ian for your great help.

-jcw

Reply all
Reply to author
Forward
0 new messages