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