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