GtkWnd.cpp

Zbigniew Rebacz, 12/29/2013 01:48 PM

Download (10 KB)

 
1
#include <CtrlCore/CtrlCore.h>
2

    
3
#ifdef GUI_GTK
4

    
5
NAMESPACE_UPP
6

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

    
9
Vector<Callback>  Ctrl::hotkey;
10
Vector<dword>     Ctrl::keyhot;
11
Vector<dword>     Ctrl::modhot;
12

    
13
Vector<Ctrl::Win> Ctrl::wins;
14

    
15
Ptr<Ctrl>         Ctrl::activeCtrl;
16

    
17
int        Ctrl::WndCaretTime;
18
bool       Ctrl::WndCaretVisible;
19

    
20
int Ctrl::FindId(int id)
21
{
22
        for(int i = 0; i < wins.GetCount(); i++)
23
                if(wins[i].id == id)
24
                        return i;
25
        return -1;
26
}
27

    
28
int Ctrl::FindCtrl(Ctrl *ctrl)
29
{
30
        for(int i = 0; i < wins.GetCount(); i++)
31
                if(wins[i].ctrl == ctrl)
32
                        return i;
33
        return -1;
34
}
35

    
36
int Ctrl::FindGtkWindow(GtkWidget *gtk)
37
{
38
        for(int i = 0; i < wins.GetCount(); i++)
39
                if(wins[i].gtk == gtk)
40
                        return i;
41
        return -1;
42
}
43

    
44
int Ctrl::FindGdkWindow(GdkWindow *gdk)
45
{
46
        for(int i = 0; i < wins.GetCount(); i++)
47
                if(wins[i].gdk == gdk)
48
                        return i;
49
        return -1;
50
}
51

    
52
bool Ctrl::IsAlphaSupported()
53
{
54
        return false;
55
}
56

    
57
bool Ctrl::IsCompositedGui()
58
{
59
    GuiLock __;
60
    static bool b = gdk_display_supports_composite(gdk_display_get_default());
61
    return b;
62
}
63

    
64
Vector<Ctrl *> Ctrl::GetTopCtrls()
65
{
66
        GuiLock __;
67
        Vector<Ctrl *> h;
68
        for(int i = 0; i < wins.GetCount(); i++)
69
                h.Add(wins[i].ctrl);
70
        return h;
71
}
72

    
73
void  Ctrl::SetMouseCursor(const Image& image)
74
{
75
        GuiLock __;
76
        int64 id = image.GetSerialId();
77
        Ctrl *topctrl = NULL;
78
        Top *top = NULL;
79
        if(mouseCtrl)
80
                topctrl = mouseCtrl->GetTopCtrl();
81
        if(topctrl)
82
                top = topctrl->top;
83
        if(top && id != top->cursor_id) {
84
                top->cursor_id = id;
85
                int64 aux = image.GetAuxData();
86
                GdkCursor *c = NULL;
87
                if(aux)
88
                        c = gdk_cursor_new((GdkCursorType)(aux - 1));
89
                else
90
                if(IsNull(image))
91
                        c = gdk_cursor_new(GDK_BLANK_CURSOR);
92
                else {
93
                        Point p = image.GetHotSpot();
94
                        ImageGdk m;
95
                        m.Set(image);
96
                        GdkPixbuf *pb = m;
97
                        if(pb)
98
                                c = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pb, p.x, p.y);
99
                }
100
                if(c) {
101
                        gdk_window_set_cursor(topctrl->gdk(), c);
102
                        gdk_cursor_unref(c);
103
                }
104
        }
