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