Request for testing--Tk-Cocoa

View: New views
10 Messages — Rating Filter:   Alert me  

Request for testing--Tk-Cocoa

by Kevin Walzer-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi all,

To my knowledge I'm the only person who has filed any bugs against
Tk-Cocoa (now CVS HEAD of Tk 8.6) at SF. See
https://sourceforge.net/search/?group_artifact_id=112997&type_of_search=artifact&group_id=12997&words=cocoa.


I think it would be great if others would give Tk-Cocoa a serious test
drive and if anything else might be lurking there, and file the
appropriate bugs, and even patches if possible.

Thanks,
Kevin

--
Kevin Walzer
Code by Kevin
http://www.codebykevin.com

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac

Re: Request for testing--Tk-Cocoa

by Youness Alaoui-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Kevin, everyone,

You're right, we should probably all give tk-cocoa a spin... at least see if our apps run smoothly on it..

So anyways, I tried with the latest git from das's repository.. I had compiled an embeded Wish.app from the 'de-carbon-8-5' branch, and I tried to use aMSN with it, and the result is this : http://pastebin.com/m5d2397be
so now I've tried to compile the git master instead (since tk-cocoa is now merged into the master branch) and I got compilation issues because it couldn't compile tcl/pkgs/itcl and tcl/pkgs/tdbc/
so I had to delete the tcl/pkgs/*/configure files, so they don't get picked up by the Makefile.. 
Then Tcl built successfully...

But then I had another compilation issue, this time with Tk :
In file included from /Users/kakaroto/coding/tcltk/tk/unix/../macosx/tkMacOSXBitmap.c:16In file included from /Users/kakaroto/coding/tcltk/tk/unix/../macosx/tkMacOSXBitmap.c:16:
/Users/kakaroto/coding/tcltk/tk/unix/../macosx/tkMacOSXPrivate.h:29:49: error: objc/runtime.h: No such file or directory

Unfortunately, the makefile doesn't add /usr/include in the include dirs for gcc, so it can't find /usr/include/objc/runtime.h... but when I try to add it myself by exporting CFLAGS before doing the configure, I end up with an error because /usr/include/tcl.h is used instead of the one from my local build dir...

Anyways, I added -I/usr/include in AQUA_INCLUDES of Tk's Makefile (after the -I$(MAC_OSX_DIR).. but then I got another problem... this time here's the log : http://pastebin.com/m560cda72
I don't know how to fix this since Cocoa.h and Carbon.h seem to be included correctly, so I don't know why it can't find CGFloat and NSUInteger types...

Hope that helps!

KaKaRoTo


On Thu, Aug 13, 2009 at 7:12 PM, Kevin Walzer <kw@...> wrote:
Hi all,

To my knowledge I'm the only person who has filed any bugs against
Tk-Cocoa (now CVS HEAD of Tk 8.6) at SF. See
https://sourceforge.net/search/?group_artifact_id=112997&type_of_search=artifact&group_id=12997&words=cocoa.


I think it would be great if others would give Tk-Cocoa a serious test
drive and if anything else might be lurking there, and file the
appropriate bugs, and even patches if possible.

Thanks,
Kevin

--
Kevin Walzer
Code by Kevin
http://www.codebykevin.com

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac

Re: Request for testing--Tk-Cocoa

by Youness Alaoui-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

ah sorry, I fixed it just after sending the email.. I actually had exported CFLAGS and LDFLAGS in order to build a universal binary and I was using -isysroot /Developer/SDKs/MacOSX10.4u.sdk instead of the 10.5.sdk.. once I fixed my CFLAGS and LDFLAGS, Tk also compiled successfully...

Anyways, I tried running aMSN again, and I get the exact same crash as with the 8.5 Tk Cocoa...
I've uploaded the aMSN.app I'm using in case others want to try it and reproduce this bug in order to fix it... (it looks like aMSN loads, but then crashes once we try to create the UI).
You can get it from here :
It's a .tar.bz2 file, so you would need to 'tar -xjvf aMSN-Cocoa-8.6.app.tar.bz2' in order to get your .app dir, it's 25MB...

Thanks,
KaKaRoTo


On Fri, Aug 14, 2009 at 2:37 AM, Youness Alaoui <kakaroto@...> wrote:
Hi Kevin, everyone,

You're right, we should probably all give tk-cocoa a spin... at least see if our apps run smoothly on it..

So anyways, I tried with the latest git from das's repository.. I had compiled an embeded Wish.app from the 'de-carbon-8-5' branch, and I tried to use aMSN with it, and the result is this : http://pastebin.com/m5d2397be
so now I've tried to compile the git master instead (since tk-cocoa is now merged into the master branch) and I got compilation issues because it couldn't compile tcl/pkgs/itcl and tcl/pkgs/tdbc/
so I had to delete the tcl/pkgs/*/configure files, so they don't get picked up by the Makefile.. 
Then Tcl built successfully...

But then I had another compilation issue, this time with Tk :
In file included from /Users/kakaroto/coding/tcltk/tk/unix/../macosx/tkMacOSXBitmap.c:16In file included from /Users/kakaroto/coding/tcltk/tk/unix/../macosx/tkMacOSXBitmap.c:16:
/Users/kakaroto/coding/tcltk/tk/unix/../macosx/tkMacOSXPrivate.h:29:49: error: objc/runtime.h: No such file or directory

Unfortunately, the makefile doesn't add /usr/include in the include dirs for gcc, so it can't find /usr/include/objc/runtime.h... but when I try to add it myself by exporting CFLAGS before doing the configure, I end up with an error because /usr/include/tcl.h is used instead of the one from my local build dir...

