widget.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 2001-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at usc dot edu>
00008 //
00009 // created: Fri Jun 15 17:05:12 2001
00010 // commit: $Id: widget.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/tk/widget.cc $
00012 //
00013 // --------------------------------------------------------------------
00014 //
00015 // This file is part of GroovX.
00016 //   [http://ilab.usc.edu/rjpeters/groovx/]
00017 //
00018 // GroovX is free software; you can redistribute it and/or modify it
00019 // under the terms of the GNU General Public License as published by
00020 // the Free Software Foundation; either version 2 of the License, or
00021 // (at your option) any later version.
00022 //
00023 // GroovX is distributed in the hope that it will be useful, but
00024 // WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 // General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License
00029 // along with GroovX; if not, write to the Free Software Foundation,
00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
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 /* don't send key events to their normal windows */,
00130                   GrabModeAsync /* pointer mode */,
00131                   GrabModeAsync /* keyboard mode */,
00132                   CurrentTime /* when grab should take place */);
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 /*tkWin*/)
00156 {
00157 GVX_TRACE("WindowSystem::winInfo[agl]");
00158   // FIXME
00159   throw rutz::error("WindowSystem::winInfo not supported", SRC_POS);
00160 }
00161 
00162 void WindowSystem::iconify(Tk_Window /*tkWin*/)
00163 {
00164 GVX_TRACE("WindowSystem::iconify[agl]");
00165   // FIXME
00166   throw rutz::error("WindowSystem::iconify not supported", SRC_POS);
00167 }
00168 
00169 void WindowSystem::grabKeyboard(Tk_Window /*tkWin*/)
00170 {
00171 GVX_TRACE("WindowSystem::grabKeyboard[agl]");
00172   // don't need to do anything to grab keyboard with Mac OS X Aqua
00173 }
00174 
00175 void WindowSystem::ungrabKeyboard(Tk_Window /*tkWin*/)
00176 {
00177 GVX_TRACE("WindowSystem::ungrabKeyboard[agl]");
00178   // don't need to do anything to (un)grab keyboard with Mac OS X Aqua
00179 }
00180 
00181 #endif
00182 
00184 //
00185 // tcl::TkWidget::TkWidgImpl definition
00186 //
00188 
00189 namespace
00190 {
00191   unsigned long EVENT_MASK = (ExposureMask |
00192                               StructureNotifyMask |
00193                               KeyPressMask |
00194                               ButtonPressMask |
00195                               EnterWindowMask |
00196                               LeaveWindowMask);
00197 
00198   // These are just to make sure that all our clientdata casts go
00199   // to/from the right types.
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   // This is an escape hatch for top-level frameless windows gone
00304   // awry... need to always provide a reliable way to iconify the
00305   // window since the title bar and "minimize" button might not exist.
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   // Need to save and later restore the event "state" in order that
00326   // subsequent processing of this event (e.g. processing by Tk "bind"
00327   // tables") proceeds correctly.
00328   const unsigned int saveState = ev->state;
00329 
00330   // Turn off (temporarily) any ControlMask so that we get a more
00331   // sensible output from XLookupString().
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   // Restore the state
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             // Idiot-check that we don't have recursive destroy calls
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 // tcl::TkWidget member definitions
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   // Need to specify Tk_ReqHeight(rep->tkWin) instead of
00503   // Tk_Height(rep->tkWin), since the latter might not reflect the
00504   // requested height if the event loop has not been entered since a
00505   // call to setHeight().
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   // Need to specify Tk_ReqWidth(rep->tkWin) instead of
00513   // Tk_Width(rep->tkWin), since the latter might not reflect the
00514   // requested height if the event loop has not been entered since a
00515   // call to setWidth().
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   // If we are exiting, don't bother destroying the widget; otherwise...
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       // Empty string means to unset the cursor
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       // OK, creating the new cursor succeeded, now free the old one
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   // NOTE: The XWarpPointer emulation routine provided by Tk for Mac
00625   // OS X Aqua currently does nothing (as of Tk 8.5a1).
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   // Oddly enough, we can't just call takeFocus() directly here. In
00680   // particular, we run into problems if grabKeyboard() is called from
00681   // an EnterNotify callback. In that case, if we call takeFocus()
00682   // during that callback, Tk somehow seems to erase our focus request
00683   // by the time control returns back to the main event loop. So, if
00684   // we make the call as an idle callback instead, then we don't
00685   // switch focus until after Tk is completely finished processing the
00686   // EnterNotify event.
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    // If the script is the empty string, then we want to destroy the
00734    // binding, so we need to actually give an empty string to the
00735    // "bind" command; any empty pair of braces "{ }" will not
00736    // suffice.
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

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:41 2008 by Doxygen version 1.5.5.