1 /*
2    Copyright (c) by Valery Goryachev (Wal)
3 */
4 
5 
6 #include <X11/Xutil.h>
7 
8 #include "swl.h"
9 #include "swl_wincore_internal.h"
10 #include <sys/times.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <locale.h>
14 #include <set>
15 
16 #ifdef USEFREETYPE
17 #include <ft2build.h>
18 #include FT_FREETYPE_H
19 #endif
20 #ifdef _DEBUG
21 // for typeid
22 #include <typeinfo>
23 #endif
24 
25 #if defined( __APPLE__ )
26 const unsigned int MetaMask = 0x0010;
27 #endif
28 
29 namespace wal
30 {
31 	Win* GetWinByID( WinID hWnd );
32 	int DelWinFromHash( WinID w );
33 	unsigned RunTimers();
34 	void AddWinToHash( WinID handle, Win* w );
35 	void AppBlock( WinID w );
36 	void AppUnblock( WinID w );
37 
38 //static
39 	Display*     display = 0;
40 //static
41 	XVisualInfo visualInfo;
42 	static int     screen = 0;
43 	static Colormap      colorMap;
44 	static Visual*     visual;
45 	static XIM     inputMethod = 0;
46 	static XIC     inputContext = 0; //???
47 
48 	static Atom       atom_WM_PROTOCOLS;
49 	static Atom       atom_WM_DELETE_WINDOW = 0; //Атом, чтоб window manager не закрывал окна самостоятельно
50 
51 //WinID     Win::focusWinId =0;
52 	static WinID      activeWinId = 0;
53 	static WinID      captureWinId = 0;
54 
55 //static SCImage winIcon;
56 	static Pixmap winIconPixmap = None;
57 	static Pixmap winIconMask = None;
58 
59 	static unsigned toNone( unsigned n );
60 //static
61 	unsigned ( *CreateColor )( unsigned ) = toNone; //toRGB24;//toNone;
62 	static int connectionId = -1;
63 	static unsigned whiteColor = 0xFFFFFF, blackColor = 0;
64 
CreateColorFromRGB(unsigned c)65 	inline unsigned CreateColorFromRGB( unsigned c ) { return CreateColor( c ); }
66 
67 ///////////////////////
68 	clock_t CPS = 1;
TimeInit()69 	static void TimeInit()
70 	{
71 		CPS = sysconf( _SC_CLK_TCK );
72 
73 		if ( CPS <= 0 ) { CPS = 1; }
74 	}
75 
76 // ????????????????????????????
GetTickMiliseconds()77 	unsigned GetTickMiliseconds()
78 	{
79 		struct tms t;
80 		clock_t ct = times( &t );
81 		return ( ct * 1000 ) / CPS;
82 	}
83 
84 
85 
86 ////////////  FreeType inc /////////////////////
87 #include "swl_wincore_freetype_inc.h"
88 
89 
90 ///// { Clipboard data
91 
92 	static ClipboardText clipboardText;
93 	static Atom atom_PRIMARY = 0;
94 	static Atom atom_CLIPBOARD = 0;
95 	static Atom atom_TARGETS = 0;
96 	static Atom atom_STRING = 0;
97 	static Atom atom_UTF8 = 0;
98 	static Atom atom_COMPOUND = 0;
99 	static Atom atom_CDEST = 0;
100 	static Atom atom_INCR = 0;
101 
102 	static Window clipboardWinId = 0;
103 
GetScreenSize()104 	cpoint GetScreenSize()
105 	{
106 		cpoint s;
107 
108 		XWindowAttributes xwAttr;
109 
110 		Status ret = XGetWindowAttributes( display, DefaultRootWindow( display ), &xwAttr );
111 		if ( ret == 0 )
112 		{
113 			throw_msg( "Error in XGetWindowAttributes/screen size" );
114 		}
115 		s.x = xwAttr.width;
116 		s.y = xwAttr.height;
117 
118 		return s;
119 	}
120 
X11_Clipbopard_Init()121 	static void X11_Clipbopard_Init()
122 	{
123 		atom_PRIMARY = XInternAtom( display, "PRIMARY", False );
124 		atom_CLIPBOARD = XInternAtom( display, "CLIPBOARD", False );
125 
126 		atom_STRING = XInternAtom( display, "STRING", True );
127 		atom_UTF8 = XInternAtom( display, "UTF8_STRING", False );
128 		atom_TARGETS = XInternAtom( display, "TARGETS", False );
129 		atom_COMPOUND = XInternAtom( display, "COMPOUND_TEXT", False );
130 		atom_CDEST = XInternAtom( display, "SWL_CLIPDEST", False );
131 		atom_INCR = XInternAtom( display, "INCR", False );
132 
133 		XSetWindowAttributes attrs;
134 
135 		attrs.event_mask =  PropertyChangeMask;
136 
137 		unsigned long valueMask = CWEventMask;
138 
139 		valueMask |= CWOverrideRedirect;
140 		attrs.override_redirect = True;
141 
142 		clipboardWinId = XCreateWindow(
143 		                    display,
144 		                    DefaultRootWindow( display ),
145 		                    0, 0, 10, 10,
146 		                    0,
147 		                    CopyFromParent,
148 		                    InputOutput,
149 		                    visual,
150 		                    valueMask, &attrs );
151 	}
152 
ClipboardSetText(Win * w,ClipboardText & text)153 	void ClipboardSetText( Win* w, ClipboardText& text )
154 	{
155 		clipboardText = text;
156 		XSetSelectionOwner( display, atom_PRIMARY, clipboardWinId, CurrentTime );
157 		XSetSelectionOwner( display, atom_CLIPBOARD, clipboardWinId, CurrentTime );
158 	}
159 
160 
ClipboardClear()161 	void ClipboardClear()
162 	{
163 		clipboardText.Clear();
164 		XSetSelectionOwner( display, atom_PRIMARY, None, CurrentTime );
165 		XSetSelectionOwner( display, atom_CLIPBOARD, None, CurrentTime );
166 	}
167 
168 
169 
170 ///// } (Clipboard data)
171 
172 
173 
174 ///////////////////////////////////   Init
175 
176 
177 //////////////////////////////// PseudoColor
178 
179 #define CBCOUNT (16*16*16)
180 	static int stColors[CBCOUNT];
181 
AbsInt(int a)182 	inline int AbsInt( int a ) { return a < 0 ? -a : a; }
183 
184 	struct RgbColorStruct
185 	{
186 		int r, g, b;
RgbColorStructwal::RgbColorStruct187 		RgbColorStruct(): r( 0 ), g( 0 ), b( 0 ) {}
RgbColorStructwal::RgbColorStruct188 		RgbColorStruct( unsigned bgr ): r( bgr & 0xFF ), g( ( bgr >> 8 ) & 0xFF ), b( ( bgr >> 16 ) & 0xFF ) {}
operator =wal::RgbColorStruct189 		void operator = ( unsigned bgr ) { r = ( bgr & 0xFF ); g = ( bgr >> 8 ) & 0xFF; b = ( bgr >> 16 ) & 0xFF; }
Dist2wal::RgbColorStruct190 		unsigned long Dist2( RgbColorStruct& a )
191 		{
192 			unsigned long dr = AbsInt( r - a.r );
193 			unsigned long dg = AbsInt( g - a.g );
194 			unsigned long db = AbsInt( b - a.b );
195 			return dr * dr + dg * dg + db * db;
196 		}
197 	};
198 
199 	struct TempStruct
200 	{
201 		RgbColorStruct rgb;
202 		int lastCNum;
203 		unsigned long lastDist2;
TempStructwal::TempStruct204 		TempStruct(): lastCNum( 0 ), lastDist2( 0xFFFFFFFF ) {}
205 	};
206 
MakeStColors(unsigned * col,int count)207 	static void MakeStColors( unsigned* col, int count )
208 	{
209 		TempStruct ts[CBCOUNT];
210 
211 		int i;
212 
213 		for ( int r = 0; r < 16; r++ )
214 			for ( int g = 0; g < 16; g++ )
215 				for ( int b = 0; b < 16; b++ )
216 				{
217 					int n = b * 256 + g * 16 + r;
218 					ts[n].rgb.r = ( r << 4 );
219 					ts[n].rgb.g = ( g << 4 );
220 					ts[n].rgb.b = ( b << 4 );
221 				}
222 
223 
224 		for ( i = 0; i < count; i++ )
225 		{
226 			RgbColorStruct rgb( col[i] );
227 
228 			for ( int j = 0; j < CBCOUNT; j++ )
229 			{
230 				unsigned long d2 = rgb.Dist2( ts[j].rgb );
231 
232 				if ( ts[j].lastDist2 > d2 )
233 				{
234 					ts[j].lastDist2 = d2;
235 					ts[j].lastCNum = i;
236 				}
237 			}
238 		}
239 
240 		for ( i = 0; i < CBCOUNT; i++ ) { stColors[i] = ts[i].lastCNum; }
241 	}
242 
CreatePseudoColor(unsigned bgr)243 	static unsigned CreatePseudoColor( unsigned bgr )
244 	{
245 		return stColors[ ( ( bgr >> 4 ) & 0xF ) + ( ( bgr >> 8 ) & 0xF0 ) + ( ( bgr >> 12 ) & 0xF00 ) ];
246 	}
247 
InitPseudoColor()248 	static void InitPseudoColor()
249 	{
250 		int n = visualInfo.colormap_size;
251 
252 		if ( n > 4096 ) { n = 4096; }
253 
254 		XColor xc[4096];
255 		unsigned bgr[4096];
256 		int i;
257 
258 		for ( i = 0; i < n; i++ ) { xc[i].pixel = i; }
259 
260 		XQueryColors( display, colorMap, xc, n );
261 
262 		if ( visualInfo.c_class == PseudoColor || visualInfo.c_class == GrayScale )
263 		{
264 			//зафиксировать бля все цвета в палитре по умолчанию
265 			for ( i = 0; i < n; i++ )
266 			{
267 				int ret = XAllocColor( display, colorMap, &( xc[i] ) );
268 				if ( ret == 0 )
269 				{
270 					throw_msg( "Error in XAllocColor" );
271 				}
272 			}
273 
274 		}
275 
276 		int count = 0;
277 
278 		for ( i = 0; i < n; i++ )
279 			if ( xc[i].flags & ( DoRed | DoBlue | DoGreen ) )
280 			{
281 				unsigned c = 0;
282 
283 				if ( xc[i].flags & DoRed )
284 				{
285 					c |= ( ( xc[i].red >> 8 ) & 0xFF );
286 				}
287 
288 				if ( xc[i].flags & DoGreen )
289 				{
290 					c |= ( ( xc[i].green >> 8 ) & 0xFF ) << 8;
291 				}
292 
293 				if ( xc[i].flags & DoBlue )
294 				{
295 					c |= ( ( xc[i].blue >> 8 ) & 0xFF ) << 16;
296 				}
297 
298 				bgr[count++] = c;
299 			}
300 
301 
302 		MakeStColors( bgr, count );
303 		CreateColor = CreatePseudoColor;
304 	}
305 
306 
307 //////////////////////////////// TrueColor
308 
toRGB24(unsigned n)309 	static unsigned toRGB24( unsigned n ) { return ( ( n << 16 ) & 0xFF0000 ) | ( n & 0xFF00 ) | ( ( n >> 16 ) & 0xFF ); }
toNone(unsigned n)310 	static unsigned toNone( unsigned n ) { return n; }
311 	static int red_rs, red_ls;
312 	static int blue_rs, blue_ls;
313 	static int green_rs, green_ls;
314 
toTrueColor(unsigned n)315 	static unsigned toTrueColor( unsigned n )
316 	{
317 		return   ( ( ( n & 0x0000FF ) >> red_rs  ) << red_ls  ) |
318 		         ( ( ( n & 0x00FF00 ) >> green_rs ) << green_ls ) |
319 		         ( ( ( n & 0xFF0000 ) >> blue_rs ) << blue_ls );
320 	}
321 
CalcColorShifts(unsigned long mask,int * sh)322 	static int CalcColorShifts( unsigned long mask, int* sh )
323 	{
324 		int i;
325 
326 		for ( i = 0; i < int( sizeof( mask ) * 8 ) && ( mask & 1 ) == 0; i++, mask >>= 1 ) { EMPTY_OPER; }
327 
328 		*sh = ( ( mask & 1 ) ? i : 0 );
329 
330 		for ( i = 0; i < int( sizeof( mask ) * 8 ) && ( mask & 1 ); i++, mask >>= 1 ) { EMPTY_OPER; }
331 
332 		return ( ( mask & 1 ) == 0 ) ? i : 0;
333 	}
334 
InitTrueColor()335 	void InitTrueColor() //called if visual class is TrueColor
336 	{
337 		if (  visualInfo.red_mask == 0xFF0000 &&
338 		      visualInfo.green_mask == 0x00FF00 &&
339 		      visualInfo.blue_mask == 0x0000FF )
340 		{
341 			CreateColor = toRGB24;
342 		}
343 		else if (  visualInfo.red_mask == 0x0000FF &&
344 		           visualInfo.green_mask == 0x00FF00 &&
345 		           visualInfo.blue_mask == 0xFF0000 )
346 		{
347 			CreateColor = toNone;
348 		}
349 		else
350 		{
351 			int sh, d;
352 			d = CalcColorShifts( visualInfo.red_mask, &sh );
353 			red_rs = ( 8 - d ) + 0;
354 			red_ls = sh;
355 			d = CalcColorShifts( visualInfo.blue_mask, &sh );
356 			blue_rs = ( 8 - d ) + 16;
357 			blue_ls = sh;
358 			d = CalcColorShifts( visualInfo.green_mask, &sh );
359 			green_rs = ( 8 - d ) + 8;
360 			green_ls = sh;
361 
362 			if ( red_rs < 0 ) { red_ls += -red_rs; red_rs = 0; }
363 
364 			CreateColor = toTrueColor;
365 			//dbg_printf("(%i,%i) (%i,%i) (%i,%i) \n", red_rs, red_ls, blue_rs, blue_ls, green_rs, green_ls);
366 
367 		}
368 	}
369 
370 
371 	static int xErrorCount = 0;
372 	static char xErrorLastText[0x100];
373 
ErrorHandler(Display * d,XErrorEvent * e)374 	static int ErrorHandler( Display* d, XErrorEvent* e )
375 	{
376 
377 		XGetErrorText( d, e->error_code, xErrorLastText, sizeof( xErrorLastText ) );
378 
379 		printf( "XError: %s\n", xErrorLastText );
380 		xErrorCount++;
381 		return 0;
382 	}
383 
384 
AppInit()385 	void AppInit()
386 	{
387 		TimeInit();
388 		display = XOpenDisplay( 0 );
389 
390 		if ( !display )
391 		{
392 			throw_msg( "can`t open X display (XOpenDisplay)" );
393 		}
394 
395 		screen  = DefaultScreen( display );
396 		visual  = DefaultVisual( display, screen );
397 		colorMap   = DefaultColormap( display, screen );
398 
399 		int nv = 0;
400 		XVisualInfo* vi = XGetVisualInfo( display, 0, &visualInfo, &nv );
401 
402 		if ( !nv || !vi )
403 		{
404 			throw_msg( "no VisualInfo list" );
405 		}
406 
407 		int i;
408 
409 		for ( i = 0; i < nv; i++ )
410 			if ( vi[i].visual == visual )
411 			{
412 				break;
413 			}
414 
415 		if ( i >= nv )
416 		{
417 			throw_msg( "default VisualInfo not found" );
418 		}
419 
420 		visualInfo = vi[i];
421 		XFree( vi );
422 
423 		connectionId = XConnectionNumber( display );
424 		whiteColor = WhitePixel( display, screen );
425 		blackColor = BlackPixel( display, screen );
426 
427 		switch ( visualInfo.c_class )
428 		{
429 			case TrueColor:
430 				InitTrueColor();
431 				break;
432 
433 			case GrayScale:      //!!!
434 			case StaticGray: ;      //!!!
435 
436 			case StaticColor:
437 			case PseudoColor:
438 				InitPseudoColor();
439 				break;
440 
441 
442 			case DirectColor:
443 				throw_msg( "DirectColor visual class is not supported" );
444 
445 			default:
446 				throw_msg( "Unknown visual class" );
447 		}
448 
449 		setlocale( LC_ALL, "" );
450 		inputMethod = XOpenIM( display, 0, 0, 0 );
451 
452 		if ( inputMethod )
453 		{
454 			XSetLocaleModifiers( "@im=local" );
455 			inputContext = XCreateIC( inputMethod, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, DefaultRootWindow( display ),
456 			                          NULL ); //для борьбы с "missing sentinel in function call" надо написать NULL а не 0 (вот уроды)
457 
458 			//0 );
459 			if ( !inputContext )
460 			{
461 				fprintf( stderr, "Can`t create input context (X)\n" );
462 			}
463 
464 			if ( !XSupportsLocale() )
465 			{
466 				fprintf( stderr, "Locale not supported by X\n" );
467 			}
468 		}
469 
470 		XSetErrorHandler( ErrorHandler );
471 		//Atoms
472 		atom_WM_DELETE_WINDOW = XInternAtom( display, "WM_DELETE_WINDOW", True );
473 		atom_WM_PROTOCOLS = XInternAtom( display, "WM_PROTOCOLS", True );
474 
475 
476 		X11_Clipbopard_Init();
477 
478 		BaseInit();
479 	}
480 
DrawExposeRect(Win * w)481 	void DrawExposeRect( Win* w )
482 	{
483 		if ( !w ) { return; }
484 
485 		if ( !w->exposeRect.IsEmpty() )
486 		{
487 			GC gc( w );
488 			w->Paint( gc, w->exposeRect );
489 			w->exposeRect.Zero();
490 		}
491 	}
492 
493 
494 	static std::set<WinID> repaintHash;
495 
ForeachDrawExpose(WinID id,void * data)496 	static void ForeachDrawExpose( WinID id, void* data )
497 	{
498 		DrawExposeRect( GetWinByID( id ) );
499 	}
500 
PostRepaint()501 	static void PostRepaint()
502 	{
503 		for ( const auto& i : repaintHash ) ForeachDrawExpose( i, nullptr );
504 		repaintHash.clear();
505 	}
506 
AddRepaint(Win * w)507 	static void AddRepaint( Win* w )
508 	{
509 		if ( !w ) { return; }
510 
511 		repaintHash.insert( w->GetID() );
512 	}
513 
MovePopups(Win * w,int xDelta,int yDelta)514 	static void MovePopups( Win* w, int xDelta, int yDelta )
515 	{
516 		if ( !w ) { return; }
517 
518 		int n = w->ChildCount();
519 
520 		for ( int i = 0; i < n; i++ )
521 		{
522 			Win* c = w->GetChild( i );
523 
524 			if ( c->Type() == Win::WT_POPUP )
525 			{
526 				crect r = c->ScreenRect();
527 				r.left  += xDelta;
528 				r.right += xDelta;
529 				r.top += yDelta;
530 				r.bottom += yDelta;
531 				c->Move( r );
532 			}
533 			else if ( c->Type() != Win::WT_MAIN )
534 			{
535 				MovePopups( c, xDelta, yDelta );
536 			}
537 		}
538 	}
539 
540 
ChildKeyRecursive(Win * parent,Win * child,cevent_key * ev)541 	static bool ChildKeyRecursive( Win* parent, Win* child, cevent_key* ev )
542 	{
543 		if ( !parent ) { return false; }
544 
545 		if ( parent->Type() != Win::WT_MAIN && ChildKeyRecursive( parent->Parent(), child, ev ) ) { return true; }
546 
547 		return parent->IsEnabled() && parent->EventChildKey( child, ev );
548 	}
549 
550 	static bool g_AsyncKeyMap[0xFFFF];
551 
DoKeyEvent(int type,Win * w,KeySym ks,unsigned km,unicode_t ch,bool FromMouseWheel=false)552 	static void DoKeyEvent( int type, Win* w, KeySym ks, unsigned km,  unicode_t ch, bool FromMouseWheel = false )
553 	{
554 //	printf( "type = %i ks = %x km = %u, ch = %u\n", type, (unsigned int)ks, km, ch );
555 
556 		// update async table
557 		if ( ks < 0xFFFF )
558 		{
559 			g_AsyncKeyMap[ ks ] = ( type == EV_KEYDOWN );
560 		}
561 
562 		switch ( ks )
563 		{
564 			case XK_a:
565 				ks = XK_A;
566 				break;
567 
568 			case XK_b:
569 				ks = XK_B;
570 				break;
571 
572 			case XK_c:
573 				ks = XK_C;
574 				break;
575 
576 			case XK_d:
577 				ks = XK_D;
578 				break;
579 
580 			case XK_e:
581 				ks = XK_E;
582 				break;
583 
584 			case XK_f:
585 				ks = XK_F;
586 				break;
587 
588 			case XK_g:
589 				ks = XK_G;
590 				break;
591 
592 			case XK_h:
593 				ks = XK_H;
594 				break;
595 
596 			case XK_i:
597 				ks = XK_I;
598 				break;
599 
600 			case XK_j:
601 				ks = XK_J;
602 				break;
603 
604 			case XK_k:
605 				ks = XK_K;
606 				break;
607 
608 			case XK_l:
609 				ks = XK_L;
610 				break;
611 
612 			case XK_m:
613 				ks = XK_M;
614 				break;
615 
616 			case XK_n:
617 				ks = XK_N;
618 				break;
619 
620 			case XK_o:
621 				ks = XK_O;
622 				break;
623 
624 			case XK_p:
625 				ks = XK_P;
626 				break;
627 
628 			case XK_q:
629 				ks = XK_Q;
630 				break;
631 
632 			case XK_r:
633 				ks = XK_R;
634 				break;
635 
636 			case XK_s:
637 				ks = XK_S;
638 				break;
639 
640 			case XK_t:
641 				ks = XK_T;
642 				break;
643 
644 			case XK_u:
645 				ks = XK_U;
646 				break;
647 
648 			case XK_v:
649 				ks = XK_V;
650 				break;
651 
652 			case XK_w:
653 				ks = XK_W;
654 				break;
655 
656 			case XK_x:
657 				ks = XK_X;
658 				break;
659 
660 			case XK_y:
661 				ks = XK_Y;
662 				break;
663 
664 			case XK_z:
665 				ks = XK_Z;
666 				break;
667 
668 			// remap numpad keys: https://github.com/corporateshark/WCMCommander/issues/198
669 
670 			case XK_KP_Left:
671 				ks = XK_Left;
672 				break;
673 
674 			case XK_KP_Right:
675 				ks = XK_Right;
676 				break;
677 
678 			case XK_KP_Up:
679 				ks = XK_Up;
680 				break;
681 
682 			case XK_KP_Down:
683 				ks = XK_Down;
684 				break;
685 
686 			case XK_KP_Prior:
687 				ks = XK_Prior;
688 				break;
689 
690 			case XK_KP_Next:
691 				ks = XK_Next;
692 				break;
693 
694 			case XK_KP_Home:
695 				ks = XK_Home;
696 				break;
697 
698 			case XK_KP_End:
699 				ks = XK_End;
700 				break;
701 
702 			case XK_KP_Insert:
703 				ks = XK_Insert;
704 				break;
705 
706 			case XK_KP_Delete:
707 				ks = XK_Delete;
708 				break;
709 		}
710 
711 		if ( g_AsyncKeyMap[XK_Control_L] ) km |= EXT_KM_LCTRL;
712 		if ( g_AsyncKeyMap[XK_Control_R] ) km |= EXT_KM_RCTRL;
713 		if ( g_AsyncKeyMap[XK_Shift_L] ) km |= EXT_KM_LSHIFT;
714 		if ( g_AsyncKeyMap[XK_Shift_R] ) km |= EXT_KM_RSHIFT;
715 		if ( g_AsyncKeyMap[XK_Alt_L] ) km |= EXT_KM_LALT;
716 		if ( g_AsyncKeyMap[XK_Alt_R] ) km |= EXT_KM_RALT;
717 #if defined(__APPLE__)
718 		if ( g_AsyncKeyMap[XK_Meta_L] ) km |= EXT_KM_LCTRL;
719 		if ( g_AsyncKeyMap[XK_Meta_R] ) km |= EXT_KM_RCTRL;
720 #endif
721 
722 		cevent_key ev( type, ks , km, 1, ch, FromMouseWheel );
723 
724 		if ( w->Type() != Win::WT_MAIN && ChildKeyRecursive( w->Parent(), w, &ev ) )
725 		{
726 			return;
727 		}
728 
729 		if ( !w->IsEnabled() ) { return; }
730 
731 		w->EventKey( &ev );
732 	}
733 
KeyEvent(int type,XKeyEvent * event)734 	void KeyEvent( int type, XKeyEvent* event )
735 	{
736 		Win* w = GetWinByID( Win::focusWinId );
737 
738 		if ( !w ) { return; }
739 
740 		if ( w->Blocked() ) { return; }
741 
742 		unsigned state = event->state;
743 
744 		unsigned km = 0;
745 #if defined( __APPLE__ )
746 
747 		if ( state & MetaMask ) { km |= KM_CTRL; }
748 
749 #endif
750 
751 		if ( state & ShiftMask ) { km |= KM_SHIFT; }
752 
753 		if ( state & ControlMask ) { km |= KM_CTRL; }
754 
755 		if ( state & Mod1Mask ) { km |= KM_ALT; }
756 
757 		KeySym ks = 0;
758 
759 		if ( inputMethod )
760 		{
761 
762 			static wchar_t* buf = 0;
763 			static int bufLen = 0;
764 
765 			if ( bufLen == 0 )
766 			{
767 				buf = ( wchar_t* ) malloc( 0x100 * sizeof( wchar_t ) );
768 
769 				if ( buf ) { bufLen = 0x100; }
770 				else
771 				{
772 					fprintf( stderr, "out of memory\n" );
773 					exit( 1 );
774 				}
775 			}
776 
777 			Status ret;
778 			int n = 0;
779 
780 			while ( true )
781 			{
782 				n = XwcLookupString( inputContext, event, buf, 0x100, &ks, &ret );
783 
784 				if ( ret != XBufferOverflow ) { break; }
785 
786 				wchar_t* p = ( wchar_t* )malloc( bufLen * 2 * sizeof( wchar_t ) );
787 
788 				if ( !p ) { return; }
789 
790 				free( buf );
791 				buf = p;
792 				bufLen *= 2;
793 			}
794 
795 			if ( ret !=  XLookupNone )
796 			{
797 				if ( n > 0 )
798 				{
799 					for ( int i = 0; i < n; i++ )
800 					{
801 						DoKeyEvent( type, w, ks, km, buf[i] );
802 					}
803 				}
804 				else
805 				{
806 					DoKeyEvent( type, w, ks, km, 0 );
807 				}
808 
809 				return;
810 			}
811 		}
812 
813 
814 		char buf[256] = "";
815 		int n = XLookupString( event, buf, sizeof( buf ), &ks, NULL );
816 
817 		if ( n > 0 )
818 		{
819 			for ( int i = 0; i < n; i++ )
820 			{
821 				DoKeyEvent( type, w, ks, km, buf[i] );
822 			}
823 		}
824 		else
825 		{
826 			DoKeyEvent( type, w, ks, km, 0 );
827 		}
828 	}
829 
Distance(int a,int b)830 	inline int Distance( int a, int b )
831 	{
832 		return a > b ? a - b : b - a;
833 	}
834 
835 
836 	static void _ClipboardRequest( XEvent* event );
837 
838 #ifdef _DEBUG
839 struct {int id; const char* name;}
840 eventNames[] ={
841 { KeyPress, "KeyPress"},
842 { KeyRelease, "KeyRelease"},
843 { ButtonPress, "ButtonPress"},
844 { ButtonRelease, "ButtonRelease"},
845 { MotionNotify, "MotionNotify"},
846 { EnterNotify, "EnterNotify"},
847 { LeaveNotify, "LeaveNotify"},
848 { FocusIn, "FocusIn"},
849 { FocusOut, "FocusOut"},
850 { KeymapNotify, "KeymapNotify"},
851 { Expose, "Expose"},
852 { GraphicsExpose, "GraphicsExpose"},
853 { NoExpose, "NoExpose"},
854 { VisibilityNotify, "VisibilityNotify"},
855 { CreateNotify, "CreateNotify"},
856 { DestroyNotify, "DestroyNotify"},
857 { UnmapNotify, "UnmapNotify"},
858 { MapNotify, "MapNotify"},
859 { MapRequest, "MapRequest"},
860 { ReparentNotify, "ReparentNotify"},
861 { ConfigureNotify, "ConfigureNotify"},
862 { ConfigureRequest, "ConfigureRequest"},
863 { GravityNotify, "GravityNotify"},
864 { ResizeRequest, "ResizeRequest"},
865 { CirculateNotify, "CirculateNotify"},
866 { CirculateRequest, "CirculateRequest"},
867 { PropertyNotify, "PropertyNotify"},
868 { SelectionClear, "SelectionClear"},
869 { SelectionRequest, "SelectionRequest"},
870 { SelectionNotify, "SelectionNotify"},
871 { ColormapNotify, "ColormapNotify"},
872 { ClientMessage, "ClientMessage"},
873 { MappingNotify, "MappingNotify"},
874 { GenericEvent, "GenericEvent"},
875 };
876 
getEventName(int id)877 static const char* getEventName(int id)
878 {
879   for(int i=0; i<sizeof(eventNames)/sizeof(eventNames[0]); i++)
880   {
881     if(id == eventNames[i].id)
882       return eventNames[i].name;
883   }
884   static char ret[32];
885   sprintf(ret, "Event_%d", id);
886   return ret;
887 }
888 
889 #endif
890 
DoEvents(XEvent * event)891 	int DoEvents( XEvent* event ) //return count of windows
892 	{
893 	#ifdef _DEBUG
894 		//if(event->type!=MotionNotify)
895 		//	if(event->type==FocusIn || event->type==FocusOut)
896 		//		dbg_printf( "e(%s) ", getEventName(event->type) );
897 		//fflush( stdout );
898 	#endif
899 
900 		switch ( event->type )
901 		{
902 
903 			case KeyPress:
904 				KeyEvent( EV_KEYDOWN, ( XKeyEvent* )event );
905 				break; //   2
906 
907 			case KeyRelease:
908 				KeyEvent( EV_KEYUP, ( XKeyEvent* ) event );
909 				break; //   3
910 
911 			case ButtonPress: //4
912 			case ButtonRelease:
913 				// 5
914 			{
915 				Win* w = GetWinByID( event->xany.window );
916 
917 				if ( !w ) { break; }
918 
919 				XButtonEvent* e = &event->xbutton;
920 
921 				int type = ( ( event->type == ButtonPress ) ? EV_MOUSE_PRESS : EV_MOUSE_RELEASE );
922 
923 				if ( !w->IsEnabled() ) { break; }
924 
925 				if ( w->Blocked() ) { break; }
926 
927 				int xPos = e->x;
928 				int yPos = e->y;
929 
930 				unsigned km = 0;
931 				unsigned state = event->xbutton.state;
932 #if defined( __APPLE__ )
933 
934 				if ( state & MetaMask ) { km |= KM_CTRL; }
935 
936 #endif
937 
938 				if ( state & ShiftMask ) { km |= KM_SHIFT; }
939 
940 				if ( state & ControlMask ) { km |= KM_CTRL; }
941 
942 				if ( state & Mod1Mask ) { km |= KM_ALT; }
943 
944 				unsigned bf = 0;
945 
946 //			printf( "Button = %i\n", e->button );
947 
948 				unsigned button = 0;
949 
950 				switch ( e->button )
951 				{
952 					case Button1:
953 						button = MB_L;
954 						break;
955 
956 					case Button2:
957 						button = MB_M;
958 						break;
959 
960 					case Button3:
961 						button = MB_R;
962 						break;
963 
964 					case Button4:
965 						button = MB_X1;
966 						break;
967 
968 					case Button5:
969 						button = MB_X2;
970 						break;
971 				}
972 
973 				// mouse wheel up
974 				if ( e->button == Button4 && event->type == ButtonPress )
975 				{
976 					DoKeyEvent( EV_KEYDOWN, w, VK_UP, 0, 0, true );
977 					DoKeyEvent( EV_KEYUP,   w, VK_UP, 0, 0, true );
978 					break;
979 				}
980 
981 				// mouse wheel down
982 				if ( e->button == Button5 && event->type == ButtonPress )
983 				{
984 
985 					DoKeyEvent( EV_KEYDOWN, w, VK_DOWN, 0, 0, true );
986 					DoKeyEvent( EV_KEYUP, w, VK_DOWN, 0, 0, true );
987 					break;
988 				}
989 
990 				if ( button == MB_L && event->type == ButtonPress )
991 				{
992 					static Time lastLeftClick = 0;
993 					static int lastX = 0, lastY = 0;
994 					static const Time doubleTime = 500;
995 					static const int maxXDistance = 5, maxYDistance = 5; //максимальное изменение координат при двойном нажатии
996 
997 					if ( event->xbutton.time - lastLeftClick <= doubleTime &&
998 					     Distance( lastX, event->xbutton.x_root ) <= maxXDistance &&
999 					     Distance( lastY, event->xbutton.y_root ) <= maxYDistance )
1000 					{
1001 						type = EV_MOUSE_DOUBLE;
1002 						lastLeftClick = 0;
1003 					}
1004 					else
1005 					{
1006 						lastLeftClick = event->xbutton.time;
1007 						lastX = event->xbutton.x_root;
1008 						lastY = event->xbutton.y_root;
1009 					}
1010 				}
1011 
1012 
1013 				cevent_mouse evm( type, cpoint( xPos, yPos ), button, bf, km );
1014 
1015 
1016 				w->Event( &evm );
1017 			}
1018 			break;
1019 
1020 			case MotionNotify:
1021 			{
1022 
1023 				Win* w = GetWinByID( event->xany.window );
1024 
1025 				if ( !w ) { break; }
1026 
1027 				XMotionEvent* e = &event->xmotion;
1028 
1029 				if ( !w->IsEnabled() ) { break; }
1030 
1031 				if ( w->Blocked() ) { break; }
1032 
1033 				cevent_mouse ev( EV_MOUSE_MOVE, cpoint( e->x, e->y ), 0, 0, 0 );
1034 				w->Event( &ev );
1035 
1036 			}
1037 
1038 			break; //   6
1039 
1040 			case EnterNotify:
1041 			{
1042 				Win* w = GetWinByID( event->xany.window );
1043 
1044 				if ( !w ) { break; }
1045 
1046 				cevent ev( EV_ENTER );
1047 				w->Event( &ev );
1048 				//dbg_printf("EnterNotify\n");
1049 			}
1050 			break; //   7
1051 
1052 			case LeaveNotify:
1053 			{
1054 				Win* w = GetWinByID( event->xany.window );
1055 
1056 				if ( !w ) { break; }
1057 
1058 				cevent evl( EV_LEAVE );
1059 				w->Event( &evl );
1060 			}
1061 			break; //   8
1062 
1063 
1064 			case FocusIn:
1065 			{
1066 				if (  event->xfocus.detail == NotifyVirtual ||
1067 				      event->xfocus.detail == NotifyNonlinearVirtual ||
1068 				      event->xfocus.detail == NotifyPointer )
1069 				{
1070 					break;
1071 				}
1072 
1073 				Window id = event->xany.window;
1074 				Win* w = GetWinByID( id );
1075 
1076 				for ( ; w && w->type != Win::WT_MAIN && w->type != Win::WT_POPUP; w = w->parent )
1077 				{
1078 					EMPTY_OPER;
1079 				}
1080 
1081 				if ( w && w->handle != id )
1082 				{
1083 					id = w->handle;
1084 				}
1085 
1086 				if ( activeWinId == id )
1087 				{
1088 					break;
1089 				}
1090 
1091 
1092 				if ( Win::focusWinId )
1093 				{
1094 					Win* prevFocus = GetWinByID( Win::focusWinId );
1095 					Win::focusWinId = 0;
1096 
1097 					if ( prevFocus )
1098 					{
1099 						Win* w = prevFocus;
1100 
1101 						for ( ; w && w->parent && w->type != Win::WT_MAIN && w->type != Win::WT_POPUP; w = w->parent )
1102 						{
1103 							w->parent->lastFocusChild = w->handle;
1104 						}
1105 
1106 						cevent ekf( EV_KILLFOCUS );
1107 						prevFocus->Event( &ekf );
1108 
1109 					}
1110 				}
1111 
1112 				Win* prevActive = GetWinByID( activeWinId );
1113 
1114 				if ( activeWinId )
1115 				{
1116 					activeWinId = 0;
1117 
1118 					if ( prevActive )
1119 					{
1120 						cevent_activate ev( false, w );
1121 						activeWinId = 0;
1122 						prevActive->Event( &ev );
1123 					}
1124 				}
1125 
1126 				if ( !w ) { break; }
1127 
1128 				if ( w->blockedBy )
1129 				{
1130 					Win* t = GetWinByID( w->blockedBy );
1131 
1132 					if ( t )
1133 					{
1134 						if ( t->Type() == Win::WT_CHILD )
1135 						{
1136 							t->SetFocus();
1137 						}
1138 						else
1139 						{
1140 							t->Activate();
1141 						}
1142 					}
1143 
1144 					break;
1145 				}
1146 
1147 				cevent_activate ev( true, prevActive );
1148 				activeWinId = id;
1149 				w->Event( &ev );
1150 				Win::focusWinId = id;
1151 				cevent ecf( EV_SETFOCUS );
1152 				w->Event( &ecf );
1153 			}
1154 
1155 			break; //   9
1156 
1157 			case FocusOut:
1158 			{
1159 				if (  event->xfocus.detail == NotifyVirtual ||
1160 				      event->xfocus.detail == NotifyNonlinearVirtual ||
1161 				      event->xfocus.detail == NotifyPointer )
1162 				{
1163 					break;
1164 				}
1165 
1166 				{
1167 					// close all popups
1168 					Win* w = GetWinByID( activeWinId );
1169 					if( w )
1170 					{
1171 						while(w->parent)
1172 							w=w->parent;
1173 						ccollect<WinID> wl;
1174 						w->PopupTreeList( wl );
1175 						for(int i=0;i<wl.count();i++)
1176 						{
1177 							Win* popup = GetWinByID( wl[i] );
1178 							if(popup)
1179 							{
1180 								if(popup->parent)
1181 									popup->Parent()->Command( CMD_MENU_INFO, SCMD_MENU_CANCEL, popup, 0 );
1182 							}
1183 
1184 						}
1185 					}
1186 				}
1187 
1188 				if ( activeWinId == event->xany.window )
1189 				{
1190 					Win* w = GetWinByID( activeWinId );
1191 					activeWinId = 0;
1192 
1193 					if ( !w ) { break; }
1194 
1195 					if ( Win::focusWinId )
1196 					{
1197 						Win* t = GetWinByID( Win::focusWinId );
1198 						Win::focusWinId = 0;
1199 
1200 						if ( t )
1201 						{
1202 							Win* w = t;
1203 
1204 							for ( ; w && w->parent && w->type != Win::WT_MAIN && w->type != Win::WT_POPUP; w = w->parent )
1205 							{
1206 								w->parent->lastFocusChild = w->handle;
1207 							}
1208 
1209 							cevent eKF( EV_KILLFOCUS );
1210 							t->Event( &eKF );
1211 						}
1212 					}
1213 
1214 					Window focus_return;
1215 					int revert_to_return;
1216 					XGetInputFocus( display, &focus_return, &revert_to_return );
1217 					cevent_activate ev0( false, GetWinByID( focus_return ) );
1218 					w->Event( &ev0 );
1219 				}
1220 
1221 			}
1222 
1223 			break; //10
1224 
1225 			case KeymapNotify:
1226 				break; //   11
1227 
1228 			case Expose:
1229 			{
1230 				Win* w = GetWinByID( event->xexpose.window );
1231 
1232 				if ( !w ) { break; }
1233 
1234 				crect r( event->xexpose.x, event->xexpose.y,
1235 				         event->xexpose.x + event->xexpose.width, event->xexpose.y + event->xexpose.height );
1236 				w->AddExposeRect( r );
1237 
1238 				if ( !event->xexpose.count )
1239 				{
1240 					AddRepaint( w );
1241 				}
1242 			}
1243 			break; //12
1244 
1245 			case GraphicsExpose:
1246 				break; //13
1247 
1248 			case NoExpose:
1249 				break; //14
1250 
1251 			case VisibilityNotify:
1252 				break; //15
1253 
1254 			case CreateNotify:
1255 				break; //16
1256 
1257 			case DestroyNotify:
1258 				break; //17
1259 
1260 			case UnmapNotify:
1261 			{
1262 				Win* w = GetWinByID( event->xmap.window );
1263 
1264 				if ( w )
1265 				{
1266 					cevent_show evShowFalse( false );
1267 					w->Event( &evShowFalse );
1268 				}
1269 
1270 			}
1271 			break; //18
1272 
1273 			case MapNotify:
1274 			{
1275 				Win* w = GetWinByID( event->xmap.window );
1276 
1277 				if ( w && ( w->Type() == Win::WT_MAIN || w->Type() == Win::WT_POPUP ) &&  w->showType == Win::SHOW_ACTIVE )
1278 				{
1279 					w->Activate();
1280 				}
1281 
1282 				if ( w )
1283 				{
1284 					cevent_show evShowTrue( true );
1285 					w->Event( &evShowTrue );
1286 				}
1287 
1288 			}
1289 			break; //19
1290 
1291 			case MapRequest:
1292 				dbg_printf( "MapRequest\n" );
1293 				break; //20
1294 
1295 			case ReparentNotify:
1296 			{
1297 				Win* w = GetWinByID( event->xreparent.window );
1298 
1299 				if ( w ) { w->reparent = event->xreparent.parent; }
1300 			}
1301 
1302 			break; //   21
1303 
1304 			case ConfigureNotify:
1305 			{
1306 				Win* w = GetWinByID( event->xconfigure.window );
1307 
1308 				if ( !w ) { break; }
1309 
1310 				bool resized = //true;
1311 				   ( w->position.Width() != event->xconfigure.width ||
1312 				     w->position.Height() != event->xconfigure.height );
1313 
1314 				bool moved =
1315 				   ( w->position.left != event->xconfigure.x ||
1316 				     w->position.top != event->xconfigure.y );
1317 
1318 
1319 				int xDelta = event->xconfigure.x - w->position.left;
1320 				int yDelta = event->xconfigure.y - w->position.top;
1321 
1322 				w->position.Set(
1323 				   event->xconfigure.x,
1324 				   event->xconfigure.y,
1325 				   event->xconfigure.x + event->xconfigure.width,
1326 				   event->xconfigure.y + event->xconfigure.height
1327 				);
1328 
1329 				if ( resized )
1330 				{
1331 					cevent_size evSize( cpoint ( event->xconfigure.width, event->xconfigure.height ) );
1332 					w->Event( &evSize );
1333 				}
1334 
1335 				if ( moved )
1336 				{
1337 					cevent_move evMove( cpoint ( event->xconfigure.x, event->xconfigure.y ) );
1338 					w->Event( &evMove );
1339 				}
1340 
1341 				if ( w->Type() != Win::WT_CHILD )
1342 				{
1343 					MovePopups( w, xDelta, yDelta );
1344 				}
1345 
1346 				//dbg_printf( "ConfigureNotify above(%x)\n", event->xconfigure.above );
1347 			}
1348 			break; //   22
1349 
1350 			case ConfigureRequest:
1351 				break; //23
1352 
1353 			case GravityNotify:
1354 				break; //   24
1355 
1356 			case ResizeRequest:
1357 				break; //   25
1358 
1359 			case CirculateNotify:
1360 				break; //   26
1361 
1362 			case CirculateRequest:
1363 				break; //27
1364 
1365 			case PropertyNotify:
1366 				break; //   28
1367 
1368 			case SelectionClear:
1369 				break; //   29
1370 
1371 			case SelectionRequest:
1372 
1373 				_ClipboardRequest( event );
1374 
1375 				break; //30
1376 
1377 			case SelectionNotify:
1378 				break; //   31
1379 
1380 			case ColormapNotify:
1381 				break; //   32
1382 
1383 			case ClientMessage:
1384 			{
1385 				Win* w = GetWinByID( event->xclient.window );
1386 				bool IsWMProtocols = event->xclient.message_type == atom_WM_PROTOCOLS;
1387 				bool IsWMDeleteWindow = (Atom) event->xclient.data.l[0] == atom_WM_DELETE_WINDOW;
1388 
1389 				if ( w && IsWMProtocols && IsWMDeleteWindow )
1390 				{
1391 					cevent ev( EV_CLOSE );
1392 					w->Event( &ev );
1393 				}
1394 			}
1395 			break; //   33
1396 
1397 			case MappingNotify:
1398 				XRefreshKeyboardMapping( &( event->xmapping ) );
1399 				dbg_printf( "MappingNotify\n" );
1400 				break; //   34
1401 
1402 			/*
1403 			   case GenericEvent:
1404 			      dbg_printf("GenericEvent\n");
1405 			      break; //   35
1406 			*/
1407 			case LASTEvent:
1408 				dbg_printf( "LASTEvent\n" );
1409 				break; //36
1410 
1411 			default:
1412 				dbg_printf( "Event being thrown away\n" );
1413 				break;
1414 		}
1415 
1416 		return 1; ///!!! need correction
1417 	}
1418 
1419 	static bool appExit = false;
1420 
AppExit()1421 	void AppExit() { appExit = true; }
1422 
AppRun()1423 	int AppRun()
1424 	{
1425 		appExit = false;
1426 
1427 		while ( true )
1428 		{
1429 			wth_DoEvents();
1430 
1431 			if ( appExit ) { return 0; }
1432 
1433 			while ( XEventsQueued( display, QueuedAfterFlush ) > 0 )
1434 			{
1435 				XEvent event;
1436 				XNextEvent( display, &event );
1437 				wth_DoEvents();
1438 
1439 				if ( !DoEvents( &event ) ) { return 0; }
1440 
1441 				if ( appExit ) { return 0; }
1442 			}
1443 
1444 			unsigned w = RunTimers();
1445 			PostRepaint();
1446 
1447 			if ( XEventsQueued( display, QueuedAfterFlush ) > 0 )
1448 			{
1449 				continue;
1450 			}
1451 
1452 			fd_set fds;
1453 			FD_ZERO( &fds );
1454 			FD_SET( connectionId, &fds );
1455 			int tSignalFd = wthInternalEvent.SignalFD();
1456 			FD_SET( tSignalFd, &fds );
1457 
1458 			struct timeval tv;
1459 			tv.tv_sec = w / 1000;
1460 			tv.tv_usec = ( w % 1000 ) * 1000;
1461 
1462 			int n = connectionId > tSignalFd ? connectionId : tSignalFd;
1463 
1464 			select( n + 1, &fds,  0, 0, &tv );
1465 		}
1466 	}
1467 
1468 
1469 ///////////////////////////////////////////////    ф-ции clipboard-а {
1470 
1471 	/*
1472 	   циклы обработки сообщений _Clipboard... игноригуют все сообщения от кнопок и мыши
1473 	   в этих циклах не приходят сообщения таймеров и потоков !!!
1474 
1475 	   это для clipboard-а
1476 	   криво, но хоть так
1477 	*/
1478 
_ClipboardWaitSelectionNotify(XEvent * pEvent,bool stopOnExcape,int maxWaitSeconds=10)1479 	static int _ClipboardWaitSelectionNotify( XEvent* pEvent, bool stopOnExcape, int maxWaitSeconds = 10 ) // 0 - ok
1480 	{
1481 		time_t startTime = time( 0 );
1482 
1483 		xErrorCount = 0;
1484 
1485 		while ( true )
1486 		{
1487 			while ( XEventsQueued( display, QueuedAfterFlush ) > 0 )
1488 			{
1489 				XNextEvent( display, pEvent );
1490 
1491 				if ( pEvent->type == SelectionNotify ) { return 0; }
1492 
1493 				if ( pEvent->type == KeyPress || pEvent->type == KeyRelease )
1494 				{
1495 					if ( stopOnExcape && pEvent->xkey.keycode == 27 ) { return -3; }
1496 
1497 					continue;
1498 				}
1499 
1500 				if ( pEvent->type == ButtonPress || pEvent->type == ButtonRelease )
1501 				{
1502 					continue;
1503 				}
1504 
1505 				if ( !DoEvents( pEvent ) ) { return -1; }
1506 
1507 			}
1508 
1509 			if ( xErrorCount > 0 ) { return -1; }
1510 
1511 			PostRepaint();
1512 
1513 			if ( XEventsQueued( display, QueuedAfterFlush ) > 0 )
1514 			{
1515 				continue;
1516 			}
1517 
1518 			fd_set fds;
1519 			FD_ZERO( &fds );
1520 			FD_SET( connectionId, &fds );
1521 
1522 			struct timeval tv;
1523 			tv.tv_sec = 1;
1524 			tv.tv_usec = 0;
1525 
1526 			int n = connectionId;
1527 
1528 			if ( time( 0 ) - startTime >= maxWaitSeconds ) { return -1; }
1529 
1530 			select( n + 1, &fds,  0, 0, &tv );
1531 		}
1532 	}
1533 
_ClipboardWaitPropertyNotify(XEvent * pEvent,Window id,Atom prop,bool stopOnExcape,int maxWaitSeconds=10)1534 	static int _ClipboardWaitPropertyNotify( XEvent* pEvent, Window id, Atom prop, bool stopOnExcape, int maxWaitSeconds = 10 ) // 0 - ok
1535 	{
1536 		time_t startTime = time( 0 );
1537 
1538 		while ( true )
1539 		{
1540 			while ( XEventsQueued( display, QueuedAfterFlush ) > 0 )
1541 			{
1542 				XNextEvent( display, pEvent );
1543 
1544 				if ( pEvent->type == PropertyNotify )
1545 				{
1546 					if ( pEvent->xproperty.window == id && pEvent->xproperty.atom == prop && pEvent->xproperty.state == PropertyNewValue ) { return 0; }
1547 				}
1548 
1549 				if ( pEvent->type == KeyPress || pEvent->type == KeyRelease )
1550 				{
1551 					if ( stopOnExcape && pEvent->xkey.keycode == 27 ) { return -3; }
1552 
1553 					continue;
1554 				}
1555 
1556 				if ( pEvent->type == ButtonPress || pEvent->type == ButtonRelease )
1557 				{
1558 					continue;
1559 				}
1560 
1561 				if ( !DoEvents( pEvent ) ) { return -1; }
1562 
1563 			}
1564 
1565 			PostRepaint();
1566 
1567 			if ( XEventsQueued( display, QueuedAfterFlush ) > 0 )
1568 			{
1569 				continue;
1570 			}
1571 
1572 			fd_set fds;
1573 			FD_ZERO( &fds );
1574 			FD_SET( connectionId, &fds );
1575 
1576 			struct timeval tv;
1577 			tv.tv_sec = 1;
1578 			tv.tv_usec = 0;
1579 
1580 			int n = connectionId;
1581 
1582 			if ( time( 0 ) - startTime >= maxWaitSeconds ) { return -1; }
1583 
1584 			select( n + 1, &fds,  0, 0, &tv );
1585 		}
1586 	}
1587 
1588 
1589 	class CharQueue
1590 	{
1591 		enum { BS = 1024 };
1592 
1593 		struct Node
1594 		{
1595 			char data[BS];
1596 			Node* next;
Nodewal::CharQueue::Node1597 			Node(): next( 0 ) {}
1598 		};
1599 
1600 		int firstPos;
1601 		int lastCount;
1602 		int count;
1603 		Node* first, *last;
1604 
PreparePut()1605 		int PreparePut() { if ( !last ) { first = last = new Node; lastCount = 0; } else if ( lastCount >= BS ) { last->next = new Node; last = last->next; lastCount = 0; } return BS - lastCount; }
CheckFirst()1606 		void CheckFirst() { if ( firstPos >= BS ) { Node* p = first; first = first->next; delete p; firstPos = 0; if ( !first ) { last = 0; } }; }
1607 	public:
CharQueue()1608 		CharQueue(): firstPos( 0 ), lastCount( 0 ), count( 0 ), first( 0 ), last( 0 ) {}
Clear()1609 		void Clear() { while ( first ) { Node* p = first; first = first->next; delete p; } last = 0; count = 0; }
Count() const1610 		int Count() const { return count; }
Put(int c)1611 		void Put( int c ) { PreparePut(); last->data[lastCount++] = c; count++; }
Put(const char * s,int size)1612 		void Put( const char* s, int size ) { while ( size > 0 ) { int n = PreparePut(); if ( n > size ) { n = size; } memcpy( last->data + lastCount, s, n * sizeof( char ) ); lastCount += n; size -= n; s += n; count += n; } }
Get()1613 		int Get() { if ( count <= 0 ) { return 0; } int c = first->data[firstPos++]; count--; CheckFirst(); return c; }
1614 
Get(char * s,int size)1615 		int Get( char* s, int size )
1616 		{
1617 			if ( size > count ) { size = count; }
1618 
1619 			if ( size <= 0 ) { return 0; }
1620 
1621 			int ret = size;
1622 
1623 			while ( size > 0 )
1624 			{
1625 				int n = BS - firstPos;
1626 
1627 				if ( n > size ) { n = size; }
1628 
1629 				memcpy( s, first->data + firstPos, n );
1630 				size -= n;
1631 				firstPos += n;
1632 				count -= n;
1633 				s += n;
1634 				CheckFirst();
1635 			}
1636 
1637 			return ret;
1638 		}
1639 
GetArray()1640 		std::vector<char> GetArray() { std::vector<char> p; if ( count > 0 ) { p.resize( count ); Get( p.data(), count ); } return p; }
GetArray(int * pCount)1641 		std::vector<char> GetArray( int* pCount ) { int n = count; std::vector<char> p; if ( count > 0 ) { p.resize( count ); Get( p.data(), count ); } if ( pCount ) { *pCount = n; } return p; }
1642 
~CharQueue()1643 		~CharQueue() { Clear(); }
1644 	};
1645 
1646 
CharQueueToClipboartAsUtf8(ClipboardText * text,CharQueue * q)1647 	static   void CharQueueToClipboartAsUtf8( ClipboardText* text, CharQueue* q )
1648 	{
1649 		int size;
1650 		std::vector<char> p = q->GetArray( &size );
1651 
1652 		char* s = p.data();
1653 
1654 		while ( size > 0 )
1655 		{
1656 			if ( *s & 0x80 )
1657 			{
1658 				unicode_t t;
1659 				int n;
1660 
1661 				if ( ( *s & 0xE0 ) == 0xC0 )
1662 				{
1663 					t = ( *s & 0x3F );
1664 					n = 1;
1665 				}
1666 				else if ( ( *s & 0xF0 ) == 0xE0 )
1667 				{
1668 					t = ( *s & 0x1F );
1669 					n = 2;
1670 				}
1671 				else if ( ( *s &  0xF8 ) == 0xF0 )
1672 				{
1673 					t = ( *s & 0x07 );
1674 					n = 3;
1675 				}
1676 				else
1677 				{
1678 					text->Append( ( *( s++ ) & 0x7F ) );
1679 					size--;
1680 					continue;
1681 				}
1682 
1683 				s++;
1684 				size--;
1685 
1686 				for ( ; size > 0 && ( *s & 0xC0 ) == 0x80; size--, n--, s++ )
1687 				{
1688 					t = ( t << 6 ) + ( *s & 0x3F );
1689 				}
1690 
1691 				text->Append( t );
1692 			}
1693 			else
1694 			{
1695 				text->Append( *( s++ ) );
1696 				size--;
1697 			}
1698 		}
1699 	}
1700 
ClipboardToCharQueueAsUtf8(CharQueue * q,ClipboardText * text)1701 	static   void ClipboardToCharQueueAsUtf8( CharQueue* q, ClipboardText* text )
1702 	{
1703 		int n = text->Count();
1704 
1705 		for ( int i = 0; i < n; i++ )
1706 		{
1707 			unsigned c = text->Get( i );
1708 
1709 			if ( c < 0x800 )
1710 			{
1711 				if ( c < 0x80 )
1712 				{
1713 					q->Put( c );
1714 				}
1715 				else
1716 				{
1717 					q->Put( ( 0xC0 | ( c >> 6 ) ) );
1718 					q->Put( 0x80 | ( c & 0x3F ) );
1719 				}
1720 			}
1721 			else
1722 			{
1723 				char s[4];
1724 
1725 				if ( c < 0x10000 ) //1110xxxx 10xxxxxx 10xxxxxx
1726 				{
1727 					s[2] = 0x80 | ( c & 0x3F );
1728 					c >>= 6;
1729 					s[1] = 0x80 | ( c & 0x3F );
1730 					c >>= 6;
1731 					s[0] = ( c & 0x0F ) | 0xE0;
1732 					q->Put( s, 3 );
1733 				}
1734 				else     //11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1735 				{
1736 					s[3] = 0x80 | ( c & 0x3F );
1737 					c >>= 6;
1738 					s[2] = 0x80 | ( c & 0x3F );
1739 					c >>= 6;
1740 					s[1] = 0x80 | ( c & 0x3F );
1741 					c >>= 6;
1742 					s[0] = ( c & 0x7 ) | 0xF0;
1743 					q->Put( s, 4 );
1744 				}
1745 			}
1746 
1747 		}
1748 	}
1749 
1750 
ClipboardToCharQueueAsLatin1(CharQueue * q,ClipboardText * text)1751 	static   void ClipboardToCharQueueAsLatin1( CharQueue* q, ClipboardText* text )
1752 	{
1753 		int n = text->Count();
1754 
1755 		for ( int i = 0; i < n; i++ )
1756 		{
1757 			unsigned c = text->Get( i );
1758 			q->Put( c >= 0x100 ? '?' : char( c ) );
1759 		}
1760 	}
1761 
1762 
1763 // return >=0 - ok
1764 // return <0 - error
1765 
GetWinPropSize(Window winId,Atom prop,Atom * pRetType)1766 	static int GetWinPropSize( Window winId, Atom prop, Atom* pRetType ) //в байтах
1767 	{
1768 		int retFormat;
1769 		unsigned long retNItems;
1770 		unsigned long retBytesAfter;
1771 		unsigned char* propDataPtr = 0;
1772 
1773 		int ret = XGetWindowProperty( display, winId, prop,
1774 		                              0,
1775 		                              0,
1776 		                              False, AnyPropertyType,
1777 		                              pRetType, &retFormat, &retNItems, &retBytesAfter, &propDataPtr );
1778 
1779 		if ( ret != Success ) { return -1; }
1780 
1781 		if ( propDataPtr ) { XFree( propDataPtr ); }
1782 
1783 		return retBytesAfter;
1784 	}
1785 
ReadCharProp(Window winId,Atom prop,CharQueue * buf)1786 	static bool ReadCharProp( Window winId, Atom prop, CharQueue* buf )
1787 	{
1788 		Atom retType;
1789 		int ret;
1790 
1791 		int size = GetWinPropSize( winId, prop, &retType );
1792 
1793 		if ( size < 0 ) { return false; }
1794 
1795 		int retFormat;
1796 		unsigned long retNItems;
1797 		unsigned long retBytesAfter;
1798 		unsigned char* propDataPtr = 0;
1799 
1800 		if ( retType != atom_INCR )
1801 		{
1802 			ret = XGetWindowProperty( display, winId, prop,
1803 			                          0,
1804 			                          size, //???
1805 			                          False, AnyPropertyType,
1806 			                          &retType, &retFormat, &retNItems, &retBytesAfter, &propDataPtr );
1807 
1808 			if ( ret != Success ) { return false; }
1809 
1810 			switch ( retFormat )
1811 			{
1812 				case 8:
1813 					size = retNItems;
1814 					break;
1815 
1816 				case 16:
1817 					size = retNItems * 2;
1818 					break;
1819 
1820 				case 32:
1821 					size = retNItems * 4;
1822 					break;
1823 
1824 				default:
1825 					size = -1;
1826 			}
1827 
1828 			if ( !propDataPtr ) { size = -1; }
1829 
1830 			if ( size > 0 )
1831 			{
1832 				buf->Put( ( char* )propDataPtr, size );
1833 			}
1834 
1835 			if ( propDataPtr ) { XFree( propDataPtr ); propDataPtr = 0; }
1836 
1837 			XDeleteProperty( display, winId, prop );
1838 
1839 			return size >= 0;
1840 		}
1841 
1842 		/// INCR mode
1843 		//
1844 
1845 
1846 		XDeleteProperty( display, winId, prop );
1847 
1848 		size = 0;
1849 
1850 		while ( true )
1851 		{
1852 			XEvent event;
1853 
1854 			if ( _ClipboardWaitPropertyNotify( &event, winId, prop, true ) ) { return false; }
1855 
1856 			size = GetWinPropSize( winId, prop, &retType );
1857 
1858 			if ( size <= 0 ) { break; }
1859 
1860 			ret = XGetWindowProperty( display, winId, prop,
1861 			                          0,
1862 			                          size, //???
1863 			                          False, AnyPropertyType,
1864 			                          &retType, &retFormat, &retNItems, &retBytesAfter, &propDataPtr );
1865 
1866 			if ( ret != Success ) { return false; }
1867 
1868 			switch ( retFormat )
1869 			{
1870 				case 8:
1871 					size = retNItems;
1872 					break;
1873 
1874 				case 16:
1875 					size = retNItems * 2;
1876 					break;
1877 
1878 				case 32:
1879 					size = retNItems * 4;
1880 					break;
1881 
1882 				default:
1883 					size = -1;
1884 			}
1885 
1886 			if ( !propDataPtr ) { size = -1; }
1887 
1888 			if ( size > 0 )
1889 			{
1890 				buf->Put( ( char* )propDataPtr, size );
1891 			}
1892 
1893 			if ( propDataPtr ) { XFree( propDataPtr ); propDataPtr = 0; }
1894 
1895 			XDeleteProperty( display, winId, prop );
1896 		}
1897 
1898 		return size == 0;
1899 	}
1900 
1901 
RunGetClipboard(Win * w,ClipboardText * text)1902 	static void RunGetClipboard( Win* w, ClipboardText* text )
1903 	{
1904 		Atom cbAtom = atom_CLIPBOARD;
1905 		Window selOwner = XGetSelectionOwner( display, cbAtom );
1906 
1907 
1908 		if ( selOwner == None )
1909 		{
1910 			cbAtom = atom_PRIMARY;
1911 			selOwner = XGetSelectionOwner( display, cbAtom );
1912 
1913 			if ( selOwner == None ) { return; }
1914 		}
1915 
1916 
1917 		if ( selOwner == clipboardWinId )
1918 		{
1919 //printf("selOwner == clipboardWinId\n");
1920 			*text = clipboardText;
1921 			return;
1922 		}
1923 
1924 		XConvertSelection( display, cbAtom, atom_UTF8,  atom_CDEST, clipboardWinId, CurrentTime );
1925 
1926 		XEvent event;
1927 
1928 		if ( _ClipboardWaitSelectionNotify( &event, true ) ) { return; }
1929 
1930 		if ( event.xselection.requestor != clipboardWinId ||
1931 		     event.xselection.selection !=  cbAtom )
1932 		{
1933 			return;
1934 		}
1935 
1936 		if ( event.xselection.target != atom_UTF8 ) { return; }
1937 
1938 		if ( event.xselection.property == None ) { return; }
1939 
1940 		if ( event.xselection.property != atom_CDEST ) { return; }
1941 
1942 		CharQueue cb;
1943 
1944 		if ( !ReadCharProp( clipboardWinId, atom_CDEST, &cb ) ) { return; }
1945 
1946 		CharQueueToClipboartAsUtf8( text, &cb );
1947 	}
1948 
ClipboardGetText(Win * w,ClipboardText * text)1949 	void ClipboardGetText( Win* w, ClipboardText* text )
1950 	{
1951 		static bool isRun = false; //чтоб рекурсивно не вызывалось
1952 
1953 		if ( isRun || !text || !w )
1954 		{
1955 			return;
1956 		}
1957 
1958 		isRun = true;
1959 
1960 		try
1961 		{
1962 			RunGetClipboard( w, text );
1963 		}
1964 		catch ( ... )
1965 		{
1966 			isRun = false;
1967 			throw;
1968 		}
1969 
1970 		isRun = false;
1971 	}
1972 
1973 
_ClipboardRequest(XEvent * event)1974 	static void _ClipboardRequest( XEvent* event )
1975 	{
1976 		CharQueue q;
1977 
1978 		XEvent reply;
1979 		reply.type = SelectionNotify;
1980 		reply.xselection.display = display;
1981 		reply.xselection.selection = event->xselectionrequest.selection;
1982 		reply.xselection.target = event->xselectionrequest.target;
1983 		reply.xselection.requestor = event->xselectionrequest.requestor;
1984 		reply.xselection.property = event->xselectionrequest.property;
1985 		reply.xselection.time = event->xselectionrequest.time;
1986 
1987 		/*
1988 		   !!!протестировать нормально и доделать
1989 
1990 		   непонятно надо ли делать INCR mode
1991 
1992 		   обязательные targets ???
1993 		   TARGETS
1994 		   MULTIPLE
1995 		   TIMESTAMP
1996 		*/
1997 
1998 		if ( event->type != SelectionRequest ) { return; }
1999 
2000 		if ( event->xselectionrequest.selection != atom_PRIMARY && event->xselectionrequest.selection != atom_CLIPBOARD )
2001 		{
2002 			goto Nah;
2003 		}
2004 
2005 
2006 		if ( event->xselectionrequest.target == atom_TARGETS )
2007 		{
2008 			Atom possibleTargets[] =
2009 			{
2010 				atom_STRING,
2011 				atom_UTF8,
2012 				atom_COMPOUND
2013 			};
2014 
2015 			XChangeProperty( display,
2016 			                 event->xselectionrequest.requestor,
2017 			                 event->xselectionrequest.property,
2018 			                 event->xselectionrequest.target,
2019 			                 32, PropModeReplace,
2020 			                 ( unsigned char* ) possibleTargets,
2021 			                 2 ); //!!!
2022 
2023 			XSendEvent( display, event->xselectionrequest.requestor, True, 0, &reply );
2024 			return;
2025 		}
2026 
2027 
2028 		if ( event->xselectionrequest.target == atom_UTF8 ) { ClipboardToCharQueueAsUtf8( &q, &clipboardText ); }
2029 		else if ( event->xselectionrequest.target == atom_STRING ) { ClipboardToCharQueueAsLatin1( &q, &clipboardText ); }
2030 		else
2031 		{
2032 //printf("!!!CLIPBOARD UNKNOWN TARGET (%i), (%s)\n", int(event->xselectionrequest.target), XGetAtomName(display, event->xselectionrequest.target));
2033 			goto Nah;
2034 		}
2035 
2036 		if ( q.Count() <= 0 ) { goto Nah; }
2037 
2038 		{
2039 			int size;
2040 			std::vector<char> p = q.GetArray( &size );
2041 
2042 			XChangeProperty( display,
2043 			                 event->xselectionrequest.requestor,
2044 			                 event->xselectionrequest.property,
2045 			                 event->xselectionrequest.target,
2046 			                 8,
2047 			                 PropModeReplace,
2048 			                 ( unsigned char* )p.data(),
2049 			                 size );
2050 
2051 			XSendEvent( display, event->xselectionrequest.requestor, True, 0, &reply );
2052 			return;
2053 		}
2054 
2055 Nah:
2056 		reply.xselection.property = None;
2057 		XSendEvent( display, event->xselectionrequest.requestor, True, 0, &reply );
2058 	}
2059 
2060 
2061 /////////////////////////////////////////// } (clipboard)
2062 
2063 
2064 
2065 
2066 //////////////////////////////////////   GC
2067 
2068 	XFontStruct* GC::defaultFontStruct = 0;
2069 
_Init(Drawable id)2070 	void GC::_Init( Drawable id )
2071 	{
2072 		curFont = 0;
2073 		valueMask = 0;
2074 		lineX = 0;
2075 		lineY = 0;
2076 		winId = id;
2077 		lineRgb = 0;
2078 		lineColor = blackColor;
2079 		textRgb = 0;
2080 		textColor = blackColor;
2081 		fillRgb = 0xFFFFFFFF;
2082 		fillColor = whiteColor;
2083 
2084 		//defaults
2085 		gcValues.foreground = 0;
2086 		gcValues.background = 1;
2087 		gcValues.line_width = 0;
2088 		gcValues.line_style = LineSolid;
2089 		gcValues.cap_style =  CapProjecting;  //CapButt;
2090 		gcValues.join_style = JoinMiter;
2091 		gcValues.fill_style = FillSolid;
2092 		gcValues.fill_rule = EvenOddRule;
2093 		gcValues.arc_mode = ArcPieSlice;
2094 		gcValues.ts_x_origin = 0;
2095 		gcValues.ts_y_origin = 0;
2096 		gcValues.font = 0;
2097 		gcValues.subwindow_mode = ClipByChildren;
2098 		gcValues.graphics_exposures = True;
2099 		gcValues.clip_x_origin = 0;
2100 		gcValues.clip_y_origin = 0;
2101 		gcValues.clip_mask = None;
2102 		gcValues.dash_offset =  0;
2103 
2104 		gc = XCreateGC( display, winId, GCCapStyle , &gcValues );
2105 
2106 		if ( !defaultFontStruct )
2107 		{
2108 			defaultFontStruct = XQueryFont( display, XGContextFromGC( gc ) );
2109 		}
2110 
2111 		fontAscent = ( defaultFontStruct ) ? defaultFontStruct->ascent : 0;
2112 	}
2113 
2114 
GC(Win * win)2115 	GC::GC( Win* win )
2116 		: gc( None )
2117 	{
2118 		_Init( win ? win->GetID() : DefaultRootWindow( display ) );
2119 	}
2120 
GC(SCImage * im)2121 	GC::GC( SCImage* im )
2122 		: gc( None )
2123 	{
2124 		_Init( im->GetXDrawable() );
2125 	}
2126 
GC(Drawable id)2127 	GC::GC( Drawable id )
2128 		: gc( None )
2129 	{
2130 		_Init( id );
2131 	}
2132 
2133 
2134 	/*
2135 	GC::GC(Win *win)
2136 	:  valueMask(0),
2137 	   lineX(0), lineY(0),
2138 	   winId(win?win->GetID():DefaultRootWindow(display)),
2139 	   lineRgb(0), lineColor(blackColor),
2140 	   textRgb(0), textColor(blackColor),
2141 	   fillRgb(0xFFFFFFFF), fillColor(whiteColor)
2142 	{
2143 	   //defaults
2144 	   gcValues.foreground=0;
2145 	   gcValues.background=1;
2146 	   gcValues.line_width=0;
2147 	   gcValues.line_style=LineSolid;
2148 	   gcValues.cap_style =  CapProjecting;  //CapButt;
2149 	   gcValues.join_style=JoinMiter;
2150 	   gcValues.fill_style=FillSolid;
2151 	   gcValues.fill_rule=EvenOddRule;
2152 	   gcValues.arc_mode=ArcPieSlice;
2153 	   gcValues.ts_x_origin=0;
2154 	   gcValues.ts_y_origin=0;
2155 	   gcValues.font=0;
2156 	   gcValues.subwindow_mode = ClipByChildren;
2157 	   gcValues.graphics_exposures = True;
2158 	   gcValues.clip_x_origin= 0;
2159 	   gcValues.clip_y_origin= 0;
2160 	   gcValues.clip_mask=None;
2161 	   gcValues.dash_offset =  0;
2162 
2163 	   gc = XCreateGC(display, winId, GCCapStyle , &gcValues);
2164 
2165 	   if (!defaultFontStruct)
2166 	      defaultFontStruct = XQueryFont(display, XGContextFromGC(gc));
2167 
2168 	   fontAscent = (defaultFontStruct)? defaultFontStruct->ascent : 0;
2169 	}
2170 	*/
2171 
SetFg(unsigned c)2172 	inline void GC::SetFg( unsigned c )
2173 	{
2174 		if ( gcValues.foreground != c )
2175 		{
2176 			valueMask |= GCForeground;
2177 			gcValues.foreground = c;
2178 		}
2179 	}
2180 
SetBg(unsigned c)2181 	inline void GC::SetBg( unsigned c )
2182 	{
2183 		if ( gcValues.background != c )
2184 		{
2185 			valueMask |= GCBackground;
2186 			gcValues.background = c;
2187 		}
2188 	}
2189 
SetFillColor(unsigned rgb)2190 	void GC::SetFillColor( unsigned rgb )
2191 	{
2192 		if ( fillRgb == rgb ) { return; }
2193 
2194 		fillRgb = rgb;
2195 		fillColor = CreateColorFromRGB( rgb );
2196 	}
2197 
SetLine(unsigned rgb,int width,int style)2198 	void GC::SetLine( unsigned rgb, int width, int style )
2199 	{
2200 		if ( width == 1 ) { width = 0; }
2201 
2202 		int s = ( style == DOT ) ? LineOnOffDash : LineSolid;
2203 
2204 		if ( lineRgb == rgb && width  == gcValues.line_width && s == gcValues.line_style ) { return; }
2205 
2206 		gcValues.line_width = width;
2207 		gcValues.line_style = s;
2208 		valueMask |= GCLineWidth | GCLineStyle;
2209 		lineRgb = rgb;
2210 		lineColor = CreateColorFromRGB( rgb );
2211 	}
2212 
2213 
Set(cfont * font)2214 	void GC::Set( cfont* font )
2215 	{
2216 		curFont = 0;
2217 
2218 		if ( !font ) { return; }
2219 
2220 		if ( font->type == cfont::TYPE_X11 )
2221 		{
2222 			XFontStruct* fs  = ( XFontStruct* )font->data;
2223 
2224 			if ( fs )
2225 			{
2226 				XSetFont( display, gc, fs->fid );
2227 				fontAscent = fs->ascent;
2228 			}
2229 
2230 			return;
2231 		}
2232 
2233 		if ( font->type == cfont::TYPE_FT )
2234 		{
2235 			curFont = font;
2236 			return;
2237 		}
2238 	}
2239 
CheckValues()2240 	inline void GC::CheckValues()
2241 	{
2242 		if ( valueMask )
2243 		{
2244 			XChangeGC( display, gc, valueMask, &gcValues );
2245 			valueMask = 0;
2246 		}
2247 	}
2248 
FillRect(crect r)2249 	void GC::FillRect( crect r )
2250 	{
2251 		if ( r.Width() <= 0 || r.Height() <= 0 ) { return; }
2252 
2253 		SetFg( fillColor );
2254 		CheckValues();
2255 		XFillRectangle( display, winId, gc, r.left, r.top, r.Width(), r.Height() );
2256 	}
2257 
FillRectXor(crect r)2258 	void GC::FillRectXor( crect r )
2259 	{
2260 		if ( r.Width() <= 0 || r.Height() <= 0 ) { return; }
2261 
2262 		SetFg( fillColor );
2263 		CheckValues();
2264 		XSetFunction( display, gc, GXxor );
2265 		XFillRectangle( display, winId, gc, r.left, r.top, r.Width(), r.Height() );
2266 		XSetFunction( display, gc, GXcopy );
2267 	}
2268 
SetTextColor(unsigned rgb)2269 	void GC::SetTextColor( unsigned rgb )
2270 	{
2271 		if ( textRgb == rgb ) { return; }
2272 
2273 		textRgb = rgb;
2274 		textColor = CreateColorFromRGB( rgb );
2275 
2276 	}
2277 
SetClipRgn(crect * r)2278 	void GC::SetClipRgn( crect* r )
2279 	{
2280 		if ( r )
2281 		{
2282 			XRectangle xr;
2283 			xr.x = r->left;
2284 			xr.y = r->top;
2285 			xr.width = r->Width();
2286 			xr.height = r->Height();
2287 
2288 			XSetClipRectangles( display, gc, 0, 0, &xr, 1, Unsorted );
2289 		}
2290 		else
2291 		{
2292 			XSetClipMask( display, gc, None );
2293 		}
2294 	}
2295 
DrawIcon(int x,int y,cicon * ico)2296 	void GC::DrawIcon( int x, int y, cicon* ico )
2297 	{
2298 		if ( ico ) { ico->Draw( *this, x, y ); }
2299 	}
2300 
DrawIconF(int x,int y,cicon * ico)2301 	void GC::DrawIconF( int x, int y, cicon* ico )
2302 	{
2303 		if ( ico ) { ico->DrawF( *this, x, y ); }
2304 	}
2305 
2306 
TextOut(int x,int y,const unicode_t * s,int charCount)2307 	void GC::TextOut( int x, int y, const unicode_t* s, int charCount )
2308 	{
2309 		if ( charCount < 0 )
2310 		{
2311 			charCount = unicode_strlen( s );
2312 		}
2313 
2314 		if ( charCount <= 0 ) { return; }
2315 
2316 #ifdef USEFREETYPE
2317 
2318 		if ( curFont && curFont->type == cfont::TYPE_FT )
2319 		{
2320 			( ( FTU::FFace* )curFont->data )->OutText( *this, x, y, s, charCount );
2321 			return;
2322 		}
2323 
2324 #endif
2325 
2326 		SetFg( textColor );
2327 		CheckValues();
2328 		std::vector<XChar2b> sc( charCount );
2329 
2330 		for ( int i = 0; i < charCount; i++ )
2331 		{
2332 			unicode_t c = s[i];
2333 			sc[i].byte2 = ( c & 0xFF );
2334 			sc[i].byte1 = ( ( c >> 8 ) & 0xFF );
2335 		}
2336 
2337 		XDrawString16( display, winId, gc, x, y + fontAscent, sc.data(), charCount );
2338 	}
2339 
TextOutF(int x,int y,const unicode_t * s,int charCount)2340 	void GC::TextOutF( int x, int y, const unicode_t* s, int charCount )
2341 	{
2342 		if ( charCount < 0 )
2343 		{
2344 			charCount = unicode_strlen( s );
2345 		}
2346 
2347 		if ( charCount <= 0 ) { return; }
2348 
2349 #ifdef USEFREETYPE
2350 
2351 		if ( curFont && curFont->type == cfont::TYPE_FT )
2352 		{
2353 			( ( FTU::FFace* )curFont->data )->OutTextF( *this, x, y, s, charCount );
2354 			return;
2355 		}
2356 
2357 #endif
2358 		SetFg( textColor );
2359 		SetBg( fillColor );
2360 		CheckValues();
2361 		std::vector<XChar2b> sc( charCount );
2362 
2363 		for ( int i = 0; i < charCount; i++ )
2364 		{
2365 			unicode_t c = s[i];
2366 			sc[i].byte2 = ( c & 0xFF );
2367 			sc[i].byte1 = ( ( c >> 8 ) & 0xFF );
2368 		}
2369 
2370 		XDrawImageString16( display, winId, gc, x, y + fontAscent, sc.data(), charCount );
2371 	}
2372 
2373 
MoveTo(int x,int y)2374 	void GC::MoveTo( int x, int y )
2375 	{
2376 		lineX = x;
2377 		lineY = y;
2378 	}
2379 
LineTo(int x,int y)2380 	void GC::LineTo( int x, int y )
2381 	{
2382 		SetFg( lineColor );
2383 		CheckValues();
2384 		XDrawLine( display, winId, gc, lineX, lineY, x, y );
2385 		lineX = x;
2386 		lineY = y;
2387 	}
2388 
SetPixel(int x,int y,unsigned rgb)2389 	void GC::SetPixel( int x, int y, unsigned rgb )
2390 	{
2391 		valueMask |= GCForeground;
2392 		gcValues.foreground = CreateColorFromRGB( rgb );
2393 		CheckValues();
2394 		XDrawPoint( display, winId, gc, x, y );
2395 	}
2396 
GetTextExtents(const unicode_t * s,int charCount)2397 	cpoint GC::GetTextExtents( const unicode_t* s, int charCount )
2398 	{
2399 		if ( !s ) { return cpoint( 0, 0 ); }
2400 
2401 		if ( charCount < 0 )
2402 		{
2403 			charCount = unicode_strlen( s );
2404 		}
2405 
2406 #ifdef USEFREETYPE
2407 
2408 		if ( curFont && curFont->type == cfont::TYPE_FT )
2409 		{
2410 			return ( ( FTU::FFace* )curFont->data )->GetTextExtents( s, charCount );
2411 		}
2412 
2413 #endif
2414 
2415 		int direction;
2416 		int ascent;
2417 		int descent;
2418 		XCharStruct ret;
2419 
2420 		if ( charCount == 0 )
2421 		{
2422 			XChar2b xc;
2423 			xc.byte2 = ' ';
2424 			xc.byte1 = 0;
2425 			XQueryTextExtents16( display, XGContextFromGC( gc ), &xc, 1, &direction, &ascent, &descent, &ret );
2426 			ret.width = 0;
2427 		}
2428 		else
2429 		{
2430 			std::vector<XChar2b> sc( charCount );
2431 
2432 			for ( int i = 0; i < charCount; i++ )
2433 			{
2434 				unicode_t c = s[i];
2435 				sc[i].byte2 = ( c & 0xFF );
2436 				sc[i].byte1 = ( ( c >> 8 ) & 0xFF );
2437 			}
2438 
2439 			XQueryTextExtents16( display, XGContextFromGC( gc ), sc.data(), charCount, &direction, &ascent, &descent, &ret );
2440 		}
2441 
2442 		return cpoint( ret.width, ascent + descent );
2443 	}
2444 
Ellipce(crect r)2445 	void GC::Ellipce( crect r )
2446 	{
2447 		SetFg( lineColor );
2448 		CheckValues();
2449 		int w = r.Width() - 1;
2450 		int h = r.Height() - 1;
2451 
2452 		if ( w < 0 ) { w = 1; }
2453 
2454 		if ( h < 0 ) { h = 1; }
2455 
2456 		XDrawArc( display, winId, gc, r.left, r.top, w, h, 0, 360 * 64 );
2457 	}
2458 
~GC()2459 	GC::~GC() { XFreeGC( display, gc ); }
2460 
2461 
2462 //////////////////////////// Win
2463 
2464 
2465 
Win(WTYPE t,unsigned hints,Win * _parent,const crect * rect,int uiNId)2466 	Win::Win( WTYPE t, unsigned hints, Win* _parent, const crect* rect, int uiNId )
2467 		:
2468 		parent( _parent ),
2469 		type( t ),
2470 		blockedBy( 0 ),
2471 		modal( 0 ),
2472 		whint( hints ),
2473 		state( 0 ),
2474 
2475 		captured( false ),
2476 		lastFocusChild( 0 ),
2477 		upLayout( 0 ),
2478 		layout( 0 ),
2479 		uiNameId( uiNId ),
2480 
2481 		reparent( 0 ),
2482 		exposeRect( 0, 0, 0, 0 )
2483 	{
2484 		crect r = ( rect ? *rect : crect( 0, 0, 1, 1 ) );
2485 
2486 		if ( r.top >= r.bottom ) { r.bottom = r.top + 1; }
2487 
2488 		if ( r.left >= r.right ) { r.right = r.left + 1; }
2489 
2490 		position = r;
2491 
2492 
2493 		XSetWindowAttributes attrs;
2494 
2495 		attrs.event_mask =
2496 		   KeyPressMask      |  //Keyboard down events
2497 		   KeyReleaseMask       |  //Keyboard up events
2498 		   ButtonPressMask   |  //Pointer button down events
2499 		   ButtonReleaseMask    |  //Pointer button up events
2500 		   EnterWindowMask   |  //Pointer window entry events
2501 		   LeaveWindowMask   |  //Pointer window leave events
2502 		   PointerMotionMask    |  //All pointer motion events
2503 //		PointerMotionHintMask  |  //Fewer pointer motion events
2504 		   Button1MotionMask    |  //Pointer motion while button 1 down
2505 		   Button2MotionMask    |  //Pointer motion while button 2 down
2506 		   Button3MotionMask    |  //Pointer motion while button 3 down
2507 		   Button4MotionMask    |  //Pointer motion while button 4 down
2508 		   Button5MotionMask    |  //Pointer motion while button 5 down
2509 		   ButtonMotionMask  |  //Pointer motion while any button down
2510 		   KeymapStateMask   |  //Any keyboard state change on EnterNotify , LeaveNotify , FocusIn or FocusOut
2511 		   ExposureMask      |  //Any exposure (except GraphicsExpose and NoExpose )
2512 		   VisibilityChangeMask    |  //Any change in visibility
2513 		   StructureNotifyMask  |  //Any change in window configuration.
2514 //		ResizeRedirectMask  |  //Redirect resize of this window
2515 //		SubstructureNotifyMask    |  //Notify about reconfiguration of children
2516 //		SubstructureRedirectMask| //Redirect reconfiguration of children
2517 		   FocusChangeMask   |  //Any change in keyboard focus
2518 		   PropertyChangeMask   |  //Any change in property
2519 		   ColormapChangeMask   |  //Any change in colormap
2520 		   OwnerGrabButtonMask;       //Modifies handling of pointer events
2521 
2522 
2523 		Window xparent =
2524 		   ( !parent || type == WT_MAIN || type == WT_POPUP ) ?
2525 		   DefaultRootWindow( display ) : parent->GetID();
2526 
2527 
2528 		unsigned long valueMask = CWEventMask;
2529 
2530 		valueMask |= CWBorderPixmap;
2531 		attrs.border_pixmap = None;
2532 
2533 		valueMask |= CWBackPixmap;
2534 		attrs.background_pixmap = None;
2535 
2536 		if ( type == WT_POPUP )
2537 		{
2538 			valueMask |= CWOverrideRedirect;
2539 			attrs.override_redirect = True;
2540 		}
2541 
2542 		handle = XCreateWindow(
2543 		            display,
2544 		            xparent,
2545 		            r.left, r.top, r.Width(), r.Height(),
2546 		            0,
2547 		            CopyFromParent,
2548 		            InputOutput,
2549 		            visual,
2550 		            valueMask, &attrs );
2551 
2552 		AddWinToHash( handle, this );
2553 
2554 		if ( parent )
2555 		{
2556 			parent->childList.append( this );
2557 
2558 			if ( type == WT_MAIN || type == WT_POPUP )
2559 			{
2560 				XSetTransientForHint( display, handle, parent->GetID() );
2561 			}
2562 
2563 		}
2564 
2565 		if ( rect && !rect->IsEmpty() )
2566 		{
2567 			LSize ls;
2568 			ls.Set( *rect );
2569 			SetLSize( ls );
2570 		}
2571 
2572 
2573 		if ( type == WT_MAIN && atom_WM_DELETE_WINDOW != None )
2574 		{
2575 			XSetWMProtocols( display, handle, &atom_WM_DELETE_WINDOW, 1 );
2576 		}
2577 
2578 		if ( type == WT_MAIN )
2579 		{
2580 			XSizeHints hints;
2581 			hints.flags = PMinSize;
2582 			hints.min_width = 10;
2583 			hints.min_height = 10;
2584 			XSetWMNormalHints( display, handle, &hints );
2585 
2586 			/*
2587 			      if (winIcon.GetXDrawable() != None)
2588 			      {
2589 			         XWMHints wm_hints;
2590 			         wm_hints.icon_pixmap = winIcon.GetXDrawable();
2591 			         wm_hints.flags = IconPixmapHint ;
2592 			         XSetWMProperties(display, handle, 0, 0, 0, 0, 0, &wm_hints, 0);
2593 			      }
2594 			*/
2595 			if ( winIconPixmap != None && winIconMask != None )
2596 			{
2597 				XWMHints wm_hints;
2598 				wm_hints.icon_pixmap = winIconPixmap;
2599 				wm_hints.icon_mask = winIconMask;
2600 				wm_hints.flags = IconPixmapHint | IconMaskHint;
2601 				XSetWMHints( display, handle, &wm_hints );
2602 			}
2603 		};
2604 
2605 		XClassHint* Hint = XAllocClassHint();
2606 
2607 		if ( Hint )
2608 		{
2609 			Hint->res_name = (char*)"WCM Commander";
2610 			Hint->res_class = (char*)"WCMCommander";
2611 			XSetClassHint( display, handle, Hint );
2612 			XFree( Hint );
2613 		}
2614 	}
2615 
2616 
2617 
DoModal()2618 	int Win::DoModal()
2619 	{
2620 		bool visibled = IsVisible();
2621 		bool enabled = IsEnabled();
2622 		WinID lastParentFC = parent ? parent->lastFocusChild : 0;
2623 
2624 		try
2625 		{
2626 			WinID oldActive = activeWinId;
2627 
2628 			if ( !visibled ) { Show(); }
2629 
2630 			if ( !enabled ) { Enable( true ); }
2631 
2632 			AppBlock( GetID() );
2633 			UnblockTree( GetID() );
2634 
2635 			ModalStruct modalStruct;
2636 			modal = &modalStruct;
2637 
2638 			Activate();
2639 			SetFocus();
2640 
2641 			while ( !modalStruct.end )
2642 			{
2643 				wth_DoEvents();
2644 
2645 				if ( modalStruct.end ) { break; }
2646 
2647 				while ( XEventsQueued( display, QueuedAfterFlush ) > 0 )
2648 				{
2649 					XEvent event;
2650 					XNextEvent( display, &event );
2651 					wth_DoEvents();
2652 
2653 					if ( !DoEvents( &event ) ) { return 0; }
2654 
2655 					if ( modalStruct.end )
2656 					{
2657 						goto stopped;
2658 					}
2659 				}
2660 
2661 				unsigned w = RunTimers();
2662 				PostRepaint();
2663 
2664 				if ( XEventsQueued( display, QueuedAfterFlush ) > 0 )
2665 				{
2666 					continue;
2667 				}
2668 
2669 				fd_set fds;
2670 				FD_ZERO( &fds );
2671 				FD_SET( connectionId, &fds );
2672 				int tSignalFd = wthInternalEvent.SignalFD();
2673 				FD_SET( tSignalFd, &fds );
2674 
2675 				struct timeval tv;
2676 				tv.tv_sec = w / 1000;
2677 				tv.tv_usec = ( w % 1000 ) * 1000;
2678 
2679 				int n = connectionId > tSignalFd ? connectionId : tSignalFd;
2680 
2681 				select( n + 1, &fds,  0, 0, &tv );
2682 			}
2683 
2684 stopped:
2685 			modal = 0;
2686 			AppUnblock( GetID() );
2687 
2688 			if ( !visibled ) { Hide(); }
2689 
2690 			if ( type == WT_CHILD && parent )
2691 			{
2692 				Win* w = GetWinByID( lastParentFC );
2693 
2694 				if ( w ) { w->SetFocus(); }
2695 			}
2696 
2697 			if ( oldActive )
2698 			{
2699 				Win* w = GetWinByID( oldActive );
2700 
2701 				if ( w ) { w->Activate(); } //w->SetFocus();
2702 			}
2703 
2704 
2705 			return modalStruct.id;
2706 		}
2707 		catch ( ... )
2708 		{
2709 			modal = 0;
2710 			AppUnblock( GetID() );
2711 
2712 			if ( !visibled ) { Hide(); }
2713 
2714 			throw;
2715 		}
2716 	}
2717 
Move(crect rect,bool repaint)2718 	void Win::Move( crect rect, bool repaint )
2719 	{
2720 		int w = rect.Width();
2721 		int h = rect.Height();
2722 
2723 		if ( w <= 0 ) { w = 1; }
2724 
2725 		if ( h <= 0 ) { h = 1; }
2726 
2727 		XMoveResizeWindow( display, GetID() , rect.left, rect.top, w, h );
2728 
2729 		if ( repaint ) { Invalidate(); }
2730 	}
2731 
GrabPointer(Window handle)2732 	static bool GrabPointer( Window handle )
2733 	{
2734 		return   ::XGrabPointer( display, handle, False,
2735 		                         ButtonPressMask   |
2736 		                         ButtonReleaseMask    |
2737 		                         PointerMotionMask,
2738 		                         GrabModeAsync, GrabModeAsync,
2739 		                         None, None, CurrentTime ) == GrabSuccess;
2740 	}
2741 
SetCapture(CaptureSD * sd)2742 	bool Win::SetCapture( CaptureSD* sd )
2743 	{
2744 		if ( !captured )
2745 		{
2746 			if ( captureWinId )
2747 			{
2748 				if ( sd ) { sd->h = captureWinId; }
2749 
2750 				::XUngrabPointer( display, CurrentTime );
2751 				captureWinId = 0;
2752 			}
2753 
2754 			if ( GrabPointer( handle ) )
2755 			{
2756 				//dbg_printf("Captured %p\n", this);
2757 				captured = true;
2758 				captureWinId = handle;
2759 				return true;
2760 			}
2761 		}
2762 
2763 		return false;
2764 	}
2765 
ReleaseCapture(CaptureSD * sd)2766 	void Win::ReleaseCapture( CaptureSD* sd )
2767 	{
2768 		if ( captured )
2769 		{
2770 			::XUngrabPointer( display, CurrentTime );
2771 			//dbg_printf("UnCaptured %p\n", this);
2772 			captured = false;
2773 
2774 			if ( sd && sd->h && GrabPointer( sd->h ) )
2775 			{
2776 				captureWinId = sd->h;
2777 			}
2778 			else
2779 			{
2780 				captureWinId = 0;
2781 			}
2782 		}
2783 	}
2784 
Activate()2785 	void Win::Activate()
2786 	{
2787 		if ( ( Type() != WT_MAIN && Type() != WT_POPUP ) ||
2788 		     !IsVisible() ||
2789 		     //blockedBy ||
2790 		     activeWinId == handle
2791 		   )
2792 		{
2793 			return;
2794 		}
2795 
2796 		::XSetInputFocus( display, handle, RevertToNone, CurrentTime );
2797 
2798 
2799 		if ( focusWinId )
2800 		{
2801 			Win* prevFocus = GetWinByID( focusWinId );
2802 			focusWinId = 0;
2803 
2804 			if ( prevFocus )
2805 			{
2806 				Win* w = prevFocus;
2807 
2808 				for ( ; w && w->parent && w->type != Win::WT_MAIN && w->type != Win::WT_POPUP; w = w->parent )
2809 				{
2810 					w->parent->lastFocusChild = w->handle;
2811 				}
2812 
2813 				cevent evKF( EV_KILLFOCUS );
2814 				prevFocus->Event( &evKF );
2815 			}
2816 		}
2817 
2818 		Win* prevActive = GetWinByID( activeWinId );
2819 
2820 		if ( activeWinId )
2821 		{
2822 
2823 			activeWinId = 0;
2824 
2825 			if ( prevActive )
2826 			{
2827 				cevent_activate ev( false, this );
2828 				prevActive->Event( &ev );
2829 			}
2830 		}
2831 
2832 		cevent_activate evActivate( true, prevActive );
2833 		activeWinId = handle;
2834 		Event( &evActivate );
2835 		focusWinId = handle;
2836 
2837 		cevent evSF( EV_SETFOCUS );
2838 		Event( &evSF );
2839 	}
2840 
AddExposeRect(crect r)2841 	void Win::AddExposeRect( crect r )
2842 	{
2843 		if ( exposeRect.IsEmpty() )
2844 		{
2845 			exposeRect = r;
2846 		}
2847 		else
2848 		{
2849 			if ( r.left < exposeRect.left ) { exposeRect.left = r.left; }
2850 
2851 			if ( r.top < exposeRect.top ) { exposeRect.top = r.top; }
2852 
2853 			if ( r.right > exposeRect.right ) { exposeRect.right = r.right; }
2854 
2855 			if ( r.bottom > exposeRect.bottom ) { exposeRect.bottom = r.bottom; }
2856 		}
2857 	}
2858 
Invalidate()2859 	void Win::Invalidate()
2860 	{
2861 		AddExposeRect( ClientRect() );
2862 		AddRepaint( this );
2863 	}
2864 
Show(SHOW_TYPE type)2865 	void Win::Show( SHOW_TYPE type )
2866 	{
2867 		if ( type == SHOW_MAXIMIZE )
2868 		{
2869 			XWindowAttributes xwa;
2870 			Status ret = XGetWindowAttributes( display, DefaultRootWindow(display), &xwa );
2871 			if ( ret == 0 )
2872 			{
2873 				throw_msg( "Error in XGetWindowAttributes" );
2874 			}
2875 
2876 			XMoveResizeWindow( display, GetID(), 0, 0, xwa.width, xwa.height );
2877 			return;
2878 		}
2879 
2880 		::XMapWindow( display, GetID() );
2881 		showType = type; //used in mapping event
2882 		SetState( S_VISIBLE );
2883 	}
2884 
Hide()2885 	void Win::Hide()
2886 	{
2887 		::XUnmapWindow( display, GetID() );
2888 		ClearState( S_VISIBLE );
2889 	};
2890 
2891 
RecalcLayouts()2892 	void Win::RecalcLayouts()
2893 	{
2894 		if ( !layout ) { return; }
2895 
2896 		wal::ccollect<WSS> list;
2897 		layout->SetPos( ClientRect(), list );
2898 
2899 		for ( int i = 0; i < list.count(); i++ )
2900 		{
2901 			list[i].w->Move( list[i].rect, true );
2902 			list[i].w->Invalidate();
2903 		}
2904 
2905 		Invalidate();
2906 	}
2907 
SetName(const unicode_t * name)2908 	void Win::SetName( const unicode_t* name )
2909 	{
2910 		if ( type == WT_MAIN )
2911 		{
2912 			unicode_t u[100];
2913 			unicode_strncpy0( u, name, sizeof( u ) / sizeof( u[0] ) );
2914 
2915 			char buf[400];
2916 			unicode_to_utf8( buf, u );
2917 			XStoreName( display, handle, buf );
2918 		}
2919 	}
2920 
SetName(const char * utf8Name)2921 	void Win::SetName( const char* utf8Name )
2922 	{
2923 		if ( type == WT_MAIN )
2924 		{
2925 			XStoreName( display, handle, utf8Name );
2926 		}
2927 
2928 	}
2929 
SetFocus()2930 	void Win::SetFocus()
2931 	{
2932 		if ( InFocus() ) { return; }
2933 
2934 		if ( blockedBy )
2935 		{
2936 			Win* w = GetWinByID( blockedBy );
2937 
2938 			if ( w ) { w->SetFocus(); }
2939 
2940 			return;
2941 		}
2942 
2943 		Win* p = this;
2944 
2945 		for ( ; p && p->type != WT_MAIN && p->type != WT_POPUP; ) { p = p->parent; }
2946 
2947 		if ( p )
2948 		{
2949 			p->Activate();
2950 
2951 			if ( focusWinId != handle )
2952 			{
2953 				Win* f = GetWinByID( focusWinId );
2954 
2955 				if ( f )
2956 				{
2957 					cevent evKF( EV_KILLFOCUS );
2958 					f->Event( &evKF );
2959 				}
2960 
2961 				focusWinId = handle;
2962 
2963 				if ( type != WT_MAIN && type != WT_POPUP && parent )
2964 				{
2965 					parent->lastFocusChild = handle;
2966 				}
2967 
2968 				cevent evSF( EV_SETFOCUS );
2969 				Event( &evSF );
2970 			}
2971 		}
2972 	}
2973 
OnTop()2974 	void Win::OnTop()
2975 	{
2976 		::XRaiseWindow( display, handle );
2977 	}
2978 
2979 
ClientRect()2980 	crect Win::ClientRect()
2981 	{
2982 		return crect( 0, 0, position.Width(), position.Height() );
2983 	}
2984 
ScreenRect()2985 	crect Win::ScreenRect()
2986 	{
2987 		crect r = position;
2988 		int x = 0, y = 0;
2989 		ClientToScreen( &x, &y );
2990 		return crect( x, y, x + r.Width(), y + r.Height() );
2991 	}
2992 
Rect()2993 	crect Win::Rect()
2994 	{
2995 		return position;
2996 	}
2997 
ClientToScreen(int * x,int * y)2998 	void Win::ClientToScreen( int* x, int* y )
2999 	{
3000 		Window cw;
3001 		::XTranslateCoordinates( display, GetID(), XDefaultRootWindow( display ), *x, *y, x, y, &cw );
3002 	}
3003 
~Win()3004 	Win::~Win()
3005 	{
3006 		if ( captureWinId == handle )
3007 		{
3008 			captureWinId = 0;
3009 		}
3010 
3011 		wth_DropWindow( this );
3012 
3013 		if ( modal ) // ???? может и не надо
3014 		{
3015 			( ( ModalStruct* )modal )->EndModal( 0 );
3016 		}
3017 
3018 		if ( handle )
3019 		{
3020 			DelAllTimers();
3021 			XDestroyWindow( display, handle );
3022 			DelWinFromHash( handle );
3023 		}
3024 
3025 		for ( int i = 0; i < childList.count(); i++ )
3026 		{
3027 			childList[i]->parent = 0;
3028 		}
3029 
3030 		if ( parent )
3031 		{
3032 			for ( int i = 0; i < parent->childList.count(); i++ )
3033 				if ( parent->childList[i] == this )
3034 				{
3035 					parent->childList.del( i );
3036 					break;
3037 				}
3038 		}
3039 
3040 		if ( upLayout )
3041 		{
3042 			upLayout->DelObj( this );
3043 		}
3044 
3045 	}
3046 
SetIcon(const char ** ps)3047 	void Win::SetIcon( const char** ps )
3048 	{
3049 		XPMImage xpm;
3050 		xpm.Load( ps, 16000 );
3051 
3052 		if ( xpm.Width() <= 0 || xpm.Height() <= 0 ) { return; }
3053 
3054 		int w = xpm.Width();
3055 		int h = xpm.Height();
3056 
3057 		Image32 i32;
3058 		i32.copy( xpm );
3059 
3060 		if ( winIconPixmap != None )
3061 		{
3062 			XFreePixmap( display, winIconPixmap );
3063 			winIconPixmap = None;
3064 		}
3065 
3066 		if ( winIconMask != None )
3067 		{
3068 			XFreePixmap( display, winIconMask );
3069 			winIconMask = None;
3070 		}
3071 
3072 		winIconPixmap = XCreatePixmap( display, DefaultRootWindow( display ), w, h, visualInfo.depth );
3073 		winIconMask = XCreatePixmap( display, DefaultRootWindow( display ), w, h, 1 );
3074 
3075 		{
3076 			IntXImage intXImage( i32 );
3077 			GC gc( winIconPixmap );
3078 			intXImage.Put( gc, 0, 0, 0, 0, w, h );
3079 		}
3080 
3081 		{
3082 			::GC gc;
3083 			XGCValues v;
3084 			gc = XCreateGC( display, winIconMask, 0, &v );
3085 
3086 			v.foreground = 0;
3087 			XChangeGC( display, gc, GCForeground, &v );
3088 			XFillRectangle( display, winIconMask, gc, 0, 0, w, h );
3089 
3090 			v.foreground = 1;
3091 			XChangeGC( display, gc, GCForeground, &v );
3092 
3093 			uint32_t* p = i32.line( 0 );
3094 
3095 			for ( int y = 0; y < h; y++ )
3096 			{
3097 				for ( int x = 0; x < w; x++, p++ )
3098 					if ( *p < 0x80000000 )
3099 					{
3100 						XDrawPoint( display, winIconMask, gc, x, y );
3101 					}
3102 			}
3103 
3104 			XFreeGC( display, gc );
3105 		}
3106 	}
3107 
3108 /////////////////////////////////////////////  cfont
3109 
cfont(GC & gc,const char * name,int pointSize,cfont::Weight weight,unsigned flags)3110 	cfont::cfont( GC& gc, const char* name, int pointSize, cfont::Weight weight, unsigned flags )
3111 		: type( -1 ), data( 0 )
3112 	{
3113 		char buf[1024];
3114 		const char* w;
3115 
3116 		switch ( weight )
3117 		{
3118 			case Normal:
3119 				w = "medium";
3120 				break;
3121 
3122 			case Light:
3123 				w = "light";
3124 				break;
3125 
3126 			case Bold:
3127 				w = "bold";
3128 				break;
3129 
3130 			default:
3131 				w = "*";
3132 		}
3133 
3134 		const char* slant = "r";
3135 
3136 		if ( flags & Italic )
3137 		{
3138 			slant = "i";
3139 		}
3140 
3141 		sprintf( buf, "-*-%s-%s-%s-*-*-*-%i-*-*-*-*-iso10646-*", name, w, slant,  pointSize * 10 );
3142 
3143 		XFontStruct* xfs = XLoadQueryFont( display, buf );
3144 
3145 		if ( !xfs )
3146 		{
3147 			dbg_printf( "font not found %s\n", buf );
3148 		}
3149 		else
3150 		{
3151 			type = TYPE_X11;
3152 			data = xfs;
3153 			_uri = buf;
3154 			dbg_printf( "font %s created Ok!!!\n", buf );
3155 		}
3156 	}
3157 
uri()3158 	const char* cfont::uri()
3159 	{
3160 		return _uri.data() ? _uri.data() : "";
3161 	}
3162 
3163 
printable_name()3164 	const char* cfont::printable_name()
3165 	{
3166 		if ( _name.data() ) { return _name.data(); }
3167 
3168 		if ( type == TYPE_X11 )
3169 		{
3170 			return uri();
3171 		}
3172 
3173 #ifdef   USEFREETYPE
3174 
3175 		if ( type == TYPE_FT )
3176 		{
3177 			if ( !data ) { return ""; }
3178 
3179 			const char* name = ( ( FTU::FFace* )data )->Name();
3180 			const char* style = ( ( FTU::FFace* )data )->StyleName();
3181 
3182 			if ( !name || !style ) { return ""; }
3183 
3184 			char buf[1024];
3185 			snprintf( buf, sizeof( buf ) - 1, "%s-%s %i", name, style, ( ( FTU::FFace* )data )->Size() / 64 );
3186 			_name = buf;
3187 			return _name.data();
3188 		}
3189 
3190 #endif
3191 		return "";
3192 	}
3193 
3194 
cfont(const char * uriStr)3195 	cfont::cfont( const char* uriStr )
3196 		: type( -1 ), data( 0 )
3197 	{
3198 		const char* s = uriStr;
3199 
3200 		while ( *s && *s <= 32 ) { s++; }
3201 
3202 		if ( *s == '-' ) //x11 variant
3203 		{
3204 			XFontStruct* xfs = XLoadQueryFont( display, s );
3205 
3206 			if ( xfs )
3207 			{
3208 				type = TYPE_X11;
3209 				data = xfs;
3210 				_uri = s;
3211 			}
3212 
3213 			return;
3214 		}
3215 
3216 #ifdef USEFREETYPE
3217 
3218 		if ( *s == '+' ) //FreeType +[ptsize*10]:<path>
3219 		{
3220 			const char* t = s + 1;
3221 			int size = 0;
3222 
3223 			for ( ; *t >= '0' && *t <= '9'; t++ ) { size = size * 10 + ( *t - '0' ); }
3224 
3225 			if ( *t == ':' )
3226 			{
3227 				t++;
3228 			}
3229 			else
3230 			{
3231 				t = s + 1;
3232 				size = 100;
3233 			}
3234 
3235 			while ( *t && *t <= 32 ) { t++; }
3236 
3237 			if ( size < 10 ) { size = 10; }
3238 
3239 			if ( size > 1000 ) { size = 1000; }
3240 
3241 			FTU::FFace* p = new  FTU::FFace();
3242 
3243 			if ( p->Load( t, 0, ( size * 64 ) / 10 ) )
3244 			{
3245 				delete p;
3246 			}
3247 			else
3248 			{
3249 				type = TYPE_FT;
3250 				data = p;
3251 				_uri = s;
3252 			}
3253 
3254 			return;
3255 		}
3256 
3257 #endif
3258 	}
3259 
3260 
cfont(const char * fileName,int pointSize)3261 	cfont::cfont( const char* fileName, int pointSize )
3262 		: type( -1 ), data( 0 )
3263 	{
3264 #ifdef USEFREETYPE
3265 		FTU::FFace* p = new  FTU::FFace();
3266 
3267 		if ( p->Load( fileName, 0, ( pointSize * 64 ) / 10 ) )
3268 		{
3269 			delete p;
3270 		}
3271 		else
3272 		{
3273 			type = TYPE_FT;
3274 			data = p;
3275 			char buf[1024];
3276 			snprintf( buf, sizeof( buf ), "+%i:%s", pointSize, fileName );
3277 			_uri = buf;
3278 		}
3279 
3280 #endif
3281 	}
3282 
3283 
drop()3284 	void cfont::drop()
3285 	{
3286 		if ( type == TYPE_X11 )
3287 		{
3288 			XFreeFont( display, ( XFontStruct* )data );
3289 		}
3290 
3291 #ifdef USEFREETYPE
3292 		else if ( type == TYPE_FT )
3293 		{
3294 			delete ( FTU::FFace* )data;
3295 		}
3296 
3297 #endif
3298 		type = -1;
3299 		data = 0;
3300 	}
3301 
3302 
3303 
3304 
3305 //////////////////////////////////////// cicon
3306 
3307 	extern void MakeDisabledImage32( Image32* dest, const Image32& src );
3308 
3309 	/*
3310 	struct Node {
3311 	   SCImage image;
3312 	   std::vector<char> mash;
3313 	   unigned bgColor;
3314 	};
3315 	*/
3316 
CreateIconDataNode(Image32 & _image,unsigned bgColor,bool enabled)3317 	static clPtr<IconData::Node> CreateIconDataNode( Image32& _image, unsigned bgColor, bool enabled )
3318 	{
3319 		clPtr<IconData::Node> node = new IconData::Node;
3320 		node->bgColor = bgColor;
3321 
3322 		int w = _image.width();
3323 		int h = _image.height();
3324 
3325 		if ( w <= 0 || h <= 0 ) { return node; }
3326 
3327 		Image32 im;
3328 
3329 		if ( enabled )
3330 		{
3331 			im.copy( _image );
3332 		}
3333 		else
3334 		{
3335 			MakeDisabledImage32( &im, _image );
3336 		}
3337 
3338 		uint32_t* p = im.line( 0 );
3339 		int count = w * h;
3340 
3341 		bool masked = false;
3342 
3343 		for ( ; count > 0; count--, p++ )
3344 		{
3345 			if ( *p & 0xFF000000 )
3346 			{
3347 				masked = masked || *p >= 0x80000000;
3348 
3349 				unsigned fgColor = *p;
3350 				unsigned c = ( fgColor >> 24 ) & 0xFF;
3351 
3352 				if ( c == 0xFF ) { *p = bgColor; }
3353 				else
3354 				{
3355 					unsigned c1 = 255 - c;
3356 					*p =
3357 					   ( ( ( ( bgColor & 0x0000FF ) * c + ( fgColor & 0x0000FF ) * c1 ) >> 8 ) & 0x0000FF ) +
3358 					   ( ( ( ( bgColor & 0x00FF00 ) * c + ( fgColor & 0x00FF00 ) * c1 ) >> 8 ) & 0x00FF00 ) +
3359 					   ( ( ( ( bgColor & 0xFF0000 ) * c + ( fgColor & 0xFF0000 ) * c1 ) >> 8 ) & 0xFF0000 );
3360 				}
3361 
3362 			}
3363 		}
3364 
3365 		if ( masked )
3366 		{
3367 			uint32_t* p = _image.line( 0 );
3368 			int count = im.width() * im.height();
3369 
3370 			node->mask.resize( count );
3371 			char* m = node->mask.data();
3372 
3373 			for ( ; count > 0; count--, p++, m++ )
3374 			{
3375 				*m = ( *p >= 0x80000000 ) ? 0 : 1;
3376 			}
3377 
3378 		}
3379 
3380 
3381 		IntXImage xim( im );
3382 		node->image.Create( w, h );
3383 		wal::GC gc( &node->image );
3384 		xim.Put( gc, 0, 0, 0, 0, w, h );
3385 		return node;
3386 	}
3387 
PutIconDataNode(wal::GC & gc,SCImage * im,int x,int y)3388 	static void PutIconDataNode( wal::GC& gc, SCImage* im, int x, int y )
3389 	{
3390 		if ( !im ) { return; }
3391 
3392 		XCopyArea( display, im->GetXDrawable(), gc.GetXDrawable(), gc.XHandle(), 0, 0, im->Width(), im->Height(),  x, y );
3393 	}
3394 
PutIconDataNode(wal::GC & gc,SCImage * im,char * mask,int dest_x,int dest_y)3395 	static void PutIconDataNode( wal::GC& gc, SCImage* im, char* mask, int dest_x, int dest_y )
3396 	{
3397 		if ( !im ) { return; }
3398 
3399 		if ( !mask )
3400 		{
3401 			PutIconDataNode( gc, im, dest_x, dest_y );
3402 			return;
3403 		}
3404 
3405 		int src_x = 0;
3406 		int src_y = 0;
3407 		int w = im->Width();
3408 		int h = im->Height();
3409 
3410 		if ( w <= 0 || h <= 0 ) { return; }
3411 
3412 		int right =  w;
3413 		int bottom = h;
3414 
3415 		crect r( 0, -1, 0, -1 );
3416 		char* m = mask;
3417 
3418 		for ( int y = src_y; y < bottom; y++, m += im->Width() )
3419 		{
3420 			int x = src_x;
3421 
3422 			while ( x < right )
3423 			{
3424 				while ( x < right && !m[x] ) { x++; }
3425 
3426 				if ( x < right )
3427 				{
3428 					int x1 = x;
3429 
3430 					while ( x < right && m[x] ) { x++; }
3431 
3432 					if ( r.bottom == y && r.left == x1 && r.right == x )
3433 					{
3434 						r.bottom++;
3435 					}
3436 					else
3437 					{
3438 //printf("copy %i\n", y);
3439 						if ( !r.IsEmpty() )
3440 						{
3441 							XCopyArea( display, im->GetXDrawable(), gc.GetXDrawable(), gc.XHandle(), r.left, r.top, r.Width(), r.Height(),  dest_x + r.left, dest_y + r.top );
3442 						}
3443 
3444 						r.Set( x1, y, x, y + 1 );
3445 					}
3446 				}
3447 			}
3448 		}
3449 
3450 		if ( !r.IsEmpty() )
3451 		{
3452 			XCopyArea( display, im->GetXDrawable(), gc.GetXDrawable(), gc.XHandle(), r.left, r.top, r.Width(), r.Height(),  dest_x + r.left, dest_y + r.top );
3453 		}
3454 	}
3455 
3456 
Draw(wal::GC & gc,int x,int y,bool enabled)3457 	void cicon::Draw( wal::GC& gc, int x, int y, bool enabled )
3458 	{
3459 		if ( !data ) { return; }
3460 
3461 		unsigned bgColor = gc.FillRgb();
3462 		clPtr<IconData::Node>* pNode = enabled ? &data->normal : &data->disabled;
3463 
3464 		if ( !pNode->ptr() )
3465 		{
3466 			*pNode = CreateIconDataNode( data->image, bgColor, enabled );
3467 		}
3468 
3469 		PutIconDataNode( gc, &( pNode[0]->image ), pNode[0]->mask.data(), x, y );
3470 	}
3471 
DrawF(wal::GC & gc,int x,int y,bool enabled)3472 	void cicon::DrawF( wal::GC& gc, int x, int y, bool enabled )
3473 	{
3474 		if ( !data ) { return; }
3475 
3476 		unsigned bgColor = gc.FillRgb();
3477 		clPtr<IconData::Node>* pNode = enabled ? &data->normal : &data->disabled;
3478 
3479 		if ( !pNode->ptr() || pNode[0]->bgColor != bgColor )
3480 		{
3481 			*pNode = CreateIconDataNode( data->image, bgColor, enabled );
3482 		}
3483 
3484 		PutIconDataNode( gc, &( pNode[0]->image ), x, y );
3485 	}
3486 
3487 
3488 ////////////////////////////////////// IntXImage
3489 
3490 
init(int w,int h)3491 	void IntXImage::init( int w, int h )
3492 	{
3493 		static unsigned byte_order_test = 0x77;
3494 		memset( &im, 0, sizeof( im ) );
3495 		im.width = w;
3496 		im.height = h;
3497 		im.xoffset = 0;
3498 		im.depth = visualInfo.depth;
3499 
3500 		if ( visualInfo.c_class == TrueColor )
3501 		{
3502 			im.format =  ZPixmap ;
3503 			data.resize( w * h * 4 ); //32 bit
3504 			im.data = data.data();
3505 			im.byte_order = ( ( ( char* )&byte_order_test )[0] == 0x77 ) ? LSBFirst : MSBFirst;
3506 			im.bitmap_unit = 32;
3507 			im.bitmap_bit_order = MSBFirst;
3508 			im.bitmap_pad = 32;
3509 
3510 			im.bytes_per_line = w * 4; //
3511 			im.bits_per_pixel = 32;
3512 			im.red_mask = visualInfo.red_mask;
3513 			im.green_mask = visualInfo.green_mask;
3514 			im.blue_mask = visualInfo.blue_mask;
3515 		}
3516 		else
3517 		{
3518 			im.format = XYPixmap;
3519 			im.bytes_per_line = ( w + 31 ) / 32 * 4;
3520 			data.resize( im.bytes_per_line * visualInfo.depth * h ); //32 bit
3521 			im.data = data.data();
3522 			im.byte_order = ( ( ( char* )&byte_order_test )[0] == 0x77 ) ? LSBFirst : MSBFirst;
3523 			im.bitmap_unit = 32;
3524 			im.bitmap_bit_order = MSBFirst;
3525 			im.bitmap_pad = 32;
3526 		}
3527 
3528 		XInitImage( &im );
3529 	}
3530 
3531 
Set(Image32 & image)3532 	void IntXImage::Set( Image32& image )
3533 	{
3534 		clear();
3535 
3536 		int w = image.width();
3537 		int h = image.height();
3538 
3539 		if ( w <= 0 || h <= 0 ) { return; }
3540 
3541 		init( w, h );
3542 
3543 		if ( visualInfo.c_class != TrueColor )
3544 		{
3545 			int i;
3546 			bool masked = false;
3547 
3548 			for ( int y = 0; y < h; y++ )
3549 			{
3550 				uint32_t* t = image.line( y );
3551 				char* m = ( masked ) ? mask.data() + y * w : 0;
3552 
3553 				for ( i = 0; i < w; i++ )
3554 				{
3555 					if ( t[i] > 0x80000000 )
3556 					{
3557 						if ( !masked )
3558 						{
3559 							mask.resize( w * h );
3560 							memset( mask.data(), 1, w * h );
3561 							masked = true;
3562 							m = mask.data() + y * w;
3563 						}
3564 
3565 						m[i] = 0;
3566 					}
3567 
3568 					XPutPixel( &im, i, y, CreateColor( t[i] & 0xFFFFFF ) );
3569 				}
3570 			}
3571 
3572 			return;
3573 		}
3574 
3575 
3576 
3577 		uint32_t* p = ( uint32_t* )data.data();
3578 		uint32_t* t = image.line( 0 );
3579 
3580 		uint32_t lastPixVal = 0;
3581 		uint32_t lastColor = CreateColor( lastPixVal );
3582 		int n;
3583 
3584 		for ( n = w * h; n > 0; n--, p++, t++ )
3585 		{
3586 			uint32_t pixVal = *t;
3587 
3588 			if ( lastPixVal >= 0x80000000 )
3589 			{
3590 				goto haveMask;
3591 			}
3592 
3593 			if ( pixVal == lastPixVal )
3594 			{
3595 				*p = lastColor;
3596 			}
3597 			else
3598 			{
3599 				lastPixVal = pixVal;
3600 				*p = lastColor =  CreateColor( pixVal );
3601 			}
3602 		}
3603 
3604 		return;
3605 
3606 haveMask:
3607 		mask.resize( w * h );
3608 		memset( mask.data(), 1, w * h );
3609 
3610 		char* m = mask.data() + w * h - n;
3611 
3612 		for ( ; n > 0; n--, p++, t++, m++ )
3613 		{
3614 			uint32_t pixVal = *t;
3615 
3616 			if ( pixVal >= 0x80000000 )
3617 			{
3618 				*m = 0;
3619 			}
3620 
3621 			if ( pixVal == lastPixVal )
3622 			{
3623 				*p = lastColor;
3624 			}
3625 			else
3626 			{
3627 				lastPixVal = pixVal;
3628 				*p = lastColor =  CreateColor( pixVal );
3629 			}
3630 		}
3631 	}
3632 
Put(wal::GC & gc,int src_x,int src_y,int dest_x,int dest_y,int w,int h)3633 	void IntXImage::Put( wal::GC& gc, int src_x, int src_y, int dest_x, int dest_y, int w, int h )
3634 	{
3635 		if ( !data.data() ) { return; }
3636 
3637 		int right = src_x + w;
3638 		int bottom = src_y + h;
3639 
3640 		if ( src_x < 0 ) { src_x = 0; }
3641 
3642 		if ( src_y < 0 ) { src_y = 0; }
3643 
3644 		if ( right > im.width ) { right = im.width; }
3645 
3646 		if ( bottom > im.height ) { bottom = im.height; }
3647 
3648 		w = right - src_x;
3649 		h = bottom - src_y;
3650 
3651 		if ( w <= 0 || h <= 0 ) { return; }
3652 
3653 		if ( mask.data() )
3654 		{
3655 
3656 			crect r( 0, -1, 0, -1 );
3657 			char* m = mask.data();
3658 
3659 			for ( int y = src_y; y < bottom; y++, m += im.width )
3660 			{
3661 				int x = src_x;
3662 
3663 				while ( x < right )
3664 				{
3665 					while ( x < right && !m[x] ) { x++; }
3666 
3667 					if ( x < right )
3668 					{
3669 						int x1 = x;
3670 
3671 						while ( x < right && m[x] ) { x++; }
3672 
3673 						if ( r.bottom == y && r.left == x1 && r.right == x )
3674 						{
3675 							r.bottom++;
3676 						}
3677 						else
3678 						{
3679 							if ( !r.IsEmpty() )
3680 								XPutImage( display, gc.GetXDrawable(), gc.XHandle(), &im, r.left, r.top,
3681 								           dest_x + r.left, dest_y + r.top, r.Width(), r.Height() );
3682 
3683 							r.Set( x1, y, x, y + 1 );
3684 						}
3685 					}
3686 				}
3687 			}
3688 
3689 			if ( !r.IsEmpty() )
3690 				XPutImage( display, gc.GetXDrawable(), gc.XHandle(), &im, r.left, r.top,
3691 				           dest_x + r.left, dest_y + r.top, r.Width(), r.Height() );
3692 
3693 
3694 		}
3695 		else
3696 		{
3697 			XPutImage( display, gc.GetXDrawable(), gc.XHandle(), &im, src_x, src_y, dest_x, dest_y, w, h );
3698 		}
3699 	}
3700 
IntXImage(Image32 & image)3701 	IntXImage::IntXImage( Image32& image )
3702 	{
3703 		Set( image );
3704 	}
3705 
~IntXImage()3706 	IntXImage::~IntXImage() {}
3707 
3708 
3709 
3710 
3711 ////////  SCImage (Screen compatible image) /////////////////////////////////////////////////
3712 
Destroy()3713 	void SCImage::Destroy()
3714 	{
3715 		if ( handle != None )
3716 		{
3717 			XFreePixmap( display, handle );
3718 			handle = None;
3719 		}
3720 
3721 		width = height = 0;
3722 	}
3723 
SCImage()3724 	SCImage::SCImage(): width( 0 ), height( 0 ), handle( None ) {}
3725 
Create(int w,int h)3726 	void SCImage::Create( int w, int h )
3727 	{
3728 		Destroy();
3729 
3730 //printf("Pixmap w=%i h = %i\n", w, h);
3731 
3732 		if ( w <= 0 || h <= 0 )
3733 		{
3734 			width = height = 0;
3735 			handle = None;
3736 			return;
3737 		}
3738 
3739 		handle = XCreatePixmap( display, DefaultRootWindow( display ), w, h, visualInfo.depth );
3740 //printf("Pixmap created\n");
3741 		width = w;
3742 		height = h;
3743 	}
3744 
~SCImage()3745 	SCImage::~SCImage() { Destroy(); }
3746 
3747 
WthInternalEvent()3748 	WthInternalEvent::WthInternalEvent(): signaled( false )
3749 	{
3750 		if ( pipe( const_cast<int*>( fd ) ) )
3751 		{
3752 			fprintf( stderr, "can`t create internal pipe (WthInternalEvent)\n" );
3753 			exit( 1 );
3754 		}
3755 	};
3756 
~WthInternalEvent()3757 	WthInternalEvent::~WthInternalEvent()
3758 	{
3759 		close( fd[0] );
3760 		close( fd[1] );
3761 	}
3762 
SetSignal()3763 	void WthInternalEvent::SetSignal()
3764 	{
3765 		MutexLock lock( &mutex );
3766 
3767 		if ( signaled ) { return; }
3768 
3769 		char c = 0;
3770 		ssize_t ret = write( fd[1], &c, sizeof( c ) );
3771 
3772 		if ( ret < 0 ) { throw_syserr( 0, "internal error WthInternalEvent" ); }
3773 
3774 		signaled = true;
3775 	}
3776 
SignalFD()3777 	int WthInternalEvent::SignalFD() { return fd[0]; }
3778 
ClearSignal()3779 	void WthInternalEvent::ClearSignal()
3780 	{
3781 		MutexLock lock( &mutex );
3782 
3783 		if ( !signaled ) { return; }
3784 
3785 		char c;
3786 		ssize_t ret = read( fd[0], &c, sizeof( c ) );
3787 		signaled = false;
3788 
3789 		if ( ret < 0 ) { throw_syserr( 0, "internal error WthInternalEvent" ); }
3790 	};
3791 
3792 #if defined _DEBUG
dbg_dump(int indent)3793 void Win::dbg_dump(int indent)
3794 {
3795 
3796 }
3797 #endif
3798 } // namespace wal
3799