Anyways, I added -I/usr/include in AQUA_INCLUDES of Tk's Makefile (after the -I$(MAC_OSX_DIR).. but then I got another problem... this time here's the log : http://pastebin.com/m560cda72
I don't know how to fix this since Cocoa.h and Carbon.h seem to be included correctly, so I don't know why it can't find CGFloat and NSUInteger types...

Hope that helps!

KaKaRoTo


On Thu, Aug 13, 2009 at 7:12 PM, Kevin Walzer <kw@...> wrote:
Hi all,

To my knowledge I'm the only person who has filed any bugs against
Tk-Cocoa (now CVS HEAD of Tk 8.6) at SF. See
https://sourceforge.net/search/?group_artifact_id=112997&type_of_search=artifact&group_id=12997&words=cocoa.


I think it would be great if others would give Tk-Cocoa a serious test
drive and if anything else might be lurking there, and file the
appropriate bugs, and even patches if possible.

Thanks,
Kevin

--
Kevin Walzer
Code by Kevin
http://www.codebykevin.com

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac



------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac

Re: Request for testing--Tk-Cocoa

by Daniel A. Steffen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Youness,

On Fri, Aug 14, 2009 at 08:37, Youness
Alaoui<kakaroto@...> wrote:
> So anyways, I tried with the latest git from das's repository.. I had
> compiled an embeded Wish.app from the 'de-carbon-8-5' branch, and I tried to
> use aMSN with it, and the result is this : http://pastebin.com/m5d2397be

the backtrace you pasted is somewhat bogus, e.g. there is no
TkpGetNativeAppBitmap + 4975, in general is is better to use a develop
build (i.e. with symbols) to produce meaningful backtraces in crash
reports.

In any case, I managed to reproduce this with my own build and the
aMSN tarball you provided, and it turns out that the NSException (not
a crash strictly speaking) is due to aMSN doing something slightly
peculiar: it is drawing a partially transparent image into a window
which has never been displayed yet...
Drawing images with alpha is implemented in Tk via XGetImage() of the
background behind the image followed by manual compositing and drawing
the resulting image.
In TkAqua Cocoa, XGetImage() is based on XCopyArea() which for windows
is implemented via  NSCopyBits() from the window backbuffer. This is
where the exception occurs because the NSWindow in question doesn't
have a backbuffer yet...
The fix is simple, c.f. patch below, just add a check for existence of
the underlying windowserver window before the call that causes an
exception in the absence of a backbuffer.
Will commit this to HEAD and de-carbon-8-5 shortly.

With this fix in place, aMSN appears to come up correctly, I have not
explored it further to see if there are any other issues.
If you discover any, please make sure to file them in the SF
bugtracker instead of/in addition to mentioning them here. I will have
little to no time to spend on Tk (and this list) in the next few
months unfortunately, so things that only get mentioned here are very
likely to get lost...