105
}
106

    
107
Ctrl *Ctrl::GetOwner()
108
{
109
        GuiLock __;
110
        return top ? top->owner : NULL;
111
}
112

    
113
Ctrl *Ctrl::GetActiveCtrl()
114
{
115
        GuiLock __;
116
        if(focusCtrl)
117
                return focusCtrl->GetTopCtrl();
118
        return activeCtrl;
119
}
120

    
121
// Vector<Callback> Ctrl::hotkey;
122

    
123
#ifndef GDK_WINDOWING_X11
124

    
125
// There is no generic support in GTK for HotKey
126

    
127
int Ctrl::RegisterSystemHotKey(dword key, Callback cb)
128
{
129
        return -1;
130
}
131

    
132
void Ctrl::UnregisterSystemHotKey(int id)
133
{
134
}
135

    
136
#endif
137

    
138
void  Ctrl::AnimateCaret()
139
{
140
        GuiLock __;
141
        int v = !(((GetTickCount() - WndCaretTime) / 500) & 1);
142
        if(v != WndCaretVisible) {
143
                WndCaretVisible = v;
144
                RefreshCaret();
145
        }
146
}
147

    
148
void Ctrl::PaintCaret(SystemDraw& w)
149
{
150
        GuiLock __;
151
        LLOG("PaintCaret " << Name() << ", caretCtrl: " << caretCtrl << ", WndCaretVisible: " << WndCaretVisible);
152
        if(this == caretCtrl && WndCaretVisible)
153
                w.DrawRect(caretx, carety, caretcx, caretcy, InvertColor);
154
}
155

    
156
void Ctrl::SetCaret(int x, int y, int cx, int cy)
157
{
158
        GuiLock __;
159
        LLOG("SetCaret " << Name());
160
        if(this == caretCtrl)
161
                RefreshCaret();
162
        caretx = x;
163
        carety = y;
164
        caretcx = cx;
165
        caretcy = cy;
166
        if(this == caretCtrl) {
167
                WndCaretTime = GetTickCount();
168
                RefreshCaret();
169
                AnimateCaret();
170
        }
171
}
172

    
173
void Ctrl::SyncCaret() {
174
        GuiLock __;
175
        if(focusCtrl != caretCtrl) {
176
                LLOG("SyncCaret DO " << Upp::Name(caretCtrl) << " -> " << Upp::Name(focusCtrl));
177
                RefreshCaret();
178
                caretCtrl = focusCtrl;
179
                RefreshCaret();
180
        }
181
}
182

    
183
Rect Ctrl::GetWndScreenRect() const
184
{
185
        GuiLock __;
186
        if(top) {
187
                gint x, y;
188
                gdk_window_get_position(gdk(), &x, &y);
189
                gint width = gdk_window_get_width(gdk());
190
                gint height = gdk_window_get_height(gdk());
191
                return RectC(x, y, width, height);
192
        }
193
        return Null;
194
}
195

    
196
void Ctrl::WndShow(bool b)
197
{
198
        GuiLock __;
199
        LLOG("WndShow " << Name() << ", " << b);
200
        if(top) {
201
                if(b)
202
                        gtk_widget_show_now(top->window);
203
                else
204
                        gtk_widget_hide(top->window);
205
                StateH(SHOW);
206
        }
207
}
208

    
209
bool Ctrl::IsWndOpen() const {
210
        GuiLock __;
211
        return top && top->window && top->window->window;
212
}
213

    
214
void Ctrl::SetAlpha(byte alpha)
215
{
216
        GuiLock __;
217
}
218

    
219
Rect Ctrl::GetWorkArea() const
220
{
221
        GuiLock __;
222
        return GetWorkArea(GetRect().TopLeft());
223
}
224

    
225
void Ctrl::GetWorkArea(Array<Rect>& rc)
226
{
227
        GuiLock __;
228
        GdkScreen *s = gdk_screen_get_default();
229
        int n = gdk_screen_get_n_monitors(s);
230
        rc.Clear();
231
        Vector<int> netwa;
232
        for(int i = 0; i < n; i++) {
233
                GdkRectangle rr;
234
                Rect r;
235
#if GTK_CHECK_VERSION (3, 3, 5) // U++ does not work with gtk3 yet, but be prepared
236
                gdk_screen_get_monitor_workarea(s, i, &rr);
237
                r = RectC(r.x, r.y, r.width, r.height);
238
#else
239
                gdk_screen_get_monitor_geometry (s, i, &rr);
240
                r = RectC(rr.x, rr.y, rr.width, rr.height);
241
        #ifdef GDK_WINDOWING_X11
242
                if(i == 0)
243
                        netwa = GetPropertyInts(gdk_screen_get_root_window(gdk_screen_get_default()),
244
                                                "_NET_WORKAREA");
245
                if(netwa.GetCount())
246
                        r = r & RectC(netwa[0], netwa[1], netwa[2], netwa[3]);
247
        #endif
248
#endif
249
                rc.Add(r);
250
        }
251
}
252

    
253
Rect Ctrl::GetWorkArea(Point pt)
254
{
255
        Array<Rect> rc;
256
        GetWorkArea(rc);
257
        for(int i = 0; i < rc.GetCount(); i++)
258
                if(rc[i].Contains(pt))
259
                        return rc[i];
260
        return GetPrimaryWorkArea();
261
}
262

    
263
Rect Ctrl::GetVirtualWorkArea()
264
{
265
        Rect out = GetPrimaryWorkArea();
266
        Array<Rect> rc;
267
        GetWorkArea(rc);
268
        for(int i = 0; i < rc.GetCount(); i++)
269
                out |= rc[i];
270
        return out;
271
}
272

    
273
Rect Ctrl::GetVirtualScreenArea()
274
{
275
        GuiLock __;
276
        gint x, y, width, height;
277
        gdk_window_get_geometry(gdk_screen_get_root_window(gdk_screen_get_default()),
278
                                &x, &y, &width, &height, NULL);
279
        return RectC(x, y, width, height);
280
}
281

    
282
Rect Ctrl::GetPrimaryWorkArea()
283
{
284
        Array<Rect> rc;
285
        GetWorkArea(rc);
286
        return rc.GetCount() ? rc[0] : GetVirtualScreenArea();
287
}
288

    
289
Rect Ctrl::GetPrimaryScreenArea()
290
{
291
        return GetPrimaryWorkArea();
292
}
293

    
294
int Ctrl::GetKbdDelay()
295
{
296
        GuiLock __;
297
        return 500;
298
}
299

    
300
int Ctrl::GetKbdSpeed()
301
{
302
        GuiLock __;
303
        return 1000 / 32;
304
}
305

    
306
void Ctrl::SetWndForeground()
307
{
308
        GuiLock __;
309
        if(top)
310
                gtk_window_present(gtk());
311
}
312

    
313
bool Ctrl::IsWndForeground() const
314
{
315
        GuiLock __;
316
        LLOG("IsWndForeground");
317
        return top && gtk_window_is_active(gtk());
318
}
319

    
320
bool Ctrl::HasWndFocus() const
321
{
322
        GuiLock __;
323
        return top && gtk_window_is_active(gtk());
324
}
325

    
326
void Ctrl::FocusSync()
327
{
328
        GuiLock __;
329
        if(focusCtrlWnd && gtk_window_is_active(focusCtrlWnd->gtk()))
330
                return;
331
        Ptr<Ctrl> focus = NULL;
332
        static Ctrl *ctrl;
333
        for(int i = 0; i < wins.GetCount(); i++)
334
                if(gtk_window_is_active((GtkWindow *)wins[i].gtk)) {
335
                        focus = wins[i].ctrl;
336
                        break;
337
                }
338
        if(focus != ctrl) {
339
                if(ctrl)
340
                        ctrl->KillFocusWnd();
341
                ctrl = focus;
342
                if(ctrl)
343
                        ctrl->SetFocusWnd();
344
                SyncCaret();
345
        }
346
}
347

    
348
bool Ctrl::SetWndFocus()
349
{
350
        GuiLock __;
351
        LLOG("SetWndFocus0 " << Upp::Name(this) << ", top: " << top);
352
        if(top) {
353
                LLOG("SetWndFocus0 DO gdk: " << gdk());
354
                SetWndForeground();
355
                int t0 = msecs();
356
                while(!gtk_window_is_active(gtk()) && msecs() - t0 < 500) // Wait up to 500ms for window to become active - not ideal, but only possibility
357
                        FetchEvents(true);
358
                FocusSync();
359
        }
360
        return true;
361
}
362

    
363
void Ctrl::WndInvalidateRect(const Rect& r)
364
{
365
        GuiLock __;
366
        LLOG("WndInvalidateRect " << r);
367
        gdk_window_invalidate_rect(gdk(), GdkRect(r), TRUE);
368
//        gtk_widget_queue_draw_area(top->window, r.left, r.top, r.GetWidth(), r.GetHeight());
369
}
370

    
371
void  Ctrl::WndScrollView(const Rect& r, int dx, int dy)
372
{
373
        GuiLock __;
374
        LLOG("ScrollView " << rect);
375
        WndInvalidateRect(r);
376
}
377

    
378
bool Ctrl::SweepConfigure(bool wait)
379
{
380
        Ptr<Ctrl> this_ = this;
381
        bool r = false;
382
        FetchEvents(wait);
383
        for(int i = 0; i < Events.GetCount() && this_; i++) {
384
                Event& e = Events[i];
385
                if(e.type == GDK_CONFIGURE && this_ && top->id == e.windowid) {
386
                        Rect rect = e.value;
387
                        LLOG("SweepConfigure " << rect);
388
                        if(GetRect() != rect)
389
                                SetWndRect(rect);
390
                        r = true;
391
                        e.type = EVENT_NONE;
392
                }
393
        }
394
        return r;
395
}
396

    
397
void Ctrl::WndSetPos(const Rect& rect)
398
{
399
        LLOG("WndSetPos0 " << rect);
400
        GuiLock __;
401
        if(!top)
402
                return;
403
        Ptr<Ctrl> this_ = this;
404
        SweepConfigure(false); // Remove any previous GDK_CONFIGURE for this window
405
        if(!this_)
406
                return;
407
//        gtk_window_move(gtk(), rect.left, rect.top);
408
//        gtk_window_resize(gtk(), rect.GetWidth(), rect.GetHeight());
409
        gdk_window_move_resize(gdk(), rect.left, rect.top, rect.GetWidth(), rect.GetHeight());
410
        int t0 = msecs();
411
        do { // Wait up to 500ms for corresponding GDK_CONFIGURE to arrive
412
                if(SweepConfigure(true))
413
                        break;
414
        }
415
        while(msecs() - t0 < 500);
416
        LLOG("-- WndSetPos0 " << rect << " " << msecs() - t0);
417
}
418

    
419
void Ctrl::WndEnable(bool b)
420
{
421
        GuiLock __;
422
        if(top) {
423
                gtk_widget_set_sensitive(top->window, b);
424
                StateH(ENABLE);
425
        }
426
}
427

    
428
void Ctrl::WndUpdate(const Rect& r)
429
{
430
        GuiLock __;
431
        LLOG("WndUpdate0r " << r);
432
        WndUpdate(); // Not found a way how to update only part of window
433
}
434

    
435
void Ctrl::WndUpdate()
436
{
437
        GuiLock __;
438
        LLOG("WndUpdate0");
439
        gdk_window_process_updates(gdk(), TRUE);
440
        FetchEvents(FALSE); // Should pickup GDK_EXPOSE and repaint the window
441
        gdk_flush();
442
}
443

    
444
Rect Ctrl::GetDefaultWindowRect()
445
{
446
        GuiLock __; 
447
        Size sz = GetPrimaryWorkArea().GetSize();
448
        static int pos = min(sz.cx / 10, 50);
449
        pos += 10;
450
        int cx = sz.cx * 2 / 3;
451
        int cy = sz.cy * 2 / 3;
452
        if(pos + cx + 50 > sz.cx || pos + cy + 50 > sz.cy)
453
                pos = 0;
454
        return RectC(pos + 20, pos + 20, cx, cy);
455
}
456

    
457
ViewDraw::ViewDraw(Ctrl *ctrl)
458
{
459
        EnterGuiMutex();
460
        Ctrl *top = ctrl->GetTopCtrl();
461
        cr = gdk_cairo_create(top->gdk());
462
        Clipoff(ctrl->GetScreenView() - top->GetScreenRect().TopLeft());
463
}
464

    
465
ViewDraw::~ViewDraw()
466
{
467
        cairo_destroy(cr);
468
        LeaveGuiMutex();
469
}
470

    
471
Vector<WString> SplitCmdLine__(const char *cmd)
472
{
473
        Vector<WString> out;
474
        while(*cmd)
475
                if((byte)*cmd <= ' ')
476
                        cmd++;
477
                else if(*cmd == '\"') {
478
                        WString quoted;
479
                        while(*++cmd && (*cmd != '\"' || *++cmd == '\"'))
480
                                quoted.Cat(FromSystemCharset(String(cmd, 1)).ToWString());
481
                        out.Add(quoted);
482
                }
483
                else {
484
                        const char *begin = cmd;
485
                        while((byte)*cmd > ' ')
486
                                cmd++;
487
                        out.Add(String(begin, cmd).ToWString());
488
                }
489
        return out;
490
}
491

    
492
END_UPP_NAMESPACE
493

    
494
#endif