00001
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00033
00034 #ifndef GROOVX_TK_WIDGET_CC_UTC20050628165845_DEFINED
00035 #define GROOVX_TK_WIDGET_CC_UTC20050628165845_DEFINED
00036
00037 #include "tk/widget.h"
00038
00039 #include "geom/vec2.h"
00040
00041 #include "nub/ref.h"
00042
00043 #include "tcl/interp.h"
00044
00045 #include "rutz/error.h"
00046 #include "rutz/fstring.h"
00047 #include "rutz/sfmt.h"
00048
00049 #include <cstdio>
00050 #include <iostream>
00051 #include <tcl.h>
00052 #include <tk.h>
00053 #include <X11/Xutil.h>
00054
00055 #include "rutz/trace.h"
00056 #include "rutz/debug.h"
00057 GVX_DBG_REGISTER
00058
00059 using rutz::fstring;
00060
00061 namespace WindowSystem
00062 {
00063 void winInfo(Tk_Window tkWin);
00064 void iconify(Tk_Window tkWin);
00065 void grabKeyboard(Tk_Window tkWin);
00066 void ungrabKeyboard(Tk_Window tkWin);
00067 }
00068
00069 #if defined(GVX_GL_PLATFORM_GLX)
00070
00071 void WindowSystem::winInfo(Tk_Window tkWin)
00072 {
00073 GVX_TRACE("WindowSystem::winInfo[glx]");
00074 Display* dpy = Tk_Display(tkWin);
00075
00076 int natoms = 0;
00077 Atom* atoms = XListProperties(dpy, Tk_WindowId(tkWin),
00078 &natoms);
00079
00080 fprintf(stderr, "%d atoms\n", natoms);
00081
00082 for (int i = 0; i < natoms; ++i)
00083 {
00084 const char* name = XGetAtomName(dpy, atoms[i]);
00085
00086 fprintf(stderr, "[%d] %s\n", i, name);
00087
00088 long long_offset = 0;
00089 long long_length = 16;
00090
00091 Atom actual_type_return = 0;
00092 int actual_format_return = 0;
00093 unsigned long nitems_return = 0;
00094 unsigned long bytes_after_return = 0;
00095 unsigned char* prop_return = 0;
00096
00097 XGetWindowProperty(dpy, Tk_WindowId(tkWin),
00098 atoms[i],
00099 long_offset,
00100 long_length,
00101 False,
00102 AnyPropertyType,
00103 &actual_type_return,
00104 &actual_format_return,
00105 &nitems_return,
00106 &bytes_after_return,
00107 &prop_return);
00108
00109 XFree(prop_return);
00110 }
00111
00112 XFree(atoms);
00113 }
00114
00115 void WindowSystem::iconify(Tk_Window tkWin)
00116 {
00117 GVX_TRACE("WindowSystem::iconify[glx]");
00118 XIconifyWindow(Tk_Display(tkWin),
00119 Tk_WindowId(tkWin),
00120 Tk_ScreenNumber(tkWin));
00121 }
00122
00123 void WindowSystem::grabKeyboard(Tk_Window tkWin)
00124 {
00125 GVX_TRACE("WindowSystem::grabKeyboard[glx]");
00126 const int result =
00127 XGrabKeyboard(Tk_Display(tkWin),
00128 Tk_WindowId(tkWin),
00129 False ,
00130 GrabModeAsync ,
00131 GrabModeAsync ,
00132 CurrentTime );
00133
00134 switch (result)
00135 {
00136 case AlreadyGrabbed:
00137 throw rutz::error("couldn't grab keyboard: keyboard already grabbed", SRC_POS);
00138 case GrabNotViewable:
00139 throw rutz::error("couldn't grab keyboard: grab window not viewable", SRC_POS);
00140 case GrabInvalidTime:
00141 throw rutz::error("couldn't grab keyboard: grab time invalid", SRC_POS);
00142 case GrabFrozen:
00143 throw rutz::error("couldn't grab keyboard: pointer already frozen", SRC_POS);
00144 }
00145 }
00146
00147 void WindowSystem::ungrabKeyboard(Tk_Window tkWin)
00148 {
00149 GVX_TRACE("WindowSystem::ungrabKeyboard[glx]");
00150 XUngrabKeyboard(Tk_Display(tkWin), CurrentTime);
00151 }
00152
00153 #elif defined(GVX_GL_PLATFORM_AGL)
00154
00155 void WindowSystem::winInfo(Tk_Window )
00156 {
00157 GVX_TRACE("WindowSystem::winInfo[agl]");
00158
00159 throw rutz::error("WindowSystem::winInfo not supported", SRC_POS);
00160 }
00161
00162 void WindowSystem::iconify(Tk_Window )
00163 {
00164 GVX_TRACE("WindowSystem::iconify[agl]");
00165
00166 throw rutz::error("WindowSystem::iconify not supported", SRC_POS);
00167 }
00168
00169 void WindowSystem::grabKeyboard(Tk_Window )
00170 {
00171 GVX_TRACE("WindowSystem::grabKeyboard[agl]");
00172
00173 }
00174
00175 void WindowSystem::ungrabKeyboard(Tk_Window )
00176 {
00177 GVX_TRACE("WindowSystem::ungrabKeyboard[agl]");
00178
00179 }
00180
00181 #endif
00182
00184
00185
00186
00188
00189 namespace
00190 {
00191 unsigned long EVENT_MASK = (ExposureMask |
00192 StructureNotifyMask |
00193 KeyPressMask |
00194 ButtonPressMask |
00195 EnterWindowMask |
00196 LeaveWindowMask);
00197
00198
00199
00200 void* cast_to_void(TkWidgImpl* p) { return static_cast<void*>(p); }
00201 TkWidgImpl* cast_from_void(void* p) { return static_cast<TkWidgImpl*>(p); }
00202 }
00203
00204 class TkWidgImpl : public nub::volatile_object
00205 {
00206 TkWidgImpl(const TkWidgImpl&);
00207 TkWidgImpl& operator=(const TkWidgImpl&);
00208
00209 public:
00210 TkWidgImpl(tcl::TkWidget* o, tcl::interpreter& p,
00211 const char* classname,
00212 const char* pathname,
00213 bool topLevel);
00214
00215 virtual ~TkWidgImpl() throw();
00216
00217 tcl::TkWidget* owner;
00218 tcl::interpreter interp;
00219 Tk_Window const tkWin;
00220 Tk_Cursor cursor;
00221
00222 bool updatePending;
00223 bool shutdownRequested;
00224
00225 void dbgButtonPress(const tcl::ButtonPressEvent& ev)
00226 {
00227 std::cerr << "ButtonPress: "
00228 << "button " << ev.button
00229 << " x " << ev.x << " y " << ev.y << std::endl;
00230 }
00231
00232 void dbgKeyPress(const tcl::KeyPressEvent& ev)
00233 {
00234 std::cerr << "KeyPress: "
00235 << "keys '" << ev.keys << "'"
00236 << " control " << ev.controlPressed
00237 << " x " << ev.x << " y " << ev.y << std::endl;
00238 }
00239
00240 void buttonEventProc(XButtonEvent* ev);
00241
00242 void keyEventProc(XKeyEvent* ev);
00243
00244 static void cEventCallback(ClientData clientData, XEvent* ev) throw();
00245
00246 static void cRenderCallback(ClientData clientData) throw();
00247
00248 static void cEventuallyFreeCallback(char* clientData) throw();
00249
00250 static void cTakeFocusCallback(ClientData clientData) throw();
00251 };
00252
00253 TkWidgImpl::TkWidgImpl(tcl::TkWidget* o, tcl::interpreter& p,
00254 const char* classname,
00255 const char* pathname,
00256 bool topLevel) :
00257 owner(o),
00258 interp(p),
00259 tkWin(Tk_CreateWindowFromPath(interp.intp(),
00260 Tk_MainWindow(interp.intp()),
00261 const_cast<char*>(pathname),
00262 topLevel ? (char*) "" : (char*) 0)),
00263 cursor(0),
00264 updatePending(false),
00265 shutdownRequested(false)
00266 {
00267 GVX_TRACE("TkWidgImpl::TkWidgImpl");
00268
00269 if (tkWin == 0)
00270 {
00271 throw rutz::error("TkWidget couldn't create Tk_Window", SRC_POS);
00272 }
00273
00274 Tk_SetClass(tkWin, classname);
00275
00276 Tk_CreateEventHandler(tkWin, EVENT_MASK,
00277 TkWidgImpl::cEventCallback,
00278 cast_to_void(this));
00279 }
00280
00281 TkWidgImpl::~TkWidgImpl() throw()
00282 {
00283 GVX_TRACE("TkWidgImpl::~TkWidgImpl");
00284
00285 if (cursor != 0)
00286 Tk_FreeCursor(Tk_Display(tkWin), cursor);
00287
00288 Tk_DeleteEventHandler(tkWin, EVENT_MASK,
00289 TkWidgImpl::cEventCallback,
00290 cast_to_void(this));
00291
00292 Tcl_CancelIdleCall(cRenderCallback, cast_to_void(this));
00293 Tk_DestroyWindow(tkWin);
00294 }
00295
00296 void TkWidgImpl::buttonEventProc(XButtonEvent* ev)
00297 {
00298 GVX_TRACE("TkWidgImpl::buttonEventProc");
00299
00300 const bool controlPressed = ev->state & ControlMask;
00301 const bool shiftPressed = ev->state & ShiftMask;
00302
00303
00304
00305
00306 if (controlPressed && shiftPressed)
00307 {
00308 switch (ev->button)
00309 {
00310 case 1: owner->minimize(); return;
00311 case 3: owner->destroyWidget(); return;
00312 }
00313 }
00314
00315 tcl::ButtonPressEvent e = {ev->button, ev->x, ev->y};
00316 owner->sigButtonPressed.emit(e);
00317 }
00318
00319 void TkWidgImpl::keyEventProc(XKeyEvent* ev)
00320 {
00321 GVX_TRACE("TkWidgImpl::keyEventProc");
00322
00323 const bool controlPressed = ev->state & ControlMask;
00324
00325
00326
00327
00328 const unsigned int saveState = ev->state;
00329
00330
00331
00332 ev->state &= ~ControlMask;
00333
00334 char buf[32];
00335 #if defined(GVX_GL_PLATFORM_GLX)
00336 const int len = XLookupString(ev, &buf[0], 30, 0, 0);
00337 buf[len] = '\0';
00338 #elif defined(GVX_GL_PLATFORM_AGL)
00339 strncpy(buf, ev->trans_chars, 31);
00340 buf[31] = '\0';
00341 #endif
00342
00343
00344 ev->state = saveState;
00345
00346 tcl::KeyPressEvent e = {&buf[0], ev->x, ev->y, controlPressed};
00347 owner->sigKeyPressed.emit(e);
00348 }
00349
00350 void TkWidgImpl::cEventCallback(ClientData clientData,
00351 XEvent* ev) throw()
00352 {
00353 GVX_TRACE("TkWidgImpl::cEventCallback");
00354
00355 TkWidgImpl* const rep = cast_from_void(clientData);
00356 tcl::TkWidget* const widg = rep->owner;
00357
00358 try
00359 {
00360 switch (ev->type)
00361 {
00362 case Expose:
00363 {
00364 GVX_TRACE("TkWidgImpl::cEventCallback-Expose");
00365 if (ev->xexpose.count == 0)
00366 {
00367 widg->requestRedisplay();
00368 }
00369 }
00370 break;
00371 case ConfigureNotify:
00372 {
00373 GVX_TRACE("TkWidgImpl::cEventCallback-ConfigureNotify");
00374
00375 widg->reshapeCallback(Tk_Width(rep->tkWin),
00376 Tk_Height(rep->tkWin));
00377 widg->requestRedisplay();
00378 }
00379 break;
00380 case EnterNotify:
00381 widg->grabKeyboard();
00382 break;
00383 case LeaveNotify:
00384 widg->ungrabKeyboard();
00385 break;
00386 case KeyPress:
00387 rep->keyEventProc(&(ev->xkey));
00388 break;
00389 case ButtonPress:
00390 rep->buttonEventProc(&(ev->xbutton));
00391 break;
00392 case MapNotify:
00393 {
00394 GVX_TRACE("TkWidget::cEventCallback-MapNotify");
00395 }
00396 break;
00397 case DestroyNotify:
00398 {
00399 GVX_TRACE("TkWidget::cEventCallback-DestroyNotify");
00400
00401
00402 GVX_ASSERT(!rep->shutdownRequested);
00403
00404 rep->shutdownRequested = true;
00405
00406 Tcl_EventuallyFree(cast_to_void(rep),
00407 cEventuallyFreeCallback);
00408 }
00409 break;
00410 }
00411 }
00412 catch (...)
00413 {
00414 rep->interp.handle_live_exception("cEventCallback", SRC_POS);
00415 rep->interp.background_error();
00416 }
00417 }
00418
00419 void TkWidgImpl::cRenderCallback(ClientData clientData) throw()
00420 {
00421 GVX_TRACE("TkWidgImpl::cRenderCallback");
00422
00423 TkWidgImpl* const rep = cast_from_void(clientData);
00424
00425 try
00426 {
00427 rep->owner->displayCallback();
00428 rep->updatePending = false;
00429 }
00430 catch (...)
00431 {
00432 rep->interp.handle_live_exception("cRenderCallback", SRC_POS);
00433 rep->interp.background_error();
00434 }
00435 }
00436
00437 void TkWidgImpl::cEventuallyFreeCallback(char* clientData) throw()
00438 {
00439 GVX_TRACE("TkWidgImpl::cEventuallyFreeCallback");
00440 TkWidgImpl* const rep = cast_from_void(clientData);
00441 delete rep->owner;
00442 }
00443
00444 void TkWidgImpl::cTakeFocusCallback(ClientData clientData) throw()
00445 {
00446 GVX_TRACE("TkWidgImpl::cTakeFocusCallback");
00447 TkWidgImpl* const rep = cast_from_void(clientData);
00448 try
00449 {
00450 rep->owner->takeFocus();
00451 }
00452 catch (...)
00453 {
00454 rep->interp.handle_live_exception("cEventCallback", SRC_POS);
00455 rep->interp.background_error();
00456 }
00457 }
00458
00460
00461
00462
00464
00465 tcl::TkWidget::TkWidget(tcl::interpreter& interp,
00466 const char* classname,
00467 const char* pathname,
00468 bool topLevel) :
00469 rep(new TkWidgImpl(this, interp, classname, pathname, topLevel))
00470 {
00471 GVX_TRACE("tcl::TkWidget::TkWidget");
00472
00473 this->mark_as_volatile();
00474 }
00475
00476 tcl::TkWidget::~TkWidget() throw()
00477 {
00478 GVX_TRACE("tcl::TkWidget::~TkWidget");
00479 delete rep;
00480 }
00481
00482 int tcl::TkWidget::width() const
00483 {
00484 GVX_TRACE("tcl::TkWidget::width");
00485 return Tk_Width(rep->tkWin);
00486 }
00487
00488 int tcl::TkWidget::height() const
00489 {
00490 GVX_TRACE("tcl::TkWidget::height");
00491 return Tk_Height(rep->tkWin);
00492 }
00493
00494 geom::vec2<int> tcl::TkWidget::size() const
00495 {
00496 return geom::vec2<int>(width(), height());
00497 }
00498
00499 void tcl::TkWidget::setWidth(int w)
00500 {
00501 GVX_TRACE("tcl::TkWidget::setWidth");
00502
00503
00504
00505
00506 Tk_GeometryRequest(rep->tkWin, w, Tk_ReqHeight(rep->tkWin));
00507 }
00508
00509 void tcl::TkWidget::setHeight(int h)
00510 {
00511 GVX_TRACE("tcl::TkWidget::setHeight");
00512
00513
00514
00515
00516 Tk_GeometryRequest(rep->tkWin, Tk_ReqWidth(rep->tkWin), h);
00517 }
00518
00519 void tcl::TkWidget::setSize(geom::vec2<int> sz)
00520 {
00521 GVX_TRACE("tcl::TkWidget::setSize");
00522 Tk_GeometryRequest(rep->tkWin, sz.x(), sz.y());
00523 }
00524
00525 void tcl::TkWidget::destroyWidget()
00526 {
00527 GVX_TRACE("tcl::TkWidget::destroyWidget");
00528
00529
00530 if ( !rep->interp.is_deleted() )
00531 {
00532 Tk_DestroyWindow(rep->tkWin);
00533 }
00534 }
00535
00536 void tcl::TkWidget::winInfo() throw()
00537 {
00538 GVX_TRACE("tcl::TkWidget::winInfo");
00539
00540 WindowSystem::winInfo(rep->tkWin);
00541 }
00542
00543 tcl::interpreter& tcl::TkWidget::interp() const
00544 {
00545 return rep->interp;
00546 }
00547
00548 Tk_Window tcl::TkWidget::tkWin() const
00549 {
00550 GVX_ASSERT(rep->tkWin != 0);
00551 return rep->tkWin;
00552 }
00553
00554 const char* tcl::TkWidget::pathname() const
00555 {
00556 GVX_ASSERT(rep->tkWin != 0);
00557 return Tk_PathName(rep->tkWin);
00558 }
00559
00560 double tcl::TkWidget::pixelsPerInch() const
00561 {
00562 GVX_TRACE("tcl::TkWidget::pixelsPerInch");
00563
00564 GVX_ASSERT(rep->tkWin != 0);
00565
00566 Screen* scr = Tk_Screen(rep->tkWin);
00567 const int screen_pixel_width = WidthOfScreen(scr);
00568 const int screen_mm_width = WidthMMOfScreen(scr);
00569
00570 const double screen_inch_width = screen_mm_width / 25.4;
00571
00572 const double screen_ppi = screen_pixel_width / screen_inch_width;
00573
00574 dbg_eval_nl(3, screen_ppi);
00575 return screen_ppi;
00576 }
00577
00578 void tcl::TkWidget::setCursor(const char* cursor_spec)
00579 {
00580 GVX_TRACE("tcl::TkWidget::setCursor");
00581 if (cursor_spec == 0 || cursor_spec == '\0')
00582 {
00583
00584 if (rep->cursor != 0)
00585 Tk_FreeCursor(Tk_Display(rep->tkWin), rep->cursor);
00586
00587 rep->cursor = 0;
00588
00589 Tk_UndefineCursor(rep->tkWin);
00590 }
00591 else
00592 {
00593 Tk_Cursor new_cursor = Tk_GetCursor(rep->interp.intp(),
00594 rep->tkWin, cursor_spec);
00595
00596 if (new_cursor == 0)
00597 {
00598 throw rutz::error(rutz::sfmt("couldn't set cursor to '%s'",
00599 cursor_spec), SRC_POS);
00600 }
00601
00602
00603 if (rep->cursor != 0)
00604 Tk_FreeCursor(Tk_Display(rep->tkWin), rep->cursor);
00605
00606 rep->cursor = new_cursor;
00607
00608 Tk_DefineCursor(rep->tkWin, rep->cursor);
00609 }
00610 }
00611
00612 const char* tcl::TkWidget::getCursor() const
00613 {
00614 GVX_TRACE("tcl::TkWidget::getCursor");
00615 return rep->cursor == 0
00616 ? ""
00617 : Tk_NameOfCursor(Tk_Display(rep->tkWin), rep->cursor);
00618 }
00619
00620 void tcl::TkWidget::warpPointer(int x, int y) const
00621 {
00622 GVX_TRACE("tcl::TkWidget::warpPointer");
00623
00624
00625
00626 XWarpPointer(Tk_Display(rep->tkWin),
00627 0, Tk_WindowId(rep->tkWin),
00628 0, 0, 0, 0,
00629 x, y);
00630 }
00631
00632 void tcl::TkWidget::pack()
00633 {
00634 GVX_TRACE("tcl::TkWidget::pack");
00635
00636 if (!Tk_IsTopLevel(rep->tkWin))
00637 {
00638 const fstring pack_cmd =
00639 rutz::sfmt("pack %s -side left -expand 1 -fill both; update",
00640 pathname());
00641 rep->interp.eval(pack_cmd);
00642 }
00643 }
00644
00645 void tcl::TkWidget::repack(const char* options)
00646 {
00647 GVX_TRACE("tcl::TkWidget::repack");
00648
00649 if (!Tk_IsTopLevel(rep->tkWin))
00650 {
00651 rep->interp.eval(rutz::sfmt("pack %s %s; update",
00652 pathname(), options));
00653 }
00654 }
00655
00656 void tcl::TkWidget::unpack()
00657 {
00658 GVX_TRACE("tcl::TkWidget::unpack");
00659
00660 if (!Tk_IsTopLevel(rep->tkWin))
00661 {
00662 rep->interp.eval(rutz::sfmt("pack forget %s", pathname()));
00663 }
00664 }
00665
00666 void tcl::TkWidget::iconify()
00667 {
00668 GVX_TRACE("tcl::TkWidget::iconify");
00669
00670 WindowSystem::iconify(rep->tkWin);
00671 }
00672
00673 void tcl::TkWidget::grabKeyboard()
00674 {
00675 GVX_TRACE("tcl::TkWidget::grabKeyboard");
00676
00677 WindowSystem::grabKeyboard(rep->tkWin);
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687 Tcl_DoWhenIdle(TkWidgImpl::cTakeFocusCallback,
00688 cast_to_void(rep));
00689 }
00690
00691 void tcl::TkWidget::ungrabKeyboard()
00692 {
00693 GVX_TRACE("tcl::TkWidget::ungrabKeyboard");
00694
00695 WindowSystem::ungrabKeyboard(rep->tkWin);
00696 }
00697
00698 void tcl::TkWidget::maximize()
00699 {
00700 GVX_TRACE("tcl::TkWidget::maximize");
00701
00702 const int w = WidthOfScreen(Tk_Screen(rep->tkWin));
00703 const int h = HeightOfScreen(Tk_Screen(rep->tkWin));
00704 setSize(geom::vec2<int>(w, h));
00705
00706 Tk_Window mainWin = rep->tkWin;
00707 while ( !Tk_IsTopLevel(mainWin) )
00708 {
00709 mainWin = Tk_Parent(mainWin);
00710 }
00711
00712 Tk_MoveToplevelWindow(mainWin, 0, 0);
00713
00714 grabKeyboard();
00715 }
00716
00717 void tcl::TkWidget::minimize()
00718 {
00719 GVX_TRACE("tcl::TkWidget::minimize");
00720
00721 ungrabKeyboard();
00722
00723 setSize(geom::vec2<int>(200, 200));
00724 }
00725
00726 void tcl::TkWidget::bind(const fstring& event_sequence,
00727 const fstring& script)
00728 {
00729 GVX_TRACE("tcl::TkWidget::bind");
00730
00731 const fstring cmd_str =
00732 script.length() == 0
00733
00734
00735
00736
00737 ? rutz::sfmt("bind %s %s \"\"", pathname(), event_sequence.c_str())
00738 : rutz::sfmt("bind %s %s { %s }",
00739 pathname(), event_sequence.c_str(), script.c_str());
00740
00741 rep->interp.eval(cmd_str);
00742 }
00743
00744 void tcl::TkWidget::takeFocus()
00745 {
00746 GVX_TRACE("tcl::TkWidget::takeFocus");
00747
00748 rep->interp.eval(rutz::sfmt("focus -force %s", pathname()));
00749 }
00750
00751 void tcl::TkWidget::loseFocus()
00752 {
00753 GVX_TRACE("tcl::TkWidget::loseFocus");
00754 Tk_Window toplev = rep->tkWin;
00755
00756 while (!Tk_IsTopLevel(toplev))
00757 {
00758 toplev = Tk_Parent(toplev);
00759 GVX_ASSERT(toplev != 0);
00760 }
00761
00762 const char* pathname = Tk_PathName(toplev);
00763
00764 rep->interp.eval(rutz::sfmt("wm iconify %s; wm deiconify %s ",
00765 pathname, pathname));
00766 }
00767
00768 void tcl::TkWidget::requestRedisplay()
00769 {
00770 GVX_TRACE("tcl::TkWidget::requestRedisplay");
00771
00772 if (!rep->updatePending)
00773 {
00774 Tcl_DoWhenIdle(TkWidgImpl::cRenderCallback, cast_to_void(rep));
00775 rep->updatePending = true;
00776 }
00777 }
00778
00779 void tcl::TkWidget::hook()
00780 {
00781 sigButtonPressed.connect(rep, &TkWidgImpl::dbgButtonPress);
00782 sigKeyPressed.connect(rep, &TkWidgImpl::dbgKeyPress);
00783 }
00784
00785 static const char __attribute__((used)) vcid_groovx_tk_widget_cc_utc20050628165845[] = "$Id: widget.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00786 #endif // !GROOVX_TK_WIDGET_CC_UTC20050628165845_DEFINED