X11Top.cpp

X11Top.cpp (Ubuntu - Unity fix) - Zbigniew Rebacz, 09/07/2013 01:43 AM

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

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

    
375
        long curr_pid = getpid();
376

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
514
END_UPP_NAMESPACE
515

    
516
#endif