> so now I've tried to compile the git master instead (since tk-cocoa is now
> merged into the master branch) and I got compilation issues because it
> couldn't compile tcl/pkgs/itcl and tcl/pkgs/tdbc/
> so I had to delete the tcl/pkgs/*/configure files, so they don't get picked
> up by the Makefile..

Unfortunately the tcl git cvs mirror has some issues to be aware of:
due to limitations in git-cvsimport, it does not automatically handle
content on cvs vendor branches. The best way to workaround this is to
create your own branch from master and manually merge in the vendor
branches in the tcl repo (currently branches libtommath, itcl and
tdbc). Luckily changes to vendor branches are infrequent so this is no
a huge deal (I tried for quite some time to fix this deficiency but it
stems from fundamental issues in the cvsps tool that would take a
major effort to fix...)
My 'das' branch is an example in the tcltk git repo that has these
merges (along with some other small changes).
If you only want to get at the latest code, and don't intend to make
changes/do local development with the git repo, it is probably easier
to just use cvs and get the HEAD...

On Fri, Aug 14, 2009 at 09:01, Youness
Alaoui<kakaroto@...> wrote:
> ah sorry, I fixed it just after sending the email.. I actually had exported
> CFLAGS and LDFLAGS in order to build a universal binary and I was using
> -isysroot /Developer/SDKs/MacOSX10.4u.sdk instead of the 10.5.sdk..

indeed 10.5 or later is required both to build and to run TkAqua Cocoa.

HTH

Cheers,

Daniel

Index: macosx/tkMacOSXDraw.c
===================================================================
RCS file: /cvsroot/tktoolkit/tk/macosx/tkMacOSXDraw.c,v
retrieving revision 1.35
diff -u -p -r1.35 tkMacOSXDraw.c
--- macosx/tkMacOSXDraw.c 6 Jul 2009 20:29:21 -0000 1.35
+++ macosx/tkMacOSXDraw.c 14 Aug 2009 13:11:38 -0000
@@ -174,7 +174,8 @@ XCopyArea(
  TkMacOSXRestoreDrawingContext(&dc);
     } else if (TkMacOSXDrawableWindow(src)) {
  NSView *view = TkMacOSXDrawableView(srcDraw);
- NSInteger gs = [[view window] gState];
+ NSWindow *w = [view window];
+ NSInteger gs = [w windowNumber] > 0 ? [w gState] : 0;
  /* // alternative using per-view gState:
  NSInteger gs = [view gState];
  if (!gs) {

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac

Re: Request for testing--Tk-Cocoa

by Kevin Walzer-5 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi KaKaRoTo,

I was able to launch aMSN-Cocoa.

Here's some quick feedback based on some brief usage:

1. Screenshot of it after launch: Looks fine.

http://www.codebykevin.com/amsn-cocoa.png

2. I noticed that some of the menus had mixed sizes, etc. in the fonts:

http://www.codebykevin.com/amsn-menu.png

It looks like the aMSN menu entries were in a smaller font, and the
hard-coded menu items are in standard font. Tk-Carbon ignores custom
menu settings unless you enable the custom MDEF support that Daniel
Steffen added a couple of years ago. The Cocoa menu fully supports
standard menu customization such as font sizes, images, etc. In any
event this will need to be made more consistent.

3. I contributed a "windowlist" package that added a window menu item,
which Tom Hennigan committed: this package probably isn't needed with
Tk-Cocoa because Cocoa has a window menu built-in, it just needs to be
enabled with $menu.window. In the menu screenshot you'll see the
hard-coded window menu items (standard in Cocoa) and my custom entries.

4. I noticed the Growl plugin doesn't work with Tk-Cocoa. Not sure why
this is the case, but you might want to consider swapping out the binary
Tcl-Growl extension (now unsupported by the Growl team) for my own
macgrowl package--see http://www.codebykevin.com/opensource/oss.html .
My version talks to Growl via its AppleScript interface. It works fine
and is one less binary dependency to compile.

5. The build crashes when I try to bring up the preferences window. This
might be the same issue with image transparency that Daniel Steffen
noted. I have two backtraces, one from Crash Reporter:


1   libobjc.A.dylib               0x942aee3b objc_exception_throw + 40
2   com.apple.CoreFoundation       0x90ebee8b +[NSException
raise:format:arguments:] + 155
3   com.apple.Foundation           0x923e4e84 -[NSAssertionHandler
handleFailureInMethod:object:file:lineNumber:description:] + 116
4   com.apple.AppKit               0x9570099f -[NSView lockFocus] + 280
5   com.apple.AppKit               0x957efdce -[NSWindow gState] + 102
6   com.tcltk.tklibrary           0x001fb150 XCopyArea + 514
7   com.tcltk.tklibrary           0x002155e3 XGetImage + 253
8   com.tcltk.tklibrary           0x001b29b8
Tk_PhotoPutZoomedBlock_NoComposite + 9191
9   com.tcltk.tklibrary           0x001a3f16 Tk_RedrawImage + 169
10  com.tcltk.tklibrary           0x001f1bec TkpGetNativeAppBitmap + 4975
11  com.tcltk.tcllibrary           0x0a0a264e TclServiceIdle + 61
12  com.tcltk.tcllibrary           0x0a086f98 Tcl_DoOneEvent + 371
13  com.tcltk.tcllibrary           0x0a04eddc TclInThreadExit + 218
14  com.tcltk.tcllibrary           0x0a00e25b TclInvokeObjectCommand + 738
15  com.tcltk.tcllibrary           0x0a00dee5 TclNRRunCallbacks + 86
16  com.tcltk.tcllibrary           0x0a05237b TclStackAlloc + 7489
17  com.tcltk.tcllibrary           0x0a00dee5 TclNRRunCallbacks + 86
18  com.tcltk.tcllibrary           0x0a012130 Tcl_EvalObjv + 1826
19  com.tcltk.tcllibrary           0x0a01248f Tcl_EvalEx + 46
20  com.tcltk.tcllibrary           0x0a078db2 Tcl_FSEvalFileEx + 571
21  com.tcltk.tklibrary           0x0015d32d Tk_MainEx + 1484
22  com.tcltk.wish.amsn           0x0000563f 0x1000 + 17983
23  com.tcltk.wish.amsn           0x000055ea 0x1000 + 17898

...and one from Terminal:

009-08-14 10:50:05.627 aMSN[57763:10b] *** Assertion failure in
-[NSThemeFrame lockFocus],
/SourceCache/AppKit/AppKit-949.46/AppKit.subproj/NSView.m:4755
2009-08-14 10:50:05.633 aMSN[57763:10b] -[NSThemeFrame(0x14b1b70)
lockFocus] failed with window=0x14c1a90, windowNumber=-1, [self
isHiddenOrHasHiddenAncestor]=0
2009-08-14 10:50:06.463 aMSN[57763:10b] *** Assertion failure in
-[NSThemeFrame lockFocus],
/SourceCache/AppKit/AppKit-949.46/AppKit.subproj/NSView.m:4755
2009-08-14 10:50:06.464 aMSN[57763:10b] An uncaught exception was raised
2009-08-14 10:50:06.464 aMSN[57763:10b] -[NSThemeFrame(0x14b1b70)
lockFocus] failed with window=0x14c1a90, windowNumber=-1, [self
isHiddenOrHasHiddenAncestor]=0
2009-08-14 10:50:06.465 aMSN[57763:10b] *** Terminating app due to
uncaught exception 'NSInternalInconsistencyException', reason:
'-[NSThemeFrame(0x14b1b70) lockFocus] failed with window=0x14c1a90,
windowNumber=-1, [self isHiddenOrHasHiddenAncestor]=0'

I'm not an expert here, but if you post a revised build based on
Daniel's patch, I'll take another look.

6. aMSN-Cocoa kept losing its connection to the MSN server. Regular aMSN
does not display this problem. It was not related to network issues on
my machine, it appeared to be simply dropping its connection and
reconnecting at random intervals. I have no idea what the problem is,
just that I do not see a similar issue in aMSN-Carbon.

Hope this helps,
Kevin

--
Kevin Walzer
Code by Kevin
http://www.codebykevin.com

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac

Re: Request for testing--Tk-Cocoa

by Daniel A. Steffen-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Kevin,

On Fri, Aug 14, 2009 at 17:02, Kevin Walzer<kw@...> wrote:
> 5. The build crashes when I try to bring up the preferences window. This
> might be the same issue with image transparency that Daniel Steffen
> noted. I have two backtraces, one from Crash Reporter:

that definitely looks like the same problem. I just committed the
patch for this in HEAD, if you do an embedded build from HEAD and
replace the frameworks in aMSN-Cocoa-8.6.app/Contents/Frameworks with
the frameworks from embedded Wish.app you should be able to test the
fix.

Cheers,

Daniel

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac

Re: Request for testing--Tk-Cocoa

by Youness Alaoui-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks Daniel for the quick patch! I can confirm your fix works fine here! If I find any more crashes/exceptions, I'll report it to the tk SF tracker. 
Thanks Kevin for the nice test you did on aMSN! I'll try to fix all those issues and start using Tk Cocoa from now on so I can find any new bugs after a long run and daily use.
By the way, I also noticed 3 other issues :
1 - drawing widgets seems extremely slow compared to TkCarbon, try the preferences window and change from one tab to another, you'll see it draw each widget one at a time, while on Carbon, it was instantenuous.
2 - At one point, when I opened the preferences window, aMSN froze, I used Command-, and the 'aMSN' menu stayed highlited, and it looked as if the runloop had stopped because it didn't handle my mouse events anymore (focus on windows, or the close/minimize/maximize buttons stopped getting hovered..). It doesn't always happen, but it's still easily reproducable... 
3 - there's a little icon in the titlebar before the title of each of the chat windows...
I'll file these bugs (1 and 2) to the Tk SF tracker.
Thanks,
KaKaRoTo

On Fri, Aug 14, 2009 at 11:13 AM, Daniel A. Steffen <das@...> wrote:
Hi Kevin,

On Fri, Aug 14, 2009 at 17:02, Kevin Walzer<kw@...> wrote:
> 5. The build crashes when I try to bring up the preferences window. This
> might be the same issue with image transparency that Daniel Steffen
> noted. I have two backtraces, one from Crash Reporter:

that definitely looks like the same problem. I just committed the
patch for this in HEAD, if you do an embedded build from HEAD and
replace the frameworks in aMSN-Cocoa-8.6.app/Contents/Frameworks with
the frameworks from embedded Wish.app you should be able to test the
fix.

Cheers,

Daniel


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac

Parent Message unknown Re: Request for testing--Tk-Cocoa

by Daniel A. Steffen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Youness,

On Fri, Aug 14, 2009 at 19:26, Youness
Alaoui<kakaroto@...> wrote:
> 1 - drawing widgets seems extremely slow compared to TkCarbon, try the
> preferences window and change from one tab to another, you'll see it draw
> each widget one at a time, while on Carbon, it was instantenuous.

I haven't observed slowness, but I have seen rendering freezes, due to
the issue below

> 2 - At one point, when I opened the preferences window, aMSN froze, I used
> Command-, and the 'aMSN' menu stayed highlited, and it looked as if the
> runloop had stopped because it didn't handle my mouse events anymore (focus
> on windows, or the close/minimize/maximize buttons stopped getting
> hovered..). It doesn't always happen, but it's still easily reproducable...

I have seen that, breaking into the debugger at that point shows that
this is caused by aMSN calling [update] or [vwait] at inopportune
times (e.g. I have seen these called from an [after] event handler and
from a channel notification handler), doing this causes recursive
entry of the runloop at locations where Tk and AppKit do not expect
this to happen...

The tcl event loop is called more frequently in TkAqua Cocoa than it
was in Carbon (Cocoa internally uses nested runloops more frequently,
and tcl events are processed as part of every nested runloop traversal
in fact, c.f. tclMacOSXNotify.c), this does have advantages like
allowing fileevent & timer processing during menu/control etc tracking
for instance, but this does also give you more rope to hang yourself
with...

In general, [update] and [vwait] should only rarely need to be called
in an event-driven app, and certainly should not be called from any
code that can be run from inside an event handler or any other code
executed as part of event loop traversal, doing that is just asking
for trouble and has the potential for re-entering those same event
handlers and causing deep recursion & other bugs (c.f. tk bug 2830991
as another example of this). The issue of nested [vwait]s etc is not
unique to TkAqua Cocoa, it causes problems on other platforms as well,
c.f. wiki & tcl-core discussion a while back. You may want to
investigate using coroutines and [yield] in Tcl 8.6 to replace
instances of where you are currently using [vwait].

Cheers,

Daniel

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac

Re: Request for testing--Tk-Cocoa

by Daniel A. Steffen :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Youness,

On Fri, Aug 14, 2009 at 22:06, Daniel A.
Steffen<das@...> wrote:
> On Fri, Aug 14, 2009 at 19:26, Youness
> Alaoui<kakaroto@...> wrote:
>> 1 - drawing widgets seems extremely slow compared to TkCarbon, try the
>> preferences window and change from one tab to another, you'll see it draw
>> each widget one at a time, while on Carbon, it was instantenuous.
>
> I haven't observed slowness

with the workaround for 2. below in place, I have now also observed
this as well.
It turns out to be related to the idle-time redrawing behaviour of Tk,
 the only items affected are widgets drawn via native NSViews, i.e.
push/check/radiobuttons, scrollbars and menubuttons.

At idle time when these are drawn, NSWindow flushing is enabled
(whereas in the ordinary AppKit draw loop it is disabled) and thus
their drawing is immediately flushed to screen.
To workaround this it suffices to disable/enable flushing for the
containing window in TkMacOSXSetup/RestoreDrawingContext(), c.f. patch
below (against de-carbon-8-5, but should apply to HEAD as well).
Note that the window is always flushed at the next passage through the
event loop anyway (via -tkDisplayIfNeeded), or upon explicit call to
[update] (via XSync()).

The patch avoids the issue and AFAICT doesn't appear to break
anything, but I would appreciate some wider testing before I commit.

>> 2 - At one point, when I opened the preferences window, aMSN froze, I used
>> Command-, and the 'aMSN' menu stayed highlited, and it looked as if the
>> runloop had stopped because it didn't handle my mouse events anymore (focus
>> on windows, or the close/minimize/maximize buttons stopped getting
>> hovered..). It doesn't always happen, but it's still easily reproducable...
>
> I have seen that, breaking into the debugger at that point shows that
> this is caused by aMSN calling [update] or [vwait] at inopportune
> times (e.g. I have seen these called from an [after] event handler and
> from a channel notification handler), doing this causes recursive
> entry of the runloop at locations where Tk and AppKit do not expect
> this to happen...

I cannot do anything about the nested [vwait]s, but I have been able
to avoid the lockups from nested [update]s, c.f. patch to tcl notifier
below. It should only affect code running with the notifier in
embedded mode (i.e. probably only TkAqua Cocoa so far), certainly the
tcl test suite appears unaffected.

The fix consists mainly of making sure that event loops entered
recursively from the runloop observer's Tcl_ServiceAll() processing
(e.g. via some event handler calling [update]) run in the
tcl-events-only runloop mode, and that polling Tcl_WaitForEvent()'s
called at that time wake up the notifier thread in all cases.
The one tricky thing is that a second runloop observer is needed for
the tcl-events-only runloop mode (with the same observer handler as
the original), as it turns out that CFRunLoop prevents the handler of
a given observer from being entered recursively...

As this is a slightly more invasive change, I would appreciate if a
few people could do some testing and running of the tcl testsuite to
make sure this is not breaking something unexpected, I don't have time
to do extensive testing myself ATM...

Thanks!

Cheers,

Daniel

--
** Daniel A. Steffen                   **
** <mailto:das@...> **


diff --git tk/macosx/tkMacOSXDraw.c tk/macosx/tkMacOSXDraw.c
index 83492e8..23dd70e 100644
--- tk/macosx/tkMacOSXDraw.c
+++ tk/macosx/tkMacOSXDraw.c
@@ -1565,6 +1565,7 @@ TkMacOSXSetupDrawingContext(
     if (dontDraw) {
  goto end;
     }
+    [[view window] disableFlushWindow];
     dc.view = view;
     dc.context = [[NSGraphicsContext currentContext] graphicsPort];
     dc.portBounds = NSRectToCGRect([view bounds]);
@@ -1690,6 +1691,7 @@ TkMacOSXRestoreDrawingContext(
 {
     if (dcPtr->context) {
  CGContextSynchronize(dcPtr->context);
+ [[dcPtr->view window] enableFlushWindow];
  if (dcPtr->focusLocked) {
     [dcPtr->view unlockFocus];
  } else {
diff --git tcl/macosx/tclMacOSXNotify.c tcl/macosx/tclMacOSXNotify.c
index 706c988..193a46e 100644
--- tcl/macosx/tclMacOSXNotify.c
+++ tcl/macosx/tclMacOSXNotify.c
@@ -246,6 +246,8 @@ typedef struct ThreadSpecificData {
  * performed. */
     int runLoopRunning; /* True if this thread's Tcl runLoop is running */
     int runLoopNestingLevel; /* Level of nested runLoop invocations */
