GtkWnd.cpp

Zbigniew Rebacz, 03/02/2014 11:38 PM

Download (10.8 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
        int primary = gdk_screen_get_primary_monitor(gdk_screen_get_default());
312
        
313
        static Array<Rect> rc;
314
        if(rc.IsEmpty())
315
                GetWorkArea(rc);
316
        return primary >= 0 && primary < rc.GetCount() ? rc[primary] : GetVirtualScreenArea();
317
}
318

    
319
Rect Ctrl::GetPrimaryScreenArea()
320
{
321
        return GetPrimaryWorkArea();
322
}
323

    
324
int Ctrl::GetKbdDelay()
325
{
326
        GuiLock __;
327
        return 500;
328
}
329

    
330
int Ctrl::GetKbdSpeed()
331
{
332
        GuiLock __;
333
        return 1000 / 32;
334
}
335

    
336
void Ctrl::SetWndForeground()
337
{
338
        GuiLock __;
339
        if(IsOpen())
340
                gtk_window_present(gtk());
341
}
342

    
343
bool Ctrl::IsWndForeground() const
344
{
345
        GuiLock __;
346
        LLOG("IsWndForeground");
347
        return IsOpen() && gtk_window_is_active(gtk());
348
}
349

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

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

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

    
393
void Ctrl::WndInvalidateRect(const Rect& r)
394
{
395
        GuiLock __;
396
        LLOG("WndInvalidateRect " << r);
397
        gdk_window_invalidate_rect(gdk(), GdkRect(r), TRUE);
398
//        gtk_widget_queue_draw_area(top->window, r.left, r.top, r.GetWidth(), r.GetHeight());
399
}
400

    
401
void  Ctrl::WndScrollView(const Rect& r, int dx, int dy)
402
{
403
        GuiLock __;
404
        LLOG("ScrollView " << rect);
405
        WndInvalidateRect(r);
406
}
407

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

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

    
449
void Ctrl::WndEnable(bool b)
450
{
451
        GuiLock __;
452
        if(IsOpen()) {
453
                gtk_widget_set_sensitive(top->window, b);
454
                StateH(ENABLE);
455
        }
456
}
457

    
458
void Ctrl::WndUpdate(const Rect& r)
459
{
460
        GuiLock __;
461
        LLOG("WndUpdate0r " << r);
462
        WndUpdate(); // Not found a way how to update only part of window
463
}
464

    
465
void Ctrl::WndUpdate()
466
{
467
        GuiLock __;
468
        LLOG("WndUpdate0");
469
        gdk_window_process_updates(gdk(), TRUE);
470
        FetchEvents(FALSE); // Should pickup GDK_EXPOSE and repaint the window
471
        gdk_flush();
472
}
473

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

    
489
ViewDraw::ViewDraw(Ctrl *ctrl)
490
{
491
        EnterGuiMutex();
492
        Ctrl *top = ctrl->GetTopCtrl();
493
        cr = gdk_cairo_create(top->gdk());
494
        Clipoff(ctrl->GetScreenView() - top->GetScreenRect().TopLeft());
495
}
496

    
497
ViewDraw::~ViewDraw()
498
{
499
        cairo_destroy(cr);
500
        LeaveGuiMutex();
501
}
502

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

    
524
END_UPP_NAMESPACE
525

    
526
#endif