GtkWnd.cpp

Zbigniew Rebacz, 03/17/2014 04:53 PM

Download (10.9 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
        LLOG("SetMouseCursor");
76
        GuiLock __;
77
        int64 id = image.GetSerialId();
78
        Ctrl *topctrl = NULL;
79
        Top *top = NULL;
80
        if(mouseCtrl)
81
                topctrl = mouseCtrl->GetTopCtrl();
82
        else
83
                topctrl = GetActiveCtrl();
84
        if(topctrl)
85
                top = topctrl->top;
86
        if(top && id != top->cursor_id) {
87
                top->cursor_id = id;
88
                int64 aux = image.GetAuxData();
89
                GdkCursor *c = NULL;
90
                if(aux)
91
                        c = gdk_cursor_new((GdkCursorType)(aux - 1));
92
                else
93
                if(IsNull(image))
94
                        c = gdk_cursor_new(GDK_BLANK_CURSOR);
95
                else {
96
                        Point p = image.GetHotSpot();
97
                        ImageGdk m;
98
                        m.Set(image);
99
                        GdkPixbuf *pb = m;
100
                        if(pb)
101
                                c = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pb, p.x, p.y);
102
                }
103
                if(c && topctrl->IsOpen()) {
104
                        gdk_window_set_cursor(topctrl->gdk(), c);
105
                        gdk_cursor_unref(c);
106
                        gdk_flush(); // Make it visible immediately
107
                }
108
        }