+    int runLoopServicingEvents; /* True if this thread's runLoop is servicing
+ * tcl events */
     /* Must hold the notifierLock before accessing the following fields: */
     /* Start notifierLock section */
     int onList; /* True if this thread is on the waitingList */
@@ -277,7 +279,7 @@ typedef struct ThreadSpecificData {
  /* Any other thread alerts a notifier that an
  * event is ready to be processed by signaling
  * this CFRunLoopSource. */
-    CFRunLoopObserverRef runLoopObserver;
+    CFRunLoopObserverRef runLoopObserver, runLoopObserverTcl;
  /* Adds/removes this thread from waitingList
  * when the CFRunLoop starts/stops. */
     CFRunLoopTimerRef runLoopTimer;
@@ -453,7 +455,7 @@ Tcl_InitNotifier(void)
  CFRunLoopSourceRef runLoopSource;
  CFRunLoopSourceContext runLoopSourceContext;
  CFRunLoopObserverContext runLoopObserverContext;
- CFRunLoopObserverRef runLoopObserver;
+ CFRunLoopObserverRef runLoopObserver, runLoopObserverTcl;

  bzero(&runLoopSourceContext, sizeof(CFRunLoopSourceContext));
  runLoopSourceContext.info = tsdPtr;
@@ -477,12 +479,21 @@ Tcl_InitNotifier(void)
     "CFRunLoopObserver");
  }
  CFRunLoopAddObserver(runLoop, runLoopObserver, kCFRunLoopCommonModes);
