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