GtkWnd.cpp

Zbigniew Rebacz, 01/09/2014 01:06 AM

Download (10.3 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
                        gdk_flush(); // Make it visible immediately
104
                }
105
        }
106
}
107

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

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

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

    
124
#ifndef GDK_WINDOWING_X11
125

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

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

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

    
137
#endif
138

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

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

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

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

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

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

    
215
bool Ctrl::IsWndOpen() const {
216
        GuiLock __;
217
        return top && top->window && top->window->window;
218
}
219

    
220
void Ctrl::SetAlpha(byte alpha)
221
{
222
        GuiLock __;
223
}
224

    
225
Rect Ctrl::GetWorkArea() const
226
{
227
        GuiLock __;
228
        return GetWorkArea(GetRect().TopLeft());
229
}
230

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

    
259
Rect Ctrl::GetWorkArea(Point pt)
260
{
261
        Array<Rect> rc;
262
        GetWorkArea(rc);
263
        for(int i = 0; i < rc.GetCount(); i++)
264
                if(rc[i].Contains(pt))
265
                        return rc[i];
266
        return GetPrimaryWorkArea();
267
}
268

    
269
Rect Ctrl::GetVirtualWorkArea()
270
{
271
        Rect out = GetPrimaryWorkArea();
272
        Array<Rect> rc;
273
        GetWorkArea(rc);
274
        for(int i = 0; i < rc.GetCount(); i++)
275
                out |= rc[i];
276
        return out;
277
}
278

    
279
Rect Ctrl::GetVirtualScreenArea()
280
{
281
        GuiLock __;
282
        gint x, y, width, height;
283
        gdk_window_get_geometry(gdk_screen_get_root_window(gdk_screen_get_default()),
284
                                &x, &y, &width, &height, NULL);
285
        return RectC(x, y, width, height);
286
}
287

    
288
Rect Ctrl::GetPrimaryWorkArea()
289
{
290
        GuiLock __;
291
        int primary = gdk_screen_get_primary_monitor(gdk_screen_get_default());
292
        Array<Rect> rc;
293
        GetWorkArea(rc);
294
        return primary < rc.GetCount() ? rc[primary] : GetVirtualScreenArea();
295
}
296

    
297
Rect Ctrl::GetPrimaryScreenArea()
298
{
299
        return GetPrimaryWorkArea();
300
}
301

    
302
int Ctrl::GetKbdDelay()
303
{
304
        GuiLock __;
305
        return 500;
306
}
307

    
308
int Ctrl::GetKbdSpeed()
309
{
310
        GuiLock __;
311
        return 1000 / 32;
312
}
313

    
314
void Ctrl::SetWndForeground()
315
{
316
        GuiLock __;
317
        if(top)
318
                gtk_window_present(gtk());
319
}
320

    
321
bool Ctrl::IsWndForeground() const
322
{
323
        GuiLock __;
324
        LLOG("IsWndForeground");
325
        return top && gtk_window_is_active(gtk());
326
}
327

    
328
bool Ctrl::HasWndFocus() const
329
{
330
        GuiLock __;
331
        return top && gtk_window_is_active(gtk());
332
}
333

    
334
void Ctrl::FocusSync()
335
{
336
        GuiLock __;
337
        if(focusCtrlWnd && gtk_window_is_active(focusCtrlWnd->gtk()))
338
                return;
339
        Ptr<Ctrl> focus = NULL;
340
        static Ctrl *ctrl;
341
        for(int i = 0; i < wins.GetCount(); i++)
342
                if(gtk_window_is_active((GtkWindow *)wins[i].gtk)) {
343
                        focus = wins[i].ctrl;
344
                        break;
345
                }
346
        if(focus != ctrl) {
347
                if(ctrl)
348
                        ctrl->KillFocusWnd();
349
                ctrl = focus;
350
                if(ctrl)
351
                        ctrl->SetFocusWnd();
352
                SyncCaret();
353
        }
354
}
355

    
356
bool Ctrl::SetWndFocus()
357
{
358
        GuiLock __;
359
        LLOG("SetWndFocus0 " << Upp::Name(this) << ", top: " << top);
360
        if(top) {
361
                LLOG("SetWndFocus0 DO gdk: " << gdk());
362
                SetWndForeground();
363
                int t0 = msecs();
364
                while(!gtk_window_is_active(gtk()) && msecs() - t0 < 500) // Wait up to 500ms for window to become active - not ideal, but only possibility
365
                        FetchEvents(true);
366
                FocusSync();
367
        }
368
        return true;
369
}
370

    
371
void Ctrl::WndInvalidateRect(const Rect& r)
372
{
373
        GuiLock __;
374
        LLOG("WndInvalidateRect " << r);
375
        gdk_window_invalidate_rect(gdk(), GdkRect(r), TRUE);
376
//        gtk_widget_queue_draw_area(top->window, r.left, r.top, r.GetWidth(), r.GetHeight());
377
}
378

    
379
void  Ctrl::WndScrollView(const Rect& r, int dx, int dy)
380
{
381
        GuiLock __;
382
        LLOG("ScrollView " << rect);
383
        WndInvalidateRect(r);
384
}
385

    
386
bool Ctrl::SweepConfigure(bool wait)
387
{
388
        Ptr<Ctrl> this_ = this;
389
        bool r = false;
390
        FetchEvents(wait);
391
        for(int i = 0; i < Events.GetCount() && this_; i++) {
392
                Event& e = Events[i];
393
                if(e.type == GDK_CONFIGURE && this_ && top->id == e.windowid) {
394
                        Rect rect = e.value;
395
                        LLOG("SweepConfigure " << rect);
396
                        if(GetRect() != rect)
397
                                SetWndRect(rect);
398
                        r = true;
399
                        e.type = EVENT_NONE;
400
                }
401
        }
402
        return r;
403
}
404

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

    
427
void Ctrl::WndEnable(bool b)
428
{
429
        GuiLock __;
430
        if(top) {
431
                gtk_widget_set_sensitive(top->window, b);
432
                StateH(ENABLE);
433
        }
434
}
435

    
436
void Ctrl::WndUpdate(const Rect& r)
437
{
438
        GuiLock __;
439
        LLOG("WndUpdate0r " << r);
440
        WndUpdate(); // Not found a way how to update only part of window
441
}
442

    
443
void Ctrl::WndUpdate()
444
{
445
        GuiLock __;
446
        LLOG("WndUpdate0");
447
        gdk_window_process_updates(gdk(), TRUE);
448
        FetchEvents(FALSE); // Should pickup GDK_EXPOSE and repaint the window
449
        gdk_flush();
450
}
451

    
452
Rect Ctrl::GetDefaultWindowRect()
453
{
454
        GuiLock __; 
455
        Rect r  = GetPrimaryWorkArea();
456
        Size sz = r.GetSize();
457
        
458
        static int pos = min(sz.cx / 10, 50);
459
        pos += 10;
460
        int cx = sz.cx * 2 / 3;
461
        int cy = sz.cy * 2 / 3;
462
        if(pos + cx + 50 > sz.cx || pos + cy + 50 > sz.cy)
463
                pos = 0;
464
        return RectC(r.left + pos + 20, r.top + pos + 20, cx, cy);
465
}
466

    
467
ViewDraw::ViewDraw(Ctrl *ctrl)
468
{
469
        EnterGuiMutex();
470
        Ctrl *top = ctrl->GetTopCtrl();
471
        cr = gdk_cairo_create(top->gdk());
472
        Clipoff(ctrl->GetScreenView() - top->GetScreenRect().TopLeft());
473
}
474

    
475
ViewDraw::~ViewDraw()
476
{
477
        cairo_destroy(cr);
478
        LeaveGuiMutex();
479
}
480

    
481
Vector<WString> SplitCmdLine__(const char *cmd)
482
{
483
        Vector<WString> out;
484
        while(*cmd)
485
                if((byte)*cmd <= ' ')
486
                        cmd++;
487
                else if(*cmd == '\"') {
488
                        WString quoted;
489
                        while(*++cmd && (*cmd != '\"' || *++cmd == '\"'))
490
                                quoted.Cat(FromSystemCharset(String(cmd, 1)).ToWString());
491
                        out.Add(quoted);
492
                }
493
                else {
494
                        const char *begin = cmd;
495
                        while((byte)*cmd > ' ')
496
                                cmd++;
497
                        out.Add(String(begin, cmd).ToWString());
498
                }
499
        return out;
500
}
501

    
502
END_UPP_NAMESPACE
503

    
504
#endif