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