- CFRunLoopAddObserver(runLoop, runLoopObserver,
+ runLoopObserverTcl = CFRunLoopObserverCreate(NULL,
+ kCFRunLoopEntry|kCFRunLoopExit|kCFRunLoopBeforeWaiting, TRUE,
+ LONG_MIN, UpdateWaitingListAndServiceEvents,
+ &runLoopObserverContext);
+ if (!runLoopObserverTcl) {
+    Tcl_Panic("Tcl_InitNotifier: could not create "
+    "CFRunLoopObserver");
+ }
+ CFRunLoopAddObserver(runLoop, runLoopObserverTcl,
  tclEventsOnlyRunLoopMode);

  tsdPtr->runLoop = runLoop;
  tsdPtr->runLoopSource = runLoopSource;
  tsdPtr->runLoopObserver = runLoopObserver;
+ tsdPtr->runLoopObserverTcl = runLoopObserverTcl;
  tsdPtr->runLoopTimer = NULL;
  tsdPtr->waitTime = CF_TIMEINTERVAL_FOREVER;
  tsdPtr->tsdLock = SPINLOCK_INIT;
@@ -710,6 +721,9 @@ Tcl_FinalizeNotifier(
  CFRunLoopObserverInvalidate(tsdPtr->runLoopObserver);
  CFRelease(tsdPtr->runLoopObserver);
  tsdPtr->runLoopObserver = NULL;
+ CFRunLoopObserverInvalidate(tsdPtr->runLoopObserverTcl);
+ CFRelease(tsdPtr->runLoopObserverTcl);
+ tsdPtr->runLoopObserverTcl = NULL;
  if (tsdPtr->runLoopTimer) {
     CFRunLoopTimerInvalidate(tsdPtr->runLoopTimer);
     CFRelease(tsdPtr->runLoopTimer);
@@ -1150,9 +1164,8 @@ int
 Tcl_WaitForEvent(
     Tcl_Time *timePtr) /* Maximum block time, or NULL. */
 {
-    int result, polling;
+    int result, polling, runLoopRunning;
     CFTimeInterval waitTime;
-    CFStringRef runLoopMode;
     SInt32 runLoopStatus;
     ThreadSpecificData *tsdPtr;

@@ -1206,16 +1219,12 @@ Tcl_WaitForEvent(
      * added to the common run loop modes might get lost.
      */

-    if (tsdPtr->runLoopRunning) {
- runLoopMode = tclEventsOnlyRunLoopMode;
-    } else {
- runLoopMode = kCFRunLoopDefaultMode;
- tsdPtr->runLoopRunning = 1;
-    }
-    runLoopStatus = CFRunLoopRunInMode(runLoopMode, waitTime, TRUE);
-    if (runLoopMode == kCFRunLoopDefaultMode) {
- tsdPtr->runLoopRunning = 0;
-    }
+    runLoopRunning = tsdPtr->runLoopRunning;
+    tsdPtr->runLoopRunning = 1;
+    runLoopStatus = CFRunLoopRunInMode(tsdPtr->runLoopServicingEvents ||
+    runLoopRunning ? tclEventsOnlyRunLoopMode : kCFRunLoopDefaultMode,
+    waitTime, TRUE);
+    tsdPtr->runLoopRunning = runLoopRunning;

     LOCK_NOTIFIER_TSD;
     tsdPtr->polling = 0;
@@ -1333,19 +1342,22 @@ UpdateWaitingListAndServiceEvents(
 {
     ThreadSpecificData *tsdPtr = (ThreadSpecificData*) info;

+    if (tsdPtr->sleeping) {
+ return;
+    }
     switch (activity) {
     case kCFRunLoopEntry:
  tsdPtr->runLoopNestingLevel++;
- if (tsdPtr->runLoopNestingLevel == 1 && !tsdPtr->sleeping &&
- (tsdPtr->numFdBits > 0 || tsdPtr->polling)) {
+ if (tsdPtr->numFdBits > 0 || tsdPtr->polling) {
     LOCK_NOTIFIER;
-    OnOffWaitingList(tsdPtr, 1, 1);
+    if (!OnOffWaitingList(tsdPtr, 1, 1) && tsdPtr->polling) {
+       write(triggerPipe, "", 1);
+    }
     UNLOCK_NOTIFIER;
  }
  break;
     case kCFRunLoopExit:
- if (tsdPtr->runLoopNestingLevel == 1 && !tsdPtr->sleeping &&
- (tsdPtr->numFdBits > 0 || tsdPtr->polling)) {
+ if (tsdPtr->runLoopNestingLevel == 1) {
     LOCK_NOTIFIER;
     OnOffWaitingList(tsdPtr, 0, 1);
     UNLOCK_NOTIFIER;
@@ -1353,9 +1365,11 @@ UpdateWaitingListAndServiceEvents(
  tsdPtr->runLoopNestingLevel--;
  break;
     case kCFRunLoopBeforeWaiting:
- if (!tsdPtr->sleeping && tsdPtr->runLoopTimer &&
+ if (tsdPtr->runLoopTimer && !tsdPtr->runLoopServicingEvents &&
  (tsdPtr->runLoopNestingLevel > 1 || !tsdPtr->runLoopRunning)) {
+    tsdPtr->runLoopServicingEvents = 1;
     while (Tcl_ServiceAll() && tsdPtr->waitTime == 0) {}
+    tsdPtr->runLoopServicingEvents = 0;
  }
  break;
     default:

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac

Re: Request for testing--Tk-Cocoa

by Youness Alaoui-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Daniel,

On Fri, Aug 14, 2009 at 9:26 PM, Daniel A. Steffen <das@...> wrote:
Hi Youness,

On Fri, Aug 14, 2009 at 22:06, Daniel A.
Steffen<das@...> wrote:
> On Fri, Aug 14, 2009 at 19:26, Youness
> Alaoui<kakaroto@...> wrote:
>> 1 - drawing widgets seems extremely slow compared to TkCarbon, try the
>> preferences window and change from one tab to another, you'll see it draw
>> each widget one at a time, while on Carbon, it was instantenuous.
>
> I haven't observed slowness

with the workaround for 2. below in place, I have now also observed
this as well.
It turns out to be related to the idle-time redrawing behaviour of Tk,
 the only items affected are widgets drawn via native NSViews, i.e.
push/check/radiobuttons, scrollbars and menubuttons.

At idle time when these are drawn, NSWindow flushing is enabled
(whereas in the ordinary AppKit draw loop it is disabled) and thus
their drawing is immediately flushed to screen.
To workaround this it suffices to disable/enable flushing for the
containing window in TkMacOSXSetup/RestoreDrawingContext(), c.f. patch
below (against de-carbon-8-5, but should apply to HEAD as well).
Note that the window is always flushed at the next passage through the
event loop anyway (via -tkDisplayIfNeeded), or upon explicit call to
[update] (via XSync()).

The patch avoids the issue and AFAICT doesn't appear to break
anything, but I would appreciate some wider testing before I commit.
Hi, I've tested it and seems to work just fine, the slowness compeltely disappeared now! Good job!
 


>> 2 - At one point, when I opened the preferences window, aMSN froze, I used
>> Command-, and the 'aMSN' menu stayed highlited, and it looked as if the
>> runloop had stopped because it didn't handle my mouse events anymore (focus
>> on windows, or the close/minimize/maximize buttons stopped getting
>> hovered..). It doesn't always happen, but it's still easily reproducable...
>
> I have seen that, breaking into the debugger at that point shows that
> this is caused by aMSN calling [update] or [vwait] at inopportune
> times (e.g. I have seen these called from an [after] event handler and
> from a channel notification handler), doing this causes recursive
> entry of the runloop at locations where Tk and AppKit do not expect
> this to happen...

I cannot do anything about the nested [vwait]s, but I have been able
to avoid the lockups from nested [update]s, c.f. patch to tcl notifier
below. It should only affect code running with the notifier in
embedded mode (i.e. probably only TkAqua Cocoa so far), certainly the
tcl test suite appears unaffected.

The fix consists mainly of making sure that event loops entered
recursively from the runloop observer's Tcl_ServiceAll() processing
(e.g. via some event handler calling [update]) run in the
tcl-events-only runloop mode, and that polling Tcl_WaitForEvent()'s
called at that time wake up the notifier thread in all cases.
The one tricky thing is that a second runloop observer is needed for
the tcl-events-only runloop mode (with the same observer handler as
the original), as it turns out that CFRunLoop prevents the handler of
a given observer from being entered recursively...

As this is a slightly more invasive change, I would appreciate if a
few people could do some testing and running of the tcl testsuite to
make sure this is not breaking something unexpected, I don't have time
to do extensive testing myself ATM...
I tested de-carbon-8-5 (to which you already committed these patches) and it worked nicely.I tried the preferences window a couple of times and it worked correctly, and I haven't experienced a freeze so far. Good job Daniel!
By the way, slightly off-topic, I've heard all the rumors about the [update] command to avoid, etc.. but it's a bit hard to do that, we use it a lot in a lot of cases, and in all cases, we had absolutely no choice... and considering that any function call in Tk is the result of an 'after' or a file event, or a UI interaction, etc.. it would be useless to have 'update' but not be able to use it in some obscure situations... 
About [vwait], I didn't know we used that... Would it make a difference to use [tkwait variable] or is that just the exact same thing? There are some use cases where we also have no choice but to use that command ([tkwait variable]), so...
In any case, so far so good, it seems to work fine, thanks!
Thanks again,
Youness.
 


Thanks!

Cheers,

Daniel

--
** Daniel A. Steffen                   **
** <mailto:das@...> **


diff --git tk/macosx/tkMacOSXDraw.c tk/macosx/tkMacOSXDraw.c
index 83492e8..23dd70e 100644
--- tk/macosx/tkMacOSXDraw.c
+++ tk/macosx/tkMacOSXDraw.c
@@ -1565,6 +1565,7 @@ TkMacOSXSetupDrawingContext(
           if (dontDraw) {
               goto end;
           }
+           [[view window] disableFlushWindow];
           dc.view = view;
           dc.context = [[NSGraphicsContext currentContext] graphicsPort];
           dc.portBounds = NSRectToCGRect([view bounds]);
@@ -1690,6 +1691,7 @@ TkMacOSXRestoreDrawingContext(
 {
    if (dcPtr->context) {
       CGContextSynchronize(dcPtr->context);
+       [[dcPtr->view window] enableFlushWindow];
       if (dcPtr->focusLocked) {
           [dcPtr->view unlockFocus];
       } else {
diff --git tcl/macosx/tclMacOSXNotify.c tcl/macosx/tclMacOSXNotify.c
index 706c988..193a46e 100644
--- tcl/macosx/tclMacOSXNotify.c
+++ tcl/macosx/tclMacOSXNotify.c
@@ -246,6 +246,8 @@ typedef struct ThreadSpecificData {
                                * performed. */
    int runLoopRunning;                /* True if this thread's Tcl runLoop is running */
    int runLoopNestingLevel;   /* Level of nested runLoop invocations */
+    int runLoopServicingEvents;        /* True if this thread's runLoop is servicing
+                                * tcl events */
    /* Must hold the notifierLock before accessing the following fields: */
    /* Start notifierLock section */
    int onList;                        /* True if this thread is on the waitingList */
@@ -277,7 +279,7 @@ typedef struct ThreadSpecificData {
                               /* Any other thread alerts a notifier that an
                                * event is ready to be processed by signaling
                                * this CFRunLoopSource. */
-    CFRunLoopObserverRef runLoopObserver;
+    CFRunLoopObserverRef runLoopObserver, runLoopObserverTcl;
                               /* Adds/removes this thread from waitingList
                                * when the CFRunLoop starts/stops. */
    CFRunLoopTimerRef runLoopTimer;
@@ -453,7 +455,7 @@ Tcl_InitNotifier(void)
       CFRunLoopSourceRef runLoopSource;
       CFRunLoopSourceContext runLoopSourceContext;
       CFRunLoopObserverContext runLoopObserverContext;
-       CFRunLoopObserverRef runLoopObserver;
+       CFRunLoopObserverRef runLoopObserver, runLoopObserverTcl;

       bzero(&runLoopSourceContext, sizeof(CFRunLoopSourceContext));
       runLoopSourceContext.info = tsdPtr;
@@ -477,12 +479,21 @@ Tcl_InitNotifier(void)
                   "CFRunLoopObserver");
       }
       CFRunLoopAddObserver(runLoop, runLoopObserver, kCFRunLoopCommonModes);
-       CFRunLoopAddObserver(runLoop, runLoopObserver,
+       runLoopObserverTcl = CFRunLoopObserverCreate(NULL,
+               kCFRunLoopEntry|kCFRunLoopExit|kCFRunLoopBeforeWaiting, TRUE,
+               LONG_MIN, UpdateWaitingListAndServiceEvents,
+               &runLoopObserverContext);
+       if (!runLoopObserverTcl) {
+           Tcl_Panic("Tcl_InitNotifier: could not create "
+                   "CFRunLoopObserver");
+       }
+       CFRunLoopAddObserver(runLoop, runLoopObserverTcl,
               tclEventsOnlyRunLoopMode);

       tsdPtr->runLoop = runLoop;
       tsdPtr->runLoopSource = runLoopSource;
       tsdPtr->runLoopObserver = runLoopObserver;
+       tsdPtr->runLoopObserverTcl = runLoopObserverTcl;
       tsdPtr->runLoopTimer = NULL;
       tsdPtr->waitTime = CF_TIMEINTERVAL_FOREVER;
       tsdPtr->tsdLock = SPINLOCK_INIT;
@@ -710,6 +721,9 @@ Tcl_FinalizeNotifier(
       CFRunLoopObserverInvalidate(tsdPtr->runLoopObserver);
       CFRelease(tsdPtr->runLoopObserver);
       tsdPtr->runLoopObserver = NULL;
+       CFRunLoopObserverInvalidate(tsdPtr->runLoopObserverTcl);
+       CFRelease(tsdPtr->runLoopObserverTcl);
+       tsdPtr->runLoopObserverTcl = NULL;
       if (tsdPtr->runLoopTimer) {
           CFRunLoopTimerInvalidate(tsdPtr->runLoopTimer);
           CFRelease(tsdPtr->runLoopTimer);
@@ -1150,9 +1164,8 @@ int
 Tcl_WaitForEvent(
    Tcl_Time *timePtr)         /* Maximum block time, or NULL. */
 {
-    int result, polling;
+    int result, polling, runLoopRunning;
    CFTimeInterval waitTime;
-    CFStringRef runLoopMode;
    SInt32 runLoopStatus;
    ThreadSpecificData *tsdPtr;

@@ -1206,16 +1219,12 @@ Tcl_WaitForEvent(
     * added to the common run loop modes might get lost.
     */

-    if (tsdPtr->runLoopRunning) {
-       runLoopMode = tclEventsOnlyRunLoopMode;
-    } else {
-       runLoopMode = kCFRunLoopDefaultMode;
-       tsdPtr->runLoopRunning = 1;
-    }
-    runLoopStatus = CFRunLoopRunInMode(runLoopMode, waitTime, TRUE);
-    if (runLoopMode == kCFRunLoopDefaultMode) {
-       tsdPtr->runLoopRunning = 0;
-    }
+    runLoopRunning = tsdPtr->runLoopRunning;
+    tsdPtr->runLoopRunning = 1;
+    runLoopStatus = CFRunLoopRunInMode(tsdPtr->runLoopServicingEvents ||
+           runLoopRunning ? tclEventsOnlyRunLoopMode : kCFRunLoopDefaultMode,
+           waitTime, TRUE);
+    tsdPtr->runLoopRunning = runLoopRunning;

    LOCK_NOTIFIER_TSD;
    tsdPtr->polling = 0;
@@ -1333,19 +1342,22 @@ UpdateWaitingListAndServiceEvents(
 {
    ThreadSpecificData *tsdPtr = (ThreadSpecificData*) info;

+    if (tsdPtr->sleeping) {
+       return;
+    }
    switch (activity) {
    case kCFRunLoopEntry:
       tsdPtr->runLoopNestingLevel++;
-       if (tsdPtr->runLoopNestingLevel == 1 && !tsdPtr->sleeping &&
-               (tsdPtr->numFdBits > 0 || tsdPtr->polling)) {
+       if (tsdPtr->numFdBits > 0 || tsdPtr->polling) {
           LOCK_NOTIFIER;
-           OnOffWaitingList(tsdPtr, 1, 1);
+           if (!OnOffWaitingList(tsdPtr, 1, 1) && tsdPtr->polling) {
+              write(triggerPipe, "", 1);
+           }
           UNLOCK_NOTIFIER;
       }
       break;
    case kCFRunLoopExit:
-       if (tsdPtr->runLoopNestingLevel == 1 && !tsdPtr->sleeping &&
-               (tsdPtr->numFdBits > 0 || tsdPtr->polling)) {
+       if (tsdPtr->runLoopNestingLevel == 1) {
           LOCK_NOTIFIER;
           OnOffWaitingList(tsdPtr, 0, 1);
           UNLOCK_NOTIFIER;
@@ -1353,9 +1365,11 @@ UpdateWaitingListAndServiceEvents(
       tsdPtr->runLoopNestingLevel--;
       break;
    case kCFRunLoopBeforeWaiting:
-       if (!tsdPtr->sleeping && tsdPtr->runLoopTimer &&
+       if (tsdPtr->runLoopTimer && !tsdPtr->runLoopServicingEvents &&
               (tsdPtr->runLoopNestingLevel > 1 || !tsdPtr->runLoopRunning)) {
+           tsdPtr->runLoopServicingEvents = 1;
           while (Tcl_ServiceAll() && tsdPtr->waitTime == 0) {}
+           tsdPtr->runLoopServicingEvents = 0;
       }
       break;
    default:


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tcl-mac mailing list
tcl-mac@...
https://lists.sourceforge.net/lists/listinfo/tcl-mac