TopWinX11.cpp

Jan DolinĂ¡r, 01/31/2011 02:09 PM

Download (9.79 KB)

 
1
#include "CtrlCore.h"
2

    
3
NAMESPACE_UPP
4

    
5
#define LLOG(x)    //DLOG(x)
6

    
7
#ifdef PLATFORM_X11
8

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

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

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

    
73
void TopWindow::DefSyncTitle()
74
{
75
        GuiLock __; 
76
        if(title2 == title)
77
                return;
78
        title2 = title;
79
        if(IsOpen() && GetWindow()) {
80
                Window w = GetWindow();
81
                XStoreName(Xdisplay, w, title.ToString());
82
                XSetIconName(Xdisplay, w, title.ToString());
83
                String utf8title = FromUnicode(title, CHARSET_UTF8);
84
                XChangeProperty(Xdisplay, w, XAtom("_NET_WM_NAME"), XAtom("UTF8_STRING"),
85
                                8, PropModeReplace,
86
                                (const unsigned char *)~utf8title, utf8title.GetLength());
87
                XChangeProperty(Xdisplay, w, XAtom("_NET_WM_ICON_NAME"), XAtom("UTF8_STRING"),
88
                                8, PropModeReplace,
89
                                (const unsigned char *)~utf8title, utf8title.GetLength());
90
        }
91
}
92

    
93
void TopWindow::SyncTitle0()
94
{
95
        GuiLock __; 
96
        LLOG("SyncTitle: " << title);
97
        KillTimeCallback(TIMEID_DEFSYNCTITLE);
98
        SetTimeCallback(0, THISBACK(DefSyncTitle), TIMEID_DEFSYNCTITLE);
99
        LLOG("*SyncTitle: " << title);
100
}
101

    
102
void WmState(Window w, bool set, Atom a1, Atom a2 = 0)
103
{
104
        XEvent e;
105
        memset(&e, 0, sizeof(e));
106
        e.xclient.type = ClientMessage;
107
        e.xclient.message_type = XAtom("_NET_WM_STATE");
108
        e.xclient.display = Xdisplay;
109
        e.xclient.window = w;
110
        e.xclient.format = 32;
111
        e.xclient.data.l[0] = set;
112
        e.xclient.data.l[1] = a1;
113
        e.xclient.data.l[2] = a2;
114
        XSendEvent(Xdisplay, Xroot, false, SubstructureNotifyMask | SubstructureRedirectMask, &e);
115
}
116

    
117
void TopWindow::SyncCaption0()
118
{
119
        GuiLock __; 
120
        LLOG("SyncCaption");
121
        SyncTitle();
122
        if(IsOpen() && GetWindow()) {
123
                unsigned long wina[6];
124
                memset(wina, 0, sizeof(wina));
125
                int n = 0;
126
                Window w = GetWindow();
127
                if(tool)
128
                        wina[n++] = XAtom("_NET_WM_WINDOW_TYPE_UTILITY");
129
                if(GetOwner())
130
                        wina[n++] = XAtom("_NET_WM_WINDOW_TYPE_DIALOG");
131
                wina[n++] = XAtom("_NET_WM_WINDOW_TYPE_NORMAL");
132
                XChangeProperty(Xdisplay, GetWindow(), XAtom("_NET_WM_WINDOW_TYPE"), XAtom("ATOM"), 32,
133
                                PropModeReplace, (const unsigned char *)wina, n);
134
                n = 0;
135
                WmState(w, topmost, XAtom("_NET_WM_STATE_ABOVE"));
136
                WmState(w, state == MAXIMIZED, XAtom("_NET_WM_STATE_MAXIMIZED_HORZ"), XAtom("_NET_WM_STATE_MAXIMIZED_VERT"));
137
                if(state == MINIMIZED)
138
                        XIconifyWindow(Xdisplay, GetWindow(), Xscreenno);
139
                else
140
                        XMapWindow(Xdisplay, GetWindow());
141

    
142
                WmState(w, state == MINIMIZED, XAtom("_NET_WM_STATE_HIDDEN"));
143
                WmState(w, fullscreen, XAtom("_NET_WM_STATE_FULLSCREEN"));
144

    
145
//                XChangeProperty(Xdisplay, GetWindow(), XAtom("_NET_WM_STATE"), XAtom("ATOM"), 32,
146
//                                PropModeReplace, (const unsigned char *)wina, n);
147
                wm_hints->flags = InputHint|WindowGroupHint|StateHint;
148
                if(urgent){
149
                        if(IsForeground()) urgent = false;
150
                        wm_hints->flags |= XUrgencyHint;
151
                        WmState(w,urgent,XAtom("_NET_WM_STATE_DEMANDS_ATTENTION"));
152
                }
153
                wm_hints->initial_state = NormalState;
154
                wm_hints->input = XTrue;
155
                Ctrl *owner = GetOwner();
156
                wm_hints->window_group = owner ? owner->GetWindow() : w;
157
                if(!icon.IsEmpty()) {
158
                        Size isz = icon.GetSize();
159
                        int len = 2 + isz.cx * isz.cy;
160
                        Buffer<unsigned long> data(len);
161
                        unsigned long *t = data;
162
                        *t++ = isz.cx;
163
                        *t++ = isz.cy;
164
                        for(int y = 0; y < isz.cy; y++) {
165
                                const RGBA *q = icon[y];
166
                                for(int x = isz.cx; x--;) {
167
                                        *t++ = ((dword)q->a << 24) |
168
                                               (dword)q->b | ((dword)q->g << 8) | ((dword)q->r << 16);
169
                                        q++;
170
                                }
171
                        }
172
                        XChangeProperty(Xdisplay, w, XAtom("_NET_WM_ICON"), XA_CARDINAL, 32, PropModeReplace,
173
                                        (const unsigned char *)~data, len);
174
                }
175
                XSetWMHints(Xdisplay, w, wm_hints);
176
        }
177
}
178

    
179
void TopWindow::CenterRect(Ctrl *owner)
180
{
181
        GuiLock __;
182
        SetupRect();
183
        if(owner && center == 1 || center == 2) {
184
                Size sz = GetRect().Size();
185
                Rect r, wr;
186
                wr = Ctrl::GetWorkArea();
187
                GuiLock __;
188
                Rect fm = windowFrameMargin;
189
                if((fm.left|fm.right|fm.top|fm.bottom) == 0)
190
                        fm = Rect(8, 32, 8, 8);
191
                if(center == 1)
192
                        r = owner->GetRect();
193
                else
194
                        r = wr;
195
                Point p = r.CenterPos(sz);
196
                r = RectC(p.x, p.y, sz.cx, sz.cy);
197
                wr.left += fm.left;
198
                wr.right -= fm.right;
199
                wr.top += fm.top;
200
                wr.bottom -= fm.bottom;
201
                if(r.top < wr.top) {
202
                        r.bottom += wr.top - r.top;
203
                        r.top = wr.top;
204
                }
205
                if(r.bottom > wr.bottom)
206
                        r.bottom = wr.bottom;
207
                minsize.cx = min(minsize.cx, r.GetWidth());
208
                minsize.cy = min(minsize.cy, r.GetHeight());
209
                SetRect(r);
210
        }
211
}
212

    
213
void TopWindow::Open(Ctrl *owner)
214
{
215
        GuiLock __; 
216
        if(dokeys && (!GUI_AKD_Conservative() || GetAccessKeysDeep() <= 1))
217
                DistributeAccessKeys();
218
        UsrLogT(3, "OPEN " + Desc(this));
219
        LLOG("OPEN " << Name() << " owner: " << UPP::Name(owner));
220
        IgnoreMouseUp();
221
        bool weplace = owner && center == 1 || center == 2 || !GetRect().IsEmpty();
222
        if(fullscreen)
223
                SetRect(0, 0, Xwidth, Xheight);
224
        else
225
                CenterRect(owner);
226
        LLOG("Open NextRequest " << NextRequest(Xdisplay));
227
        Create(owner, false, false);
228
        xminsize.cx = xmaxsize.cx = Null;
229
        title2.Clear();
230
        if(!weplace) {
231
                LLOG("SyncCaption");
232
                SyncCaption0();
233
        }
234
        LLOG("SyncSizeHints");
235
        size_hints->flags = 0;
236
        SyncSizeHints();
237
        Rect r = GetRect();
238
        size_hints->x = r.left;
239
        size_hints->y = r.top;
240
        size_hints->width = r.Width();
241
        size_hints->height = r.Height();
242
        size_hints->win_gravity = StaticGravity;
243
        size_hints->flags |= PPosition|PSize|PWinGravity;
244
        if(owner) {
245
                ASSERT(owner->IsOpen());
246
                LLOG("XSetTransientForHint");
247
                XSetTransientForHint(Xdisplay, GetWindow(), owner->GetWindow());
248
        }
249
        LLOG("XSetWMNormalHints");
250
        XSetWMNormalHints(Xdisplay, GetWindow(), size_hints);
251
        Atom protocols[2];
252
        protocols[0] = XAtom("WM_DELETE_WINDOW");
253
        protocols[1] = XAtom("WM_TAKE_FOCUS");
254
        LLOG("XSetWMProtocols");
255
        XSetWMProtocols(Xdisplay, GetWindow(), protocols, 2);
256
        String x = GetExeTitle().ToString();
257
        const char *progname = ~x;
258
        class_hint->res_name = (char *)progname;
259
        class_hint->res_class = (char *)progname;
260
        XSetClassHint(Xdisplay, GetWindow(), class_hint);
261
        LLOG("WndShow(" << visible << ")");
262
        WndShow(visible);
263
        if(visible) {
264
                XEvent e;
265
                LLOG("XWindowEvent");
266
                XWindowEvent(Xdisplay, top->window, VisibilityChangeMask, &e);
267
                ignoretakefocus = true;
268
                SetTimeCallback(500, THISBACK(EndIgnoreTakeFocus));
269
                LLOG("SetWndFocus");
270
                SetWndFocus();
271
                for(int i = 0; i < 50; i++) {
272
                        // X11 tries to move our window, so ignore the first set of ConfigureNotify
273
                        // and move the window into position after FocusIn - but not if we want WM to
274
                        // place the window
275
                        if(weplace)
276
                                while(XCheckTypedWindowEvent(Xdisplay, top->window, ConfigureNotify, &e)) {
277
                                        if(e.xconfigure.window != top->window)
278
                                                ProcessEvent(&e);
279
                                }        
280
                        if(XCheckTypedWindowEvent(Xdisplay, top->window, FocusIn, &e)) {
281
                                ProcessEvent(&e);
282
                                if(e.xfocus.window == top->window)
283
                                        break;
284
                        }
285
                        Sleep(10);
286
                }
287
        }
288
        if(weplace) {
289
                WndSetPos0(GetRect());
290
                LLOG("SyncCaption");
291
                SyncCaption0();
292
        }
293
        LLOG(">Open NextRequest " << NextRequest(Xdisplay));
294
        LLOG(">OPENED " << Name());
295
        PlaceFocus();
296
        StateH(OPEN);
297
        Vector<int> fe = GetPropertyInts(top->window, XAtom("_NET_FRAME_EXTENTS"));
298
        if(fe.GetCount() >= 4 &&
299
           fe[0] >= 0 && fe[0] <= 16 && fe[1] >= 0 && fe[1] <= 16 && //fluxbox returns wrong numbers - quick&dirty workaround
300
           fe[2] >= 0 && fe[2] <= 64 && fe[3] >= 0 && fe[3] <= 48)
301
        {
302
                GuiLock __;
303
                windowFrameMargin.left = max(windowFrameMargin.left, fe[0]);
304
                windowFrameMargin.right = max(windowFrameMargin.right, fe[1]);
305
                windowFrameMargin.top = max(windowFrameMargin.top, fe[2]);
306
                windowFrameMargin.bottom = max(windowFrameMargin.bottom, fe[3]);
307
        }
308
        if(IsOpen() && top)
309
                top->owner = owner;
310

    
311
        int version = 5;
312
        XChangeProperty(Xdisplay, GetWindow(), XAtom("XdndAware"), XA_ATOM, 32,
313
                                        0, (byte *)&version, 1);
314
        FixIcons();
315
}
316

    
317
void TopWindow::Open()
318
{
319
        GuiLock __; 
320
        Open(GetActiveWindow());
321
}
322

    
323
void TopWindow::OpenMain()
324
{
325
        GuiLock __; 
326
        Open(NULL);
327
}
328

    
329
void TopWindow::Minimize(bool)
330
{
331
        GuiLock __; 
332
        state = MINIMIZED;
333
        SyncCaption();
334
}
335

    
336
void TopWindow::Maximize(bool effect)
337
{
338
        GuiLock __; 
339
        state = MAXIMIZED;
340
        SyncCaption();
341
}
342

    
343
void TopWindow::Overlap(bool effect)
344
{
345
        GuiLock __; 
346
        state = OVERLAPPED;
347
        SyncCaption();
348
}
349

    
350
TopWindow& TopWindow::FullScreen(bool b)
351
{
352
        GuiLock __; 
353
        fullscreen = b;
354
        SyncCaption();
355
        return *this;
356
}
357

    
358
TopWindow& TopWindow::TopMost(bool b, bool)
359
{
360
        GuiLock __; 
361
        topmost = b;
362
        return *this;
363
}
364

    
365
bool TopWindow::IsTopMost() const
366
{
367
        GuiLock __; 
368
        return topmost;
369
}
370

    
371
#endif
372

    
373
END_UPP_NAMESPACE