X11Top.cpp

TopWindow::CenterRect - fixed , serialization vol 2 - Zbigniew Rebacz, 12/14/2013 02:38 AM

Download (13.7 KB)

 
1
#include "CtrlCore.h"
2

    
3
#ifdef GUI_X11
4

    
5
NAMESPACE_UPP
6

    
7
#define LLOG(x)  //  DLOG(x)
8

    
9
Rect TopWindow::windowFrameMargin;
10

    
11
void TopWindow::SyncSizeHints()
12
{
13
        GuiLock __; 
14
        Size min = GetMinSize();
15
        Size max = GetMaxSize();
16
        if(!sizeable)
17
                min = max = GetRect().Size();
18
        Window w = GetWindow();
19
        if(w && (min != xminsize || max != xmaxsize) && !frameless) {
20
                xminsize = min;
21
                xmaxsize = max;
22
                size_hints->min_width = min.cx;
23
                size_hints->min_height = min.cy;
24
                size_hints->max_width = max.cx;
25
                size_hints->max_height = max.cy;
26
                size_hints->flags = PMinSize|PMaxSize;
27
                XSetWMNormalHints(Xdisplay, w, size_hints);
28
        }
29
}
30

    
31
void TopWindow::EndIgnoreTakeFocus()
32
{
33
        GuiLock __; 
34
        ignoretakefocus = false;
35
}
36

    
37
void TopWindow::EventProc(XWindow& w, XEvent *event)
38
{
39
        GuiLock __; 
40
        Ptr<Ctrl> this_ = this;
41
        if(event->type == ClientMessage) {
42
                if(event->xclient.format == 32 && event->xclient.message_type)
43
                        if(event->xclient.message_type == XAtom("WM_PROTOCOLS")) {
44
                                Atom a = event->xclient.data.l[0];
45
                                if(a == XAtom("WM_DELETE_WINDOW") && IsEnabled()) {
46
                                        LLOG("DELETE_WINDOW " << Name());
47
                                        WhenClose();
48
                                        return;
49
                                }
50
                                if(a == XAtom("WM_TAKE_FOCUS")) {
51
                                        LLOG("TAKE_FOCUS serial: " << event->xclient.serial);
52
                                        Xeventtime = event->xclient.data.l[1];
53
                                        TakeFocus();
54
                                        return;
55
                                }
56
                                if(a == XAtom("_NET_WM_PING")) {
57
                                        XEvent ev = *event;
58
                                        ev.xclient.window = Xroot;
59
                                        XSendEvent(Xdisplay, Xroot, 0, SubstructureRedirectMask|SubstructureNotifyMask, &ev);
60
                                        return;
61
                                }
62
                                LLOG("Unknown WM_PROTOCOLS: " << XAtomName(a));
63
                        }
64
        }
65
        else
66
        if(event->type == PropertyNotify && event->xproperty.atom == XAtom("_NET_WM_STATE")) {
67
                LLOG("_NET_WM_STATE notify");
68
                Vector<int> p = GetPropertyInts(GetWindow(), XAtom("_NET_WM_STATE"));
69
                if(FindIndex(p, (int)XAtom("_NET_WM_STATE_HIDDEN")) >= 0) {
70
                        state = MINIMIZED;
71
                        LLOG("MINIMIZED");
72
                }
73
                else
74
                if(FindIndex(p, (int)XAtom("_NET_WM_STATE_MAXIMIZED_HORZ")) >= 0 &&
75
                   FindIndex(p, (int)XAtom("_NET_WM_STATE_MAXIMIZED_VERT")) >= 0) {
76
                        state = MAXIMIZED;
77
                        LLOG("MAXIMIZED");
78
                }
79
                else {
80
                        state = OVERLAPPED;
81
                        LLOG("OVERLAPPED");
82
                }
83
        }
84
        if(this_) Ctrl::EventProc(w, event);
85
        if(this_) SyncSizeHints();
86
}
87

    
88
void TopWindow::DefSyncTitle()
89
{
90
        GuiLock __; 
91
        if(title2 == title)
92
                return;
93
        title2 = title;
94
        if(IsOpen() && GetWindow()) {
95
                Window w = GetWindow();
96
                XStoreName(Xdisplay, w, title.ToString());
97
                XSetIconName(Xdisplay, w, title.ToString());
98
                String utf8title = FromUnicode(title, CHARSET_UTF8);
99
                XChangeProperty(Xdisplay, w, XAtom("_NET_WM_NAME"), XAtom("UTF8_STRING"),
100
                                8, PropModeReplace,
101
                                (const unsigned char *)~utf8title, utf8title.GetLength());
102
                XChangeProperty(Xdisplay, w, XAtom("_NET_WM_ICON_NAME"), XAtom("UTF8_STRING"),
103
                                8, PropModeReplace,
104
                                (const unsigned char *)~utf8title, utf8title.GetLength());
105
        }
106
}
107

    
108
void TopWindow::SyncTitle()
109
{
110
        GuiLock __; 
111
        LLOG("SyncTitle: " << title);
112
        KillTimeCallback(TIMEID_DEFSYNCTITLE);
113
        SetTimeCallback(0, THISBACK(DefSyncTitle), TIMEID_DEFSYNCTITLE);
114
        LLOG("*SyncTitle: " << title);
115
}
116

    
117
void WmState(Window w, bool set, Atom a1, Atom a2 = 0)
118
{
119
        XEvent e;
120
        memset(&e, 0, sizeof(e));
121
        e.xclient.type = ClientMessage;
122
        e.xclient.message_type = XAtom("_NET_WM_STATE");
123
        e.xclient.display = Xdisplay;
124
        e.xclient.window = w;
125
        e.xclient.format = 32;
126
        e.xclient.data.l[0] = set;
127
        e.xclient.data.l[1] = a1;
128
        e.xclient.data.l[2] = a2;
129
        XSendEvent(Xdisplay, Xroot, false, SubstructureNotifyMask | SubstructureRedirectMask, &e);
130
}
131

    
132
void TopWindow::SyncState()
133
{
134
        GuiLock __; 
135
        LLOG("SyncState");
136
        SyncCaption();
137
        if(IsOpen() && GetWindow()) {                
138
                Window w = GetWindow();
139
                WmState(w, topmost, XAtom("_NET_WM_STATE_ABOVE"));
140
                WmState(w, state == MAXIMIZED, XAtom("_NET_WM_STATE_MAXIMIZED_HORZ"), XAtom("_NET_WM_STATE_MAXIMIZED_VERT"));
141
                if(state == MINIMIZED)
142
                        XIconifyWindow(Xdisplay, GetWindow(), Xscreenno);
143
                else
144
                        XMapWindow(Xdisplay, GetWindow());
145

    
146
                WmState(w, state == MINIMIZED, XAtom("_NET_WM_STATE_HIDDEN"));
147
                WmState(w, fullscreen, XAtom("_NET_WM_STATE_FULLSCREEN"));
148
        }
149
}
150

    
151
typedef struct {
152
    unsigned long flags;
153
    unsigned long functions;
154
    unsigned long decorations;
155
    long input_mode;
156
    unsigned long status;
157
} MWMHints;
158

    
159
#define MWM_HINTS_DECORATIONS   (1L << 1)
160
#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
161
#define PROP_MWM_HINTS_ELEMENTS PROP_MOTIF_WM_HINTS_ELEMENTS
162

    
163

    
164

    
165
void TopWindow::SyncCaption()
166
{
167
        GuiLock __; 
168
        LLOG("SyncCaption0");
169
        SyncTitle();
170
        if(IsOpen() && GetWindow()) {
171
                unsigned long wina[6];
172
                memset(wina, 0, sizeof(wina));
173
                int n = 0;
174
                Window w = GetWindow();
175
                if(tool)
176
                        wina[n++] = XAtom("_NET_WM_WINDOW_TYPE_UTILITY");
177
                if(GetOwner())
178
                        wina[n++] = XAtom("_NET_WM_WINDOW_TYPE_DIALOG");
179
                wina[n++] = XAtom("_NET_WM_WINDOW_TYPE_NORMAL");
180
                XChangeProperty(Xdisplay, GetWindow(), XAtom("_NET_WM_WINDOW_TYPE"), XAtom("ATOM"), 32,
181
                                PropModeReplace, (const unsigned char *)wina, n);
182

    
183
//                n = 0;
184
//                XChangeProperty(Xdisplay, GetWindow(), XAtom("_NET_WM_STATE"), XAtom("ATOM"), 32,
185
//                                PropModeReplace, (const unsigned char *)wina, n);
186
                wm_hints->flags = InputHint|WindowGroupHint|StateHint;
187
                if(urgent) {
188
                        if(IsForeground()) urgent = false;
189
                        wm_hints->flags |= XUrgencyHint;
190
                        WmState(w, urgent, XAtom("_NET_WM_STATE_DEMANDS_ATTENTION"));
191
                }
192
                wm_hints->initial_state = NormalState;
193
                wm_hints->input = XTrue;
194
                Ctrl *owner = GetOwner();
195
                wm_hints->window_group = owner ? owner->GetWindow() : w;
196
                if(!icon.IsEmpty()) {
197
                        int len = 0;
198
                        Buffer<unsigned long> data = PreperIcon(icon, len);
199
                        XChangeProperty(Xdisplay, w, XAtom("_NET_WM_ICON"), XA_CARDINAL, 32, PropModeReplace,
200
                                       (const unsigned char *)~data, len);
201
                        if (!largeicon.IsEmpty()) {
202
                                data = PreperIcon(largeicon, len);
203
                                XChangeProperty(Xdisplay, w, XAtom("_NET_WM_ICON"), XA_CARDINAL, 32, PropModePrepend,
204
                                           (const unsigned char *)~data, len);
205
                        }
206
                }
207
                XSetWMHints(Xdisplay, w, wm_hints);
208

    
209
                MWMHints mwmhints;
210
                memset(&mwmhints, 0, sizeof(mwmhints));
211
                mwmhints.flags = MWM_HINTS_DECORATIONS;
212
                mwmhints.decorations = !frameless;
213
                XChangeProperty(Xdisplay, w, XAtom("_MOTIF_WM_HINTS"), XAtom("_MOTIF_WM_HINTS"), 32,
214
                                PropModeReplace,
215
                                (unsigned char *) &mwmhints, PROP_MWM_HINTS_ELEMENTS);
216
        }
217
}
218

    
219
Buffer<unsigned long> TopWindow::PreperIcon(const Image& icon, int& len) {
220
        Size isz = icon.GetSize();
221
        len = 2 + isz.cx * isz.cy;
222
        Buffer<unsigned long> data(len);
223
        unsigned long *t = data;
224
        *t++ = isz.cx;
225
        *t++ = isz.cy;
226
        for(int y = 0; y < isz.cy; y++) {
227
                const RGBA *q = icon[y];
228
                for(int x = isz.cx; x--;) {
229
                        *t++ = ((dword)q->a << 24) |
230
                                   (dword)q->b | ((dword)q->g << 8) | ((dword)q->r << 16);
231
                        q++;
232
                }
233
        }
234
        return data;
235
}
236

    
237
void TopWindow::CenterRect(Ctrl *owner)
238
{
239
        GuiLock __;
240
        SetupRect();
241
        if((owner&& center == 1) || center == 2) {
242
                Rect r, wr;
243
                wr = Ctrl::GetWorkArea();
244
                Size sz = GetRect().Size();
245
                Rect fm = windowFrameMargin;
246
                if((fm.left|fm.right|fm.top|fm.bottom) == 0)
247
                        fm = Rect(8, 32, 8, 8);
248
                if(owner && center == 1)
249
                        r = owner->GetRect();
250
                else
251
                        r = wr;
252
                Point p = r.CenterPos(sz);
253
                
254
                if ((p.x + sz.cx <= wr.Width() + wr.left) && (p.y + sz.cy <= wr.Height() + wr.top)) {
255
                        r = RectC(p.x, p.y, sz.cx, sz.cy);
256
                        wr.left += fm.left;
257
                        wr.right -= fm.right;
258
                        wr.top += fm.top;
259
                        wr.bottom -= fm.bottom;
260
                        if(r.top < wr.top) {
261
                                r.bottom += wr.top - r.top;
262
                                r.top = wr.top;
263
                        }
264
                        if(r.bottom > wr.bottom)
265
                                r.bottom = wr.bottom;
266
                        minsize.cx = min(minsize.cx, r.GetWidth());
267
                        minsize.cy = min(minsize.cy, r.GetHeight());
268
                        SetRect(r);
269
                }        
270
        }
271
}
272

    
273
void TopWindow::Open(Ctrl *owner)
274
{
275
        LLOG("TopWindow::Open");
276
        GuiLock __; 
277
        if(dokeys && (!GUI_AKD_Conservative() || GetAccessKeysDeep() <= 1))
278
                DistributeAccessKeys();
279
        USRLOG("   OPEN " + Desc(this));
280
        LLOG("OPEN " << Name() << " owner: " << UPP::Name(owner));
281
        IgnoreMouseUp();
282
        bool weplace = owner && center == 1 || center == 2 || !GetRect().IsEmpty();
283
        if(fullscreen)
284
                SetRect(0, 0, Xwidth, Xheight);
285
        else
286
                CenterRect(owner);
287
        LLOG("Open NextRequest " << NextRequest(Xdisplay));
288
        Create(owner, false, false);
289
        XSetWMProperties (Xdisplay, GetWindow(), NULL, NULL, NULL, 0, NULL, NULL, NULL);
290
        xminsize.cx = xmaxsize.cx = Null;
291
        title2.Clear();
292
        if(!weplace) {
293
                LLOG("SyncCaption");
294
                SyncCaption();
295
        }
296
        LLOG("SyncSizeHints");
297
        size_hints->flags = 0;
298
        SyncSizeHints();
299
        Rect r = GetRect();
300
        size_hints->x = r.left;
301
        size_hints->y = r.top;
302
        size_hints->width = r.Width();
303
        size_hints->height = r.Height();
304
        size_hints->win_gravity = StaticGravity;
305
        size_hints->flags |= PPosition|PSize|PWinGravity;
306
        if(owner) {
307
                ASSERT(owner->IsOpen());
308
                LLOG("XSetTransientForHint");
309
                XSetTransientForHint(Xdisplay, GetWindow(), owner->GetWindow());
310
        }
311
        LLOG("XSetWMNormalHints");
312
        XSetWMNormalHints(Xdisplay, GetWindow(), size_hints);
313
        Atom protocols[3];
314
        protocols[0] = XAtom("WM_DELETE_WINDOW");
315
        protocols[1] = XAtom("WM_TAKE_FOCUS");
316
        protocols[2] = XAtom("_NET_WM_PING");
317
        LLOG("XSetWMProtocols");
318
        XSetWMProtocols(Xdisplay, GetWindow(), protocols, 3);
319
        String x = GetExeTitle().ToString();
320
        const char *progname = ~x;
321
        class_hint->res_name = (char *)progname;
322
        class_hint->res_class = (char *)progname;
323
        XSetClassHint(Xdisplay, GetWindow(), class_hint);
324
        LLOG("WndShow(" << visible << ")");
325
        WndShow(visible);
326
        if(visible) {
327
                XEvent e;
328
                LLOG("XWindowEvent");
329
                XWindowEvent(Xdisplay, top->window, VisibilityChangeMask, &e);
330
                ignoretakefocus = true;
331
                SetTimeCallback(500, THISBACK(EndIgnoreTakeFocus));
332
                LLOG("SetWndFocus");
333
                SetWndFocus();
334
                for(int i = 0; i < 50; i++) {
335
                        // X11 tries to move our window, so ignore the first set of ConfigureNotify
336
                        // and move the window into position after FocusIn - but not if we want WM to
337
                        // place the window
338
                        if(weplace)
339
                                while(XCheckTypedWindowEvent(Xdisplay, top->window, ConfigureNotify, &e)) {
340
                                        if(e.xconfigure.window != top->window)
341
                                                ProcessEvent(&e);
342
                                }        
343
                        if(XCheckTypedWindowEvent(Xdisplay, top->window, FocusIn, &e)) {
344
                                ProcessEvent(&e);
345
                                if(e.xfocus.window == top->window)
346
                                        break;
347
                        }
348
                        Sleep(10);
349
                }
350
        }
351
        if(weplace) {
352
                WndSetPos(GetRect());
353
                LLOG("SyncCaption");
354
                SyncCaption();
355
        }
356
        LLOG(">Open NextRequest " << NextRequest(Xdisplay));
357
        LLOG(">OPENED " << Name());
358
        PlaceFocus();
359
        StateH(OPEN);
360
        Vector<int> fe = GetPropertyInts(top->window, XAtom("_NET_FRAME_EXTENTS"));
361
        if(fe.GetCount() >= 4 &&
362
           fe[0] >= 0 && fe[0] <= 16 && fe[1] >= 0 && fe[1] <= 16 && //fluxbox returns wrong numbers - quick&dirty workaround
363
           fe[2] >= 0 && fe[2] <= 64 && fe[3] >= 0 && fe[3] <= 48)
364
        {
365
                GuiLock __;
366
                windowFrameMargin.left = max(windowFrameMargin.left, fe[0]);
367
                windowFrameMargin.right = max(windowFrameMargin.right, fe[1]);
368
                windowFrameMargin.top = max(windowFrameMargin.top, fe[2]);
369
                windowFrameMargin.bottom = max(windowFrameMargin.bottom, fe[3]);
370
        }
371
        if(IsOpen() && top)
372
                top->owner = owner;
373

    
374
        long curr_pid = getpid();
375

    
376
        static Window wm_client_leader;
377
        ONCELOCK {
378
                wm_client_leader = XCreateSimpleWindow(Xdisplay, Xroot, 0, 0, 1, 1, 0, 0, 0);
379
                XChangeProperty(Xdisplay, wm_client_leader, XAtom("WM_CLIENT_LEADER"),
380
                                XA_WINDOW, 32, PropModeReplace, (byte *)&wm_client_leader, 1);
381
                XChangeProperty(Xdisplay, wm_client_leader, XAtom("_NET_WM_PID"), XA_CARDINAL, 32,
382
                                PropModeReplace, (byte *) &curr_pid, 1);
383
        }
384

    
385
        Window win = GetWindow();
386
        XChangeProperty(Xdisplay, win, XAtom("_NET_WM_PID"), XA_CARDINAL, 32,
387
                        PropModeReplace, (byte *) &curr_pid, 1);
388
        XChangeProperty(Xdisplay, win, XAtom("WM_CLIENT_LEADER"),
389
                        XA_WINDOW, 32, PropModeReplace, (byte *)&wm_client_leader, 1);
390

    
391
        int version = 5;
392
        XChangeProperty(Xdisplay, win, XAtom("XdndAware"), XA_ATOM, 32,
393
                                        0, (byte *)&version, 1);
394

    
395
        SyncState();
396
        FixIcons();
397
}
398

    
399
void TopWindow::Open()
400
{
401
        GuiLock __; 
402
        Open(GetActiveWindow());
403
}
404

    
405
void TopWindow::OpenMain()
406
{
407
        GuiLock __; 
408
        Open(NULL);
409
}
410

    
411
void TopWindow::Minimize(bool)
412
{
413
        GuiLock __; 
414
        state = MINIMIZED;
415
        SyncState();
416
}
417

    
418
void TopWindow::Maximize(bool effect)
419
{
420
        GuiLock __; 
421
        state = MAXIMIZED;
422
        SyncState();
423
}
424

    
425
void TopWindow::Overlap(bool effect)
426
{
427
        GuiLock __; 
428
        state = OVERLAPPED;
429
        SyncState();
430
}
431

    
432
TopWindow& TopWindow::FullScreen(bool b)
433
{
434
        GuiLock __; 
435
        fullscreen = b;
436
        SyncState();
437
        return *this;
438
}
439

    
440
TopWindow& TopWindow::TopMost(bool b, bool)
441
{
442
        GuiLock __; 
443
        topmost = b;
444
        SyncState();
445
        return *this;
446
}
447

    
448
bool TopWindow::IsTopMost() const
449
{
450
        GuiLock __; 
451
        return topmost;
452
}
453

    
454
void TopWindow::GuiPlatformConstruct()
455
{
456
        size_hints = XAllocSizeHints();
457
        wm_hints = XAllocWMHints();
458
        class_hint = XAllocClassHint();
459
        topmost = false;
460
}
461

    
462
void TopWindow::GuiPlatformDestruct()
463
{
464
        XFree(size_hints);
465
        XFree(wm_hints);
466
        XFree(class_hint);
467
}
468

    
469
void TopWindow::SerializePlacement(Stream& s, bool reminimize)
470
{
471
        GuiLock __;
472
        int version = 0;
473
        s / version;
474
        Rect rect = GetRect();
475
        s % overlapped % rect;
476
        bool mn = state == MINIMIZED;
477
        bool mx = state == MAXIMIZED;
478
        s.Pack(mn, mx);
479
        LLOG("TopWindow::SerializePlacement / " << (s.IsStoring() ? "write" : "read"));
480
        LLOG("minimized = " << mn << ", maximized = " << mx);
481
        LLOG("rect = " << rect << ", overlapped = " << overlapped);
482
        if(s.IsLoading()) {
483
                if(mn) rect = overlapped;
484
                Rect limit = GetVirtualWorkArea();
485
                Rect fm = windowFrameMargin;
486
                if((fm.left|fm.right|fm.top|fm.bottom) == 0)
487
                        fm = Rect(8, 32, 8, 8);
488
                limit.left += fm.left;
489
                limit.right -= fm.right;
490
                limit.top += fm.top;
491
                limit.bottom -= fm.bottom;
492
                Size sz = min(rect.Size(), limit.Size());
493
                rect = RectC(
494
                        minmax(rect.left, limit.left, limit.right - sz.cx),
495
                        minmax(rect.top,  limit.top,  limit.bottom - sz.cy),
496
                        sz.cx, sz.cy);
497
                state = OVERLAPPED;
498
                if(mn && reminimize)
499
                        state = MINIMIZED;
500
                if(mx)
501
                        state = MAXIMIZED;
502
                if(state == OVERLAPPED)
503
                        SetRect(rect);
504
                if(IsOpen()) {
505
                        if(state == MINIMIZED)
506
                                Minimize(false);
507
                        if(state == MAXIMIZED)
508
                                Maximize(false);
509
                }
510
        }
511
}
512

    
513
END_UPP_NAMESPACE
514

    
515
#endif