109
}
110

    
111
Ctrl *Ctrl::GetOwner()
112
{
113
        GuiLock __;
114
        return IsOpen() ? top->owner : NULL;
115
}
116

    
117
Ctrl *Ctrl::GetActiveCtrl()
118
{
119
        GuiLock __;
120
        if(focusCtrl)
121
                return focusCtrl->GetTopCtrl();
122
        return activeCtrl;
123
}
124

    
125
// Vector<Callback> Ctrl::hotkey;
126

    
127
#ifndef GDK_WINDOWING_X11
128

    
129
// There is no generic support in GTK for HotKey
130

    
131
int Ctrl::RegisterSystemHotKey(dword key, Callback cb)
132
{
133
        return -1;
134
}
135

    
136
void Ctrl::UnregisterSystemHotKey(int id)
137
{
138
}
139

    
140
#endif
141

    
142
void  Ctrl::AnimateCaret()
143
{
144
        GuiLock __;
145
        int v = !(((GetTickCount() - WndCaretTime) / 500) & 1);
146
        if(v != WndCaretVisible) {
147
                WndCaretVisible = v;
148
                RefreshCaret();
149
        }
150
}
151

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

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

    
177
void Ctrl::SyncCaret() {
178
        GuiLock __;
179
        if(focusCtrl != caretCtrl) {
180
                LLOG("SyncCaret DO " << Upp::Name(caretCtrl) << " -> " << Upp::Name(focusCtrl));
181
                RefreshCaret();
182
                caretCtrl = focusCtrl;
183
                RefreshCaret();
184
        }
185
}
186

    
187
Rect Ctrl::GetWndScreenRect() const
188
{
189
        GuiLock __;
190
        if(IsOpen()) {
191
                gint x, y;
192
                gdk_window_get_position(gdk(), &x, &y);
193
        #if GTK_CHECK_VERSION(2, 24, 0)
194
                gint width = gdk_window_get_width(gdk());
195
                gint height = gdk_window_get_height(gdk());
196
        #else
197
                gint width, height;
198
                gdk_drawable_get_size(gdk(), &width, &height);
199
        #endif
200
                return RectC(x, y, width, height);
201
        }
202
        return Null;
203
}
204

    
205
void Ctrl::WndShow(bool b)
206
{
207
        GuiLock __;
208
        LLOG("WndShow " << Name() << ", " << b);
209
        if(IsOpen()) {
210
                if(b)
211
                        gtk_widget_show_now(top->window);
212
                else
213
                        gtk_widget_hide(top->window);
214
                StateH(SHOW);
215
        }
216
}
217

    
218
bool Ctrl::IsWndOpen() const {
219
        GuiLock __;
220
        return top && top->window && top->window->window;
221
}
222

    
223
void Ctrl::SetAlpha(byte alpha)
224
{
225
        GuiLock __;
226
}
227

    
228
Rect Ctrl::GetWorkArea() const
229
{
230
        GuiLock __;
231
        static Array<Rect> rc;
232
        if(rc.IsEmpty()) 
233
                GetWorkArea(rc);
234
        
235
        Point pt = GetMousePos();
236
        for (int i = 0; i < rc.GetCount(); i++)
237
                if(rc[i].Contains(pt))
238
                        return rc[i];
239
        return GetPrimaryWorkArea();
240
}
241

    
242
void Ctrl::GetWorkArea(Array<Rect>& rc)
243
{
244
        GuiLock __;
245
        GdkScreen *s = gdk_screen_get_default();
246
        int n = gdk_screen_get_n_monitors(s);
247
        rc.Clear();
248
        Vector<int> netwa;
249
        for(int i = 0; i < n; i++) {
250
                GdkRectangle rr;
251
                Rect r;
252
#if GTK_CHECK_VERSION (3, 3, 5) // U++ does not work with gtk3 yet, but be prepared
253
                gdk_screen_get_monitor_workarea(s, i, &rr);
254
                r = RectC(r.x, r.y, r.width, r.height);
255
#else
256
                gdk_screen_get_monitor_geometry (s, i, &rr);
257
                r = RectC(rr.x, rr.y, rr.width, rr.height);
258
        #ifdef GDK_WINDOWING_X11
259
                if(i == 0)
260
                        netwa = GetPropertyInts(gdk_screen_get_root_window(gdk_screen_get_default()),
261
                                                "_NET_WORKAREA");
262
                if(netwa.GetCount())
263
                        r = r & RectC(netwa[0], netwa[1], netwa[2], netwa[3]);
264
        #endif
265
#endif
266
                rc.Add(r);
267
        }
268
}
269

    
270
Rect Ctrl::GetWorkArea(Point pt)
271
{
272
        static Array<Rect> rc;
273
        if(rc.IsEmpty())
274
                GetWorkArea(rc);
275
        for(int i = 0; i < rc.GetCount(); i++)
276
                if(rc[i].Contains(pt))
277
                        return rc[i];
278
        return GetPrimaryWorkArea();
279
}
280

    
281
Rect Ctrl::GetVirtualWorkArea()
282
{
283
        GuiLock __;
284
        static Rect r;
285
        if(r.right == 0) {
286
                r = GetPrimaryWorkArea();
287
                Array<Rect> rc;
288
                GetWorkArea(rc);
289
                for(int i = 0; i < rc.GetCount(); i++)
290
                        r |= rc[i];
291
        }
292
        return r;
293
}
294

    
295
Rect Ctrl::GetVirtualScreenArea()
296
{
297
        GuiLock __;
298
        static Rect r;
299
        if(r.right == 0) {
300
                gint x, y, width, height;
301
                gdk_window_get_geometry(gdk_screen_get_root_window(gdk_screen_get_default()),
302
                                        &x, &y, &width, &height, NULL);
303
            r = RectC(x, y, width, height);
304
        }
305
        return r;
306
}
307

    
308
Rect Ctrl::GetPrimaryWorkArea()
309
{
310
        GuiLock __;
311
        static Rect r;
312
        if (r.right == 0) {
313
                Array<Rect> rc;
314
                GetWorkArea(rc);
315
#if GTK_CHECK_VERSION(2, 20, 0)
316
                int primary = gdk_screen_get_primary_monitor(gdk_screen_get_default());
317
#else
318
                int primary = 0;
319
#endif
320
                primary >= 0 && primary < rc.GetCount() ? r = rc[primary] : r = GetVirtualScreenArea();
321
        }
322
        return r;
323
}
324

    
325
Rect Ctrl::GetPrimaryScreenArea()
326
{
327
        return GetPrimaryWorkArea();
328
}
329

    
330
int Ctrl::GetKbdDelay()
331
{
332
        GuiLock __;
333
        return 500;
334
}
335

    
336
int Ctrl::GetKbdSpeed()
337
{
338
        GuiLock __;
339
        return 1000 / 32;
340
}
341

    
342
void Ctrl::SetWndForeground()
343
{
344
        GuiLock __;
345
        if(IsOpen())
346
                gtk_window_present(gtk());
347
}
348

    
349
bool Ctrl::IsWndForeground() const
350
{
351
        GuiLock __;
352
        LLOG("IsWndForeground");
353
        return IsOpen() && gtk_window_is_active(gtk());
354
}
355

    
356
bool Ctrl::HasWndFocus() const
357
{
358
        GuiLock __;
359
        return IsOpen() && gtk_window_is_active(gtk());
360
}
361

    
362
void Ctrl::FocusSync()
363
{
364
        GuiLock __;
365
        if(focusCtrlWnd && focusCtrlWnd->IsOpen() && gtk_window_is_active(focusCtrlWnd->gtk()))
366
                return;
367
        Ptr<Ctrl> focus = NULL;
368
        static Ptr<Ctrl> ctrl;
369
        for(int i = 0; i < wins.GetCount(); i++)
370
                if(gtk_window_is_active((GtkWindow *)wins[i].gtk)) {
371
                        focus = wins[i].ctrl;
372
                        break;
373
                }
374
        if(focus != ctrl) {
375
                if(ctrl)
376
                        ctrl->KillFocusWnd();
377
                ctrl = focus;
378
                if(ctrl)
379
                        ctrl->SetFocusWnd();
380
                SyncCaret();
381
        }
382
}
383

    
384
bool Ctrl::SetWndFocus()
385
{
386
        GuiLock __;
387
        LLOG("SetWndFocus0 " << Upp::Name(this) << ", top: " << top);
388
        if(top) {
389
                LLOG("SetWndFocus0 DO gdk: " << gdk());
390
                SetWndForeground();
391
                int t0 = msecs();
392
                while(!gtk_window_is_active(gtk()) && msecs() - t0 < 500) // Wait up to 500ms for window to become active - not ideal, but only possibility
393
                        FetchEvents(true);
394
                FocusSync();
395
        }
396
        return true;
397
}
398

    
399
void Ctrl::WndInvalidateRect(const Rect& r)
400
{
401
        GuiLock __;
402
        LLOG("WndInvalidateRect " << r);
403
        gdk_window_invalidate_rect(gdk(), GdkRect(r), TRUE);
404
//        gtk_widget_queue_draw_area(top->window, r.left, r.top, r.GetWidth(), r.GetHeight());
405
}
406

    
407
void  Ctrl::WndScrollView(const Rect& r, int dx, int dy)
408
{
409
        GuiLock __;
410
        LLOG("ScrollView " << rect);
411
        WndInvalidateRect(r);
412
}
413

    
414
bool Ctrl::SweepConfigure(bool wait)
415
{
416
        Ptr<Ctrl> this_ = this;
417
        bool r = false;
418
        FetchEvents(wait);
419
        for(int i = 0; i < Events.GetCount() && this_; i++) {
420
                Event& e = Events[i];
421
                if(e.type == GDK_CONFIGURE && this_ && top->id == e.windowid) {
422
                        Rect rect = e.value;
423
                        LLOG("SweepConfigure " << rect);
424
                        if(GetRect() != rect)
425
                                SetWndRect(rect);
426
                        r = true;
427
                        e.type = EVENT_NONE;
428
                }
429
        }
430
        return r;
431
}
432

    
433
void Ctrl::WndSetPos(const Rect& rect)
434
{
435
        LLOG("WndSetPos0 " << rect);
436
        GuiLock __;
437
        if(!IsOpen())
438
                return;
439
        Ptr<Ctrl> this_ = this;
440
        SweepConfigure(false); // Remove any previous GDK_CONFIGURE for this window
441
        if(!this_ || !IsOpen())
442
                return;
443
//        gtk_window_move(gtk(), rect.left, rect.top);
444
//        gtk_window_resize(gtk(), rect.GetWidth(), rect.GetHeight());
445
        gdk_window_move_resize(gdk(), rect.left, rect.top, rect.GetWidth(), rect.GetHeight());
446
        int t0 = msecs();
447
        do { // Wait up to 500ms for corresponding GDK_CONFIGURE to arrive
448
                if(SweepConfigure(true))
449
                        break;
450
        }
451
        while(msecs() - t0 < 500);
452
        LLOG("-- WndSetPos0 " << rect << " " << msecs() - t0);
453
}
454

    
455
void Ctrl::WndEnable(bool b)
456
{
457
        GuiLock __;
458
        if(IsOpen()) {
459
                gtk_widget_set_sensitive(top->window, b);
460
                StateH(ENABLE);
461
        }
462
}
463

    
464
void Ctrl::WndUpdate(const Rect& r)
465
{
466
        GuiLock __;
467
        LLOG("WndUpdate0r " << r);
468
        WndUpdate(); // Not found a way how to update only part of window
469
}
470

    
471
void Ctrl::WndUpdate()
472
{
473
        GuiLock __;
474
        LLOG("WndUpdate0");
475
        gdk_window_process_updates(gdk(), TRUE);
476
        FetchEvents(FALSE); // Should pickup GDK_EXPOSE and repaint the window
477
        gdk_flush();
478
}
479

    
480
Rect Ctrl::GetDefaultWindowRect()
481
{
482
        GuiLock __; 
483
        Rect r  = GetPrimaryWorkArea();
484
        Size sz = r.GetSize();
485
        
486
        static int pos = min(sz.cx / 10, 50);
487
        pos += 10;
488
        int cx = sz.cx * 2 / 3;
489
        int cy = sz.cy * 2 / 3;
490
        if(pos + cx + 50 > sz.cx || pos + cy + 50 > sz.cy)
491
                pos = 0;
492
        return RectC(r.left + pos + 20, r.top + pos + 20, cx, cy);
493
}
494

    
495
ViewDraw::ViewDraw(Ctrl *ctrl)
496
{
497
        EnterGuiMutex();
498
        Ctrl *top = ctrl->GetTopCtrl();
499
        cr = gdk_cairo_create(top->gdk());
500
        Clipoff(ctrl->GetScreenView() - top->GetScreenRect().TopLeft());
501
}
502

    
503
ViewDraw::~ViewDraw()
504
{
505
        cairo_destroy(cr);
506
        LeaveGuiMutex();
507
}
508

    
509
Vector<WString> SplitCmdLine__(const char *cmd)
510
{
511
        Vector<WString> out;
512
        while(*cmd)
513
                if((byte)*cmd <= ' ')
514
                        cmd++;
515
                else if(*cmd == '\"') {
516
                        WString quoted;
517
                        while(*++cmd && (*cmd != '\"' || *++cmd == '\"'))
518
                                quoted.Cat(FromSystemCharset(String(cmd, 1)).ToWString());
519
                        out.Add(quoted);
520
                }
521
                else {
522
                        const char *begin = cmd;
523
                        while((byte)*cmd > ' ')
524
                                cmd++;
525
                        out.Add(String(begin, cmd).ToWString());
526
                }
527
        return out;
528
}
529

    
530
END_UPP_NAMESPACE
531

    
532
#endif