X11App.cpp

Zbigniew Rebacz, 01/06/2014 08:45 PM

Download (13.3 KB)

 
1
#include "CtrlCore.h"
2

    
3
#ifdef GUI_X11
4

    
5
#include <locale.h>
6

    
7
NAMESPACE_UPP
8

    
9
#define LLOG(x)  // DLOG(x)
10

    
11
XIM Ctrl::xim;
12

    
13
Atom XAtomRaw(const char *name)
14
{
15
        return XInternAtom(Xdisplay, name, XFalse);
16
}
17

    
18
Atom XAtom(const char *name)
19
{
20
        GuiLock __; 
21
        Atom x;
22
        INTERLOCKED {
23
                static VectorMap<String, int> atoms;
24
                int q = atoms.Get(name, Null);
25
                if(IsNull(q)) {
26
                        q = XAtomRaw(name);
27
                        atoms.Add(name, q);
28
                }
29
                x = q;
30
        }
31
        return x;
32
}
33

    
34
String XAtomName(Atom atom)
35
{
36
        GuiLock __; 
37
        LLOG("GetAtomName");
38
        return XGetAtomName(Xdisplay, atom);
39
}
40

    
41
String GetProperty(Window w, Atom property, Atom rtype)
42
{
43
        GuiLock __; 
44
        LLOG("GetProperty");
45
        String result;
46
        int format;
47
        unsigned long nitems, after = 1;
48
        long offset = 0;
49
        Atom type = None;
50
        unsigned char *data;
51
        long rsize = minmax((long)(XMaxRequestSize(Xdisplay) - 100), (long)256, (long)65536);
52
        while(after > 0) {
53
                if(XGetWindowProperty(Xdisplay, w, property, offset, rsize, XFalse,
54
                                  rtype, &type, &format, &nitems, &after, &data) != Success)
55
                    break;
56
            if(type == None)
57
                break;
58
                if(data) {
59
                        int len = format == 32 ? sizeof(unsigned long) * nitems : nitems * (format >> 3);
60
                        result.Cat(data, len);
61
                        XFree((char *)data);
62
                        offset += nitems / (32 / format);
63
                }
64
                else
65
                        break;
66
        }
67
        result.Shrink();
68
        XFlush(Xdisplay);
69
        return result;
70
}
71

    
72
bool WaitForEvent(Window w, int type, XEvent& event){
73
        GuiLock __; 
74
        for(int i = 0; i < 80; i++) {
75
                if(XCheckTypedWindowEvent(Xdisplay, w, type, &event))
76
                        return true;
77
                XFlush(Xdisplay);
78
                Sleep(50);
79
        }
80
        LOG("WaitForEvent failed");
81
        return false;
82
}
83

    
84

    
85
String ReadPropertyData(Window w, Atom property, Atom rtype)
86
{
87
        GuiLock __; 
88
        static Atom XA_INCR = XAtom("INCR");
89
        Atom type;
90
        int format;
91
        unsigned long nitems, after;
92
        unsigned char *ptr;
93
        String r;
94
        if(XGetWindowProperty(Xdisplay, w, property, 0, 0, XFalse, AnyPropertyType,
95
                              &type, &format, &nitems, &after, &ptr) == Success && type != None) {
96
                XFree(ptr);
97
                if(type == XA_INCR) {
98
                        XDeleteProperty(Xdisplay, w, property);
99
                        XEvent event;
100
                        for(;;) {
101
                                XFlush(Xdisplay);
102
                                if(!WaitForEvent(w, PropertyNotify, event))
103
                                        break;
104
                                if(event.xproperty.atom == property && event.xproperty.state == PropertyNewValue) {
105
                                        String x = GetProperty(w, property);
106
                                        if(!x.GetLength())
107
                                                break;
108
                                        r.Cat(x);
109
                                        XDeleteProperty(Xdisplay, w, property);
110
                                }
111
                        }
112
                }
113
                else {
114
                        r = GetProperty(w, property);
115
                        XDeleteProperty(Xdisplay, w, property);
116
                }
117
        }
118
        return r;
119
}
120

    
121
Vector<int> GetPropertyInts(Window w, Atom property, Atom rtype)
122
{
123
        GuiLock __; 
124
        Vector<int> result;
125
        String p = GetProperty(w, property, rtype);
126
        const long int *ptr = (const long int *)~p;
127
        const long int *lim = ptr + p.GetLength() / sizeof(long int);
128
        result.Reserve(p.GetLength() / sizeof(long int));
129
        while(ptr < lim)
130
                result.Add(*ptr++);
131
        return result;
132
}
133

    
134
Index<Atom>& _NET_Supported()
135
{
136
        static Index<Atom> q;
137
        return q;
138
}
139

    
140
bool X11ErrorTrap;
141

    
142
bool Ctrl::TrapX11Errors()
143
{
144
        GuiLock __; 
145
        bool b = X11ErrorTrap;
146
        X11ErrorTrap = true;
147
        return b;
148
}
149

    
150
void Ctrl::UntrapX11Errors(bool b)
151
{
152
        GuiLock __; 
153
        X11ErrorTrap = b;
154
}
155

    
156
void sPanicMessageBox(const char *title, const char *text)
157
{
158
        IGNORE_RESULT(
159
                write(2, text, strlen(text))
160
        );
161
        IGNORE_RESULT(
162
                write(2, "\n", 1)
163
        );
164
        if(Ctrl::grabWindow) {
165
                LLOG("RELEASE GRAB");
166
                XUngrabPointer(Xdisplay, CurrentTime);
167
                XFlush(Xdisplay);
168
        }
169
        XDisplay *display = XOpenDisplay(NULL);
170
        if(!display)
171
                return;
172
        int screen = DefaultScreen(display);
173
        int x = (DisplayWidth(display, screen) - 600) / 2;
174
        int y = (DisplayHeight(display, screen) - 120) / 2;
175
        Window win = XCreateSimpleWindow(display, RootWindow(display, screen),
176
                                         x, y, 600, 120, 4,
177
                                         BlackPixel(display, screen),
178
                                         WhitePixel(display, screen));
179
        XSizeHints size_hints;
180
        size_hints.flags = PPosition|PSize|PMinSize;
181
        size_hints.x = x;
182
        size_hints.y = x;
183
        size_hints.width = 600;
184
        size_hints.height = 120;
185
        size_hints.min_width = 600;
186
        size_hints.min_height = 120;
187
        char *h[1];
188
        char hh[1];
189
        *hh = 0;
190
        h[0] = hh;
191
        XSetStandardProperties(display, win, title, title, None, h, 0, &size_hints);
192
        XSelectInput(display, win, ExposureMask|KeyPressMask|ButtonPressMask|StructureNotifyMask);
193
        XGCValues values;
194
        GC gc = XCreateGC(display, win, 0, &values);
195
        unsigned long wina[1];
196
        wina[0] = XInternAtom(display, "_NET_WM_STATE_ABOVE", XFalse);
197
        XChangeProperty(display, win,
198
                        XInternAtom(display, "_NET_WM_STATE", XFalse),
199
                        XInternAtom(display, "ATOM", XFalse), 32,
200
                        PropModeReplace, (const unsigned char *)&wina, 1);
201
        XMapWindow(display, win);
202
//        XSetInputFocus(display, win, RevertToParent, CurrentTime);
203
        XRaiseWindow(display, win);
204
        XFontStruct *font_info = XQueryFont(display, XGContextFromGC(gc));
205
        for(;;) {
206
                XEvent e;
207
                XNextEvent(display, &e);
208
                switch(e.type) {
209
                case ButtonPress:
210
                        XFreeFont(display, font_info);
211
                        XFreeGC(display, gc);
212
                        XCloseDisplay(display);
213
                #ifdef _DEBUG
214
                        __BREAK__;
215
                #endif
216
                        return;
217
                case Expose:
218
                        int y = 20;
219
                        const char *b = text;
220
                        for(;;) {
221
                                const char *e = strchr(b, '\n');
222
                                if(!e) break;
223
                                XDrawString(display, win, gc, 20, y, b, e - b);
224
                                y += font_info->max_bounds.ascent + font_info->max_bounds.descent;
225
                                b = e + 1;
226
                        }
227
                        XDrawString(display, win, gc, 20, y, b, strlen(b));
228
                        break;
229
                }
230
        }
231
}
232

    
233
#ifdef _DEBUG
234
#define INI_PREFIX "DEBUG_"
235
#else
236
#define INI_PREFIX
237
#endif
238

    
239
int X11ErrorHandler(XDisplay *, XErrorEvent *error)
240
{
241
        if(X11ErrorTrap || IsPanicMode()) return 0;
242

    
243
        if(GetIniKey(INI_PREFIX "X11_ERRORS") != "1")
244
                return 0;
245

    
246
        static const char *request[] = {
247
                "",
248
                "X_CreateWindow",
249
                "X_ChangeWindowAttributes",
250
                "X_GetWindowAttributes",
251
                "X_DestroyWindow",
252
                "X_DestroySubwindows",
253
                "X_ChangeSaveSet",
254
                "X_ReparentWindow",
255
                "X_MapWindow",
256
                "X_MapSubwindows",
257
                "X_UnmapWindow",
258
                "X_UnmapSubwindows",
259
                "X_ConfigureWindow",
260
                "X_CirculateWindow",
261
                "X_GetGeometry",
262
                "X_QueryTree",
263
                "X_InternAtom",
264
                "X_GetAtomName",
265
                "X_ChangeProperty",
266
                "X_DeleteProperty",
267
                "X_GetProperty",
268
                "X_ListProperties",
269
                "X_SetSelectionOwner",
270
                "X_GetSelectionOwner",
271
                "X_ConvertSelection",
272
                "X_SendEvent",
273
                "X_GrabPointer",
274
                "X_UngrabPointer",
275
                "X_GrabButton",
276
                "X_UngrabButton",
277
                "X_ChangeActivePointerGrab",
278
                "X_GrabKeyboard",
279
                "X_UngrabKeyboard",
280
                "X_GrabKey",
281
                "X_UngrabKey",
282
                "X_AllowEvents",
283
                "X_GrabServer",
284
                "X_UngrabServer",
285
                "X_QueryPointer",
286
                "X_GetMotionEvents",
287
                "X_TranslateCoords",
288
                "X_WarpPointer",
289
                "X_SetInputFocus",
290
                "X_GetInputFocus",
291
                "X_QueryKeymap",
292
                "X_OpenFont",
293
                "X_CloseFont",
294
                "X_QueryFont",
295
                "X_QueryTextExtents",
296
                "X_ListFonts",
297
                "X_ListFontsWithInfo",
298
                "X_SetFontPath",
299
                "X_GetFontPath",
300
                "X_CreatePixmap",
301
                "X_FreePixmap",
302
                "X_CreateGC",
303
                "X_ChangeGC",
304
                "X_CopyGC",
305
                "X_SetDashes",
306
                "X_SetClipRectangles",
307
                "X_FreeGC",
308
                "X_ClearArea",
309
                "X_CopyArea",
310
                "X_CopyPlane",
311
                "X_PolyPoint",
312
                "X_PolyLine",
313
                "X_PolySegment",
314
                "X_PolyRectangle",
315
                "X_PolyArc",
316
                "X_FillPoly",
317
                "X_PolyFillRectangle",
318
                "X_PolyFillArc",
319
                "X_PutImage",
320
                "X_GetImage",
321
                "X_PolyText8",
322
                "X_PolyText16",
323
                "X_ImageText8",
324
                "X_ImageText16",
325
                "X_CreateColormap",
326
                "X_FreeColormap",
327
                "X_CopyColormapAndFree",
328
                "X_InstallColormap",
329
                "X_UninstallColormap",
330
                "X_ListInstalledColormaps",
331
                "X_AllocColor",
332
                "X_AllocNamedColor",
333
                "X_AllocColorCells",
334
                "X_AllocColorPlanes",
335
                "X_FreeColors",
336
                "X_StoreColors",
337
                "X_StoreNamedColor",
338
                "X_QueryColors",
339
                "X_LookupColor",
340
                "X_CreateCursor",
341
                "X_CreateGlyphCursor",
342
                "X_FreeCursor",
343
                "X_RecolorCursor",
344
                "X_QueryBestSize",
345
                "X_QueryExtension",
346
                "X_ListExtensions",
347
                "X_ChangeKeyboardMapping",
348
                "X_GetKeyboardMapping",
349
                "X_ChangeKeyboardControl",
350
                "X_GetKeyboardControl",
351
                "X_Bell",
352
                "X_ChangePointerControl",
353
                "X_GetPointerControl",
354
                "X_SetScreenSaver",
355
                "X_GetScreenSaver",
356
                "X_ChangeHosts",
357
                "X_ListHosts",
358
                "X_SetAccessControl",
359
                "X_SetCloseDownMode",
360
                "X_KillClient",
361
                "X_RotateProperties",
362
                "X_ForceScreenSaver",
363
                "X_SetPointerMapping",
364
                "X_GetPointerMapping",
365
                "X_SetModifierMapping",
366
                "X_GetModifierMapping",
367
                "X_NoOperation",
368
        };
369

    
370
        char h[512];
371
        XGetErrorText(Xdisplay, error->error_code, h, 512);
372
        String e;
373
        e << "X Error: " << h;
374
        if(error->request_code < __countof(request))
375
                e << "\nrequest: " << request[error->request_code];
376
        e << "\nresource id: " << (int)error->resourceid << " = " << Format("%0X", (int)error->resourceid);
377

    
378
        RLOG(e);
379
        puts(e);
380

    
381
        Panic(e);
382

    
383
        return 0;
384
}
385

    
386
void SetX11ErrorHandler()
387
{
388
        XSetErrorHandler(X11ErrorHandler);
389
}
390

    
391
INITBLOCK {
392
        InstallPanicMessageBox(sPanicMessageBox);
393
}
394

    
395
void Ctrl::InstallPanicBox()
396
{
397
        InstallPanicMessageBox(sPanicMessageBox);
398
}
399

    
400
void Ctrl::InitX11(const char *display)
401
{
402
        GuiLock __; 
403

    
404
        XInitThreads();
405

    
406
        InstallPanicMessageBox(sPanicMessageBox);
407

    
408
        InitX11Draw(display);
409
        InitTimer();
410
        byte dummy[5];
411
        Xbuttons = XGetPointerMapping(Xdisplay, dummy, 5);
412

    
413
        Xeventtime = CurrentTime;
414
        SetX11ErrorHandler();
415
        if(GetIniKey(INI_PREFIX "X11_SYNCHRONIZE") == "1")
416
                XSynchronize(Xdisplay, 1);
417
        Vector<int> nets = GetPropertyInts(Xroot, XAtom("_NET_SUPPORTED"));
418
        for(int i = 0; i < nets.GetCount(); i++)
419
                _NET_Supported().Add(nets[i]);
420

    
421
        SetStdFont(Arial(12));
422

    
423
        ReSkin();
424

    
425
        GUI_GlobalStyle_Write(GUISTYLE_XP);
426
        GUI_DragFullWindow_Write(1);
427
        GUI_PopUpEffect_Write(IsCompositedGui() ? GUIEFFECT_NONE : GUIEFFECT_SLIDE);
428
        GUI_DropShadows_Write(1);
429
        GUI_AltAccessKeys_Write(1);
430
        GUI_AKD_Conservative_Write(0);
431

    
432
        setlocale(LC_ALL, "en_US.utf8");
433
        if(XSupportsLocale()) {
434
                XSetLocaleModifiers("");
435
                xim = XOpenIM(Xdisplay, NULL, NULL, NULL);
436
        }
437
        else {
438
                xim = NULL;
439
                LOG("IM unsupported!");
440
        }
441

    
442
        Csizeinit();
443
}
444

    
445
void Ctrl::ExitX11()
446
{
447
        GuiLock __; 
448
//        if(xic)
449
//                XDestroyIC(xic);
450
        TopWindow::ShutdownWindows();
451
        CloseTopCtrls();
452
        for(int i = 0; i < hotkey.GetCount(); i++)
453
                UnregisterSystemHotKey(i);
454
        if(xim)
455
                XCloseIM(xim);
456
}
457

    
458
Vector<Rect> FindScreensResolutions()
459
{
460
        Vector<Rect> screensResolutions;
461
        int event, error;
462
        
463
        if(XineramaQueryExtension(Xdisplay, &event, &error)) {
464
                if(XineramaIsActive(Xdisplay)) {
465
                        int screensNumber = 0;
466
                        XineramaScreenInfo* info = XineramaQueryScreens(Xdisplay, &screensNumber);
467
                        for(int i = 0; i < screensNumber; i++)
468
                                screensResolutions.Add(Rect(info[i].x_org, info[i].y_org, info[i].x_org + info[i].width, info[i].y_org + info[i].height));
469
                        XFree(info);
470
                }
471
        }
472
        return screensResolutions;
473
}
474

    
475
Vector<Rect> FindScreensStruts()
476
{
477
        Vector<Rect> struts;
478
        
479
        Vector<int> clients = GetPropertyInts(Xroot, XAtom("_NET_CLIENT_LIST"));
480
        for (int i = 0; i < clients.GetCount(); i++) {
481
                Vector<int> strut = GetPropertyInts(clients[i], XAtom("_NET_WM_STRUT"));
482
                if(strut.GetCount() == 4)
483
                        struts.Add(Rect(strut[0], strut[2], strut[1], strut[3]));
484
        }
485
        return struts;
486
}
487

    
488
Rect Ctrl::GetDefaultWindowRect()
489
{
490
        GuiLock __;
491

    
492
        static int width  = 0;
493
        static int height = 0;
494
        static int left   = 0;
495
        static int top    = 0;
496
        if (width == 0 && height == 0) {
497
                Vector<Rect> screens = FindScreensResolutions();
498
                if(screens.GetCount()) {
499
                        width  = screens[0].Width();
500
                        height = screens[0].Height();
501
                        left   = screens[0].left;
502
                        top    = screens[0].top;
503
                }
504
                else {
505
                        width  = Xwidth;
506
                        height = Xheight;
507
                }
508
        }
509
        
510
        static int pos = min(width / 10, 50);
511
        pos += 10;
512
        int cx = width * 2 / 3;
513
        int cy = height * 2 / 3;
514
        if(pos + cx + 50 > width || pos + cy + 50 > height)
515
                pos = 0;
516
        return RectC(left + pos + 20, top + pos + 20, cx, cy);
517
}
518

    
519
void Ctrl::GetWorkArea(Array<Rect>& out)
520
{
521
        Vector<Rect> workAreas = FindScreensResolutions();
522
        Vector<Rect> struts    = FindScreensStruts();
523
        for (int i = 0; i < workAreas.GetCount(); i++) {
524
                if (i < struts.GetCount()) {
525
                        workAreas[i].left   += struts[i].left;
526
                        workAreas[i].right  -= struts[i].right;
527
                        workAreas[i].top    += struts[i].top;
528
                        workAreas[i].bottom -= struts[i].bottom;
529
                }
530
                out.Add(workAreas[i]);
531
        }
532
        if (out.IsEmpty())
533
                out.Add(GetPrimaryWorkArea());
534
}
535

    
536
Rect Ctrl::GetWorkArea() const
537
{
538
        GuiLock __;
539
        SyncMousePos();
540
        
541
        static Array<Rect> rc;
542
        if (rc.IsEmpty())
543
                GetWorkArea(rc);
544
        
545
        Point pt = GetMousePos();
546
        for (int i = 0; i < rc.GetCount(); i++)
547
                if(rc[i].Contains(pt))
548
                        return rc[i];
549
        return GetPrimaryWorkArea();
550
}
551

    
552
Rect Ctrl::GetWorkArea(Point pt)
553
{
554
        static Array<Rect> rc;
555
        if (rc.IsEmpty())
556
                GetWorkArea(rc);
557
        for(int i = 0; i < rc.GetCount(); i++)
558
                if(rc[i].Contains(pt))
559
                        return rc[i];
560
        return GetPrimaryWorkArea();
561
}
562

    
563
Rect Ctrl::GetVirtualWorkArea()
564
{
565
        GuiLock __;
566
        
567
        static Rect r;
568
        if(r.right == 0) {
569
                Vector<int> x = GetPropertyInts(Xroot, XAtom("_NET_WORKAREA"));
570
                if(x.GetCount())
571
                        r = RectC(x[0], x[1], x[2], x[3]);
572
                else
573
                        r = RectC(0, 0, Xwidth, Xheight);
574
        }
575
        return r;
576
}
577

    
578
Rect Ctrl::GetVirtualScreenArea()
579
{
580
        return RectC(0, 0, Xwidth, Xheight);
581
}
582

    
583
Rect Ctrl::GetPrimaryWorkArea()
584
{
585
        GuiLock __;
586
        
587
        static Rect r;
588
        if(r.right == 0) {
589
                static Array<Rect> rc;
590
                if (rc.IsEmpty())
591
                        GetWorkArea(rc);
592
                rc.GetCount() ? r = rc[0] : r = GetVirtualScreenArea();
593
        }
594
        return r;
595
}
596

    
597
Rect Ctrl::GetPrimaryScreenArea()
598
{
599
        GuiLock __;
600
        
601
        static Rect r;
602
        if(r.right == 0) {
603
                Vector<Rect> screens = FindScreensResolutions();
604
                screens.GetCount() ? r = screens[0] : r = GetVirtualScreenArea();
605
        }
606
        return r;
607
}
608

    
609
int Ctrl::GetKbdDelay()
610
{
611
        return 250;
612
}
613

    
614
int Ctrl::GetKbdSpeed()
615
{
616
        return 25;
617
}
618

    
619

    
620
#ifdef _DEBUG
621
extern bool __X11_Grabbing;
622
void _DBG_Ungrab(void) {
623
        if(__X11_Grabbing)
624
        {
625
                XUngrabPointer(Xdisplay, CurrentTime);
626
                XUngrabKeyboard(Xdisplay, CurrentTime);
627
                XFlush(Xdisplay);
628
                __X11_Grabbing = false;
629
        }
630
}
631
#endif
632

    
633
END_UPP_NAMESPACE
634

    
635
#endif