"Fossies" - the Fresh Open Source Software Archive

Member "yudit-3.0.7/swindow/swin32/SWin32.cpp" (6 Jun 2020, 89459 Bytes) of package /linux/misc/yudit-3.0.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "SWin32.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.0.5_vs_3.0.7.

    1 /** 
    2  *  Yudit Unicode Editor Source File
    3  *
    4  *  GNU Copyright (C) 1997-2006  Gaspar Sinai <gaspar@yudit.org>  
    5  *
    6  *  This program is free software; you can redistribute it and/or modify
    7  *  it under the terms of the GNU General Public License, version 2,
    8  *  dated June 1991. See file COPYYING for details.
    9  *
   10  *  This program is distributed in the hope that it will be useful,
   11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  *  GNU General Public License for more details.
   14  *
   15  *  You should have received a copy of the GNU General Public License
   16  *  along with this program; if not, write to the Free Software
   17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18  */
   19 
   20 #define SS_YUDIT_DIALOG_STYLE \
   21      (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_CLIPCHILDREN)
   22 
   23 #define SS_YUDIT_TOPLEVEL_STYLE \
   24      (WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN)
   25 
   26 #define SS_YUDIT_CHILD_STYLE \
   27       (WS_CHILD | WS_CLIPCHILDREN)
   28 
   29 /* 
   30  * You might want to comment this out to build on Wndows CE
   31  * Having it makes it more responsive, event based.
   32  * it needs ws2_32.lib
   33  */
   34  
   35 #include "stoolkit/SExcept.h"
   36 #include "stoolkit/SEvent.h"
   37 #include "stoolkit/SString.h"
   38 #include "stoolkit/SUtil.h"
   39 #include "stoolkit/SStringVector.h"
   40 #include "stoolkit/SBinHashtable.h"
   41 #include "swindow/SAwt.h"
   42 #include "swindow/SGEngine.h"
   43 #include "swindow/swin32/SWin32.h"
   44 #include "swindow/SRedrawEvent.h"
   45 
   46 
   47 #include <sys/types.h>
   48 
   49 #include <winsock2.h>
   50 
   51 #include <time.h>
   52 
   53 #define WIN32_LEAN_AND_MEAN
   54 #include <windows.h>
   55 #include <imm.h>
   56 #undef WIN32_LEAN_AND_MEAN 
   57 
   58 #include <stdio.h>
   59 
   60 
   61 #ifdef USE_WINAPI
   62 /* SEventBSD hookup hack */
   63 int main(int argc, char* argv[]);
   64 #endif
   65 
   66 extern int (*_windowsSelectHookup)(int readSize, fd_set *ro, 
   67   int writeSize, fd_set *wo, int exceptSize, fd_set *ex,
   68   struct timeval* t);
   69 
   70 static int
   71 winSelectHack (int readSize, fd_set *ro, int writeSize, fd_set *wo,
   72   int exceptSize, fd_set *ex, struct timeval* t);
   73 
   74 static int
   75 winWineHack (int readSize, fd_set *ro, int writeSize, fd_set *wo,
   76   int exceptSize, fd_set *ex, struct timeval* t);
   77 
   78 
   79 class SDoubleBuffer 
   80 {
   81 public:
   82   SDoubleBuffer (HWND _id, HDC _gotDC, 
   83      const SColor& background,
   84      int _x, int _y, 
   85      unsigned int _w, unsigned int _h);
   86   void copyToScreen  (HWND _id, HDC _gotDC);
   87   ~SDoubleBuffer ();
   88 
   89   HDC     bitmapHDC;
   90   HBITMAP bitmap; 
   91 
   92   int x;
   93   int y;
   94   unsigned int width;
   95   unsigned int height;
   96 };
   97 
   98 
   99 /**
  100  * Clipboard Stuff.
  101  */
  102 static UINT UTF8_STRING = 0;
  103 SV_UCS4 clipData;
  104 
  105 typedef struct _KeyData
  106 {
  107   SWindowListener::SKey key;
  108   bool ctrl0;
  109   bool ctrl1;
  110   bool meta0;
  111   bool meta1;
  112   bool shift0;
  113   bool shift1;
  114 } KeyData;
  115 
  116 static int putClipText();
  117 static int putClipUnicodeText();
  118 static int putClipUtf8Text();
  119 static void notifyClip ();
  120 static void processKey (KeyData* kd, bool syskey, int keycod, bool isdown);
  121 static void sendKeyReleased (KeyData* kd, SW32Window* wn, SWindowListener* ln);
  122 static void sendKeyChar (KeyData* kd, const SString& s);
  123 
  124 static bool sendAcceleratorPressed (int key, bool ctrl, bool shift, bool meta);
  125 static bool sendAcceleratorReleased ();
  126 
  127 /**
  128  * @author: Gaspar Sinai <gaspar@yudit.org>
  129  * @version: 2000-04-23
  130  * This is the abstract widget toolkit
  131  */
  132 static bool needClear = false;
  133 
  134 SBinHashtable<HBRUSH> brushes;
  135 SBinHashtable<HPEN> pens;
  136 
  137 SBinHashtable<unsigned int> minimumSizesX;
  138 SBinHashtable<unsigned int> minimumSizesY;
  139 
  140 static HPEN getBitPen (const SColor& clr);
  141 static HBRUSH getSolidBrush (const SColor& clr);
  142 
  143 static long currentTopFocusWindow=0;
  144 static long currentFocusWindow=0;
  145 
  146 /* There is only one context */
  147 HINSTANCE instance;
  148 HINSTANCE pinstance;
  149 LPSTR cmdLine;
  150 int cmdShow;
  151 HANDLE accel;
  152 /* alway reset it on colormap change */
  153 static HDC compatibleDC = 0;
  154 static HBITMAP compatibleHBitmap = 0;
  155 
  156 static bool winOK = false;
  157 
  158 typedef SBinHashtable<SW32Window*> SWindowHashtable;
  159 typedef SBinHashtable<SWindowListener*> SListenerHashtable;
  160 
  161 static SWindowHashtable windowHashtable;
  162 static SListenerHashtable listenerHashtable;
  163 
  164 static void createShadedBitmap (const SPen& pen, const SImage& im, 
  165   HBITMAP* p, HBITMAP* m, HDC odc, HDC dc);
  166 static void createColoredBitmap (const SPen& pen, const SImage& im,
  167   HBITMAP* p, HBITMAP* m, HDC odc, HDC dc);
  168 
  169 static long clipboardOwner=0;
  170 
  171 char* windowName = "Yudit";
  172 typedef SHashtable<SRedrawEvent> SRedrawEventTable;
  173 
  174 int shownWindows = 0;
  175 long buttonFlags[3];
  176 
  177 static SW32Window* getToplevelWindow (SW32Window* w);
  178 static SW32Window* getToplevelWindow (long id);
  179 
  180 /*--------------------------------------------------------------------------
  181  * You would not need this if win98 could create more than 500 bitmaps.
  182  * START
  183  *-------------------------------------------------------------------------*/
  184 SDoubleBuffer::SDoubleBuffer (HWND _id, HDC _gotDC, 
  185      const SColor& background, int _x, int _y, 
  186      unsigned int _w, unsigned int _h)
  187 {
  188   HDC winDC = (_gotDC == 0) ? GetDC(_id) : _gotDC;
  189 
  190   bitmapHDC = CreateCompatibleDC (winDC);
  191 //  fprintf (stderr, "bitmapHDC=%u\n", (unsigned int) bitmapHDC);
  192 
  193   x = _x; y = _y;
  194   width = _w; height = _h;
  195 
  196   if (width == 0) width = 1;
  197   if (height == 0) height = 1;
  198 
  199   // can't use bitmapHDC, don't ask me why
  200   bitmap = CreateCompatibleBitmap(winDC, x+width, y+height);
  201   SelectObject(bitmapHDC, bitmap);
  202   if (_gotDC == 0) ReleaseDC (_id, winDC);
  203 
  204   if (bitmap == 0)
  205   {
  206     fprintf (stderr, "Bitmap is null...\n");
  207   }
  208   // Clear the bitmap with background
  209   RECT rect; rect.left = x; rect.top = y;
  210   rect.right = x + (int) width; rect.bottom = y + (int) height;
  211   HBRUSH brush = getSolidBrush (background);
  212   int mode = SetMapMode (bitmapHDC, MM_TEXT);
  213   FillRect (bitmapHDC, &rect,  brush);
  214   SetMapMode (bitmapHDC, mode);
  215   // brush is cached, dont delete it
  216 }
  217 
  218 void
  219 SDoubleBuffer::copyToScreen  (HWND _id, HDC _gotDC)
  220 {
  221   HDC winDC = (_gotDC == 0) ? GetDC(_id) : _gotDC;
  222 
  223   // SelectClipRgn ((HDC)bitmapHDC, (HRGN) 0);
  224   // SelectClipRgn (winDC, (HRGN) 0);
  225   BitBlt (winDC, x, y, width, height, bitmapHDC, x, y, SRCCOPY);
  226 
  227   if (_gotDC == 0) ReleaseDC (_id, winDC);
  228 }
  229 
  230 SDoubleBuffer::~SDoubleBuffer ()
  231 {
  232   DeleteDC (bitmapHDC);
  233   DeleteObject (bitmap);
  234 }
  235 class SBitmapItem
  236 {
  237 public:
  238   HBITMAP bitmap;
  239   HDC     dc;
  240   int x;
  241   int y;
  242   int width;
  243   int height;
  244 };
  245 
  246 class SBitmapArea 
  247 {
  248 public:
  249   SBitmapArea  (unsigned int _xy) {
  250     xy = _xy;
  251     bitmap = 0;
  252     cursor = 0;
  253     size = 0;
  254     ison = false;
  255     dc = 0;
  256   }
  257   void  clear () {
  258     /* delete dc first. always bitmap might be selected...*/
  259     if (dc) DeleteDC (dc);
  260     if (bitmap) DeleteObject (bitmap);
  261     dc = 0;
  262     bitmap = 0;
  263     cursor = 0;
  264   }
  265   void  setOn (bool _ison) {
  266     clear();
  267     ison = _ison;
  268   }
  269   void  setSize (int _size) {
  270     clear();
  271     unsigned long l = ss_sqrtlong ((unsigned long) _size);
  272     size = (int) (l);
  273     /* limit size 4 Megs */
  274     if (xy > 2 && size * xy > 2000) size = 2000/xy;
  275   }
  276   int put (const SString& key, SBitmapItem* item, SString* old);
  277 private:
  278   bool    ison;
  279   int     xy;
  280   int     size;
  281   int     cursor;
  282   HBITMAP bitmap;
  283   HDC     dc;
  284   SStringVector keys;
  285 };
  286 
  287 /**
  288  * Put a new item in cache. 
  289  * @return -1 if old data was replaced 
  290  * 0 if it was not successful
  291  * positive if it suceesed.
  292  * it also sets origox, origoy
  293  */
  294 int
  295 SBitmapArea::put (const SString& key, SBitmapItem* item, SString* old)
  296 {
  297   /* cerate compatible bitmap */
  298   if (!ison) return 0;
  299   if (!item->dc) return 0;
  300   if (!item->bitmap) return 0;
  301   if (bitmap == 0)
  302   {
  303     if (size<2) return 0;
  304     bitmap = CreateCompatibleBitmap (item->dc, size*xy, size*xy);
  305     if (bitmap == 0)
  306     {
  307       fprintf (stderr, "could not create bitmap dime=%dx%d size=%d\n",
  308              size * xy, size * xy, xy);
  309       return 0;
  310     }
  311     dc = CreateCompatibleDC(item->dc);
  312     if (dc == 0)
  313     {
  314       fprintf (stderr, "could not create dc\n");
  315       return 0;
  316     }
  317     SelectObject (dc, bitmap);
  318     cursor = 0;
  319     keys.clear();
  320   }
  321   if (dc == 0)
  322   {
  323     return 0;
  324   }
  325   if (cursor >= size * size) 
  326   {
  327     cursor = 0;
  328   }
  329   int ret = 1;
  330   if (keys.size() > cursor)
  331   {
  332     ret = -1;
  333     old->append (keys[cursor]);
  334     keys.replace (cursor, key);
  335   }
  336   else
  337   {
  338     keys.append (key);
  339   }
  340   SelectObject (item->dc, item->bitmap);
  341   int ypos = xy * (cursor/size);
  342   int xpos = xy * (cursor%size);
  343 
  344   BitBlt (dc, xpos, ypos, item->width, item->height, 
  345       item->dc, 0, 0, SRCCOPY);
  346 
  347   item->bitmap = bitmap;
  348   item->dc = dc;
  349   item->x = xpos;
  350   item->y = ypos;
  351   cursor++;
  352   return ret;
  353 }
  354 
  355 typedef SBinHashtable<SBitmapItem*> SBitmapHash;
  356 
  357 /**
  358  * This object re-uses a big bitmap area.
  359  */
  360 class SBitmapCache
  361 {
  362 public:
  363   SBitmapCache (void);
  364   SBitmapItem* get (const SString& key) {
  365     SBitmapItem* it =  (SBitmapItem*) cache.get (key);
  366     return it;
  367   }
  368   void put (const SString& key, const SBitmapItem& item);
  369   void  setOn (bool ison) {
  370     area16.setOn (ison); area32.setOn (ison);
  371     area64.setOn (ison); area128.setOn (ison);
  372     iscaching = true;
  373     clear();
  374   }
  375   bool  isOn () {
  376     return iscaching;
  377   }
  378   void clear();
  379   void  setSize (int size) {
  380     area16.setSize (size); area32.setSize (size);
  381     area64.setSize (size); area128.setSize (size);
  382     clear();
  383   }
  384 private:
  385   bool iscaching;
  386   SBitmapHash cache;
  387   SBitmapArea area16;
  388   SBitmapArea area32;
  389   SBitmapArea area64;
  390   SBitmapArea area128;
  391 };
  392 
  393 void
  394 SBitmapCache::clear()
  395 {
  396   area16.clear (); area32.clear ();
  397   area64.clear (); area128.clear ();
  398   for (unsigned int i=0; i<cache.size(); i++)
  399   {
  400     for (unsigned int j=0; j<cache.size(i); j++)
  401     {
  402        SBitmapItem* it = cache.get(i,j);
  403        if (it) delete it;
  404     }
  405   }
  406   cache.clear();
  407 }
  408 
  409 SBitmapCache::SBitmapCache (void) :area16(16),area32(32),area64(64),area128(128)
  410 {
  411   iscaching = false;
  412 }
  413 
  414 /**
  415  * Put item to cache.
  416  * item bitmap and dc will not be touched. bitmap may get selected
  417  * in dc. 
  418  */
  419 void
  420 SBitmapCache::put (const SString& key, const SBitmapItem& _item)
  421 {
  422   if (!_item.bitmap) return;
  423   if (!iscaching)
  424   {
  425      return;
  426   }
  427   if (cache.get (key) || _item.height > 128 || _item.width > 128)
  428   {
  429      return;
  430   }
  431   SBitmapItem * item = new SBitmapItem();
  432   item->bitmap = _item.bitmap;
  433   item->dc = _item.dc;
  434   item->width = _item.width;
  435   item->height = _item.height;
  436   int ret = 0;
  437   SString old;
  438   if (item->height > 64 || item->width > 64)
  439   {
  440     ret = area128.put (key, item, &old);
  441   }
  442   else if (item->height > 32 || item->width > 32)
  443   {
  444     ret = area64.put (key, item, &old);
  445   }
  446   else if (item->height > 16 || item->width > 16)
  447   {
  448     ret = area32.put (key, item, &old);
  449   }
  450   else 
  451   {
  452     ret = area16.put (key, item, &old);
  453   }
  454   /* replaced */
  455   if (ret < 0)
  456   {
  457     SBitmapItem* bold = cache.get (old);
  458     if (bold)
  459     {
  460       cache.remove (old);
  461       delete bold;
  462     }
  463   }
  464   /* can not use it */
  465   if (ret == 0) 
  466   {
  467     delete item;
  468     return;
  469   }
  470   /* dont delete item - reused */
  471   cache.put (key, item);
  472   return;
  473 }
  474 
  475 
  476 SBitmapCache imageCache;
  477 SBitmapCache maskCache;
  478 
  479 
  480 /*--------------------------------------------------------------------------
  481  * You would not need this if win98 could create more than 500 bitmaps.
  482  * END
  483  *-------------------------------------------------------------------------*/
  484 
  485 class SWHandler : public SEventTarget
  486 {
  487 public:
  488   SWHandler(unsigned int msec, bool iswine);
  489   ~SWHandler();
  490   virtual bool done(const SEventSource* s);
  491   virtual bool timeout(const SEventSource* s);
  492   void addRedrawEvent (long id, const SRedrawEvent& evt);
  493   void moveRedrawEvent (long id, int xoffset, int yoffset);
  494   bool doWin32();
  495   bool doWin32Loop();
  496   SRedrawEventTable  redrawEventTable;
  497   SJob* job;
  498   STimer* timer;
  499 private:
  500 };
  501 
  502 
  503 /**
  504  * The command line -wine flag make this work in wine.
  505  * @param msec is zero for event based version. or >= 1 for wine.
  506  * @param iswine is true if we use just a Sleep in event loop.
  507  *  this happens because there is no socket in wine. 
  508  *  if iswine is specified msec can not be zero.
  509  */
  510 SWHandler::SWHandler(unsigned int msec, bool iswine)
  511 {
  512   job = new SJob();
  513   if (msec!=0)
  514   {
  515     timer = new STimer(msec);
  516     SEventHandler::addTimer(timer, this);
  517     if (iswine)
  518     {
  519        _windowsSelectHookup = winWineHack; 
  520       fprintf (stderr, "Hooked up 'Sleep' event handler for wine.\n");
  521     }
  522     fprintf (stderr, "Timer is set to %d msecs.\n", msec);
  523   }
  524   else
  525   {
  526 //    fprintf (stderr, "Waiting for (I think ON is a better word) multiple objects. Throw 'em at me!\n");
  527     _windowsSelectHookup = winSelectHack; 
  528     timer = 0;
  529   }
  530   SEventHandler::addJob(job, this);
  531   UTF8_STRING = RegisterClipboardFormat ("UTF8_STRING");
  532 }
  533 
  534 SWHandler::~SWHandler()
  535 {
  536   if (job) delete job;
  537   if (timer) delete timer;
  538 }
  539 
  540 bool
  541 SWHandler::done(const SEventSource* s)
  542 {
  543   if (!winOK)
  544   {
  545     return false;
  546   }
  547 
  548   /* we dont get a notice so better hurry up and process all messages. */
  549   doWin32Loop();
  550 
  551   if (redrawEventTable.size()==0) return false;
  552   /* this is the fast serving of collapsing events */
  553   /* we request redraw events only after all events are processed */
  554   SRedrawEventTable t;
  555   /* redraw block */
  556   do {
  557     t.clear();
  558     t = redrawEventTable;
  559     redrawEventTable.clear();
  560     for (unsigned int i=0; i<t.size(); i++)
  561     {
  562       for (unsigned int j=0; j<t.size(i); j++)
  563       {
  564         const SRedrawEvent* evt = t.get (i, j);
  565         if (evt == 0) continue;
  566         SString sid = t.key (i, j);
  567         long wid = sid.longValue();
  568         SW32Window* swid = (SW32Window*) windowHashtable.get(wid);
  569         if (swid == 0)
  570         {
  571           fprintf (stderr, "Window %ld not found.\n", wid);
  572           continue;
  573         }
  574         SWindowListener* li = listenerHashtable.get(swid->getID());
  575         if (li == 0)
  576         {
  577           fprintf (stderr, "Window listener for %ld not found.\n", wid);
  578           continue;
  579         }
  580 
  581         // swid->dbuffer IS 0
  582         if (swid->dbufferOn && swid->dbuffer == 0)
  583         {
  584           swid->dbuffer = (evt->width == 0 || evt->height == 0)
  585             ? new SDoubleBuffer ((HWND) swid->id, 0, 
  586                swid->background, 0, 0, 
  587                swid->getWidth(), swid->getHeight())
  588             : new SDoubleBuffer ((HWND) swid->id, 0, 
  589                swid->background, evt->x, evt->y, evt->width, evt->height);
  590         }
  591         /* FIXME : if window is not yet visible continue */
  592         if (swid->dbuffer == 0 && 
  593         evt->clear && evt->width > 0 && evt->height > 0)
  594         {
  595           swid->repaintBackground (
  596             evt->x, evt->y,
  597             evt->x + evt->width, evt->y + evt->height);
  598         }
  599         // fprintf (stderr, "deliver RedrawEvent %ld.\n", wid);
  600         if (evt->width == 0 || evt->height == 0)
  601         {
  602           li->redraw (swid, 0, 0, swid->getWidth(), swid->getHeight());
  603         }
  604         else
  605         {
  606           li->redraw (swid, evt->x, evt->y, evt->width, evt->height);
  607         }
  608         if (swid->dbuffer)
  609         {
  610            ((SDoubleBuffer*) swid->dbuffer)->copyToScreen (
  611                (HWND) swid->id, 
  612                (HDC)  0);
  613            delete (SDoubleBuffer*) swid->dbuffer;
  614            swid->dbuffer = 0;
  615         }
  616       }
  617     }
  618   } while (doWin32Loop());
  619   SEventHandler::addJob(job, this);
  620 
  621   return false;
  622 }
  623 
  624 /**
  625  * Process X11 events in a loop
  626  * @return true if at least one event was found.
  627  */
  628 bool 
  629 SWHandler::doWin32Loop()
  630 {
  631   bool done1 = false;
  632   while (doWin32())
  633   {
  634      done1 = true;
  635   } 
  636   return  done1;
  637 }
  638 
  639 /**
  640  * Process one message.
  641  * @return true if at least one message was processed.
  642  */
  643 bool
  644 SWHandler::doWin32()
  645 {
  646   MSG msg;
  647   if (!PeekMessage(&msg ,0 , 0, 0, PM_REMOVE)) return false;
  648   do {
  649     //if (!TranslateAccelarator(hwnd, accel,&msg)
  650     TranslateMessage(&msg);
  651     DispatchMessage(&msg);
  652   } while (PeekMessage(&msg ,0 , 0, 0, PM_REMOVE));
  653   return true;
  654 }
  655 
  656 /**
  657  * Add a collapsing window redraw.
  658  * @param id is the id of the window.
  659  * @param evt is the event.
  660  */
  661 void
  662 SWHandler::addRedrawEvent (long id, const SRedrawEvent& evt)
  663 {
  664   SVector <SRedrawEvent> save;
  665   SRedrawEvent newEvt (evt);
  666   const SRedrawEvent* old = 0;
  667   while ((old = redrawEventTable.get (id)))
  668   {
  669     if (newEvt.merge (*old))
  670     {
  671       redrawEventTable.remove (id);
  672       break;
  673     }
  674     save.append (*old);
  675     redrawEventTable.remove (id);
  676   }
  677   /* put back */
  678   for (unsigned int i=0; i<save.size(); i++)
  679   {
  680     redrawEventTable.put (id, save[i], false);
  681   }
  682   redrawEventTable.put (id, newEvt, false);
  683 }
  684 
  685 /**
  686  * If there is a redraw event associated with this id, move it.
  687  * @param xoffset will be added to y
  688  * @param yoffset will be added to x
  689  */
  690 void
  691 SWHandler::moveRedrawEvent (long id, int xoffset, int yoffset)
  692 {
  693   SVector <SRedrawEvent> save;
  694   const SRedrawEvent* old = 0;
  695   while ((old=redrawEventTable.get (id)))
  696   {
  697     save.append (*old);
  698     redrawEventTable.remove (id);
  699   }
  700   //fprintf (stderr, "moveRedrawEvent %u\n", save.size());
  701   for (unsigned int i=0; i<save.size(); i++)
  702   {
  703     SRedrawEvent newEvt (save[i]);
  704     newEvt.x += xoffset;
  705     newEvt.y += yoffset;
  706     redrawEventTable.put (id, newEvt, false);
  707   }
  708 }
  709 
  710 bool
  711 SWHandler::timeout(const SEventSource* s)
  712 {
  713   return true;
  714 }
  715 
  716 LRESULT CALLBACK _eventHandler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  717 
  718 
  719 SWHandler* handler=0;
  720 
  721 
  722 static void buttonEnter (long hwnd);
  723 static void buttonPressed (long wid, int button, int x, int y);
  724 static void buttonDragged (long wid, int button, int x, int y);
  725 static void buttonReleased (long wid, int button, int x, int y);
  726 static void lostCapture (long wid);
  727 static void processMouseWheel (long hwnd, int increment);
  728 
  729 /**
  730  * This is wher ewe start off
  731  */
  732 int APIENTRY
  733 WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
  734 {
  735   buttonFlags[0] = 0;
  736   buttonFlags[1] = 0;
  737   buttonFlags[2] = 0;
  738 
  739   winOK = true;
  740   instance = hInstance;
  741   pinstance = hPrevInstance;
  742   cmdLine = lpszCmdLine;
  743   cmdShow = nCmdShow;
  744 
  745   WNDCLASS wcl;
  746   wcl.hInstance = instance;
  747   wcl.lpszClassName=windowName;
  748   wcl.lpfnWndProc = _eventHandler;
  749   wcl.style = CS_CLASSDC | CS_HREDRAW | CS_VREDRAW | CS_PARENTDC;
  750   //wcl.style = CS_CLASSDC | CS_HREDRAW | CS_VREDRAW;
  751   //wcl.hIcon = LoadIcon(0, IDI_APPLICATION);
  752   //wcl.hIcon = LoadIcon(instance, MAKEINTRESOURCE(1));
  753   wcl.hIcon = LoadIcon(instance, MAKEINTRESOURCE(1));
  754   wcl.hCursor=LoadCursor(0, IDC_ARROW);
  755   wcl.lpszMenuName = 0;
  756   wcl.cbClsExtra = 0;
  757   wcl.cbWndExtra = 0;
  758   //wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  759   //wcl.hbrBackground = GetSysColorBrush(WHITE_BRUSH);
  760   //wcl.hbrBackground = GetSysColorBrush(WHITE_BRUSH);
  761   wcl.hbrBackground = 0;
  762   //wcl.hbrBackground = GetSysColorBrush(COLOR_BACKGROUND);
  763   //wcl.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
  764   if (!RegisterClass(&wcl)) return 0;
  765 
  766   SString cl;
  767   WCHAR* _cl = GetCommandLineW();
  768   if (_cl != 0) {
  769     SString u16fn ((const char*) _cl, (unsigned int) 2 * wcslen (_cl));
  770     SEncoder u8("utf-8");
  771     SEncoder u16("utf-16-le");
  772     cl = u8.encode (u16.decode (u16fn));
  773   }
  774   cl.replaceAll ("\\", "/");
  775   SStringVector l;
  776   l.smartSplit (cl);
  777   int argc = 0;
  778   unsigned int  msecs = 0;
  779   bool iswine = false;
  780   bool  debug = false;
  781   char **argv = new char*[l.size()+1];
  782   for (unsigned int i=0;i<l.size(); i++)
  783   {
  784     SString s = l[i];
  785     if (s == "-debug")
  786     {
  787        debug = true;
  788        continue;
  789     }
  790     if (s == "-wine")
  791     {
  792        iswine = true;
  793        continue;
  794     }
  795     if (s == "-timer" && i+1<l.size())
  796     {
  797        i++;
  798        SString s1 = l[i];
  799        s1.append ((char)0);
  800        sscanf (s1.array(), "%u", &msecs);
  801        continue;
  802     }
  803     argv[argc++] = s.cString();
  804   }
  805   if (debug)
  806   {
  807      FILE* mystderr = freopen ("log.txt", "w", stderr);
  808      //if (mystderr) stderr = mystderr;
  809   }
  810   if (iswine && msecs == 0)
  811   {
  812      fprintf (stderr, "Warning: -wine flag needs -timer msec\n");
  813   }
  814   argv[argc] = 0;
  815   accel = LoadAccelerators(instance, "Main");
  816   int ret;
  817   HWND hwnd = GetClipboardOwner ();
  818   if (OpenClipboard (hwnd))
  819   {
  820      UINT format = 0;
  821 //      fprintf (stderr, "clipboard format start %d\n", hwnd);
  822      while (format=EnumClipboardFormats (format))
  823      {
  824        char buff[128];
  825        buff[127] = 0;
  826        GetClipboardFormatName (format, buff, 127);
  827 //       fprintf (stderr, "clipboard format[%u]=[%s]\n", format, buff);
  828      }
  829 //      fprintf (stderr, "clipboard format end\n");
  830      CloseClipboard ();
  831   }
  832   else
  833   {
  834     fprintf (stderr, "clipboard format errror\n");
  835   }
  836   {
  837     SWHandler h(msecs, iswine);
  838     handler = &h;
  839     ret=main (argc, argv);
  840     handler = 0;
  841   }
  842   for (unsigned int j=0;j<argc; j++)
  843   {
  844     delete argv[j];
  845   }
  846   delete argv;
  847   fclose (stderr);
  848   return ret;
  849 }
  850 
  851 
  852 SW32Impl::SW32Impl()
  853 {
  854 }
  855 
  856 SW32Impl::~SW32Impl()
  857 {
  858 }
  859 
  860 bool
  861 SW32Impl::isOK()
  862 {
  863   return winOK;
  864 }
  865 
  866 SEncoder impEncoder;
  867 void
  868 SW32Impl::setEncoding(const SString& str)
  869 {
  870   SEncoder enc = SEncoder (str);
  871   if (!enc.isOK())
  872   {
  873     fprintf (stderr, "SWin32 clipboard encoder `%*.*s' unknown\n", 
  874       SSARGS(str));
  875   }
  876   else
  877   {
  878     encoder = enc;
  879     impEncoder = enc;
  880   }
  881 }
  882 
  883 SWindow*
  884 SW32Impl::getWindow (SWindowListener* l, const SString& name)
  885 {
  886   if (!isOK()) return 0;
  887   char* nm=name.cString();
  888   HWND w = CreateWindow(
  889      windowName, nm,
  890      SS_YUDIT_TOPLEVEL_STYLE,
  891      SD_WIN_X, SD_WIN_Y, SD_WIN_W, SD_WIN_H,
  892      HWND_DESKTOP,
  893      0,
  894      instance,
  895      0);
  896   delete nm;
  897   SW32Window* sw = new SW32Window (name, this, (long) w);
  898   CHECK_NEW (sw);
  899   listenerHashtable.put ((long) w, l);
  900   return sw;
  901 }
  902 
  903 SW32Window::SW32Window(const SString& n, SW32Impl* i, long _id) 
  904   : name(n), background ("white"), pen (SColor(0), SColor(0xffffffff))
  905 {
  906   parentID = 0;
  907   currentFocusWindow = 0;
  908   shown = false;
  909   clipRegion = 0;
  910   engine = 0;
  911   cdc = 0;
  912   imname = "";
  913   impl = i;
  914   id = _id;
  915   modalID = 0;
  916   clipChained = false;
  917   clipChain = 0;
  918   dbufferOn = 0;
  919   dbuffer = 0;
  920   currentScroll = 0;
  921   windowHashtable.put (id, this);
  922 }
  923 
  924 SW32Window::~SW32Window()
  925 {
  926   if (dbuffer) delete (SDoubleBuffer*) dbuffer;
  927   if (engine) delete engine;
  928   windowHashtable.remove (id);
  929   listenerHashtable.remove (id);
  930 }
  931 
  932 void
  933 SW32Window::show ()
  934 {
  935   if (!shown) shownWindows++;
  936   shown = true;
  937   static bool did=false;
  938   did = true;
  939 
  940   int dx = 0;
  941   int dy = 0;
  942   if (!parentID)
  943   {
  944     RECT rect;
  945     rect.left = getPositionX();
  946     rect.top = getPositionY();
  947     rect.right =  rect.left + (int)getWidth();
  948     rect.bottom =  rect.top + (int)getHeight();
  949     int style = (modalID) 
  950         ? SS_YUDIT_DIALOG_STYLE 
  951         : SS_YUDIT_TOPLEVEL_STYLE;
  952 
  953     if (AdjustWindowRect (&rect, style, false))
  954     {
  955       dx = rect.right - (getPositionX() + (int) getWidth());
  956       dy = rect.bottom - (getPositionY() + (int) getHeight());
  957       int d2x = (getPositionX() - rect.left);
  958       int d2y = (getPositionY() - rect.top);
  959       dx = d2x + dx;
  960       dy = d2y + dy;
  961     }
  962   }
  963 
  964   int posflag =  parentID ? SWP_NOACTIVATE : SWP_NOMOVE;
  965   if (modalID==0)
  966   {
  967      posflag |= SWP_NOZORDER;
  968   }
  969 
  970   SetWindowPos ((HWND)getID(), (HWND)modalID,
  971     getPositionX(), getPositionY(), 
  972     getWidth()+dx, getHeight()+dy,
  973     posflag | SWP_NOACTIVATE | SWP_NOZORDER
  974     | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
  975 
  976   if (!parentID)
  977   {
  978     //setSize(getWidth() + dx, getHeight()+dy);
  979     SetActiveWindow ((HWND)modalID);
  980     BringWindowToTop((HWND)id);
  981     if (modalID!=0)
  982     {
  983       EnableWindow ((HWND)modalID, false);
  984     }
  985   }
  986   
  987   //ShowWindow((HWND)id, SW_SHOWNORMAL);
  988   //ShowWindow((HWND)id, did ?SW_SHOW :cmdShow);
  989   //UpdateWindow((HWND)id);
  990 }
  991 
  992 bool
  993 SW32Window::isVisible ()
  994 {
  995   return IsWindowVisible ((HWND)getID());
  996 }
  997 
  998 void
  999 SW32Window::hide ()
 1000 {
 1001   if (shown) shownWindows--;
 1002   ShowWindow((HWND)id, SW_HIDE);
 1003   shown = false;
 1004   if (!parentID)
 1005   {
 1006     if (modalID!=0)
 1007     {
 1008       EnableWindow ((HWND)modalID, true);
 1009       SetActiveWindow ((HWND)modalID);
 1010       SetForegroundWindow ((HWND)modalID);
 1011       SW32Window* swid = (SW32Window*) windowHashtable.get(modalID);
 1012       if (swid) 
 1013       {
 1014          SW32Window* top = getToplevelWindow (this);
 1015          SW32Window* foc = (SW32Window*) windowHashtable.get(
 1016                top->currentFocusWindow);
 1017          if (foc) foc->getKeyboardFocus();
 1018       }
 1019       //BringWindowToTop((HWND)modalID);
 1020     }
 1021   }
 1022 }
 1023 
 1024 /**
 1025  * This reqests a redraw, efficiently after all events got processed.
 1026  * @param clear is true if the window needs to be cleared before calling redraw.
 1027  * @param x is the x origin of the event
 1028  * @param y is the y origin of the event
 1029  * @param width is the width of the event
 1030  * @param height is the height of the event
 1031  */
 1032 void
 1033 SW32Window::redraw (bool clear, int _x, int _y, unsigned int _width, unsigned int _height)
 1034 {
 1035   if (_x+(int)_width  < 0 || _y + (int) _height < 0)
 1036   {
 1037     return;
 1038   }
 1039   if (_x  > (int)getWidth() || _y > (int)getHeight())
 1040   {
 1041     return;
 1042   }
 1043   handler->addRedrawEvent (id, SRedrawEvent (clear, _x, _y, _width, _height)); 
 1044 }
 1045 
 1046 /**
 1047  * Reparent the window. 
 1048  * TODO: move it to x y
 1049  * @param p is the parent window
 1050  */
 1051 void
 1052 SW32Window::setParent (SWindow* p, int x, int y)
 1053 {
 1054   SW32Window* otop = getToplevelWindow (this);
 1055   SetParent ((HWND)id, (HWND)((SW32Window*)p)->id);
 1056   SetWindowLong ((HWND)id, GWL_STYLE, SS_YUDIT_CHILD_STYLE);
 1057   parentID = ((SW32Window *)p)->id;
 1058   SW32Window* top = getToplevelWindow (this);
 1059   unsigned int i;
 1060   unsigned int j;
 1061   for (i=0; i<otop->accelerators.size(); i++)
 1062   {
 1063     for (j=0; j<otop->accelerators.size(i); j++)
 1064     {
 1065        SAcceleratorListener* l = otop->accelerators.get (i,j);
 1066        if (l==0) continue;
 1067        const SString& key = otop->accelerators.key (i,j);
 1068        top->accelerators .put (key, l);
 1069     }
 1070   }
 1071   otop->accelerators.clear();
 1072 
 1073   for (i=0; i<otop->acceleratorTable.size(); i++)
 1074   {
 1075     for (j=0; j<otop->acceleratorTable.size(i); j++)
 1076     {
 1077        long acc = otop->acceleratorTable.get (i,j);
 1078        if (acc==0) continue;
 1079        const SString& key = otop->acceleratorTable.key (i,j);
 1080        top->acceleratorTable .put (key, acc);
 1081     }
 1082   }
 1083   otop->acceleratorTable.clear();
 1084 }
 1085 
 1086 void
 1087 SW32Window::resize (unsigned int _width, unsigned int _height)
 1088 {
 1089 
 1090   RECT rcClient, rcWindow;
 1091   POINT ptDiff;
 1092 
 1093   if (GetParent ((HWND)getID()) == 0 && GetClientRect((HWND)getID(), &rcClient) 
 1094     && GetWindowRect((HWND)getID(), &rcWindow))
 1095   {
 1096     // rcClient.left and rcClient.top is 0
 1097     ptDiff.x = (rcWindow.right - rcWindow.left) - (rcClient.right-rcClient.left);
 1098     ptDiff.y = (rcWindow.bottom - rcWindow.top) - (rcClient.bottom-rcClient.top);
 1099     //MoveWindow(hWnd,rcWindow.left, rcWindow.top, 
 1100     //nWidth + ptDiff.x, nHeight + ptDiff.y, TRUE);
 1101     unsigned int w = _width + ptDiff.x;
 1102     unsigned int h = _height+ ptDiff.y;
 1103 //    fprintf (stderr, "SetSize=%d %d\n", w, h);
 1104     setSize(_width, _height);
 1105     MoveWindow((HWND)getID(),rcWindow.left, rcWindow.top, w, h, TRUE);
 1106     //SetWindowPos ((HWND)getID(), 0,
 1107     //  getPositionX(), getPositionY(), 
 1108     //  w, h,
 1109     // SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
 1110   }
 1111   else
 1112   {
 1113     if (getWidth() == _width && getHeight() == _height) return;
 1114     setSize(_width, _height);
 1115     SetWindowPos ((HWND)getID(), 0,
 1116       getPositionX(), getPositionY(), 
 1117       getWidth(), getHeight(),
 1118       SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
 1119   }
 1120 }
 1121 
 1122 void
 1123 SW32Window::move (int _x, int _y)
 1124 {
 1125   if (getPositionX() == _x && getPositionY() == _y) return;
 1126   setPosition(_x, _y);
 1127   SetWindowPos ((HWND)getID(), 0,
 1128       getPositionX(), getPositionY(), 
 1129       getWidth(), getHeight(),
 1130       SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
 1131 }
 1132 
 1133 
 1134 void
 1135 SW32Window::setTitle (const SString& title)
 1136 {
 1137   SString windowName=title;
 1138   windowName.append ((char)0);
 1139 
 1140   // Windows98SE
 1141   SString ansi = utf8ToSystem (windowName);
 1142   SetWindowTextA ((HWND)id, ansi.array());
 1143   
 1144   SEncoder u8("utf-8");
 1145   SEncoder u16("utf-16-le");
 1146   SString titleW = u16.encode (u8.decode (windowName));
 1147   SetWindowTextW ((HWND)id, (WCHAR*) titleW.array());
 1148 }
 1149 
 1150 KeyData keyData = { 
 1151   SWindowListener::Key_Undefined,
 1152   false, false, false,
 1153   false, false, false
 1154 };
 1155 
 1156 LRESULT CALLBACK
 1157 _eventHandler (HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
 1158 {
 1159   SW32Window* w = 0;
 1160   SWindowListener* l = 0;
 1161   
 1162   switch(message)
 1163   {
 1164   case WM_GETMINMAXINFO:
 1165     w = windowHashtable.get ((long)hwnd);
 1166     l = listenerHashtable.get ((long)hwnd);
 1167    if (w)
 1168    {
 1169      unsigned int minx = minimumSizesX.get((long)hwnd);
 1170      unsigned int miny = minimumSizesY.get((long)hwnd);
 1171      if (minx && miny)
 1172      {
 1173        LPMINMAXINFO info = (LPMINMAXINFO) lParam;
 1174        /* is it enough ? too much trouble getting the client are size ..*/
 1175        info->ptMinTrackSize.x = minx + 10;
 1176        info->ptMinTrackSize.y = miny + 30;
 1177        return 0;
 1178        RECT rect;
 1179        rect.left = 0;
 1180        rect.top = 0;
 1181        rect.right =  minx;
 1182        rect.bottom =  miny;
 1183        int style = (w->modalID) 
 1184            ? SS_YUDIT_DIALOG_STYLE 
 1185            : SS_YUDIT_TOPLEVEL_STYLE;
 1186        if (!AdjustWindowRect (&rect, style, false))
 1187        {
 1188           return 0;
 1189        }
 1190        info->ptMinTrackSize.x = rect.right - rect.left;
 1191        info->ptMinTrackSize.y = rect.bottom - rect.top;
 1192        return 0;
 1193      }
 1194    }
 1195    break;
 1196   case WM_ACTIVATE:
 1197    break; 
 1198   case WM_KILLFOCUS:
 1199     w = windowHashtable.get ((long)hwnd);
 1200     l = listenerHashtable.get ((long)hwnd);
 1201    if (w)
 1202    {
 1203       SW32Window* top = getToplevelWindow (w);
 1204       long oldT = currentTopFocusWindow;
 1205       long oldW = currentFocusWindow;
 1206       currentTopFocusWindow = 0;
 1207       currentFocusWindow = 0;
 1208       if (oldW != 0)
 1209       {
 1210         SW32Window* wo = windowHashtable.get (oldW);
 1211         SWindowListener* lo = listenerHashtable.get (oldW);
 1212         if (wo && lo)
 1213         {
 1214           sendKeyReleased(&keyData, wo, lo);
 1215           lo->lostKeyboardFocus(wo);
 1216         }
 1217       }
 1218       return 0;
 1219    }
 1220    break;
 1221   case WM_SETFOCUS:
 1222     w = windowHashtable.get ((long)hwnd);
 1223     l = listenerHashtable.get ((long)hwnd);
 1224    if (w)
 1225    {
 1226       SW32Window* top = getToplevelWindow (w);
 1227       long oldT = currentTopFocusWindow;
 1228       long oldW = currentFocusWindow;
 1229 
 1230       currentTopFocusWindow = top->getID();
 1231       currentFocusWindow = top->currentFocusWindow;
 1232 
 1233       /* if we changed window inside top, generate lost and gained event  */
 1234       if (oldW != currentFocusWindow)
 1235       {
 1236          SW32Window* wo = windowHashtable.get (oldW);
 1237          SWindowListener* lo = listenerHashtable.get (oldW);
 1238          if (wo && lo)
 1239          {
 1240             sendKeyReleased(&keyData, wo, lo);
 1241             lo->lostKeyboardFocus(wo);
 1242          }
 1243 
 1244          SW32Window* wn = windowHashtable.get (currentFocusWindow);
 1245          SWindowListener* ln = listenerHashtable.get (currentFocusWindow);
 1246          if (wn && ln) ln->gainedKeyboardFocus(wo);
 1247       }
 1248       return 0;
 1249    }
 1250    break;
 1251   case WM_NCCALCSIZE:
 1252    /* forget it. */
 1253    break;
 1254   case WM_RENDERALLFORMATS:
 1255     putClipText();
 1256     putClipUnicodeText();
 1257     putClipUtf8Text();
 1258     return 0;
 1259   case WM_RENDERFORMAT:
 1260     if ((UINT)wParam == UTF8_STRING)
 1261     {
 1262       return putClipUtf8Text();
 1263     }
 1264     else if ((UINT)wParam == CF_UNICODETEXT)
 1265     {
 1266       return putClipUnicodeText();
 1267     }
 1268     else if ((UINT)wParam == CF_TEXT)
 1269     {
 1270       return putClipText();
 1271     }
 1272     break;
 1273   case WM_DRAWCLIPBOARD:
 1274     w = windowHashtable.get ((long)hwnd);
 1275     l = listenerHashtable.get ((long)hwnd);
 1276     if (w!=0 && w->clipChain != 0)
 1277     {
 1278        SendMessage ((HWND)w->clipChain,  message, wParam, lParam);
 1279     }
 1280     notifyClip();
 1281     return 0;
 1282   case WM_CHANGECBCHAIN:
 1283     w = windowHashtable.get ((long)hwnd);
 1284     l = listenerHashtable.get ((long)hwnd);
 1285     /* repair chain - next is gone */
 1286     if (w!=0 && (long) wParam == w->clipChain)
 1287     {
 1288       w->clipChain = (long) lParam; 
 1289     }
 1290     else if (w!=0 && w->clipChain != 0)
 1291     {
 1292       SendMessage ((HWND)w->clipChain,  message, wParam, lParam);
 1293     }
 1294     return 0;
 1295   case WM_PAINT:
 1296     w = windowHashtable.get ((long)hwnd);
 1297     l = listenerHashtable.get ((long)hwnd);
 1298     /* TODO: might be faster with addRedrawingEvent */
 1299     if (w)
 1300     {
 1301        if (GetUpdateRect (hwnd, 0, true))
 1302        {
 1303           PAINTSTRUCT pstr;
 1304           HDC dc = BeginPaint (hwnd, &pstr);
 1305           if (dc == 0) break ;
 1306 
 1307           if (w->cdc != 0)
 1308           {
 1309              //fprintf (stderr, "PAINT: WONT...");
 1310           }
 1311           else
 1312           {
 1313 #define SD_YUDIT_EVENT_COMPRESSION 1
 1314 #if SD_YUDIT_EVENT_COMPRESSION
 1315            /* Windows has crappy event compression - yudit uses its own */
 1316             handler->addRedrawEvent (w->getID(), 
 1317                SRedrawEvent (pstr.fErase, 
 1318                  pstr.rcPaint.left, pstr.rcPaint.top,
 1319                   pstr.rcPaint.right-pstr.rcPaint.left,
 1320                   pstr.rcPaint.bottom-pstr.rcPaint.top));
 1321 #else
 1322             w->cdc = dc;
 1323 
 1324         // w->dbuffer IS 0
 1325         if (w->dbufferOn && w->dbuffer == 0)
 1326         {
 1327           w->dbuffer = ( pstr.rcPaint.bottom == pstr.rcPaint.top 
 1328                  || pstr.rcPaint.left == pstr.rcPaint.right)
 1329             ? new SDoubleBuffer ((HWND) w->id, (HDC) w->cdc, 
 1330                w->background, 0, 0,
 1331                w->getWidth(), w->getHeight())
 1332             : new SDoubleBuffer ((HWND) w->id, (HDC) w->cdc, 
 1333                w->background, pstr.rcPaint.left, pstr.rcPaint.top, 
 1334                pstr.rcPaint.right-pstr.rcPaint.left, 
 1335                pstr.rcPaint.bottom-pstr.rcPaint.top);
 1336         }
 1337             if (w->dbuffer == 0 && pstr.fErase)
 1338             {
 1339               w->repaintBackground (
 1340                 pstr.rcPaint.left, pstr.rcPaint.top,
 1341                 pstr.rcPaint.right, pstr.rcPaint.bottom);
 1342             }
 1343             l->redraw (w, pstr.rcPaint.left, pstr.rcPaint.top, 
 1344               pstr.rcPaint.right-pstr.rcPaint.left,
 1345               pstr.rcPaint.bottom-pstr.rcPaint.top);
 1346         if (w->dbuffer)
 1347         {
 1348            ((SDoubleBuffer*) w->dbuffer)->copyToScreen (
 1349                (HWND) w->id, 
 1350                (HDC)  w->cdc);
 1351            delete (SDoubleBuffer*) w->dbuffer;
 1352            w->dbuffer = 0;
 1353         }
 1354             w->cdc = 0;
 1355 #endif
 1356             EndPaint (hwnd, &pstr);
 1357           }
 1358           return 0;
 1359        }
 1360     }
 1361     break;
 1362   case WM_DEVICECHANGE:
 1363     imageCache.clear();
 1364     maskCache.clear();
 1365     fprintf (stderr, "DeviceChange - Compatible DC deleted\n");
 1366     DeleteDC (compatibleDC);
 1367     compatibleDC = 0;
 1368     break;
 1369   case WM_ERASEBKGND:
 1370     w = windowHashtable.get ((long)hwnd);
 1371     l = listenerHashtable.get ((long)hwnd);
 1372     /* TODO: might be faster with addRedrawingEvent */
 1373     if (w)
 1374     {
 1375        RECT rect;
 1376        GetClientRect (hwnd, &rect);
 1377     /* does not work - race condition */
 1378 #if 0
 1379         handler->addRedrawEvent (w->getID(), SRedrawEvent (true, 
 1380             rect.left, rect.top,
 1381             rect.right-rect.left, rect.bottom-rect.top));
 1382 #else
 1383        w->cdc = ((HDC) wParam);
 1384        w->repaintBackground (
 1385           rect.left, rect.top,
 1386           rect.right, rect.bottom);
 1387        w->cdc = 0;
 1388 #endif
 1389        return 1;
 1390     }
 1391        
 1392     break;
 1393 
 1394   case WM_CAPTURECHANGED:
 1395      lostCapture((long)lParam);
 1396      return 0;
 1397     break;
 1398 //what a NAME!
 1399 //case WM_NCHITTEST:
 1400   case WM_MOUSEMOVE:
 1401       {
 1402         int fwKeys = (int) wParam;
 1403         short xPos = LOWORD (lParam);
 1404         short yPos = HIWORD (lParam);
 1405         if (fwKeys & MK_LBUTTON)
 1406         {
 1407            buttonDragged ((long) hwnd, 0, xPos, yPos); 
 1408         }
 1409         else if (fwKeys & MK_MBUTTON)
 1410         {
 1411            buttonDragged ((long) hwnd, 1, xPos, yPos); 
 1412         }
 1413         else if (fwKeys & MK_RBUTTON)
 1414         {
 1415            buttonDragged ((long) hwnd, 2, xPos, yPos); 
 1416         }
 1417         else 
 1418         {
 1419            buttonEnter ((long) hwnd);   
 1420         }
 1421       }
 1422       break;
 1423   case WM_RBUTTONDOWN:
 1424       {
 1425         short xPos = LOWORD (lParam);
 1426         short yPos = HIWORD (lParam);
 1427         buttonPressed (long (hwnd), 2, xPos, yPos);
 1428       }
 1429       break;
 1430   case WM_RBUTTONUP:
 1431       {
 1432         short xPos = LOWORD (lParam);
 1433         short yPos = HIWORD (lParam);
 1434         buttonReleased (long (hwnd), 2, xPos, yPos);
 1435       }
 1436       break;
 1437   case WM_MBUTTONDOWN:
 1438       {
 1439         short xPos = LOWORD (lParam);
 1440         short yPos = HIWORD (lParam);
 1441         buttonPressed ((long) hwnd, 1, xPos, yPos);
 1442       }
 1443       break;
 1444   case WM_MBUTTONUP:
 1445       {
 1446         short xPos = LOWORD (lParam);
 1447         short yPos = HIWORD (lParam);
 1448         buttonReleased ((long) hwnd, 1, xPos, yPos);
 1449       }
 1450       break;
 1451   case WM_LBUTTONDOWN:
 1452       {
 1453         short xPos = LOWORD (lParam);
 1454         short yPos = HIWORD (lParam);
 1455         buttonPressed ((long) hwnd, 0, xPos, yPos);
 1456       }
 1457       break;
 1458   case WM_LBUTTONUP:
 1459       {
 1460         short xPos = LOWORD (lParam);
 1461         short yPos = HIWORD (lParam);
 1462         buttonReleased ((long)hwnd, 0, xPos, yPos);
 1463       }
 1464       break;
 1465   case WM_MOUSEWHEEL:
 1466   //case MSH_MOUSEWHEEL:
 1467       {
 1468         // WM_MOUSEWHEEL is only delivered to focus window.
 1469         POINT point;
 1470         point.x = LOWORD(lParam);
 1471         point.y = HIWORD(lParam);
 1472         HWND hwndReal = WindowFromPoint (point);
 1473         // filter out middle button down.
 1474         short butt = LOWORD (wParam);
 1475         if (butt & MK_MBUTTON) break;
 1476         processMouseWheel ((long)hwndReal, (int) GET_WHEEL_DELTA_WPARAM(wParam));
 1477       }
 1478       return 0;
 1479   case WM_IME_CHAR:
 1480       //fprintf (stderr, "WM_IME_COMPOSITION\n");
 1481       {
 1482       }
 1483       break;
 1484   case WM_IME_COMPOSITION:
 1485       w = windowHashtable.get ((long)hwnd);
 1486       l = listenerHashtable.get ((long)hwnd);
 1487       //fprintf (stderr, "WM_IME_CHAR\n");
 1488       if (w && (lParam & GCS_RESULTSTR))
 1489       {
 1490          HIMC himc = ImmGetContext (hwnd);
 1491          if (!himc) break;
 1492          DWORD size = ImmGetCompositionStringW(himc, GCS_RESULTSTR, 0, 0);
 1493          HGLOBAL hglobal = GlobalAlloc (GHND, size + sizeof (WCHAR));
 1494          if (!hglobal)
 1495          {
 1496            ImmReleaseContext (hwnd, himc);
 1497            break;
 1498          }
 1499          LPSTR lpstr = (LPSTR) GlobalLock (hglobal);
 1500          if (lpstr)
 1501          {
 1502            ImmGetCompositionStringW(himc, GCS_RESULTSTR, lpstr, 
 1503              size + sizeof (WCHAR));
 1504            /* copy unicode over */ 
 1505            SV_UCS4 ucs4v;
 1506            SString str (lpstr, (unsigned int)size); 
 1507            for (unsigned int i=0; i+1<str.size(); i=i+2)
 1508            {
 1509               SS_UCS2 u = ((SS_UCS2*) str.array())[i/2];
 1510               ucs4v.append ((SS_UCS4) u);
 1511            }
 1512            /* add surrogates together */
 1513            SEncoder utf8enc ("utf-8");
 1514            SString out = utf8enc.encode (ucs4v);
 1515            keyData.key = SWindowListener::Key_Send;
 1516            sendKeyChar (&keyData, out);
 1517          }
 1518          GlobalUnlock (hglobal);
 1519          GlobalFree (hglobal);
 1520          ImmReleaseContext (hwnd, himc);
 1521          return 0;
 1522       }
 1523       break;
 1524   case WM_CHAR:
 1525   case WM_SYSDEADCHAR:
 1526       {
 1527         unsigned int lKeyData = lParam;
 1528         SString s; s.append ((char)((TCHAR) wParam));
 1529         sendKeyChar (&keyData, s);
 1530       }
 1531       return 0;
 1532   case WM_SYSKEYDOWN:
 1533       /* state, sys, code, down */
 1534       processKey (&keyData, true, wParam, true);
 1535       return 0;
 1536   case WM_SYSKEYUP:
 1537       /* state, sys, code, down */
 1538       processKey (&keyData, true, wParam, false);
 1539       return 0;
 1540   case WM_KEYDOWN:
 1541       /* state, sys, code, down */
 1542       processKey (&keyData, false, wParam, true);
 1543       return 0;
 1544   case WM_KEYUP:
 1545       /* state, sys, code, down */
 1546       processKey (&keyData, false, wParam, false);
 1547       return 0;
 1548   case WM_SIZE:
 1549     w = windowHashtable.get ((long)hwnd);
 1550     l = listenerHashtable.get ((long)hwnd);
 1551     if (w)
 1552     {
 1553       unsigned int width = (unsigned int) LOWORD (lParam);
 1554       unsigned int height = (unsigned int) HIWORD (lParam);
 1555       /*
 1556       RECT rcClient;
 1557       if (GetClientRect((HWND)hwnd, &rcClient))
 1558       {
 1559         w->setSize(rcClient.right-rcClient.left, rcClient.bottom-rcClient.top);
 1560       }
 1561       else
 1562       {
 1563         w->setSize(width, height);
 1564       }
 1565       */
 1566       w->setSize(width, height);
 1567       /* no need to send event to children */
 1568       if (!w->parentID)
 1569       {
 1570         l->resized(w, w->getPositionX(), w->getPositionY(), w->getWidth(), w->getHeight());
 1571       }
 1572       return 0;
 1573     }
 1574     break;
 1575   case WM_MOVE:
 1576     w = windowHashtable.get ((long)hwnd);
 1577     l = listenerHashtable.get ((long)hwnd);
 1578     if (w)
 1579     {
 1580       short xPos = (unsigned int) LOWORD (lParam);
 1581       short yPos = (unsigned int) HIWORD (lParam);
 1582       w->setPosition(xPos, yPos);
 1583       return 0;
 1584     }
 1585     break;
 1586   case WM_COMMAND:
 1587     break;
 1588   case WM_DESTROY:
 1589     w = windowHashtable.get ((long)hwnd);
 1590     l = listenerHashtable.get ((long)hwnd);
 1591     if (w && w->clipChained)
 1592     {
 1593       ChangeClipboardChain (hwnd, (HWND)w->clipChain);
 1594       w->clipChained = false;
 1595     }
 1596     PostQuitMessage (0);
 1597     SEventHandler::exit();
 1598     break;
 1599   case WM_CLOSE:
 1600     w = windowHashtable.get ((long)hwnd);
 1601     l = listenerHashtable.get ((long)hwnd);
 1602     if (w)
 1603     {
 1604       if (w && l && l->windowClose (w))
 1605       {
 1606          w->hide ();
 1607       }
 1608       if (shownWindows == 0)
 1609       {
 1610         if (w && w->clipChained)
 1611         {
 1612           ChangeClipboardChain (hwnd, (HWND)w->clipChain);
 1613           w->clipChained = false;
 1614         }
 1615         PostQuitMessage (0);
 1616         SEventHandler::exit();
 1617       }
 1618       return 0;
 1619     }
 1620     else
 1621     {
 1622       return 0;
 1623     }
 1624     break;
 1625   default:
 1626      return DefWindowProc(hwnd,message,wParam,lParam);
 1627   }
 1628   return DefWindowProc(hwnd,message,wParam,lParam);
 1629 }
 1630 
 1631 /**
 1632  * This event loop is especially tailored for wine
 1633  * where we can not wait on objects and we can not
 1634  * wait on sockets. What can we do? Sleep. That is
 1635  * what Word Excel and all ms stuff is doing anyway
 1636  * so we wont be any different.
 1637  */
 1638 static int
 1639 winWineHack (int readSize, fd_set *ro, int writeSize, fd_set *wo,
 1640   int exceptSize, fd_set *ex, struct timeval* t)
 1641 {
 1642   int  millisec = 2000; /* people should notice they did sg wrong. */
 1643   if (t!=0)
 1644   {
 1645      millisec = (DWORD) (t->tv_sec * 1000 + t->tv_usec / 1000);
 1646   }
 1647   Sleep (millisec);
 1648   return 0;
 1649 }
 1650 
 1651 /**
 1652  * This is a hack to make select work on windows too by  Gaspar 
 1653  * This routine will hook up int SEventBSD hook.
 1654  */
 1655 static int
 1656 winSelectHack (int readSize, fd_set *ro, int writeSize, fd_set *wo,
 1657   int exceptSize, fd_set *ex, struct timeval* t)
 1658 {
 1659   int maxFd = (readSize > writeSize) ? readSize : writeSize;
 1660   maxFd = (exceptSize > maxFd) ? exceptSize : maxFd;
 1661 
 1662   /* build events */
 1663   DWORD millisec = WSA_INFINITE;
 1664   if (t!=0)
 1665   {
 1666      millisec = (DWORD) (t->tv_sec * 1000 + t->tv_usec / 1000);
 1667   }
 1668   if (maxFd == 0 && millisec ==0)
 1669   {
 1670     return 0;
 1671   }
 1672   SBinVector<WSAEVENT> events;
 1673   SV_INT vmap;
 1674 
 1675 // Win95 does not have it.
 1676 #ifdef HAVE_WS2_32_DLL
 1677   /* Nothing only timer - or not even exceptSize - forget that */
 1678   unsigned int i;
 1679   /* go through read and write */
 1680   for (i=0; i<readSize; i++)
 1681   {
 1682      if (!FD_ISSET (i, ro)) continue;
 1683      WSAEVENT event = WSACreateEvent ();
 1684      WSAEventSelect ((SOCKET)i, event, FD_ACCEPT|FD_READ|FD_CLOSE);
 1685      events.append (events);
 1686      vmap.append (-(int)i);
 1687   }
 1688   for (i=0; i<writeSize; i++)
 1689   {
 1690      if (!FD_ISSET (i, wo)) continue;
 1691      WSAEVENT event = WSACreateEvent ();
 1692      WSAEventSelect ((SOCKET)i, event, FD_WRITE);
 1693      events.append (events);
 1694      vmap.append ((int)i);
 1695   }
 1696 
 1697   DWORD idx;
 1698   /* maybe WSA_INFINITE should be a timer ... */
 1699   idx = WSAWaitForMultipleEvents(events.size(), events.array(),
 1700     FALSE, millisec, FALSE);
 1701 #else
 1702   DWORD idx;
 1703 #endif
 1704 
 1705   /*
 1706    * We need this one because WSAWaitForMultipleEvents 
 1707    * will not react to window events. in case events.array is
 1708    * empty it fails.
 1709    */
 1710   idx = MsgWaitForMultipleObjects(events.size(), (LPHANDLE)events.array(),
 1711     FALSE, millisec, QS_ALLINPUT);
 1712   if (readSize == 0 && ro != 0) FD_ZERO (ro);
 1713   if (writeSize == 0 && wo != 0) FD_ZERO (wo);
 1714   int lerr = GetLastError();
 1715 #ifdef HAVE_WS2_32_DLL
 1716   for (i=0; i<events.size(); i++)
 1717   {
 1718     WSACloseEvent (events[i]);
 1719   }
 1720 #endif
 1721   if (idx == 0xFFFFFFFF)
 1722   {
 1723     fprintf (stderr, "SEventBSD::WaitForMultipleObjects error (%d)\n", lerr);
 1724     return -1;
 1725   }
 1726   if (idx == WAIT_TIMEOUT)
 1727   {
 1728     //fprintf (stderr, "WAIT TIMEOUT\n"); 
 1729     return 0;
 1730   }
 1731   int eventnum =  idx - WAIT_OBJECT_0;
 1732   if (eventnum == vmap.size()) 
 1733   {
 1734     //fprintf (stderr, "WINDOW EVENT!\n");
 1735     return -2; /* outside event - this is a  window event handled in jo */
 1736   }
 1737   int fd = vmap[eventnum];
 1738   if (fd < 0) // read 
 1739   {
 1740      fd = - fd;
 1741      FD_SET (fd, ro);
 1742      return 1;
 1743   }
 1744   else if ( fd > 0)
 1745   {
 1746      FD_SET (fd, wo);
 1747      return 1;
 1748   }
 1749   return -2; /* what the heck? */
 1750 }
 1751 
 1752 void
 1753 SW32Window::setBackground(const SColor &color)
 1754 {
 1755   background = color;
 1756   pen = SPen(pen.getForeground(), background, pen.getLineWidth());
 1757 }
 1758 
 1759 static HBRUSH 
 1760 getSolidBrush (const SColor& clr)
 1761 {
 1762   SString mvle = SString ((long)(clr.getValue() & 0x00ffffff));
 1763   HBRUSH brush = brushes.get (mvle); 
 1764   if (brush == 0)
 1765   {
 1766     COLORREF ref = PALETTERGB (clr.red, 
 1767       clr.green, clr.blue);
 1768     brush = ::CreateSolidBrush (ref);
 1769     brushes.put (mvle, brush);
 1770   }
 1771   return brush;
 1772 }
 1773 static HPEN 
 1774 getBitPen (const SColor& clr)
 1775 {
 1776   SString mvle = SString ((long)(clr.getValue() & 0x00ffffff));
 1777   HPEN hpen = pens.get (mvle); 
 1778   if (hpen == 0)
 1779   {
 1780      hpen = CreatePen (PS_SOLID, 0, RGB(clr.red, clr.green, clr.blue));
 1781      pens.put (mvle, hpen);
 1782   }
 1783   return hpen;
 1784 }
 1785 
 1786 void
 1787 SW32Window::repaintBackground(int left, int top, 
 1788    int right, int bottom)
 1789 {
 1790   /* remove clipping */
 1791   void* oclip = clipRegion;
 1792   clipRegion = 0;
 1793   bitfill (background, left, top, right - left, bottom - top);
 1794   clipRegion = oclip;
 1795 }
 1796 
 1797 /**
 1798  * Fill a solid rectangle
 1799  * @param x is the upper left corner
 1800  * @param y is the upper top corner
 1801  * @param width is the width of the region to fill
 1802  * @param height is the height of the region to fill
 1803  */
 1804 void
 1805 SW32Window::bitfill (const SColor& bg, int _x, int _y, 
 1806  unsigned int _width, unsigned int _height)
 1807 {
 1808   bool mydc = dcin();
 1809   RECT rect;
 1810   rect.left = _x;
 1811   rect.top = _y;
 1812   rect.right = _x + (int) _width;
 1813   rect.bottom = _y + (int) _height;
 1814 
 1815   HBRUSH brush = getSolidBrush (bg);
 1816   int mode = SetMapMode ((HDC)cdc, MM_TEXT);
 1817   FillRect ((HDC)cdc, &rect, brush);
 1818   SetMapMode ((HDC)cdc, mode);
 1819   dcout (mydc);
 1820 }
 1821 
 1822 /**
 1823  * Draw a solid line.
 1824  * @param x is the starting x point
 1825  * @param y is the starting y point
 1826  * @param x is the ending non-exclusive  x point
 1827  * @param y is the ending non-exclusive  y point
 1828  */
 1829 void
 1830 SW32Window::bitline (const SColor& fg, int _x, int _y, int _tox, int _toy)
 1831 {
 1832   bool mydc = dcin();
 1833   HPEN hpen = getBitPen (fg);
 1834   SelectObject ((HDC)cdc, hpen);
 1835   MoveToEx ((HDC)cdc, _x, _y, 0);
 1836   LineTo ((HDC)cdc, _tox, _toy);
 1837   /* no last point otherwiseon windows */
 1838   LineTo ((HDC)cdc, _tox+1, _toy);
 1839   dcout (mydc);
 1840 }
 1841 
 1842 /**
 1843  * Draw a solid point.
 1844  * @param x is the x point
 1845  * @param y is the y point
 1846  */
 1847 void
 1848 SW32Window::bitpoint (const SColor& clr, int _x, int _y)
 1849 {
 1850   bool mydc = dcin();
 1851   COLORREF ref = PALETTERGB (clr.red, clr.green, clr.blue);
 1852   ::SetPixel ((HDC)cdc, _x, _y, ref);
 1853   dcout (mydc);
 1854 }
 1855 
 1856 void
 1857 SW32Window::bitpoints (const SColor& clr, const int* _x, const int* _y, 
 1858          unsigned int _size)
 1859 {
 1860   bool mydc = dcin();
 1861   COLORREF ref = PALETTERGB (clr.red, clr.green, clr.blue);
 1862   for (unsigned int i=0; i<_size; i++)
 1863   {
 1864     ::SetPixel ((HDC)cdc, _x[i], _y[i], ref);
 1865   }
 1866   dcout (mydc);
 1867 }
 1868 
 1869 /**
 1870  * Afetr this size things wont be cached.
 1871  */
 1872 void
 1873 SW32Window::setPixmapCacheSize(unsigned int _size)
 1874 {
 1875 //  fprintf (stderr, "setPixmapCacheSize=%u\n", _size);
 1876   imageCache.setSize (_size);
 1877   maskCache.setSize (_size);
 1878 }
 1879  
 1880 /**
 1881  * turn on/off the cache and clear it
 1882  */
 1883 void
 1884 SW32Window::setPixmapCacheOn (bool _on)
 1885 {
 1886   // Win98 grocks under bitmaps.
 1887   imageCache.setOn (_on);
 1888   maskCache.setOn (_on);
 1889 }
 1890 
 1891 /**
 1892  * This one can return false if it fails.
 1893  */
 1894 void
 1895 SW32Window::putImage (int _x, int _y, const SImage& im)
 1896 {
 1897   bool mydc = dcin();
 1898 
 1899   /* bitmap may be selected in a dc . dont delet now thinking....*/
 1900   const SString& ks = (const SString&) im.getID();
 1901   char a[10];
 1902   const SColor& cf = pen.getForeground();
 1903   const SColor& cb = pen.getBackground();
 1904   a[0] = 'i';
 1905   a[1] = 'm';
 1906   a[2] = (char) cf.red;
 1907   a[3] = (char) cf.green;
 1908   a[4] = (char) cf.blue;
 1909   a[5] = (char) cb.red;
 1910   a[6] = (char) cb.green;
 1911   a[7] = (char) cb.blue;
 1912   SString key (a, 8);
 1913   key.append (ks);
 1914 
 1915   /* Bitmap is always added, mask is on-demand */
 1916   if (compatibleDC == 0)
 1917   {
 1918      compatibleDC = CreateCompatibleDC((HDC)cdc);
 1919      if (compatibleHBitmap!=0)
 1920      {
 1921        DeleteObject (compatibleHBitmap);
 1922      }
 1923      compatibleHBitmap = CreateCompatibleBitmap(compatibleDC, 8, 8);
 1924   }
 1925 
 1926   SBitmapItem* maskItem = maskCache.get (key);
 1927   SBitmapItem* bitmapItem = imageCache.get (key);
 1928   HBITMAP  bitmap;
 1929   HBITMAP  mask;
 1930   SBitmapItem bitem;
 1931   SBitmapItem mitem;
 1932   bitem.width = im.getWidth(); bitem.height = im.getHeight();
 1933   mitem.width = im.getWidth(); mitem.height = im.getHeight();
 1934   if (maskItem && bitmapItem)
 1935   {
 1936     bitmap = bitmapItem->bitmap;
 1937     mask = maskItem->bitmap;
 1938     bitem.bitmap = bitmap;
 1939     mitem.bitmap = mask;
 1940     bitem.dc = bitmapItem->dc;
 1941     mitem.dc = maskItem->dc;
 1942     bitem.x = bitmapItem->x; bitem.y = bitmapItem->y;
 1943     mitem.x = maskItem->x; mitem.y = maskItem->y;
 1944     bitem.width = bitmapItem->width; bitem.height = bitmapItem->height;
 1945     mitem.width = maskItem->width; mitem.height = maskItem->height;
 1946   }
 1947   else 
 1948   {
 1949     bitmap = 0;
 1950     mask = 0;
 1951     bitem.x = 0; bitem.y = 0;
 1952     mitem.x = 0; mitem.y = 0;
 1953     if (im.getShades() == 0)
 1954     {
 1955       createColoredBitmap (pen, im, &bitmap, &mask, (HDC)cdc, compatibleDC);
 1956     }
 1957     else
 1958     {
 1959       createShadedBitmap (pen, im, &bitmap, &mask, (HDC)cdc, compatibleDC);
 1960     }
 1961     /* cache this */
 1962     SelectObject (compatibleDC, bitmap);
 1963     bitem.dc = compatibleDC;
 1964     bitem.bitmap = bitmap;
 1965     imageCache.put (key, bitem);
 1966 
 1967     /* cache mask */
 1968     SelectObject (compatibleDC, mask);
 1969     mitem.dc = compatibleDC;
 1970     mitem.bitmap = mask;
 1971     maskCache.put (key, mitem);
 1972   }
 1973 
 1974   if (mask)
 1975   {
 1976     /* if cached, dc is not same, not necessary */
 1977     if (mitem.dc == bitem.dc) SelectObject (mitem.dc, mask);
 1978     BitBlt ((HDC)cdc, _x, _y, mitem.width, mitem.height, 
 1979          mitem.dc, mitem.x, mitem.y, SRCAND);
 1980   }
 1981 
 1982   if (bitmap)
 1983   {
 1984     /* if cached, dc is not same, not necessary */
 1985     if (mitem.dc == bitem.dc) SelectObject (bitem.dc, bitmap);
 1986     BitBlt ((HDC)cdc, _x, _y, bitem.width, bitem.height, 
 1987         bitem.dc, bitem.x, bitem.y, SRCPAINT);
 1988   }
 1989 
 1990   /* cache was used */
 1991   if (maskItem && bitmapItem)
 1992   {
 1993     dcout (mydc);
 1994     return;
 1995   }
 1996   SelectObject (compatibleDC, compatibleHBitmap);
 1997   if (bitmap) DeleteObject (bitmap);
 1998   if (mask) DeleteObject (mask);
 1999   dcout (mydc);
 2000   return;
 2001 }
 2002 
 2003 /**
 2004  * Create two bitmaps, one for the image and one for the colored ones.
 2005  * @param p is the image
 2006  * @param m is the shape image. it contains 1's where ther is no image.
 2007  * @param dc is a dc that has the original colored bitmap selcted in it.
 2008  * @param _dc is a dc we can use - it usually has a 1 depth bitmap in it
 2009  */
 2010 static void
 2011 createColoredBitmap (const SPen& pen, const SImage& im, 
 2012     HBITMAP* p, HBITMAP* m, HDC odc, HDC _dc)
 2013 {
 2014   int imageWidth = (int) im.getWidth();
 2015   int imageHeight = (int) im.getHeight();
 2016 
 2017   *p = CreateCompatibleBitmap (odc, imageWidth, imageHeight);
 2018   if (*p==0) 
 2019   {
 2020      fprintf (stderr, "can not create colored bitmap width=%u height=%u\n", 
 2021        imageWidth, imageHeight);
 2022      /* this is win98 - another piece of .... */
 2023      return;
 2024   }
 2025   SelectObject (_dc, *p);
 2026   for (int y=0; y<imageHeight; y++)
 2027   {
 2028     for (int x=0; x<imageWidth; x++)
 2029     {
 2030       SColor clr (im.getShade (x, y));
 2031       SColor bg (pen.getBackground());
 2032       if (clr.alpha != 0) bg.blend (clr);
 2033       COLORREF ref = (clr.alpha == 0)
 2034             ? PALETTERGB (0, 0, 0)
 2035             :  PALETTERGB (bg.red, bg.green, bg.blue);
 2036       SetPixel (_dc, x, y, ref);
 2037     }
 2038   }
 2039   
 2040   if (m != 0)
 2041   /* First wipe out the shape */
 2042   {
 2043     *m = CreateCompatibleBitmap (odc, imageWidth, imageHeight);
 2044     if (*m==0) 
 2045     {
 2046        fprintf (stderr, 
 2047         "can not create colored bitmap mask width=%u height=%u\n", 
 2048         imageWidth, imageHeight);
 2049        /* this is win98 - another piece of .... */
 2050        return;
 2051     }
 2052     SelectObject (_dc, *m);
 2053     for (int y=0; y<imageHeight; y++)
 2054     {
 2055       for (int x=0; x<imageWidth; x++)
 2056       {
 2057         SColor c (im.getShade (x, y));
 2058         COLORREF ref = (c.alpha==0)
 2059             ? PALETTERGB (0xff, 0xff, 0xff)
 2060             : PALETTERGB (0, 0, 0);
 2061         SetPixel (_dc, x, y, ref);
 2062       }
 2063     }
 2064   }
 2065 }
 2066 
 2067 /**
 2068  * Create two bitmaps, one for the image and one for the shade.
 2069  * @param p is the image
 2070  * @param m is the shape image. it contains 1's where ther is no image.
 2071  * @param dc is a dc that has the original colored bitmap selcted in it.
 2072  * @param _dc is a dc we can use - it usually has a 1 depth bitmap in it
 2073  */
 2074 static void
 2075 createShadedBitmap (const SPen& pen, const SImage& im, 
 2076   HBITMAP* p, HBITMAP* m, HDC odc, HDC _dc)
 2077 {
 2078   int imageWidth = (int) im.getWidth();
 2079   int imageHeight = (int) im.getHeight();
 2080 
 2081   int i;
 2082   if (m != 0)
 2083   /* First wipe out the shape */
 2084   {
 2085     *m = CreateCompatibleBitmap (odc, imageWidth, imageHeight);
 2086     if (*m==0) 
 2087     {
 2088        fprintf (stderr, "can not create mask width=%u height=%u\n", 
 2089          imageWidth, imageHeight);
 2090        /* this is win98 - another piece of .... */
 2091        return;
 2092     }
 2093     SelectObject (_dc, *m);
 2094     for (int y=0; y<imageHeight; y++)
 2095     {
 2096       for (int x=0; x<imageWidth; x++)
 2097       {
 2098         SS_WORD32 sh = im.getShade (x, y);
 2099         COLORREF  ref = (sh==0) 
 2100             ? PALETTERGB (0xff, 0xff, 0xff)
 2101             : PALETTERGB (0, 0, 0);
 2102         SetPixel (_dc, x, y, ref);
 2103       }
 2104     }
 2105   }
 2106 
 2107   int shades = im.getShades();
 2108   COLORREF* colors  = new COLORREF[shades];
 2109   CHECK_NEW (colors);
 2110   /*
 2111    * We could blend it with the corrent background, 
 2112    * but we would lose a lot of speed...
 2113    */
 2114   for (i=0; i<shades; i++)
 2115   {
 2116       SColor bg (pen.getBackground());
 2117       SColor fg (pen.getForeground().red,
 2118         pen.getForeground().green, 
 2119         pen.getForeground().blue,
 2120         (unsigned char) (i * 255 /(shades-1)));
 2121       bg.blend (fg);
 2122 
 2123       colors[i] =  PALETTERGB (bg.red, bg.green, bg.blue);
 2124   } 
 2125 
 2126 
 2127   *p = CreateCompatibleBitmap (odc, imageWidth, imageHeight);
 2128   if (*p==0) 
 2129   {
 2130      fprintf (stderr, "can not create bitmap width=%u height=%u\n", 
 2131        imageWidth, imageHeight);
 2132      /* this is win98 - another piece of .... */
 2133      return;
 2134   }
 2135   SelectObject (_dc, *p);
 2136   /* Then blot the image */
 2137   for (int y=0; y<imageHeight; y++)
 2138   {
 2139     for (int x=0; x<imageWidth; x++)
 2140     {
 2141       SS_WORD32 sh = im.getShade (x, y);
 2142       COLORREF  ref = (sh==0) 
 2143         ? PALETTERGB (0,0,0) 
 2144         : colors[im.getShade (x, y)];
 2145       SetPixel (_dc, x, y, ref);
 2146     }
 2147   }
 2148   delete colors;
 2149 }
 2150 
 2151 #define SS_SHADING_COLORS (SD_OVERSAMPLE * SD_OVERSAMPLE +1)
 2152 #define SS_DOUBLE_SCAN 1
 2153 
 2154 /**
 2155  * Drawing routines inherited from SCanvas
 2156  */
 2157 bool
 2158 SW32Window::beginImage (double _x, double _y, const SString& _id, const SColor& back)
 2159 {
 2160   pen.setBackground (back);
 2161   if (engine ==0) engine = new SGEngine();
 2162   if (isCacheOn)
 2163   {
 2164     return engine->beginImage ((int)_x, (int)_y, _id);
 2165   }
 2166   else
 2167   {
 2168     return engine->beginImage ((int)_x, (int)_y, "");
 2169   }
 2170 }
 2171 void
 2172 SW32Window::newpath ()
 2173 {
 2174   engine->newpath ();
 2175 }
 2176 
 2177 void
 2178 SW32Window::fill (const SPen& _pen)
 2179 {
 2180   if (pen != _pen)
 2181   {
 2182      pen = _pen;
 2183   }
 2184   if (engine==0) return;
 2185 
 2186   engine->fill (0, 0, getWidth(), getHeight(), pen);
 2187 }
 2188 /**
 2189  * FIXME:
 2190  * This method is not implemented 
 2191  */
 2192 void
 2193 SW32Window::stroke (const SPen& _pen)
 2194 {
 2195   if (engine ==0) return;
 2196   if (pen != _pen)
 2197   {
 2198      pen = _pen;
 2199   }
 2200   engine->stroke(0,0, getWidth(), getHeight(), pen);
 2201 }
 2202 
 2203 
 2204 /**
 2205  * FIXME: fill and return the resulting image for better cahcing.
 2206  */
 2207 void
 2208 SW32Window::endImage ()
 2209 {
 2210   if (engine==0) return;
 2211 
 2212   SImage* si= engine->endImage ();
 2213   if (si==0) return; /* offscreen */
 2214 
 2215   /* Use the putimage that does some cacheing. */
 2216   if (imageCache.isOn())
 2217   {
 2218     putImage (si->getOrigoX(), si->getOrigoY(), *si);
 2219     delete si;
 2220     return;
 2221   }
 2222   bool mydc = dcin();
 2223   /* 
 2224    *  Here comes Gaspar's version of 
 2225    * "Poor man's transparency" It depends on believing that
 2226    *  background of the window in the region is really pen.getBackground()
 2227    *  If it is not true you should get the image yourself.
 2228    */
 2229   if (compatibleDC == 0)
 2230   {
 2231      compatibleDC = CreateCompatibleDC((HDC)cdc);
 2232      if (compatibleHBitmap!=0)
 2233      {
 2234        DeleteObject (compatibleHBitmap);
 2235      }
 2236      compatibleHBitmap = CreateCompatibleBitmap(compatibleDC, 8, 8);
 2237   }
 2238   HBITMAP bitmap;
 2239   HBITMAP mask;
 2240   createShadedBitmap (pen, *si, &bitmap, &mask, (HDC)cdc, compatibleDC);
 2241   if (mask)
 2242   {
 2243     SelectObject (compatibleDC, mask);
 2244     BitBlt ((HDC)cdc, si->getOrigoX(), si->getOrigoY(), 
 2245          si->getWidth(), si->getHeight(), 
 2246          compatibleDC, 0, 0, SRCAND);
 2247   }
 2248   
 2249   if (bitmap)
 2250   {
 2251     SelectObject (compatibleDC, bitmap);
 2252     BitBlt ((HDC)cdc, si->getOrigoX(), si->getOrigoY(), 
 2253          si->getWidth(), si->getHeight(), 
 2254          compatibleDC, 0, 0, SRCPAINT);
 2255   }
 2256   /* can not delete a bitmap if it is selected in */
 2257   SelectObject (compatibleDC, compatibleHBitmap);
 2258   if (mask) DeleteObject (mask);
 2259   if (bitmap) DeleteObject (bitmap);
 2260   delete si;
 2261   dcout (mydc);
 2262 }
 2263 
 2264 
 2265 /**
 2266  * Move to a new point
 2267  * This will clear the path and push 3 element-pairs 
 2268  * one is the bounding low, second is bounding high 
 2269  * third is the new coord.
 2270  */
 2271 void
 2272 SW32Window::moveto (double x, double y)
 2273 {
 2274   if (engine ==0) return;
 2275   engine->moveto (x, y);
 2276 }
 2277 
 2278 /**
 2279  * The lowest level function to add a new element
 2280  */
 2281 void
 2282 SW32Window::lineto (double x, double y)
 2283 {
 2284   if (engine ==0) return;
 2285   engine->lineto (x, y);
 2286 }
 2287 
 2288 /** 
 2289  *  Draw a cubic beizer curve
 2290  */
 2291 void
 2292 SW32Window::curveto (double _x0, double _y0, double _x1, 
 2293   double _y1, double _x2, double _y2)
 2294 {
 2295   if (engine ==0) return;
 2296   engine->curveto (_x0, _y0, _x1, _y1, _x2, _y2);
 2297 }
 2298 
 2299 void
 2300 SW32Window::closepath()
 2301 {
 2302   if (engine ==0) return;
 2303   engine->closepath();
 2304 }
 2305 /**
 2306  * TODO: not implemented 
 2307  */
 2308 void
 2309 SW32Window::rotate (double angle)
 2310 {
 2311   if (engine ==0) engine = new SGEngine();
 2312   engine->rotate (angle);
 2313 }
 2314 
 2315 void
 2316 SW32Window::scale (double x, double y)
 2317 {
 2318   if (engine ==0) engine = new SGEngine();
 2319   engine->scale (x, y);
 2320 }
 2321 
 2322 void
 2323 SW32Window::translate (double x, double y)
 2324 {
 2325   if (engine ==0) engine = new SGEngine();
 2326   engine->translate (x, y);
 2327 }
 2328 
 2329 void
 2330 SW32Window::pushmatrix()
 2331 {
 2332   if (engine ==0) engine = new SGEngine();
 2333   engine->pushmatrix();
 2334 }
 2335 
 2336 void
 2337 SW32Window::popmatrix()
 2338 {
 2339   if (engine ==0) engine = new SGEngine();
 2340   engine->popmatrix();
 2341 }
 2342 
 2343 /**
 2344  * Clear a region (set it to the background)
 2345  * This should work with a clipped region.
 2346  * @param x is the upper left corner
 2347  * @param y is the upper top corner
 2348  * @param width is the width of the region to clear
 2349  * @param height is the height of the region to clear
 2350  */
 2351 void
 2352 SW32Window::clear (int _x, int _y, unsigned int _width, unsigned int _height)
 2353 {
 2354   bitfill (background, _x, _y, _width, _height);
 2355 }
 2356 
 2357 /**
 2358  * Copy an area on the window to another area.
 2359  * overlap is ok.
 2360  * @param x is the upper left corner
 2361  * @param y is the upper top corner
 2362  * @param width is the width of the region to copy
 2363  * @param height is the height of the region to copy
 2364  * @param tox is the destination left corner
 2365  * @param toy is the destination top corner
 2366  */
 2367 void
 2368 SW32Window::copy (int _x, int _y, unsigned int _width, unsigned int _height, 
 2369   int _tox, int _toy)
 2370 {
 2371   //XCopyArea (impl->display, (Window) id, (Window) id, 
 2372   //    gc, x, y, width, height, tox, toy);
 2373   bool mydc = dcin();
 2374   BitBlt ((HDC)cdc, _tox, _toy, _width, _height, 
 2375          (HDC)cdc, _x, _y, SRCCOPY);
 2376   handler->moveRedrawEvent (id, _tox-_x, _toy-_y);
 2377   dcout (mydc);
 2378 }
 2379 
 2380 /**
 2381  * Assign a rectangualr clip area. Everithing outside this area will be clipped.
 2382  */
 2383 void
 2384 SW32Window::setClippingArea (int _x, int _y, unsigned int _width, unsigned int _height)
 2385 {
 2386   if (clipRegion != 0)
 2387   {
 2388      DeleteObject ((HRGN) clipRegion);
 2389   }
 2390   HRGN rgn = CreateRectRgn (_x, _y, _x + (int) _width, _y + (int) _height);
 2391   clipRegion = rgn;
 2392   if (cdc) SelectClipRgn ((HDC)cdc, rgn);
 2393 }
 2394 
 2395 /**
 2396  *  clear the clipping area.
 2397  */
 2398 void
 2399 SW32Window::removeClippingArea ()
 2400 {
 2401   if (!clipRegion)
 2402   {
 2403     if (cdc)
 2404     {
 2405       SelectClipRgn ((HDC)cdc, 0);
 2406     }
 2407     return;
 2408   }
 2409   DeleteObject ((HRGN) clipRegion);
 2410   clipRegion = 0;
 2411   if (cdc)
 2412   {
 2413     SelectClipRgn ((HDC)cdc, 0);
 2414   }
 2415 }
 2416 
 2417 static int dcins = 0;
 2418 
 2419 /**
 2420  * Gointo a dc. return true if it is a borrowed resource .
 2421  * this should be passed to dcout when exiting dc
 2422  */
 2423 bool
 2424 SW32Window::dcin()
 2425 {
 2426   if (dcins >0)
 2427   {
 2428      fprintf (stderr, "SW32Window::dcin error %d\n", dcins);
 2429   }
 2430   dcins++;
 2431   if (dbuffer)
 2432   {
 2433     cdc = ((SDoubleBuffer*)dbuffer)->bitmapHDC;
 2434     SelectClipRgn ((HDC)cdc, (HRGN) clipRegion);
 2435     return false;
 2436   }
 2437   if (cdc != 0)
 2438   {
 2439     SelectClipRgn ((HDC)cdc, (HRGN) clipRegion);
 2440     return false;
 2441   }
 2442   cdc = GetDC((HWND)id);
 2443   if (cdc == 0) fprintf (stderr, "DC==NULL\n");
 2444   SelectClipRgn ((HDC)cdc, (HRGN) clipRegion);
 2445   return true;
 2446 }
 2447 void
 2448 SW32Window::dcout(bool wasin)
 2449 {
 2450   if (dcins ==0)
 2451   {
 2452      fprintf (stderr, "SW32Window::dcout error %d\n", dcins);
 2453      return;
 2454   }
 2455   else
 2456   {
 2457      dcins--;
 2458   }
 2459   SelectClipRgn ((HDC)cdc, 0);
 2460   if (wasin && dbuffer == 0)
 2461   {
 2462     ReleaseDC ((HWND)id, (HDC)cdc);
 2463     cdc = 0;
 2464   }
 2465 }
 2466 
 2467 /**
 2468  */
 2469 void
 2470 SW32Window::wait ()
 2471 {
 2472   handler->doWin32Loop();
 2473   /* we lost the job - we are in the job callback  */
 2474 
 2475   SJob* sjob = new SJob();
 2476   // SGC BUG in dialogs same job removed.
 2477   // SEventHandler::addJob(handler->job, handler);
 2478    SEventHandler::addJob(sjob, handler);
 2479   while (shown && SEventHandler::next());
 2480   SEventHandler::remove(sjob);
 2481   delete sjob;
 2482 }
 2483 
 2484 static int buttonLastX[3];
 2485 static int buttonLastY[3];
 2486 
 2487 long lastMouseWindow = 0;
 2488 
 2489 /**
 2490  * Generate a mouse enter and mouse leave event from what we have - 
 2491  * the current window where the mouse is...
 2492  */
 2493 static void 
 2494 buttonEnter (long hwnd)
 2495 {
 2496   if (lastMouseWindow == hwnd) return;
 2497   SW32Window* w=0;
 2498   SWindowListener* l=0;
 2499   if (lastMouseWindow)
 2500   {
 2501     w = windowHashtable.get (lastMouseWindow);
 2502     l = listenerHashtable.get (lastMouseWindow);
 2503     if (w != 0 && l!=0) l->leaveWindow (w);
 2504   }
 2505   lastMouseWindow = hwnd;
 2506   if (lastMouseWindow)
 2507   {
 2508     w = windowHashtable.get (lastMouseWindow);
 2509     l = listenerHashtable.get (lastMouseWindow);
 2510     if (w != 0 && l!=0) l->enterWindow (w);
 2511   }
 2512 }
 2513 
 2514 /**
 2515  * Work on buttonFlags buttons and do 
 2516  * the actual delivery of events on actual windows.
 2517  */
 2518 static void
 2519 buttonPressed (long hwnd, int button, int x, int y)
 2520 {
 2521   buttonEnter (hwnd);
 2522   if (buttonFlags[button]) return;
 2523   if (buttonFlags[0] ==0 && buttonFlags[1] == 0 && buttonFlags[2] == 0)
 2524   {
 2525     SetCapture ((HWND)hwnd);
 2526   }
 2527   buttonFlags[button] = hwnd;
 2528   buttonLastX[button] = x;
 2529   buttonLastY[button] = y;
 2530   SW32Window* w = windowHashtable.get ((long)hwnd);
 2531   SWindowListener* l = listenerHashtable.get ((long)hwnd);
 2532   if (w == 0 || l==0) return;
 2533   l->buttonPressed (w, button, x, y);
 2534 }
 2535 
 2536 static void
 2537 processMouseWheel (long hwnd, int increment) {
 2538   SW32Window* w = windowHashtable.get ((long)hwnd);
 2539   SWindowListener* l = listenerHashtable.get ((long)hwnd);
 2540   if (w == 0 || l==0) return;
 2541   w->currentScroll += increment;
 2542   if (w->currentScroll > WHEEL_DELTA * 20) {
 2543        w->currentScroll =  WHEEL_DELTA * 20;
 2544   }
 2545   if (w->currentScroll <  WHEEL_DELTA * -20) {
 2546        w->currentScroll = WHEEL_DELTA * -20;
 2547   }
 2548 
 2549   if (w->currentScroll < 0) {
 2550     while (w->currentScroll < WHEEL_DELTA) {
 2551         // caretDown
 2552        l->buttonPressed (w, 4, (int)0, (int)0);
 2553        w->currentScroll += WHEEL_DELTA*2;
 2554     }
 2555   } else {
 2556     while (w->currentScroll > WHEEL_DELTA) {
 2557        // caretUp
 2558        l->buttonPressed (w, 3, (int)0, (int)0);
 2559        w->currentScroll -= WHEEL_DELTA*2;
 2560     }
 2561   }
 2562 }
 2563 
 2564 static void
 2565 buttonDragged (long nwnd, int button, int x, int y)
 2566 {
 2567   buttonEnter (nwnd);
 2568   if (buttonFlags[button] != nwnd) return;
 2569   buttonLastX[button] = x;
 2570   buttonLastY[button] = y;
 2571   long hwnd = buttonFlags[button];
 2572   SW32Window* w = windowHashtable.get ((long)hwnd);
 2573   SWindowListener* l = listenerHashtable.get ((long)hwnd);
 2574   if (w == 0 || l==0) return;
 2575   l->buttonDragged (w, button, x, y);
 2576 }
 2577 
 2578 static void
 2579 buttonReleased (long nwnd, int button, int x, int y)
 2580 {
 2581   buttonEnter (nwnd);
 2582   if (!buttonFlags[button]) return;
 2583   bool samebutton = (nwnd == buttonFlags[button]);
 2584   buttonLastX[button] = x;
 2585   buttonLastY[button] = y;
 2586   long hwnd = buttonFlags[button];
 2587   SW32Window* w = windowHashtable.get (buttonFlags[button]);
 2588   SWindowListener* l = listenerHashtable.get (buttonFlags[button]);
 2589   buttonFlags[button] = 0;
 2590   if (buttonFlags[0] ==0 && buttonFlags[1] == 0 && buttonFlags[2] == 0)
 2591   {
 2592     ReleaseCapture ();
 2593   }
 2594   if (w != 0 && l!=0)
 2595   {
 2596     l->buttonReleased (w, button, x, y);
 2597   }
 2598 #if 0
 2599   if (samebutton) return;
 2600   /* this poor guy was at the mercy of this screwy windows */
 2601   w = windowHashtable.get ((long)hwnd);
 2602   l = listenerHashtable.get ((long)hwnd);
 2603   if (w != 0 && l!=0)
 2604   {
 2605     l->buttonReleased (w, button, x, y);
 2606   }
 2607 #endif
 2608 }
 2609 
 2610 static void
 2611 lostCapture (long wid)
 2612 {
 2613   for (unsigned int i=0; i<3; i++)
 2614   {
 2615     if (buttonFlags[i] == 0) continue;
 2616     if (wid == buttonFlags[i]) continue;
 2617     SW32Window* w = windowHashtable.get (buttonFlags[i]);
 2618     SWindowListener* l = listenerHashtable.get (buttonFlags[i]);
 2619     int x = buttonLastX[i];
 2620     int y = buttonLastY[i];
 2621     if (w == 0 || l==0) continue;
 2622     l->buttonReleased (w, i, x, y);
 2623     buttonFlags[i] = 0;
 2624   }
 2625   buttonEnter (wid);
 2626 }
 2627 
 2628 
 2629 SString
 2630 SW32Window::getClipUTF8()
 2631 {
 2632    SString cld;
 2633    bool ucs = true;
 2634    bool utf8 = true;
 2635 
 2636    notifyClip ();
 2637    SW32Window* w = windowHashtable.get (clipboardOwner);
 2638    if (w != 0) /* local guy */
 2639    {
 2640       SEncoder utf8enc ("utf-8-s");
 2641       SString out = utf8enc.encode (clipData);
 2642       return SString (out);
 2643    }
 2644 
 2645    if (OpenClipboard (0))
 2646    {
 2647      HANDLE h = GetClipboardData (UTF8_STRING);
 2648      if (!h)
 2649      {
 2650        utf8 = false;
 2651        h = GetClipboardData (CF_UNICODETEXT);
 2652        if (!h)
 2653        {
 2654          h = GetClipboardData (CF_TEXT);
 2655          ucs = false;
 2656        }
 2657      }
 2658      if (h)
 2659      {
 2660        char* str = (char*) GlobalLock (h);
 2661        if (str)
 2662        {
 2663          unsigned int lsize = GlobalSize (h);
 2664          cld = SString (str, lsize);
 2665          GlobalUnlock (h);
 2666          /* we need to terminate ucs2 if 0 is seen */
 2667          if (ucs)
 2668          {
 2669            for (unsigned int i=0; i+1<lsize; i=i+2)
 2670            {
 2671              if (cld[i] == 0 && cld[i+1]==0)
 2672              {
 2673                 cld.truncate (i);
 2674                 break;
 2675              }
 2676            }
 2677          }
 2678        }
 2679      }
 2680      else 
 2681      {
 2682        //fprintf (stderr, "<< NOTHING %u bytes\n", cld.size());
 2683      }
 2684      CloseClipboard ();
 2685    }
 2686    if (utf8)
 2687    {
 2688      /**
 2689       * Windows clipboad does not have a clue how big our data is.
 2690       * We put 0xC0, 0x80 for nulls.
 2691       */
 2692      unsigned int ssize = cld.size();
 2693      for (unsigned int i=0; i<ssize; i++)
 2694      {
 2695        if (cld[i] == 0)
 2696        {
 2697           cld.truncate (i);
 2698           break;
 2699        }
 2700      }
 2701      /* C0,80 never found in utf-8*/
 2702      SString nl; nl.append ((char)0);
 2703      cld.replaceAll ("\300\200", nl);
 2704      return SString (cld);
 2705    }
 2706    impl->encoder.clear();
 2707    SEncoder ucsenc("utf-16-le");
 2708    SV_UCS4 ucstext = (ucs) ?  ucsenc.decode (cld) : impl->encoder.decode (cld);
 2709 
 2710    /* stupid windows does not know how to copy u+0000 - this
 2711     * is the terminating character.
 2712     */
 2713    for (unsigned int i=0; i<ucstext.size(); i++)
 2714    {
 2715      if (ucstext[i] == 0) 
 2716      {
 2717        ucstext.truncate (i);
 2718        break;
 2719      }
 2720    }
 2721    SEncoder utf8enc ("utf-8-s");
 2722    return SString (utf8enc.encode (ucstext));
 2723 }
 2724 
 2725 void
 2726 SW32Window::putClipUTF8(const SString& utf8)
 2727 {
 2728   SEncoder utf8enc ("utf-8-s");
 2729   clipData = utf8enc.decode (utf8);
 2730 
 2731   if (!clipChained)
 2732   {
 2733     clipChain = (long) SetClipboardViewer ((HWND) getID());
 2734     clipChained = true;
 2735   }
 2736   if (OpenClipboard ((HWND)getID()))
 2737   {
 2738     EmptyClipboard ();
 2739     SetClipboardData (CF_UNICODETEXT, 0);
 2740     SetClipboardData (CF_TEXT, 0);
 2741     SetClipboardData (UTF8_STRING, 0);
 2742     CloseClipboard ();
 2743   }
 2744 }
 2745 
 2746 /**
 2747  * Put text onto clipboard
 2748  * @return 0 on success.
 2749  */
 2750 static int
 2751 putClipUnicodeText()
 2752 {
 2753   // They sell this API for money! Unbelievable!
 2754   if (clipData.size() == 0) return 1;
 2755   SEncoder ucs2enc("utf-16-le");
 2756   SV_UCS4 v = clipData;
 2757   v.append (0);
 2758   SString out = ucs2enc.encode (v);
 2759   HANDLE h = GlobalAlloc (GMEM_DDESHARE, out.size());
 2760   if (!h) return 1;
 2761 
 2762   char* str = (char*) GlobalLock (h);
 2763   memcpy (str, out.array(), out.size());
 2764   GlobalUnlock (h);
 2765 
 2766   if (!SetClipboardData (CF_UNICODETEXT, h))
 2767   {
 2768      GlobalFree (h);
 2769      return 1;
 2770   }
 2771   return 0;
 2772 }
 2773 
 2774 /**
 2775  * Put text onto clipboard
 2776  * @return 0 on success.
 2777  */
 2778 static int
 2779 putClipText()
 2780 {
 2781   impEncoder.clear();
 2782   // They sell this API for money! Unbelievable!
 2783   SString out = impEncoder.encode (clipData);
 2784   /* add crlf */
 2785   out.replaceAll ("\r\n", "\n");
 2786   out.replaceAll ("\r", "\n");
 2787   out.replaceAll ("\n", "\r\n");
 2788   /* LS 2028 */
 2789   out.replaceAll ("\342\200\250", "\r\n");
 2790   /* PS 2029 */
 2791   out.replaceAll ("\342\200\251", "\r\n");
 2792 
 2793   SString nl; nl.append ((char)0);
 2794   /* I did not invent this - Microsft does it too :( */
 2795   out.replaceAll (nl, " ");
 2796 
 2797   out.append ((char)0);
 2798 
 2799   HANDLE h = GlobalAlloc (GMEM_DDESHARE, out.size());
 2800   if (!h) return 1;
 2801 
 2802   char* str = (char*) GlobalLock (h);
 2803   memcpy (str, out.array(), out.size());
 2804   GlobalUnlock (h);
 2805   if (!SetClipboardData (CF_TEXT, h))
 2806   {
 2807      GlobalFree (h);
 2808      return 1;
 2809   }
 2810   return 0;
 2811 }
 2812 
 2813 /**
 2814  * Put text onto clipboard
 2815  * This is not really a utf-8 text. It has an integer in front
 2816  * in machine byte-order telling size.
 2817  * @return 0 on success.
 2818  */
 2819 static int
 2820 putClipUtf8Text()
 2821 {
 2822   if (clipData.size() == 0) return 1;
 2823   SEncoder utf8enc ("utf-8-s");
 2824   SString out = utf8enc.encode (clipData);
 2825   /* this is our null */
 2826   SString nl; nl.append ((char)0);
 2827   out.replaceAll (nl, "\300\200");
 2828 
 2829   HANDLE h = GlobalAlloc (GMEM_DDESHARE, out.size()+1);
 2830   if (!h) return 1;
 2831 
 2832   char* str = (char*) GlobalLock (h);
 2833   memcpy (str, out.array(), out.size());
 2834   str[out.size()] = 0;
 2835   GlobalUnlock (h);
 2836 
 2837   if (!SetClipboardData (UTF8_STRING, h))
 2838   {
 2839      GlobalFree (h);
 2840      return 1;
 2841   }
 2842   return 0;
 2843 }
 2844 
 2845 /**
 2846  * Notify current clipboardOwner of clip lost, assign new owner.
 2847  */
 2848 void
 2849 notifyClip ()
 2850 {
 2851   /* Before returning to event loop check if clipboard 
 2852    * owner changed. SetClipboardViewer is a crzay 
 2853    * mind's creation treat is as non-existant.
 2854    */ 
 2855   HWND owner  = GetClipboardOwner();
 2856   if ((long)owner != clipboardOwner)
 2857   {
 2858      SW32Window* w = windowHashtable.get (clipboardOwner);
 2859      SWindowListener* l = listenerHashtable.get (clipboardOwner);
 2860      if (w)
 2861      {
 2862        if (w && l) l->lostClipSelection (w);
 2863      }
 2864      clipboardOwner = (long) owner;
 2865   }
 2866 }
 2867 
 2868 void
 2869 SW32Window::setModal (SWindow* _parent, bool decorated)
 2870 {
 2871   modalID = ((SW32Window*)_parent)->getID();
 2872   SetWindowLong ((HWND)id, GWL_STYLE, 
 2873      SS_YUDIT_DIALOG_STYLE);
 2874      //WS_POPUPWINDOW | WS_CAPTION);
 2875 }
 2876 /**
 2877  * put this window in the middle
 2878  */
 2879 void
 2880 SW32Window::center (SWindow* _window)
 2881 {
 2882   HWND root = GetDesktopWindow();
 2883   // dont trust these guys
 2884   if (!root)  return;
 2885 
 2886   HWND me = root;
 2887   if (_window!=0)
 2888   {
 2889     me = (HWND) ((SW32Window*)_window)->getID();
 2890   }
 2891   RECT myrect;
 2892   if (!GetWindowRect(me, &myrect))
 2893   {
 2894     fprintf (stderr, "ERROR: can not get my window rect\n");
 2895     return;
 2896   }
 2897   RECT rootrect;
 2898   if (!GetWindowRect(root, &rootrect))
 2899   {
 2900     fprintf (stderr, "ERROR: can nto get root window rect\n");
 2901     return;
 2902   }
 2903   /* center point */
 2904   int lx = (myrect.left + myrect.right)/2;  
 2905   int ly = (myrect.top + myrect.bottom)/2;  
 2906 
 2907   int mx = lx - (int) getWidth()/2;
 2908   int my = ly - (int) getHeight()/2;
 2909 
 2910   int rootWidth = rootrect.right - rootrect.left;
 2911   int rootHeight = rootrect.bottom - rootrect.top;
 2912 
 2913   if (rootWidth < (int) getWidth() + mx + 20)
 2914   {
 2915     mx = rootWidth - (int)getWidth() - 20;
 2916   }
 2917   if (rootHeight < (int) getHeight() + my + 20)
 2918   {
 2919     my = rootHeight - (int)getHeight() - 20;
 2920   }
 2921   if (mx<0) mx = 0;
 2922   if (my<0) my = 0;
 2923   move (mx, my);
 2924 }
 2925 
 2926 void
 2927 SW32Window::getKeyboardFocus ()
 2928 {
 2929   SW32Window* top = getToplevelWindow (this);
 2930   top->currentFocusWindow = getID();
 2931   if (top->currentFocusWindow == currentFocusWindow)
 2932   {
 2933     return;
 2934   }
 2935   SetFocus ((HWND)getID());
 2936 }
 2937 
 2938 static SW32Window*
 2939 getToplevelWindow (SW32Window* w)
 2940 {
 2941   SW32Window * wn = w;
 2942   while (wn->parentID)
 2943   {
 2944     SW32Window* swid = (SW32Window*) windowHashtable.get(wn->parentID);
 2945     if (swid == 0) break; /* never happens */ 
 2946     wn = swid;
 2947   }
 2948   return wn;
 2949 }
 2950 
 2951 static SW32Window*
 2952 getToplevelWindow (long id)
 2953 {
 2954   SW32Window* wn = (SW32Window*) windowHashtable.get(wn->parentID);
 2955   if (wn == 0) return 0;
 2956   while (wn->parentID)
 2957   {
 2958     SW32Window* swid = (SW32Window*) windowHashtable.get(wn->parentID);
 2959     if (swid == 0) break; /* never happens */ 
 2960     wn = swid;
 2961   }
 2962   return wn;
 2963 }
 2964 
 2965 void
 2966 SW32Window::setMinimumSize (unsigned int _width, unsigned int _height)
 2967 {
 2968   minimumSizesX.put (id, _width);
 2969   minimumSizesY.put (id, _height);
 2970 }
 2971 
 2972 static void
 2973 sendKeyChar (KeyData* kd, const SString& _s)
 2974 {
 2975   SString s = _s;
 2976   if (s.size() == 0) return;
 2977   unsigned char c0 = (unsigned char) s[0];
 2978 
 2979   /* TABS and controls are handled in processKey */
 2980   if (s.size() == 1 && c0 < 0x20)
 2981   {
 2982      return;
 2983   }
 2984   /* 
 2985    * Deal with only 'pressed' keys. If focus changes while repeat,
 2986    * it may cause this.
 2987    */
 2988   if (kd->key == SWindowListener::Key_Undefined)
 2989   {
 2990     return;
 2991   }
 2992   bool ctrl = kd->ctrl0 || kd->ctrl1; 
 2993   bool shift = kd->shift0 || kd->shift1; 
 2994   bool meta = kd->meta0 || kd->meta1; 
 2995   if (!sendAcceleratorPressed ((int) kd->key, ctrl, shift, meta))
 2996   {
 2997     SW32Window* wn = windowHashtable.get (currentFocusWindow);
 2998     SWindowListener* ln = listenerHashtable.get (currentFocusWindow);
 2999     if (wn == 0 || ln == 0) return;
 3000     ln->keyPressed (wn, kd->key, s, ctrl, shift, meta);
 3001   }
 3002 }
 3003 
 3004 /**
 3005  * Send release key event to those unfortunatelly windows that
 3006  * lost keyboard focus as windows does not sent it :(
 3007  */
 3008 static void
 3009 sendKeyReleased (KeyData* kd, SW32Window* wn, SWindowListener* ln)
 3010 {
 3011   if (sendAcceleratorReleased ())
 3012   {
 3013     kd->ctrl0 = false;
 3014     kd->ctrl1 = false;
 3015     kd->shift0 = false;
 3016     kd->shift1 = false;
 3017     kd->meta0 = false;
 3018     kd->meta1 = false;
 3019     kd->key = SWindowListener::Key_Undefined;
 3020     return;
 3021   }
 3022   SString s;
 3023   bool ctrl = kd->ctrl0 || kd->ctrl1; 
 3024   bool shift = kd->shift0 || kd->shift1; 
 3025   bool meta = kd->meta0 || kd->meta1; 
 3026 
 3027   if (kd->ctrl0)
 3028   { 
 3029     ln->keyReleased (wn, SWindowListener::Key_Control_L, s, ctrl, shift, meta);
 3030   } 
 3031   if (kd->ctrl1)
 3032   { 
 3033     ln->keyReleased (wn, SWindowListener::Key_Control_R, s, ctrl, shift, meta);
 3034   } 
 3035   kd->ctrl0 = false;
 3036   kd->ctrl1 = false;
 3037   ctrl = false;
 3038 
 3039   if (kd->shift0)
 3040   { 
 3041     ln->keyReleased (wn, SWindowListener::Key_Shift_L, s, ctrl, shift, meta);
 3042   } 
 3043   if (kd->shift1)
 3044   { 
 3045     ln->keyReleased (wn, SWindowListener::Key_Shift_R, s, ctrl, shift, meta);
 3046   } 
 3047 
 3048   kd->shift0 = false;
 3049   kd->shift1 = false;
 3050   shift = false;
 3051 
 3052   if (kd->meta0)
 3053   { 
 3054     ln->keyReleased (wn, SWindowListener::Key_Meta_L, s, ctrl, shift, meta);
 3055   } 
 3056   if (kd->meta1)
 3057   { 
 3058     ln->keyReleased (wn, SWindowListener::Key_Meta_R, s, ctrl, shift, meta);
 3059   } 
 3060   kd->meta0 = false;
 3061   kd->meta1 = false;
 3062   meta = false;
 3063   kd->key = SWindowListener::Key_Undefined;
 3064 }
 3065 
 3066 /**
 3067  * Process a key message. Generate event if necessary.
 3068  * @param kd is a state holder.
 3069  * @param syskey is true is this is a system key (what does this
 3070  * stupid thing mean - I will never know)
 3071  * @param keycod is the VK_KEYCODE
 3072  * @param isdown is true if the key was pressed.
 3073  */
 3074 static void
 3075 processKey (KeyData* kdin, bool syskey, int keycod, bool isdown)
 3076 {
 3077   KeyData kd = { 
 3078     SWindowListener::Key_Undefined,
 3079     false, false, false,
 3080     false, false, false
 3081   };
 3082   if (isdown)
 3083   {
 3084      kd.shift0 =  kdin->shift0; kd.shift1 = kdin->shift1;
 3085      kd.meta0 =  kdin->meta0; kd.meta1 = kdin->meta1;
 3086      kd.ctrl0 =  kdin->ctrl0; kd.ctrl0 = kdin->ctrl0;
 3087   }
 3088   else
 3089   {
 3090      kd.shift0 =  ! kdin->shift0; kd.shift1 = ! kdin->shift1;
 3091      kd.meta0 =  ! kdin->meta0; kd.meta1 = ! kdin->meta1;
 3092      kd.ctrl0 =  ! kdin->ctrl0; kd.ctrl0 = ! kdin->ctrl0;
 3093   }
 3094 
 3095 // VK_SHIFT
 3096 // VK_CONTROL
 3097 // VK_MENU
 3098   bool ckey=false;
 3099 
 3100   /* translate keycode first */
 3101   switch (keycod)
 3102   {
 3103   case VK_CONTROL:
 3104     kd.ctrl0 = true; 
 3105     kd.key = SWindowListener::Key_Control_L;
 3106     break;
 3107   case VK_LCONTROL:
 3108     kd.ctrl0 = true; 
 3109     kd.key = SWindowListener::Key_Control_L;
 3110     break;
 3111   case VK_RCONTROL:
 3112     kd.ctrl1 = true; 
 3113     kd.key = SWindowListener::Key_Control_R;
 3114     break;
 3115   case VK_SHIFT: 
 3116      kd.shift0 = true; 
 3117     kd.key = SWindowListener::Key_Shift_R;
 3118     break;
 3119   case VK_LSHIFT: 
 3120     kd.key = SWindowListener::Key_Shift_L;
 3121     kd.shift0 = true; 
 3122     break;
 3123   case VK_RSHIFT: 
 3124     kd.key = SWindowListener::Key_Shift_R;
 3125     kd.shift1 = true; 
 3126     break;
 3127 
 3128   case VK_MENU: kd.key = SWindowListener::Key_Alt_L; kd.meta0 = true; break;
 3129   case VK_LMENU: kd.key = SWindowListener::Key_Alt_L; kd.meta0 = true; break;
 3130   case VK_RMENU: kd.key = SWindowListener::Key_Alt_R; kd.meta1 = true; break;
 3131 
 3132 //VK_LWIN: kd.key = SWindowListener::Key_Meta_L; kd.meta0 = true; break;
 3133 //VK_RWIN: kd.key = SWindowListener::Key_Meta_R; kd.meta1 = true; break;
 3134 //VK_LBUTTON
 3135 //VK_RBUTTON
 3136 
 3137   case VK_TAB: kd.key = SWindowListener::Key_Tab; break;
 3138   case VK_RETURN: kd.key = SWindowListener::Key_Return; break;
 3139   case VK_ESCAPE: kd.key = SWindowListener::Key_Escape; break;
 3140   case VK_CLEAR: kd.key = SWindowListener::Key_Clear; break;
 3141   case VK_SPACE: kd.key = SWindowListener::Key_Space; break;
 3142   case VK_PRIOR: kd.key = SWindowListener::Key_Prior; break;
 3143   case VK_NEXT: kd.key = SWindowListener::Key_Next; break;
 3144   case VK_END: kd.key = SWindowListener::Key_End; break;
 3145   case VK_HOME: kd.key = SWindowListener::Key_Home; break;
 3146   case VK_LEFT: kd.key = SWindowListener::Key_Left; break;
 3147   case VK_UP: kd.key = SWindowListener::Key_Up; break;
 3148   case VK_RIGHT: kd.key = SWindowListener::Key_Right; break;
 3149   case VK_DOWN: kd.key = SWindowListener::Key_Down; break;
 3150   case VK_DELETE: kd.key = SWindowListener::Key_Delete; break;
 3151   case VK_BACK: kd.key = SWindowListener::Key_BackSpace; break;
 3152   case VK_F1: kd.key = SWindowListener::Key_F1; break;
 3153   case VK_F2: kd.key = SWindowListener::Key_F2; break;
 3154   case VK_F3: kd.key = SWindowListener::Key_F3; break;
 3155   case VK_F4: kd.key = SWindowListener::Key_F4; break;
 3156   case VK_F5: kd.key = SWindowListener::Key_F5; break;
 3157   case VK_F6: kd.key = SWindowListener::Key_F6; break;
 3158   case VK_F7: kd.key = SWindowListener::Key_F7; break;
 3159   case VK_F8: kd.key = SWindowListener::Key_F8; break;
 3160   case VK_F9: kd.key = SWindowListener::Key_F9; break;
 3161   case VK_F10: kd.key = SWindowListener::Key_F10; break;
 3162   case VK_F11: kd.key = SWindowListener::Key_F11; break;
 3163   case VK_F12: kd.key = SWindowListener::Key_F12; break;
 3164 /* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
 3165 /* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
 3166   case 'A': kd.key = SWindowListener::Key_A; ckey=true; break;
 3167   case 'B': kd.key = SWindowListener::Key_B; ckey=true; break;
 3168   case 'C': kd.key = SWindowListener::Key_C; ckey=true; break;
 3169   case 'D': kd.key = SWindowListener::Key_D; ckey=true; break;
 3170   case 'E': kd.key = SWindowListener::Key_E; ckey=true; break;
 3171   case 'F': kd.key = SWindowListener::Key_F; ckey=true; break;
 3172   case 'G': kd.key = SWindowListener::Key_G; ckey=true; break;
 3173   case 'H': kd.key = SWindowListener::Key_H; ckey=true; break;
 3174   case 'I': kd.key = SWindowListener::Key_I; ckey=true; break;
 3175   case 'J': kd.key = SWindowListener::Key_J; ckey=true; break;
 3176   case 'K': kd.key = SWindowListener::Key_K; ckey=true; break;
 3177   case 'L': kd.key = SWindowListener::Key_L; ckey=true; break;
 3178   case 'M': kd.key = SWindowListener::Key_M; ckey=true; break;
 3179   case 'N': kd.key = SWindowListener::Key_N; ckey=true; break;
 3180   case 'O': kd.key = SWindowListener::Key_O; ckey=true; break;
 3181   case 'P': kd.key = SWindowListener::Key_P; ckey=true; break;
 3182   case 'Q': kd.key = SWindowListener::Key_Q; ckey=true; break;
 3183   case 'R': kd.key = SWindowListener::Key_R; ckey=true; break;
 3184   case 'S': kd.key = SWindowListener::Key_S; ckey=true; break;
 3185   case 'T': kd.key = SWindowListener::Key_T; ckey=true; break;
 3186   case 'U': kd.key = SWindowListener::Key_U; ckey=true; break;
 3187   case 'X': kd.key = SWindowListener::Key_X; ckey=true; break;
 3188   case 'Y': kd.key = SWindowListener::Key_Y; ckey=true; break;
 3189   case 'V': kd.key = SWindowListener::Key_V; ckey=true; break;
 3190   case 'W': kd.key = SWindowListener::Key_W; ckey=true; break;
 3191   case 'Z': kd.key = SWindowListener::Key_Z; ckey=true; break;
 3192   default:
 3193     kd.key = SWindowListener::Key_Send; ckey=true; break;
 3194   }
 3195   kdin-> key = kd.key;
 3196   if (isdown)
 3197   {
 3198     kdin->shift0 = kd.shift0; kdin->shift1 = kd.shift1;
 3199     kdin->meta0 = kd.meta0; kdin->meta1 = kd.meta1;
 3200     kdin->ctrl0 = kd.ctrl0; kdin->ctrl0 = kd.ctrl0;
 3201   }
 3202   else
 3203   {
 3204     kdin->shift0 =  ! kd.shift0; kdin->shift1 = ! kd.shift1;
 3205     kdin->meta0 =  ! kd.meta0; kdin->meta1 = ! kd.meta1;
 3206     kdin->ctrl0 =  ! kd.ctrl0; kdin->ctrl0 = ! kd.ctrl0;
 3207   }
 3208 
 3209   /*  */
 3210   bool ctrl = kdin->ctrl0 || kdin->ctrl1; 
 3211   bool shift = kdin->shift0 || kdin->shift1; 
 3212   bool meta = kdin->meta0 || kdin->meta1; 
 3213 
 3214   SW32Window* wn = windowHashtable.get (currentFocusWindow);
 3215   SWindowListener* ln = listenerHashtable.get (currentFocusWindow);
 3216 
 3217   if (wn != 0 || ln != 0)
 3218   {
 3219     SString s;
 3220     /* WM_IME_COMPOSITION does not give us TAB */
 3221     if (keycod == VK_TAB && isdown) 
 3222     {
 3223       s.append ("\t");
 3224     }
 3225     if (isdown)
 3226     { 
 3227       if (!sendAcceleratorPressed ((int) kdin->key, ctrl, shift, meta))
 3228       {
 3229          ln->keyPressed (wn, kdin->key, s, ctrl, shift, meta);
 3230       }
 3231     }
 3232     else
 3233     {
 3234       if (!sendAcceleratorReleased ())
 3235       {
 3236         ln->keyReleased (wn, kdin->key, s, ctrl, shift, meta);
 3237       }
 3238     }
 3239   }
 3240 }
 3241 
 3242 SAccelerator  currentAccelerator;
 3243 bool accelPressed = false;
 3244 
 3245 /**
 3246  * add and remove keyboard accelerator
 3247  */
 3248 void
 3249 SW32Window::addAccelerator (const SAccelerator& a, SAcceleratorListener* l)
 3250 {
 3251   SW32Window* top = getToplevelWindow (this);
 3252   top->accelerators.put (a.toString(), l);
 3253   top->acceleratorTable.put (a.toString(), id);
 3254 }
 3255 
 3256 void
 3257 SW32Window::removeAccelerator (const SAccelerator& a, SAcceleratorListener* l)
 3258 {
 3259   SW32Window* top = getToplevelWindow (this);
 3260   top->accelerators.remove (a.toString());
 3261   top->acceleratorTable.remove (a.toString());
 3262 }
 3263 
 3264 static bool
 3265 sendAcceleratorPressed (int key, bool ctrl, bool shift, bool meta)
 3266 {
 3267   if (currentTopFocusWindow==0) return true;
 3268   if (accelPressed) return true;
 3269 
 3270   SW32Window* top = windowHashtable.get (currentTopFocusWindow);
 3271   if (top ==0) return true;
 3272 
 3273   currentAccelerator = SAccelerator (key, ctrl, shift, meta);
 3274   long id = top->acceleratorTable.get (currentAccelerator.toString());
 3275 
 3276   if (id ==0)
 3277   {
 3278     return false;
 3279   }
 3280   SAcceleratorListener* l = top->accelerators.get (
 3281           currentAccelerator.toString());
 3282   if (l ==0)
 3283   {
 3284     return false;
 3285   }
 3286   accelPressed = true;
 3287   l->acceleratorPressed (currentAccelerator);
 3288   return true;
 3289 }
 3290 
 3291 static bool
 3292 sendAcceleratorReleased ()
 3293 {
 3294   if (currentTopFocusWindow==0) return false;
 3295   if (!accelPressed) return false;
 3296 
 3297   SW32Window* top = windowHashtable.get (currentTopFocusWindow);
 3298   if (top ==0)
 3299   {
 3300      accelPressed = false;
 3301      return true;
 3302   }
 3303 
 3304   long id = top->acceleratorTable.get (currentAccelerator.toString());
 3305   SAcceleratorListener* l = top->accelerators.get (
 3306           currentAccelerator.toString());
 3307   if (l==0 || id ==0)
 3308   { 
 3309      accelPressed = false;
 3310      return true;
 3311   }
 3312   accelPressed = false;
 3313   l->acceleratorReleased (currentAccelerator);
 3314   return true;
 3315 }
 3316 /**
 3317  * Start a native input method.
 3318  * @param name is the name of the input method:
 3319  *  like "kinput2"
 3320  * @param properties provide some attributes to the input method.
 3321  */
 3322 bool
 3323 SW32Window::startInputMethod (const SString& name, const SProperties& prop, SPreEditor* preEditor)
 3324 {
 3325   if (name == "x-none" || name == "x-ascii" || name == "x-utf-8")
 3326   {
 3327     if (imname == name) return true;
 3328     stopInputMethod();
 3329     imname = name;
 3330     return true;
 3331   }
 3332   HIMC himc = ImmGetContext((HWND)id);
 3333   if (!himc) return false;
 3334   /* ImmSetOpenStatus */
 3335 
 3336   /* stop previous one */
 3337   if (imname.size())
 3338   {
 3339      ImmSetOpenStatus (himc, false);
 3340   }
 3341   getKeyboardFocus();
 3342   ImmSetOpenStatus (himc, true);
 3343   setInputMethodProperties (prop);
 3344   imname = name;
 3345   return true;
 3346 }
 3347 
 3348 void
 3349 SW32Window::stopInputMethod ()
 3350 {
 3351   HIMC himc = ImmGetContext((HWND)id);
 3352   if (!himc) return;
 3353   /* stop previous one */
 3354   if (imname.size())
 3355   {
 3356      ImmSetOpenStatus (himc, false);
 3357   }
 3358   imname = "";
 3359 }
 3360 
 3361 /**
 3362  * Change properties of the input method on the fly.
 3363  * @param prop contains properties like:
 3364  * InputStyle: root over-the-spot off-the-spot
 3365  */
 3366 void
 3367 SW32Window::setInputMethodProperties (const SProperties& properties)
 3368 {
 3369   if (!isVisible()) return;
 3370   HIMC himc = ImmGetContext((HWND)id);
 3371   if (!himc) return;
 3372 
 3373   if (properties.get ("InputStyle")==0)
 3374   {
 3375     fprintf (stderr, "InputStyle is not present in properties.\n");
 3376     return;
 3377   }
 3378 
 3379   SString s = properties["InputStyle"];
 3380 
 3381   /* ok. now I can tell you windows can not set InputStyle sorry */
 3382    
 3383 
 3384   if (properties.get ("LineSpacing"))
 3385   {
 3386     SString lsp = properties["LineSpacing"];
 3387     lsp.append ((char)0);
 3388     int spacing;
 3389     sscanf (lsp.array(), "%d", &spacing);
 3390   }
 3391 
 3392   /* What to do with this? */
 3393   if (properties.get ("InputClientColor"))
 3394   {
 3395     SString col = properties["InputClientColor"];
 3396     col.append ((char)0);
 3397     unsigned long bg, fg;
 3398     sscanf (col.array(), "%lu,%lu", &bg, &fg);
 3399     SColor xbg = SColor((SS_WORD32)bg);
 3400     SColor xfg = SColor((SS_WORD32)fg);
 3401   }
 3402 
 3403   /* XXX: no idea how to do this... */
 3404   if (s == "preedit-over-status-under" 
 3405        && properties.get ("InputSpot")
 3406        && properties.get ("InputStatusLocation")
 3407        && properties.get ("InputStatusSize")
 3408      )
 3409   {
 3410     SString spotLocation = properties["InputSpot"];
 3411     spotLocation.append ((char)0);
 3412     int _x, _y;
 3413     sscanf (spotLocation.array(), "%d,%d", &_x, &_y);
 3414     COMPOSITIONFORM form;
 3415     form.dwStyle = CFS_POINT;
 3416     form.ptCurrentPos.x = _x;
 3417     form.ptCurrentPos.y = _y;
 3418     form.rcArea.left = 0;
 3419     form.rcArea.top = 0;
 3420     form.rcArea.right =  (int) getWidth();
 3421     form.rcArea.bottom = (int) getHeight();
 3422     ImmSetCompositionWindow (himc, &form);
 3423 
 3424     SString sl = properties["InputStatusLocation"];
 3425     sl.append ((char)0);
 3426     int statusX, statusY;
 3427     sscanf (sl.array(), "%d,%d", &statusX, &statusY);
 3428 
 3429     SString ss = properties["InputStatusSize"];
 3430     ss.append ((char)0);
 3431     int statusWidth, statusHeight;
 3432     sscanf (ss.array(), "%d,%d", &statusWidth, &statusHeight);
 3433 
 3434     POINT point;
 3435     point.x = statusX;
 3436     point.y = statusY;
 3437     ImmSetStatusWindowPos(himc, &point);
 3438   }
 3439   else if (s == "preedit-under-status-under" 
 3440        && properties.get ("InputSpot")
 3441        && properties.get ("InputStatusLocation")
 3442        && properties.get ("InputStatusSize")
 3443        && properties.get ("InputClientLocation")
 3444        && properties.get ("InputClientSize")
 3445        )
 3446   {
 3447 
 3448     SString spotLocation = properties["InputSpot"];
 3449     spotLocation.append ((char)0);
 3450     int _x, _y;
 3451     sscanf (spotLocation.array(), "%d,%d", &_x, &_y);
 3452 
 3453     SString sl = properties["InputStatusLocation"];
 3454     sl.append ((char)0);
 3455     int statusX, statusY;
 3456     sscanf (sl.array(), "%d,%d", &statusX, &statusY);
 3457 
 3458     SString ss = properties["InputStatusSize"];
 3459     ss.append ((char)0);
 3460     int statusWidth, statusHeight;
 3461     sscanf (ss.array(), "%d,%d", &statusWidth, &statusHeight);
 3462 
 3463     SString cl = properties["InputClientLocation"];
 3464     cl.append ((char)0);
 3465     int clientX, clientY;
 3466     sscanf (cl.array(), "%d,%d", &clientX, &clientY);
 3467 
 3468     SString cs = properties["InputClientSize"];
 3469     cs.append ((char)0);
 3470     int clientWidth, clientHeight;
 3471     sscanf (cs.array(), "%d,%d", &clientWidth, &clientHeight);
 3472 
 3473     POINT point;
 3474     point.x = statusX;
 3475     point.y = statusY;
 3476     ImmSetStatusWindowPos(himc, &point);
 3477 
 3478     COMPOSITIONFORM form;
 3479     form.dwStyle = CFS_RECT;
 3480     form.ptCurrentPos.x = clientX; // starting from.
 3481     form.ptCurrentPos.y = clientY;
 3482     form.rcArea.left = clientX;    // next line
 3483     form.rcArea.top = clientY;
 3484     form.rcArea.right =  clientX +  clientWidth;
 3485     form.rcArea.bottom =  clientY + clientHeight;
 3486     ImmSetCompositionWindow (himc, &form);
 3487   }
 3488   else if (s == "preedit-root-status-root")
 3489   {
 3490     COMPOSITIONFORM form;
 3491     form.dwStyle = CFS_DEFAULT;
 3492     form.ptCurrentPos.x = (int) getWidth();
 3493     form.ptCurrentPos.y = (int) getHeight();
 3494     form.rcArea.left = 0;
 3495     form.rcArea.top = 0;
 3496     form.rcArea.right =  (int) getWidth();
 3497     form.rcArea.bottom = (int) getHeight();
 3498     ImmSetCompositionWindow (himc, &form);
 3499   }
 3500   /* All the input styles */
 3501   else if (s == "preedit-over-status-over" && properties.get ("InputSpot"))
 3502   {
 3503     SString spotLocation = properties["InputSpot"];
 3504     spotLocation.append ((char)0);
 3505     int _x, _y;
 3506     sscanf (spotLocation.array(), "%d,%d", &_x, &_y);
 3507     COMPOSITIONFORM form;
 3508     form.dwStyle = CFS_POINT;
 3509     form.ptCurrentPos.x = _x;
 3510     form.ptCurrentPos.y = _y;
 3511     form.rcArea.left = 0;
 3512     form.rcArea.top = 0;
 3513     form.rcArea.right =  (int) getWidth();
 3514     form.rcArea.bottom = (int) getHeight();
 3515     ImmSetCompositionWindow (himc, &form);
 3516   }
 3517 }
 3518 
 3519 /**
 3520  * Get the current input method.
 3521  * it returns a zero sized string if input method is not started.
 3522  */
 3523 SString
 3524 SW32Window::getInputMethod ()
 3525 {
 3526   return SString(imname);
 3527 }
 3528 
 3529 unsigned long
 3530 SW32Window::getWindowID() const
 3531 {
 3532   return (unsigned long) id;
 3533 }
 3534 
 3535 // FIXME
 3536 void
 3537 SW32Window::setDoubleBuffer (bool isOn)
 3538 {
 3539   dbufferOn = isOn;
 3540 }
 3541 
 3542 bool
 3543 SW32Window::isDoubleBufferEnabled () const
 3544 {
 3545   return dbufferOn;
 3546 }