~ubuntu-branches/ubuntu/wily/geany/wily

« back to all changes in this revision

Viewing changes to scintilla/PlatGTK.cxx

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2011-12-10 07:43:26 UTC
  • mfrom: (3.3.7 sid)
  • Revision ID: package-import@ubuntu.com-20111210074326-s8yqbew5i20h33tf
Tags: 0.21-1ubuntu1
* Merge from Debian Unstable, remaining changes:
  - debian/patches/20_use_evince_viewer.patch:
     + use evince as viewer for pdf and dvi files
  - debian/patches/20_use_x_terminal_emulator.patch:
     + use x-terminal-emulator as terminal
  - debian/control
     + Add breaks on geany-plugins-common << 0.20
* Also fixes bugs:
  - Filter for MATLAB/Octave files filters everythign (LP: 885505)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Scintilla source code edit control
2
 
// PlatGTK.cxx - implementation of platform facilities on GTK+/Linux
3
 
// Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
4
 
// The License.txt file describes the conditions under which this software may be distributed.
5
 
 
6
 
#include <string.h>
7
 
#include <stdio.h>
8
 
#include <stdlib.h>
9
 
#include <stddef.h>
10
 
 
11
 
#include <glib.h>
12
 
#include <gmodule.h>
13
 
#include <gdk/gdk.h>
14
 
#include <gtk/gtk.h>
15
 
#include <gdk/gdkkeysyms.h>
16
 
 
17
 
#include "Platform.h"
18
 
 
19
 
#include "Scintilla.h"
20
 
#include "ScintillaWidget.h"
21
 
#include "UniConversion.h"
22
 
#include "XPM.h"
23
 
 
24
 
/* GLIB must be compiled with thread support, otherwise we
25
 
   will bail on trying to use locks, and that could lead to
26
 
   problems for someone.  `glib-config --libs gthread` needs
27
 
   to be used to get the glib libraries for linking, otherwise
28
 
   g_thread_init will fail */
29
 
#define USE_LOCK defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE)
30
 
/* Use fast way of getting char data on win32 to work around problems
31
 
   with gdk_string_extents. */
32
 
#define FAST_WAY
33
 
 
34
 
#include "Converter.h"
35
 
 
36
 
#ifdef _MSC_VER
37
 
// Ignore unreferenced local functions in GTK+ headers
38
 
#pragma warning(disable: 4505)
39
 
#endif
40
 
 
41
 
#ifdef SCI_NAMESPACE
42
 
using namespace Scintilla;
43
 
#endif
44
 
 
45
 
enum encodingType { singleByte, UTF8, dbcs};
46
 
 
47
 
struct LOGFONT {
48
 
        int size;
49
 
        bool bold;
50
 
        bool italic;
51
 
        int characterSet;
52
 
        char faceName[300];
53
 
};
54
 
 
55
 
#if USE_LOCK
56
 
static GMutex *fontMutex = NULL;
57
 
 
58
 
static void InitializeGLIBThreads() {
59
 
        if (!g_thread_supported()) {
60
 
                g_thread_init(NULL);
61
 
        }
62
 
}
63
 
#endif
64
 
 
65
 
static void FontMutexAllocate() {
66
 
#if USE_LOCK
67
 
        if (!fontMutex) {
68
 
                InitializeGLIBThreads();
69
 
                fontMutex = g_mutex_new();
70
 
        }
71
 
#endif
72
 
}
73
 
 
74
 
static void FontMutexFree() {
75
 
#if USE_LOCK
76
 
        if (fontMutex) {
77
 
                g_mutex_free(fontMutex);
78
 
                fontMutex = NULL;
79
 
        }
80
 
#endif
81
 
}
82
 
 
83
 
static void FontMutexLock() {
84
 
#if USE_LOCK
85
 
        g_mutex_lock(fontMutex);
86
 
#endif
87
 
}
88
 
 
89
 
static void FontMutexUnlock() {
90
 
#if USE_LOCK
91
 
        if (fontMutex) {
92
 
                g_mutex_unlock(fontMutex);
93
 
        }
94
 
#endif
95
 
}
96
 
 
97
 
// On GTK+ 1.x holds a GdkFont* but on GTK+ 2.x can hold a GdkFont* or a
98
 
// PangoFontDescription*.
99
 
class FontHandle {
100
 
        int width[128];
101
 
        encodingType et;
102
 
public:
103
 
        int ascent;
104
 
        GdkFont *pfont;
105
 
        PangoFontDescription *pfd;
106
 
        int characterSet;
107
 
        FontHandle(GdkFont *pfont_) {
108
 
                et = singleByte;
109
 
                ascent = 0;
110
 
                pfont = pfont_;
111
 
                pfd = 0;
112
 
                characterSet = -1;
113
 
                ResetWidths(et);
114
 
        }
115
 
        FontHandle(PangoFontDescription *pfd_, int characterSet_) {
116
 
                et = singleByte;
117
 
                ascent = 0;
118
 
                pfont = 0;
119
 
                pfd = pfd_;
120
 
                characterSet = characterSet_;
121
 
                ResetWidths(et);
122
 
        }
123
 
        ~FontHandle() {
124
 
                if (pfont)
125
 
                        gdk_font_unref(pfont);
126
 
                pfont = 0;
127
 
                if (pfd)
128
 
                        pango_font_description_free(pfd);
129
 
                pfd = 0;
130
 
        }
131
 
        void ResetWidths(encodingType et_) {
132
 
                et = et_;
133
 
                for (int i=0; i<=127; i++) {
134
 
                        width[i] = 0;
135
 
                }
136
 
        }
137
 
        int CharWidth(unsigned char ch, encodingType et_) {
138
 
                int w = 0;
139
 
                FontMutexLock();
140
 
                if ((ch <= 127) && (et == et_)) {
141
 
                        w = width[ch];
142
 
                }
143
 
                FontMutexUnlock();
144
 
                return w;
145
 
        }
146
 
        void SetCharWidth(unsigned char ch, int w, encodingType et_) {
147
 
                if (ch <= 127) {
148
 
                        FontMutexLock();
149
 
                        if (et != et_) {
150
 
                                ResetWidths(et_);
151
 
                        }
152
 
                        width[ch] = w;
153
 
                        FontMutexUnlock();
154
 
                }
155
 
        }
156
 
};
157
 
 
158
 
// X has a 16 bit coordinate space, so stop drawing here to avoid wrapping
159
 
static const int maxCoordinate = 32000;
160
 
 
161
 
static FontHandle *PFont(Font &f) {
162
 
        return reinterpret_cast<FontHandle *>(f.GetID());
163
 
}
164
 
 
165
 
static GtkWidget *PWidget(WindowID wid) {
166
 
        return reinterpret_cast<GtkWidget *>(wid);
167
 
}
168
 
 
169
 
static GtkWidget *PWidget(Window &w) {
170
 
        return PWidget(w.GetID());
171
 
}
172
 
 
173
 
Point Point::FromLong(long lpoint) {
174
 
        return Point(
175
 
                   Platform::LowShortFromLong(lpoint),
176
 
                   Platform::HighShortFromLong(lpoint));
177
 
}
178
 
 
179
 
Palette::Palette() {
180
 
        used = 0;
181
 
        allowRealization = false;
182
 
        allocatedPalette = 0;
183
 
        allocatedLen = 0;
184
 
        size = 100;
185
 
        entries = new ColourPair[size];
186
 
}
187
 
 
188
 
Palette::~Palette() {
189
 
        Release();
190
 
        delete []entries;
191
 
        entries = 0;
192
 
}
193
 
 
194
 
void Palette::Release() {
195
 
        used = 0;
196
 
        delete [](reinterpret_cast<GdkColor *>(allocatedPalette));
197
 
        allocatedPalette = 0;
198
 
        allocatedLen = 0;
199
 
        delete []entries;
200
 
        size = 100;
201
 
        entries = new ColourPair[size];
202
 
}
203
 
 
204
 
// This method either adds a colour to the list of wanted colours (want==true)
205
 
// or retrieves the allocated colour back to the ColourPair.
206
 
// This is one method to make it easier to keep the code for wanting and retrieving in sync.
207
 
void Palette::WantFind(ColourPair &cp, bool want) {
208
 
        if (want) {
209
 
                for (int i=0; i < used; i++) {
210
 
                        if (entries[i].desired == cp.desired)
211
 
                                return;
212
 
                }
213
 
 
214
 
                if (used >= size) {
215
 
                        int sizeNew = size * 2;
216
 
                        ColourPair *entriesNew = new ColourPair[sizeNew];
217
 
                        for (int j=0; j<size; j++) {
218
 
                                entriesNew[j] = entries[j];
219
 
                        }
220
 
                        delete []entries;
221
 
                        entries = entriesNew;
222
 
                        size = sizeNew;
223
 
                }
224
 
 
225
 
                entries[used].desired = cp.desired;
226
 
                entries[used].allocated.Set(cp.desired.AsLong());
227
 
                used++;
228
 
        } else {
229
 
                for (int i=0; i < used; i++) {
230
 
                        if (entries[i].desired == cp.desired) {
231
 
                                cp.allocated = entries[i].allocated;
232
 
                                return;
233
 
                        }
234
 
                }
235
 
                cp.allocated.Set(cp.desired.AsLong());
236
 
        }
237
 
}
238
 
 
239
 
void Palette::Allocate(Window &w) {
240
 
        if (allocatedPalette) {
241
 
                gdk_colormap_free_colors(gtk_widget_get_colormap(PWidget(w)),
242
 
                                         reinterpret_cast<GdkColor *>(allocatedPalette),
243
 
                                         allocatedLen);
244
 
                delete [](reinterpret_cast<GdkColor *>(allocatedPalette));
245
 
                allocatedPalette = 0;
246
 
                allocatedLen = 0;
247
 
        }
248
 
        GdkColor *paletteNew = new GdkColor[used];
249
 
        allocatedPalette = paletteNew;
250
 
        gboolean *successPalette = new gboolean[used];
251
 
        if (paletteNew) {
252
 
                allocatedLen = used;
253
 
                int iPal = 0;
254
 
                for (iPal = 0; iPal < used; iPal++) {
255
 
                        paletteNew[iPal].red = entries[iPal].desired.GetRed() * (65535 / 255);
256
 
                        paletteNew[iPal].green = entries[iPal].desired.GetGreen() * (65535 / 255);
257
 
                        paletteNew[iPal].blue = entries[iPal].desired.GetBlue() * (65535 / 255);
258
 
                        paletteNew[iPal].pixel = entries[iPal].desired.AsLong();
259
 
                }
260
 
                gdk_colormap_alloc_colors(gtk_widget_get_colormap(PWidget(w)),
261
 
                                          paletteNew, allocatedLen, FALSE, TRUE,
262
 
                                          successPalette);
263
 
                for (iPal = 0; iPal < used; iPal++) {
264
 
                        entries[iPal].allocated.Set(paletteNew[iPal].pixel);
265
 
                }
266
 
        }
267
 
        delete []successPalette;
268
 
}
269
 
 
270
 
static const char *CharacterSetName(int characterSet) {
271
 
        switch (characterSet) {
272
 
        case SC_CHARSET_ANSI:
273
 
                return "iso8859-*";
274
 
        case SC_CHARSET_DEFAULT:
275
 
                return "iso8859-*";
276
 
        case SC_CHARSET_BALTIC:
277
 
                return "iso8859-13";
278
 
        case SC_CHARSET_CHINESEBIG5:
279
 
                return "*-*";
280
 
        case SC_CHARSET_EASTEUROPE:
281
 
                return "*-2";
282
 
        case SC_CHARSET_GB2312:
283
 
                return "gb2312.1980-*";
284
 
        case SC_CHARSET_GREEK:
285
 
                return "*-7";
286
 
        case SC_CHARSET_HANGUL:
287
 
                return "ksc5601.1987-*";
288
 
        case SC_CHARSET_MAC:
289
 
                return "*-*";
290
 
        case SC_CHARSET_OEM:
291
 
                return "*-*";
292
 
        case SC_CHARSET_RUSSIAN:
293
 
                return "*-r";
294
 
        case SC_CHARSET_CYRILLIC:
295
 
                return "*-cp1251";
296
 
        case SC_CHARSET_SHIFTJIS:
297
 
                return "jisx0208.1983-*";
298
 
        case SC_CHARSET_SYMBOL:
299
 
                return "*-*";
300
 
        case SC_CHARSET_TURKISH:
301
 
                return "*-9";
302
 
        case SC_CHARSET_JOHAB:
303
 
                return "*-*";
304
 
        case SC_CHARSET_HEBREW:
305
 
                return "*-8";
306
 
        case SC_CHARSET_ARABIC:
307
 
                return "*-6";
308
 
        case SC_CHARSET_VIETNAMESE:
309
 
                return "*-*";
310
 
        case SC_CHARSET_THAI:
311
 
                return "iso8859-11";
312
 
        case SC_CHARSET_8859_15:
313
 
                return "iso8859-15";
314
 
        default:
315
 
                return "*-*";
316
 
        }
317
 
}
318
 
 
319
 
static bool IsDBCSCharacterSet(int characterSet) {
320
 
        switch (characterSet) {
321
 
        case SC_CHARSET_GB2312:
322
 
        case SC_CHARSET_HANGUL:
323
 
        case SC_CHARSET_SHIFTJIS:
324
 
        case SC_CHARSET_CHINESEBIG5:
325
 
                return true;
326
 
        default:
327
 
                return false;
328
 
        }
329
 
}
330
 
 
331
 
static void GenerateFontSpecStrings(const char *fontName, int characterSet,
332
 
                                    char *foundary, int foundary_len,
333
 
                                    char *faceName, int faceName_len,
334
 
                                    char *charset, int charset_len) {
335
 
        // supported font strings include:
336
 
        // foundary-fontface-isoxxx-x
337
 
        // fontface-isoxxx-x
338
 
        // foundary-fontface
339
 
        // fontface
340
 
        if (strchr(fontName, '-')) {
341
 
                char tmp[300];
342
 
                char *d1 = NULL, *d2 = NULL, *d3 = NULL;
343
 
                strncpy(tmp, fontName, sizeof(tmp) - 1);
344
 
                tmp[sizeof(tmp) - 1] = '\0';
345
 
                d1 = strchr(tmp, '-');
346
 
                // we know the first dash exists
347
 
                d2 = strchr(d1 + 1, '-');
348
 
                if (d2)
349
 
                        d3 = strchr(d2 + 1, '-');
350
 
                if (d3 && d2) {
351
 
                        // foundary-fontface-isoxxx-x
352
 
                        *d2 = '\0';
353
 
                        foundary[0] = '-';
354
 
                        foundary[1] = '\0';
355
 
                        strncpy(faceName, tmp, foundary_len - 1);
356
 
                        strncpy(charset, d2 + 1, charset_len - 1);
357
 
                } else if (d2) {
358
 
                        // fontface-isoxxx-x
359
 
                        *d1 = '\0';
360
 
                        strcpy(foundary, "-*-");
361
 
                        strncpy(faceName, tmp, faceName_len - 1);
362
 
                        strncpy(charset, d1 + 1, charset_len - 1);
363
 
                } else {
364
 
                        // foundary-fontface
365
 
                        foundary[0] = '-';
366
 
                        foundary[1] = '\0';
367
 
                        strncpy(faceName, tmp, faceName_len - 1);
368
 
                        strncpy(charset, CharacterSetName(characterSet), charset_len - 1);
369
 
                }
370
 
        } else {
371
 
                strncpy(foundary, "-*-", foundary_len);
372
 
                strncpy(faceName, fontName, faceName_len - 1);
373
 
                strncpy(charset, CharacterSetName(characterSet), charset_len - 1);
374
 
        }
375
 
}
376
 
 
377
 
static void SetLogFont(LOGFONT &lf, const char *faceName, int characterSet, int size, bool bold, bool italic) {
378
 
        memset(&lf, 0, sizeof(lf));
379
 
        lf.size = size;
380
 
        lf.bold = bold;
381
 
        lf.italic = italic;
382
 
        lf.characterSet = characterSet;
383
 
        strncpy(lf.faceName, faceName, sizeof(lf.faceName) - 1);
384
 
}
385
 
 
386
 
/**
387
 
 * Create a hash from the parameters for a font to allow easy checking for identity.
388
 
 * If one font is the same as another, its hash will be the same, but if the hash is the
389
 
 * same then they may still be different.
390
 
 */
391
 
static int HashFont(const char *faceName, int characterSet, int size, bool bold, bool italic) {
392
 
        return
393
 
            size ^
394
 
            (characterSet << 10) ^
395
 
            (bold ? 0x10000000 : 0) ^
396
 
            (italic ? 0x20000000 : 0) ^
397
 
            faceName[0];
398
 
}
399
 
 
400
 
class FontCached : Font {
401
 
        FontCached *next;
402
 
        int usage;
403
 
        LOGFONT lf;
404
 
        int hash;
405
 
        FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_);
406
 
        ~FontCached() {}
407
 
        bool SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_);
408
 
        virtual void Release();
409
 
        static FontID CreateNewFont(const char *fontName, int characterSet,
410
 
                                    int size, bool bold, bool italic);
411
 
        static FontCached *first;
412
 
public:
413
 
        static FontID FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_);
414
 
        static void ReleaseId(FontID fid_);
415
 
};
416
 
 
417
 
FontCached *FontCached::first = 0;
418
 
 
419
 
FontCached::FontCached(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_) :
420
 
next(0), usage(0), hash(0) {
421
 
        ::SetLogFont(lf, faceName_, characterSet_, size_, bold_, italic_);
422
 
        hash = HashFont(faceName_, characterSet_, size_, bold_, italic_);
423
 
        fid = CreateNewFont(faceName_, characterSet_, size_, bold_, italic_);
424
 
        usage = 1;
425
 
}
426
 
 
427
 
bool FontCached::SameAs(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_) {
428
 
        return
429
 
            lf.size == size_ &&
430
 
            lf.bold == bold_ &&
431
 
            lf.italic == italic_ &&
432
 
            lf.characterSet == characterSet_ &&
433
 
            0 == strcmp(lf.faceName, faceName_);
434
 
}
435
 
 
436
 
void FontCached::Release() {
437
 
        if (fid)
438
 
                delete PFont(*this);
439
 
        fid = 0;
440
 
}
441
 
 
442
 
FontID FontCached::FindOrCreate(const char *faceName_, int characterSet_, int size_, bool bold_, bool italic_) {
443
 
        FontID ret = 0;
444
 
        FontMutexLock();
445
 
        int hashFind = HashFont(faceName_, characterSet_, size_, bold_, italic_);
446
 
        for (FontCached *cur = first; cur; cur = cur->next) {
447
 
                if ((cur->hash == hashFind) &&
448
 
                        cur->SameAs(faceName_, characterSet_, size_, bold_, italic_)) {
449
 
                        cur->usage++;
450
 
                        ret = cur->fid;
451
 
                }
452
 
        }
453
 
        if (ret == 0) {
454
 
                FontCached *fc = new FontCached(faceName_, characterSet_, size_, bold_, italic_);
455
 
                if (fc) {
456
 
                        fc->next = first;
457
 
                        first = fc;
458
 
                        ret = fc->fid;
459
 
                }
460
 
        }
461
 
        FontMutexUnlock();
462
 
        return ret;
463
 
}
464
 
 
465
 
void FontCached::ReleaseId(FontID fid_) {
466
 
        FontMutexLock();
467
 
        FontCached **pcur = &first;
468
 
        for (FontCached *cur = first; cur; cur = cur->next) {
469
 
                if (cur->fid == fid_) {
470
 
                        cur->usage--;
471
 
                        if (cur->usage == 0) {
472
 
                                *pcur = cur->next;
473
 
                                cur->Release();
474
 
                                cur->next = 0;
475
 
                                delete cur;
476
 
                        }
477
 
                        break;
478
 
                }
479
 
                pcur = &cur->next;
480
 
        }
481
 
        FontMutexUnlock();
482
 
}
483
 
 
484
 
static GdkFont *LoadFontOrSet(const char *fontspec, int characterSet) {
485
 
        if (IsDBCSCharacterSet(characterSet)) {
486
 
                return gdk_fontset_load(fontspec);
487
 
        } else {
488
 
                return gdk_font_load(fontspec);
489
 
        }
490
 
}
491
 
 
492
 
FontID FontCached::CreateNewFont(const char *fontName, int characterSet,
493
 
                                 int size, bool bold, bool italic) {
494
 
        char fontset[1024];
495
 
        char fontspec[300];
496
 
        char foundary[50];
497
 
        char faceName[100];
498
 
        char charset[50];
499
 
        fontset[0] = '\0';
500
 
        fontspec[0] = '\0';
501
 
        foundary[0] = '\0';
502
 
        faceName[0] = '\0';
503
 
        charset[0] = '\0';
504
 
 
505
 
        if (fontName[0] == '!') {
506
 
                PangoFontDescription *pfd = pango_font_description_new();
507
 
                if (pfd) {
508
 
                        pango_font_description_set_family(pfd, fontName+1);
509
 
                        pango_font_description_set_size(pfd, size * PANGO_SCALE);
510
 
                        pango_font_description_set_weight(pfd, bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
511
 
                        pango_font_description_set_style(pfd, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
512
 
                        return new FontHandle(pfd, characterSet);
513
 
                }
514
 
        }
515
 
 
516
 
        GdkFont *newid = 0;
517
 
        // If name of the font begins with a '-', assume, that it is
518
 
        // a full fontspec.
519
 
        if (fontName[0] == '-') {
520
 
                if (strchr(fontName, ',') || IsDBCSCharacterSet(characterSet)) {
521
 
                        newid = gdk_fontset_load(fontName);
522
 
                } else {
523
 
                        newid = gdk_font_load(fontName);
524
 
                }
525
 
                if (!newid) {
526
 
                        // Font not available so substitute a reasonable code font
527
 
                        // iso8859 appears to only allow western characters.
528
 
                        newid = LoadFontOrSet("-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-*",
529
 
                                characterSet);
530
 
                }
531
 
                return new FontHandle(newid);
532
 
        }
533
 
 
534
 
        // it's not a full fontspec, build one.
535
 
 
536
 
        // This supports creating a FONT_SET
537
 
        // in a method that allows us to also set size, slant and
538
 
        // weight for the fontset.  The expected input is multiple
539
 
        // partial fontspecs seperated by comma
540
 
        // eg. adobe-courier-iso10646-1,*-courier-iso10646-1,*-*-*-*
541
 
        if (strchr(fontName, ',')) {
542
 
                // build a fontspec and use gdk_fontset_load
543
 
                int remaining = sizeof(fontset);
544
 
                char fontNameCopy[1024];
545
 
                strncpy(fontNameCopy, fontName, sizeof(fontNameCopy) - 1);
546
 
                char *fn = fontNameCopy;
547
 
                char *fp = strchr(fn, ',');
548
 
                for (;;) {
549
 
                        const char *spec = "%s%s%s%s-*-*-*-%0d-*-*-*-*-%s";
550
 
                        if (fontset[0] != '\0') {
551
 
                                // if this is not the first font in the list,
552
 
                                // append a comma seperator
553
 
                                spec = ",%s%s%s%s-*-*-*-%0d-*-*-*-*-%s";
554
 
                        }
555
 
 
556
 
                        if (fp)
557
 
                                *fp = '\0'; // nullify the comma
558
 
                        GenerateFontSpecStrings(fn, characterSet,
559
 
                                                foundary, sizeof(foundary),
560
 
                                                faceName, sizeof(faceName),
561
 
                                                charset, sizeof(charset));
562
 
 
563
 
                        g_snprintf(fontspec,
564
 
                                 sizeof(fontspec) - 1,
565
 
                                 spec,
566
 
                                 foundary, faceName,
567
 
                                 bold ? "-bold" : "-medium",
568
 
                                 italic ? "-i" : "-r",
569
 
                                 size * 10,
570
 
                                 charset);
571
 
 
572
 
                        // if this is the first font in the list, and
573
 
                        // we are doing italic, add an oblique font
574
 
                        // to the list
575
 
                        if (italic && fontset[0] == '\0') {
576
 
                                strncat(fontset, fontspec, remaining - 1);
577
 
                                remaining -= strlen(fontset);
578
 
 
579
 
                                g_snprintf(fontspec,
580
 
                                         sizeof(fontspec) - 1,
581
 
                                         ",%s%s%s-o-*-*-*-%0d-*-*-*-*-%s",
582
 
                                         foundary, faceName,
583
 
                                         bold ? "-bold" : "-medium",
584
 
                                         size * 10,
585
 
                                         charset);
586
 
                        }
587
 
 
588
 
                        strncat(fontset, fontspec, remaining - 1);
589
 
                        remaining -= strlen(fontset);
590
 
 
591
 
                        if (!fp)
592
 
                                break;
593
 
 
594
 
                        fn = fp + 1;
595
 
                        fp = strchr(fn, ',');
596
 
                }
597
 
 
598
 
                newid = gdk_fontset_load(fontset);
599
 
                if (newid)
600
 
                        return new FontHandle(newid);
601
 
 
602
 
                // if fontset load failed, fall through, we'll use
603
 
                // the last font entry and continue to try and
604
 
                // get something that matches
605
 
        }
606
 
 
607
 
        // single fontspec support
608
 
 
609
 
        GenerateFontSpecStrings(fontName, characterSet,
610
 
                                foundary, sizeof(foundary),
611
 
                                faceName, sizeof(faceName),
612
 
                                charset, sizeof(charset));
613
 
 
614
 
        g_snprintf(fontspec,
615
 
                 sizeof(fontspec) - 1,
616
 
                 "%s%s%s%s-*-*-*-%0d-*-*-*-*-%s",
617
 
                 foundary, faceName,
618
 
                 bold ? "-bold" : "-medium",
619
 
                 italic ? "-i" : "-r",
620
 
                 size * 10,
621
 
                 charset);
622
 
        newid = LoadFontOrSet(fontspec, characterSet);
623
 
        if (!newid) {
624
 
                // some fonts have oblique, not italic
625
 
                g_snprintf(fontspec,
626
 
                         sizeof(fontspec) - 1,
627
 
                         "%s%s%s%s-*-*-*-%0d-*-*-*-*-%s",
628
 
                         foundary, faceName,
629
 
                         bold ? "-bold" : "-medium",
630
 
                         italic ? "-o" : "-r",
631
 
                         size * 10,
632
 
                         charset);
633
 
                newid = LoadFontOrSet(fontspec, characterSet);
634
 
        }
635
 
        if (!newid) {
636
 
                g_snprintf(fontspec,
637
 
                         sizeof(fontspec) - 1,
638
 
                         "-*-*-*-*-*-*-*-%0d-*-*-*-*-%s",
639
 
                         size * 10,
640
 
                         charset);
641
 
                newid = gdk_font_load(fontspec);
642
 
        }
643
 
        if (!newid) {
644
 
                // Font not available so substitute a reasonable code font
645
 
                // iso8859 appears to only allow western characters.
646
 
                newid = LoadFontOrSet("-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-*",
647
 
                        characterSet);
648
 
        }
649
 
        return new FontHandle(newid);
650
 
}
651
 
 
652
 
Font::Font() : fid(0) {}
653
 
 
654
 
Font::~Font() {}
655
 
 
656
 
void Font::Create(const char *faceName, int characterSet, int size,
657
 
        bool bold, bool italic, int) {
658
 
        Release();
659
 
        fid = FontCached::FindOrCreate(faceName, characterSet, size, bold, italic);
660
 
}
661
 
 
662
 
void Font::Release() {
663
 
        if (fid)
664
 
                FontCached::ReleaseId(fid);
665
 
        fid = 0;
666
 
}
667
 
 
668
 
// Required on OS X
669
 
#ifdef SCI_NAMESPACE
670
 
namespace Scintilla {
671
 
#endif
672
 
class SurfaceImpl : public Surface {
673
 
        encodingType et;
674
 
        GdkDrawable *drawable;
675
 
        GdkGC *gc;
676
 
        GdkPixmap *ppixmap;
677
 
        int x;
678
 
        int y;
679
 
        bool inited;
680
 
        bool createdGC;
681
 
        PangoContext *pcontext;
682
 
        PangoLayout *layout;
683
 
        Converter conv;
684
 
        int characterSet;
685
 
        void SetConverter(int characterSet_);
686
 
public:
687
 
        SurfaceImpl();
688
 
        virtual ~SurfaceImpl();
689
 
 
690
 
        void Init(WindowID wid);
691
 
        void Init(SurfaceID sid, WindowID wid);
692
 
        void InitPixMap(int width, int height, Surface *surface_, WindowID wid);
693
 
 
694
 
        void Release();
695
 
        bool Initialised();
696
 
        void PenColour(ColourAllocated fore);
697
 
        int LogPixelsY();
698
 
        int DeviceHeightFont(int points);
699
 
        void MoveTo(int x_, int y_);
700
 
        void LineTo(int x_, int y_);
701
 
        void Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back);
702
 
        void RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back);
703
 
        void FillRectangle(PRectangle rc, ColourAllocated back);
704
 
        void FillRectangle(PRectangle rc, Surface &surfacePattern);
705
 
        void RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back);
706
 
        void AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill,
707
 
                ColourAllocated outline, int alphaOutline, int flags);
708
 
        void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back);
709
 
        void Copy(PRectangle rc, Point from, Surface &surfaceSource);
710
 
 
711
 
        void DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore);
712
 
        void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
713
 
        void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
714
 
        void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore);
715
 
        void MeasureWidths(Font &font_, const char *s, int len, int *positions);
716
 
        int WidthText(Font &font_, const char *s, int len);
717
 
        int WidthChar(Font &font_, char ch);
718
 
        int Ascent(Font &font_);
719
 
        int Descent(Font &font_);
720
 
        int InternalLeading(Font &font_);
721
 
        int ExternalLeading(Font &font_);
722
 
        int Height(Font &font_);
723
 
        int AverageCharWidth(Font &font_);
724
 
 
725
 
        int SetPalette(Palette *pal, bool inBackGround);
726
 
        void SetClip(PRectangle rc);
727
 
        void FlushCachedState();
728
 
 
729
 
        void SetUnicodeMode(bool unicodeMode_);
730
 
        void SetDBCSMode(int codePage);
731
 
};
732
 
#ifdef SCI_NAMESPACE
733
 
}
734
 
#endif
735
 
 
736
 
const char *CharacterSetID(int characterSet) {
737
 
        switch (characterSet) {
738
 
        case SC_CHARSET_ANSI:
739
 
                return "";
740
 
        case SC_CHARSET_DEFAULT:
741
 
                return "ISO-8859-1";
742
 
        case SC_CHARSET_BALTIC:
743
 
                return "ISO-8859-13";
744
 
        case SC_CHARSET_CHINESEBIG5:
745
 
                return "BIG-5";
746
 
        case SC_CHARSET_EASTEUROPE:
747
 
                return "ISO-8859-2";
748
 
        case SC_CHARSET_GB2312:
749
 
                return "GB2312";
750
 
        case SC_CHARSET_GREEK:
751
 
                return "ISO-8859-7";
752
 
        case SC_CHARSET_HANGUL:
753
 
                return "";
754
 
        case SC_CHARSET_MAC:
755
 
                return "MACINTOSH";
756
 
        case SC_CHARSET_OEM:
757
 
                return "ASCII";
758
 
        case SC_CHARSET_RUSSIAN:
759
 
                return "KOI8-R";
760
 
        case SC_CHARSET_CYRILLIC:
761
 
                return "CP1251";
762
 
        case SC_CHARSET_SHIFTJIS:
763
 
                return "SHIFT-JIS";
764
 
        case SC_CHARSET_SYMBOL:
765
 
                return "";
766
 
        case SC_CHARSET_TURKISH:
767
 
                return "ISO-8859-9";
768
 
        case SC_CHARSET_JOHAB:
769
 
                return "JOHAB";
770
 
        case SC_CHARSET_HEBREW:
771
 
                return "ISO-8859-8";
772
 
        case SC_CHARSET_ARABIC:
773
 
                return "ISO-8859-6";
774
 
        case SC_CHARSET_VIETNAMESE:
775
 
                return "";
776
 
        case SC_CHARSET_THAI:
777
 
                return "ISO-8859-11";
778
 
        case SC_CHARSET_8859_15:
779
 
                return "ISO-8859-15";
780
 
        default:
781
 
                return "";
782
 
        }
783
 
}
784
 
 
785
 
void SurfaceImpl::SetConverter(int characterSet_) {
786
 
        if (characterSet != characterSet_) {
787
 
                characterSet = characterSet_;
788
 
                conv.Open("UTF-8", CharacterSetID(characterSet), false);
789
 
        }
790
 
}
791
 
 
792
 
SurfaceImpl::SurfaceImpl() : et(singleByte), drawable(0), gc(0), ppixmap(0),
793
 
x(0), y(0), inited(false), createdGC(false)
794
 
, pcontext(0), layout(0), characterSet(-1) {
795
 
}
796
 
 
797
 
SurfaceImpl::~SurfaceImpl() {
798
 
        Release();
799
 
}
800
 
 
801
 
void SurfaceImpl::Release() {
802
 
        et = singleByte;
803
 
        drawable = 0;
804
 
        if (createdGC) {
805
 
                createdGC = false;
806
 
                gdk_gc_unref(gc);
807
 
        }
808
 
        gc = 0;
809
 
        if (ppixmap)
810
 
                gdk_pixmap_unref(ppixmap);
811
 
        ppixmap = 0;
812
 
        if (layout)
813
 
                g_object_unref(layout);
814
 
        layout = 0;
815
 
        if (pcontext)
816
 
                g_object_unref(pcontext);
817
 
        pcontext = 0;
818
 
        conv.Close();
819
 
        characterSet = -1;
820
 
        x = 0;
821
 
        y = 0;
822
 
        inited = false;
823
 
        createdGC = false;
824
 
}
825
 
 
826
 
bool SurfaceImpl::Initialised() {
827
 
        return inited;
828
 
}
829
 
 
830
 
void SurfaceImpl::Init(WindowID wid) {
831
 
        Release();
832
 
        PLATFORM_ASSERT(wid);
833
 
        pcontext = gtk_widget_create_pango_context(PWidget(wid));
834
 
        PLATFORM_ASSERT(pcontext);
835
 
        layout = pango_layout_new(pcontext);
836
 
        PLATFORM_ASSERT(layout);
837
 
        inited = true;
838
 
}
839
 
 
840
 
void SurfaceImpl::Init(SurfaceID sid, WindowID wid) {
841
 
        PLATFORM_ASSERT(sid);
842
 
        GdkDrawable *drawable_ = reinterpret_cast<GdkDrawable *>(sid);
843
 
        Release();
844
 
        PLATFORM_ASSERT(wid);
845
 
        pcontext = gtk_widget_create_pango_context(PWidget(wid));
846
 
        layout = pango_layout_new(pcontext);
847
 
        drawable = drawable_;
848
 
        gc = gdk_gc_new(drawable_);
849
 
        // Ask for lines that do not paint the last pixel so is like Win32
850
 
        gdk_gc_set_line_attributes(gc, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
851
 
        createdGC = true;
852
 
        inited = true;
853
 
}
854
 
 
855
 
void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID wid) {
856
 
        PLATFORM_ASSERT(surface_);
857
 
        Release();
858
 
        SurfaceImpl *surfImpl = static_cast<SurfaceImpl *>(surface_);
859
 
        PLATFORM_ASSERT(surfImpl->drawable);
860
 
        PLATFORM_ASSERT(wid);
861
 
        pcontext = gtk_widget_create_pango_context(PWidget(wid));
862
 
        PLATFORM_ASSERT(pcontext);
863
 
        layout = pango_layout_new(pcontext);
864
 
        PLATFORM_ASSERT(layout);
865
 
        if (height > 0 && width > 0)
866
 
                ppixmap = gdk_pixmap_new(surfImpl->drawable, width, height, -1);
867
 
        drawable = ppixmap;
868
 
        gc = gdk_gc_new(surfImpl->drawable);
869
 
        // Ask for lines that do not paint the last pixel so is like Win32
870
 
        gdk_gc_set_line_attributes(gc, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
871
 
        createdGC = true;
872
 
        inited = true;
873
 
}
874
 
 
875
 
void SurfaceImpl::PenColour(ColourAllocated fore) {
876
 
        if (gc) {
877
 
                GdkColor co;
878
 
                co.pixel = fore.AsLong();
879
 
                gdk_gc_set_foreground(gc, &co);
880
 
        }
881
 
}
882
 
 
883
 
int SurfaceImpl::LogPixelsY() {
884
 
        return 72;
885
 
}
886
 
 
887
 
int SurfaceImpl::DeviceHeightFont(int points) {
888
 
        int logPix = LogPixelsY();
889
 
        return (points * logPix + logPix / 2) / 72;
890
 
}
891
 
 
892
 
void SurfaceImpl::MoveTo(int x_, int y_) {
893
 
        x = x_;
894
 
        y = y_;
895
 
}
896
 
 
897
 
void SurfaceImpl::LineTo(int x_, int y_) {
898
 
        if (drawable && gc) {
899
 
                gdk_draw_line(drawable, gc,
900
 
                              x, y,
901
 
                              x_, y_);
902
 
        }
903
 
        x = x_;
904
 
        y = y_;
905
 
}
906
 
 
907
 
void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore,
908
 
                          ColourAllocated back) {
909
 
        GdkPoint gpts[20];
910
 
        if (npts < static_cast<int>((sizeof(gpts) / sizeof(gpts[0])))) {
911
 
                for (int i = 0;i < npts;i++) {
912
 
                        gpts[i].x = pts[i].x;
913
 
                        gpts[i].y = pts[i].y;
914
 
                }
915
 
                PenColour(back);
916
 
                gdk_draw_polygon(drawable, gc, 1, gpts, npts);
917
 
                PenColour(fore);
918
 
                gdk_draw_polygon(drawable, gc, 0, gpts, npts);
919
 
        }
920
 
}
921
 
 
922
 
void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
923
 
        if (gc && drawable) {
924
 
                PenColour(back);
925
 
                gdk_draw_rectangle(drawable, gc, 1,
926
 
                                   rc.left + 1, rc.top + 1,
927
 
                                   rc.right - rc.left - 2, rc.bottom - rc.top - 2);
928
 
 
929
 
                PenColour(fore);
930
 
                // The subtraction of 1 off the width and height here shouldn't be needed but
931
 
                // otherwise a different rectangle is drawn than would be done if the fill parameter == 1
932
 
                gdk_draw_rectangle(drawable, gc, 0,
933
 
                                   rc.left, rc.top,
934
 
                                   rc.right - rc.left - 1, rc.bottom - rc.top - 1);
935
 
        }
936
 
}
937
 
 
938
 
void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) {
939
 
        PenColour(back);
940
 
        if (drawable && (rc.left < maxCoordinate)) {    // Protect against out of range
941
 
                gdk_draw_rectangle(drawable, gc, 1,
942
 
                                   rc.left, rc.top,
943
 
                                   rc.right - rc.left, rc.bottom - rc.top);
944
 
        }
945
 
}
946
 
 
947
 
void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {
948
 
        if (static_cast<SurfaceImpl &>(surfacePattern).drawable) {
949
 
                // Tile pattern over rectangle
950
 
                // Currently assumes 8x8 pattern
951
 
                int widthPat = 8;
952
 
                int heightPat = 8;
953
 
                for (int xTile = rc.left; xTile < rc.right; xTile += widthPat) {
954
 
                        int widthx = (xTile + widthPat > rc.right) ? rc.right - xTile : widthPat;
955
 
                        for (int yTile = rc.top; yTile < rc.bottom; yTile += heightPat) {
956
 
                                int heighty = (yTile + heightPat > rc.bottom) ? rc.bottom - yTile : heightPat;
957
 
                                gdk_draw_pixmap(drawable,
958
 
                                                gc,
959
 
                                                static_cast<SurfaceImpl &>(surfacePattern).drawable,
960
 
                                                0, 0,
961
 
                                                xTile, yTile,
962
 
                                                widthx, heighty);
963
 
                        }
964
 
                }
965
 
        } else {
966
 
                // Something is wrong so try to show anyway
967
 
                // Shows up black because colour not allocated
968
 
                FillRectangle(rc, ColourAllocated(0));
969
 
        }
970
 
}
971
 
 
972
 
void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
973
 
        if (((rc.right - rc.left) > 4) && ((rc.bottom - rc.top) > 4)) {
974
 
                // Approximate a round rect with some cut off corners
975
 
                Point pts[] = {
976
 
                                  Point(rc.left + 2, rc.top),
977
 
                                  Point(rc.right - 2, rc.top),
978
 
                                  Point(rc.right, rc.top + 2),
979
 
                                  Point(rc.right, rc.bottom - 2),
980
 
                                  Point(rc.right - 2, rc.bottom),
981
 
                                  Point(rc.left + 2, rc.bottom),
982
 
                                  Point(rc.left, rc.bottom - 2),
983
 
                                  Point(rc.left, rc.top + 2),
984
 
                              };
985
 
                Polygon(pts, sizeof(pts) / sizeof(pts[0]), fore, back);
986
 
        } else {
987
 
                RectangleDraw(rc, fore, back);
988
 
        }
989
 
}
990
 
 
991
 
// Plot a point into a guint32 buffer symetrically to all 4 qudrants
992
 
static void AllFour(guint32 *pixels, int stride, int width, int height, int x, int y, guint32 val) {
993
 
        pixels[y*stride+x] = val;
994
 
        pixels[y*stride+width-1-x] = val;
995
 
        pixels[(height-1-y)*stride+x] = val;
996
 
        pixels[(height-1-y)*stride+width-1-x] = val;
997
 
}
998
 
 
999
 
static unsigned int GetRValue(unsigned int co) {
1000
 
        return (co >> 16) & 0xff;
1001
 
}
1002
 
 
1003
 
static unsigned int GetGValue(unsigned int co) {
1004
 
        return (co >> 8) & 0xff;
1005
 
}
1006
 
 
1007
 
static unsigned int GetBValue(unsigned int co) {
1008
 
        return co & 0xff;
1009
 
}
1010
 
 
1011
 
static guint32 u32FromRGBA(guint8 r, guint8 g, guint8 b, guint8 a) {
1012
 
        union {
1013
 
                guint8 pixVal[4];
1014
 
                guint32 val;
1015
 
        } converter;
1016
 
        converter.pixVal[0] = r;
1017
 
        converter.pixVal[1] = g;
1018
 
        converter.pixVal[2] = b;
1019
 
        converter.pixVal[3] = a;
1020
 
        return converter.val;
1021
 
}
1022
 
 
1023
 
void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill,
1024
 
                ColourAllocated outline, int alphaOutline, int flags) {
1025
 
        if (gc && drawable && rc.Width() > 0) {
1026
 
                int width = rc.Width();
1027
 
                int height = rc.Height();
1028
 
                // Ensure not distorted too much by corners when small
1029
 
                cornerSize = Platform::Minimum(cornerSize, (Platform::Minimum(width, height) / 2) - 2);
1030
 
                // Make a 32 bit deep pixbuf with alpha
1031
 
                GdkPixbuf *pixalpha = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
1032
 
 
1033
 
                guint32 valEmpty = u32FromRGBA(0,0,0,0);
1034
 
                guint32 valFill = u32FromRGBA(GetRValue(fill.AsLong()),
1035
 
                        GetGValue(fill.AsLong()), GetBValue(fill.AsLong()), alphaFill);
1036
 
                guint32 valOutline = u32FromRGBA(GetRValue(outline.AsLong()),
1037
 
                        GetGValue(outline.AsLong()), GetBValue(outline.AsLong()), alphaOutline);
1038
 
                guint32 *pixels = reinterpret_cast<guint32 *>(gdk_pixbuf_get_pixels(pixalpha));
1039
 
                int stride = gdk_pixbuf_get_rowstride(pixalpha) / 4;
1040
 
                for (int yr=0; yr<height; yr++) {
1041
 
                        for (int xr=0; xr<width; xr++) {
1042
 
                                if ((xr==0) || (xr==width-1) || (yr == 0) || (yr == height-1)) {
1043
 
                                        pixels[yr*stride+xr] = valOutline;
1044
 
                                } else {
1045
 
                                        pixels[yr*stride+xr] = valFill;
1046
 
                                }
1047
 
                        }
1048
 
                }
1049
 
                for (int c=0;c<cornerSize; c++) {
1050
 
                        for (int xr=0;xr<c+1; xr++) {
1051
 
                                AllFour(pixels, stride, width, height, xr, c-xr, valEmpty);
1052
 
                        }
1053
 
                }
1054
 
                for (int xr=1;xr<cornerSize; xr++) {
1055
 
                        AllFour(pixels, stride, width, height, xr, cornerSize-xr, valOutline);
1056
 
                }
1057
 
 
1058
 
                // Draw with alpha
1059
 
                gdk_draw_pixbuf(drawable, gc, pixalpha,
1060
 
                        0,0, rc.left,rc.top, width,height, GDK_RGB_DITHER_NORMAL, 0, 0);
1061
 
 
1062
 
                g_object_unref(pixalpha);
1063
 
        }
1064
 
}
1065
 
 
1066
 
void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
1067
 
        PenColour(back);
1068
 
        gdk_draw_arc(drawable, gc, 1,
1069
 
                     rc.left + 1, rc.top + 1,
1070
 
                     rc.right - rc.left - 2, rc.bottom - rc.top - 2,
1071
 
                     0, 32767);
1072
 
 
1073
 
        // The subtraction of 1 here is similar to the case for RectangleDraw
1074
 
        PenColour(fore);
1075
 
        gdk_draw_arc(drawable, gc, 0,
1076
 
                     rc.left, rc.top,
1077
 
                     rc.right - rc.left - 1, rc.bottom - rc.top - 1,
1078
 
                     0, 32767);
1079
 
}
1080
 
 
1081
 
void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
1082
 
        if (static_cast<SurfaceImpl &>(surfaceSource).drawable) {
1083
 
                gdk_draw_pixmap(drawable,
1084
 
                                gc,
1085
 
                                static_cast<SurfaceImpl &>(surfaceSource).drawable,
1086
 
                                from.x, from.y,
1087
 
                                rc.left, rc.top,
1088
 
                                rc.right - rc.left, rc.bottom - rc.top);
1089
 
        }
1090
 
}
1091
 
 
1092
 
static size_t UTF8Len(char ch) {
1093
 
        unsigned char uch = static_cast<unsigned char>(ch);
1094
 
        if (uch < 0x80)
1095
 
                return 1;
1096
 
        else if (uch < (0x80 + 0x40 + 0x20))
1097
 
                return 2;
1098
 
        else
1099
 
                return 3;
1100
 
}
1101
 
 
1102
 
char *UTF8FromLatin1(const char *s, int &len) {
1103
 
        char *utfForm = new char[len*2+1];
1104
 
        size_t lenU = 0;
1105
 
        for (int i=0;i<len;i++) {
1106
 
                unsigned int uch = static_cast<unsigned char>(s[i]);
1107
 
                if (uch < 0x80) {
1108
 
                        utfForm[lenU++] = uch;
1109
 
                } else {
1110
 
                        utfForm[lenU++] = static_cast<char>(0xC0 | (uch >> 6));
1111
 
                        utfForm[lenU++] = static_cast<char>(0x80 | (uch & 0x3f));
1112
 
                }
1113
 
        }
1114
 
        utfForm[lenU] = '\0';
1115
 
        len = lenU;
1116
 
        return utfForm;
1117
 
}
1118
 
 
1119
 
static char *UTF8FromIconv(const Converter &conv, const char *s, int &len) {
1120
 
        if (conv) {
1121
 
                char *utfForm = new char[len*3+1];
1122
 
                char *pin = const_cast<char *>(s);
1123
 
                size_t inLeft = len;
1124
 
                char *pout = utfForm;
1125
 
                size_t outLeft = len*3+1;
1126
 
                size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
1127
 
                if (conversions != ((size_t)(-1))) {
1128
 
                        *pout = '\0';
1129
 
                        len = pout - utfForm;
1130
 
                        return utfForm;
1131
 
                }
1132
 
                delete []utfForm;
1133
 
        }
1134
 
        return 0;
1135
 
}
1136
 
 
1137
 
// Work out how many bytes are in a character by trying to convert using iconv,
1138
 
// returning the first length that succeeds.
1139
 
static size_t MultiByteLenFromIconv(const Converter &conv, const char *s, size_t len) {
1140
 
        for (size_t lenMB=1; (lenMB<4) && (lenMB <= len); lenMB++) {
1141
 
                char wcForm[2];
1142
 
                char *pin = const_cast<char *>(s);
1143
 
                size_t inLeft = lenMB;
1144
 
                char *pout = wcForm;
1145
 
                size_t outLeft = 2;
1146
 
                size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
1147
 
                if (conversions != ((size_t)(-1))) {
1148
 
                        return lenMB;
1149
 
                }
1150
 
        }
1151
 
        return 1;
1152
 
}
1153
 
 
1154
 
static char *UTF8FromGdkWChar(GdkWChar *wctext, int wclen) {
1155
 
        char *utfForm = new char[wclen*3+1];    // Maximum of 3 UTF-8 bytes per character
1156
 
        size_t lenU = 0;
1157
 
        for (int i = 0; i < wclen && wctext[i]; i++) {
1158
 
                unsigned int uch = wctext[i];
1159
 
                if (uch < 0x80) {
1160
 
                        utfForm[lenU++] = static_cast<char>(uch);
1161
 
                } else if (uch < 0x800) {
1162
 
                        utfForm[lenU++] = static_cast<char>(0xC0 | (uch >> 6));
1163
 
                        utfForm[lenU++] = static_cast<char>(0x80 | (uch & 0x3f));
1164
 
                } else {
1165
 
                        utfForm[lenU++] = static_cast<char>(0xE0 | (uch >> 12));
1166
 
                        utfForm[lenU++] = static_cast<char>(0x80 | ((uch >> 6) & 0x3f));
1167
 
                        utfForm[lenU++] = static_cast<char>(0x80 | (uch & 0x3f));
1168
 
                }
1169
 
        }
1170
 
        utfForm[lenU] = '\0';
1171
 
        return utfForm;
1172
 
}
1173
 
 
1174
 
static char *UTF8FromDBCS(const char *s, int &len) {
1175
 
        GdkWChar *wctext = new GdkWChar[len + 1];
1176
 
        GdkWChar *wcp = wctext;
1177
 
        int wclen = gdk_mbstowcs(wcp, s, len);
1178
 
        if (wclen < 1) {
1179
 
                // In the annoying case when non-locale chars in the line.
1180
 
                // e.g. latin1 chars in Japanese locale.
1181
 
                delete []wctext;
1182
 
                return 0;
1183
 
        }
1184
 
 
1185
 
        char *utfForm = UTF8FromGdkWChar(wctext, wclen);
1186
 
        delete []wctext;
1187
 
        len = strlen(utfForm);
1188
 
        return utfForm;
1189
 
}
1190
 
 
1191
 
static size_t UTF8CharLength(const char *s) {
1192
 
        const unsigned char *us = reinterpret_cast<const unsigned char *>(s);
1193
 
        unsigned char ch = *us;
1194
 
        if (ch < 0x80) {
1195
 
                return 1;
1196
 
        } else if (ch < 0x80 + 0x40 + 0x20) {
1197
 
                return 2;
1198
 
        } else {
1199
 
                return 3;
1200
 
        }
1201
 
}
1202
 
 
1203
 
// On GTK+, wchar_t is 4 bytes
1204
 
 
1205
 
const int maxLengthTextRun = 10000;
1206
 
 
1207
 
void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len,
1208
 
                                 ColourAllocated fore) {
1209
 
        PenColour(fore);
1210
 
        if (gc && drawable) {
1211
 
                int xText = rc.left;
1212
 
                if (PFont(font_)->pfd) {
1213
 
                        char *utfForm = 0;
1214
 
                        bool useGFree = false;
1215
 
                        if (et == UTF8) {
1216
 
                                pango_layout_set_text(layout, s, len);
1217
 
                        } else {
1218
 
                                if (!utfForm) {
1219
 
                                        SetConverter(PFont(font_)->characterSet);
1220
 
                                        utfForm = UTF8FromIconv(conv, s, len);
1221
 
                                }
1222
 
                                if (!utfForm) { // iconv failed so try DBCS if DBCS mode
1223
 
                                        if (et == dbcs) {
1224
 
                                                // Convert to utf8
1225
 
                                                utfForm = UTF8FromDBCS(s, len);
1226
 
                                        }
1227
 
                                }
1228
 
                                if (!utfForm) { // iconv and DBCS failed so treat as Latin1
1229
 
                                        utfForm = UTF8FromLatin1(s, len);
1230
 
                                }
1231
 
                                pango_layout_set_text(layout, utfForm, len);
1232
 
                        }
1233
 
                        pango_layout_set_font_description(layout, PFont(font_)->pfd);
1234
 
#ifdef PANGO_VERSION
1235
 
                        PangoLayoutLine *pll = pango_layout_get_line_readonly(layout,0);
1236
 
#else
1237
 
                        PangoLayoutLine *pll = pango_layout_get_line(layout,0);
1238
 
#endif
1239
 
                        gdk_draw_layout_line(drawable, gc, xText, ybase, pll);
1240
 
                        if (useGFree) {
1241
 
                                g_free(utfForm);
1242
 
                        } else {
1243
 
                                delete []utfForm;
1244
 
                        }
1245
 
                        return;
1246
 
                }
1247
 
                // Draw text as a series of segments to avoid limitations in X servers
1248
 
                const int segmentLength = 1000;
1249
 
                bool draw8bit = true;
1250
 
                if (et != singleByte) {
1251
 
                        GdkWChar wctext[maxLengthTextRun];
1252
 
                        if (len >= maxLengthTextRun)
1253
 
                                len = maxLengthTextRun-1;
1254
 
                        int wclen;
1255
 
                        if (et == UTF8) {
1256
 
                                wclen = UTF16FromUTF8(s, len,
1257
 
                                        static_cast<wchar_t *>(static_cast<void *>(wctext)), maxLengthTextRun - 1);
1258
 
                        } else {        // dbcs, so convert using current locale
1259
 
                                char sMeasure[maxLengthTextRun];
1260
 
                                memcpy(sMeasure, s, len);
1261
 
                                sMeasure[len] = '\0';
1262
 
                                wclen = gdk_mbstowcs(
1263
 
                                        wctext, sMeasure, maxLengthTextRun - 1);
1264
 
                        }
1265
 
                        if (wclen > 0) {
1266
 
                                draw8bit = false;
1267
 
                                wctext[wclen] = L'\0';
1268
 
                                GdkWChar *wcp = wctext;
1269
 
                                while ((wclen > 0) && (xText < maxCoordinate)) {
1270
 
                                        int lenDraw = Platform::Minimum(wclen, segmentLength);
1271
 
                                        gdk_draw_text_wc(drawable, PFont(font_)->pfont, gc,
1272
 
                                                         xText, ybase, wcp, lenDraw);
1273
 
                                        wclen -= lenDraw;
1274
 
                                        if (wclen > 0) {        // Avoid next calculation if possible as may be expensive
1275
 
                                                xText += gdk_text_width_wc(PFont(font_)->pfont,
1276
 
                                                                       wcp, lenDraw);
1277
 
                                        }
1278
 
                                        wcp += lenDraw;
1279
 
                                }
1280
 
                        }
1281
 
                }
1282
 
                if (draw8bit) {
1283
 
                        while ((len > 0) && (xText < maxCoordinate)) {
1284
 
                                int lenDraw = Platform::Minimum(len, segmentLength);
1285
 
                                gdk_draw_text(drawable, PFont(font_)->pfont, gc,
1286
 
                                              xText, ybase, s, lenDraw);
1287
 
                                len -= lenDraw;
1288
 
                                if (len > 0) {  // Avoid next calculation if possible as may be expensive
1289
 
                                        xText += gdk_text_width(PFont(font_)->pfont, s, lenDraw);
1290
 
                                }
1291
 
                                s += lenDraw;
1292
 
                        }
1293
 
                }
1294
 
        }
1295
 
}
1296
 
 
1297
 
void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len,
1298
 
                                 ColourAllocated fore, ColourAllocated back) {
1299
 
        FillRectangle(rc, back);
1300
 
        DrawTextBase(rc, font_, ybase, s, len, fore);
1301
 
}
1302
 
 
1303
 
// On GTK+, exactly same as DrawTextNoClip
1304
 
void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len,
1305
 
                                  ColourAllocated fore, ColourAllocated back) {
1306
 
        FillRectangle(rc, back);
1307
 
        DrawTextBase(rc, font_, ybase, s, len, fore);
1308
 
}
1309
 
 
1310
 
void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len,
1311
 
                                  ColourAllocated fore) {
1312
 
        // Avoid drawing spaces in transparent mode
1313
 
        for (int i=0;i<len;i++) {
1314
 
                if (s[i] != ' ') {
1315
 
                        DrawTextBase(rc, font_, ybase, s, len, fore);
1316
 
                        return;
1317
 
                }
1318
 
        }
1319
 
}
1320
 
 
1321
 
class ClusterIterator {
1322
 
        PangoLayoutIter *iter;
1323
 
        PangoRectangle pos;
1324
 
        int lenPositions;
1325
 
public:
1326
 
        bool finished;
1327
 
        int positionStart;
1328
 
        int position;
1329
 
        int distance;
1330
 
        int curIndex;
1331
 
        ClusterIterator(PangoLayout *layout, int len) : lenPositions(len), finished(false),
1332
 
                positionStart(0), position(0), distance(0), curIndex(0) {
1333
 
                iter = pango_layout_get_iter(layout);
1334
 
                pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
1335
 
        }
1336
 
        ~ClusterIterator() {
1337
 
                pango_layout_iter_free(iter);
1338
 
        }
1339
 
 
1340
 
        void Next() {
1341
 
                positionStart = position;
1342
 
                if (pango_layout_iter_next_cluster(iter)) {
1343
 
                        pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
1344
 
                        position = PANGO_PIXELS(pos.x);
1345
 
                        curIndex = pango_layout_iter_get_index(iter);
1346
 
                } else {
1347
 
                        finished = true;
1348
 
                        position = PANGO_PIXELS(pos.x + pos.width);
1349
 
                        curIndex = lenPositions;
1350
 
                }
1351
 
                distance = position - positionStart;
1352
 
        }
1353
 
};
1354
 
 
1355
 
void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) {
1356
 
        if (font_.GetID()) {
1357
 
                int totalWidth = 0;
1358
 
                const int lenPositions = len;
1359
 
                if (PFont(font_)->pfd) {
1360
 
                        if (len == 1) {
1361
 
                                int width = PFont(font_)->CharWidth(*s, et);
1362
 
                                if (width) {
1363
 
                                        positions[0] = width;
1364
 
                                        return;
1365
 
                                }
1366
 
                        }
1367
 
                        pango_layout_set_font_description(layout, PFont(font_)->pfd);
1368
 
                        if (et == UTF8) {
1369
 
                                // Simple and direct as UTF-8 is native Pango encoding
1370
 
                                int i = 0;
1371
 
                                pango_layout_set_text(layout, s, len);
1372
 
                                ClusterIterator iti(layout, lenPositions);
1373
 
                                while (!iti.finished) {
1374
 
                                        iti.Next();
1375
 
                                        int places = iti.curIndex - i;
1376
 
                                        while (i < iti.curIndex) {
1377
 
                                                // Evenly distribute space among bytes of this cluster.
1378
 
                                                // Would be better to find number of characters and then
1379
 
                                                // divide evenly between characters with each byte of a character
1380
 
                                                // being at the same position.
1381
 
                                                positions[i] = iti.position - (iti.curIndex - 1 - i) * iti.distance / places;
1382
 
                                                i++;
1383
 
                                        }
1384
 
                                }
1385
 
                                PLATFORM_ASSERT(i == lenPositions);
1386
 
                        } else {
1387
 
                                int positionsCalculated = 0;
1388
 
                                if (et == dbcs) {
1389
 
                                        SetConverter(PFont(font_)->characterSet);
1390
 
                                        char *utfForm = UTF8FromIconv(conv, s, len);
1391
 
                                        if (utfForm) {
1392
 
                                                // Convert to UTF-8 so can ask Pango for widths, then
1393
 
                                                // Loop through UTF-8 and DBCS forms, taking account of different
1394
 
                                                // character byte lengths.
1395
 
                                                Converter convMeasure("UCS-2", CharacterSetID(characterSet), false);
1396
 
                                                pango_layout_set_text(layout, utfForm, strlen(utfForm));
1397
 
                                                int i = 0;
1398
 
                                                int clusterStart = 0;
1399
 
                                                ClusterIterator iti(layout, strlen(utfForm));
1400
 
                                                while (!iti.finished) {
1401
 
                                                        iti.Next();
1402
 
                                                        int clusterEnd = iti.curIndex;
1403
 
                                                        int places = g_utf8_strlen(utfForm + clusterStart, clusterEnd - clusterStart);
1404
 
                                                        int place = 1;
1405
 
                                                        while (clusterStart < clusterEnd) {
1406
 
                                                                size_t lenChar = MultiByteLenFromIconv(convMeasure, s+i, len-i);
1407
 
                                                                while (lenChar--) {
1408
 
                                                                        positions[i++] = iti.position - (places - place) * iti.distance / places;
1409
 
                                                                        positionsCalculated++;
1410
 
                                                                }
1411
 
                                                                clusterStart += UTF8CharLength(utfForm+clusterStart);
1412
 
                                                                place++;
1413
 
                                                        }
1414
 
                                                }
1415
 
                                                delete []utfForm;
1416
 
                                                PLATFORM_ASSERT(i == lenPositions);
1417
 
                                        }
1418
 
                                }
1419
 
                                if (positionsCalculated < 1 ) {
1420
 
                                        // Either Latin1 or DBCS conversion failed so treat as Latin1.
1421
 
                                        bool useGFree = false;
1422
 
                                        SetConverter(PFont(font_)->characterSet);
1423
 
                                        char *utfForm = UTF8FromIconv(conv, s, len);
1424
 
                                        if (!utfForm) {
1425
 
                                                utfForm = UTF8FromLatin1(s, len);
1426
 
                                        }
1427
 
                                        pango_layout_set_text(layout, utfForm, len);
1428
 
                                        int i = 0;
1429
 
                                        int clusterStart = 0;
1430
 
                                        // Each Latin1 input character may take 1 or 2 bytes in UTF-8
1431
 
                                        // and groups of up to 3 may be represented as ligatures.
1432
 
                                        ClusterIterator iti(layout, strlen(utfForm));
1433
 
                                        while (!iti.finished) {
1434
 
                                                iti.Next();
1435
 
                                                int clusterEnd = iti.curIndex;
1436
 
                                                int ligatureLength = g_utf8_strlen(utfForm + clusterStart, clusterEnd - clusterStart);
1437
 
                                                PLATFORM_ASSERT(ligatureLength > 0 && ligatureLength <= 3);
1438
 
                                                for (int charInLig=0; charInLig<ligatureLength; charInLig++) {
1439
 
                                                        positions[i++] = iti.position - (ligatureLength - 1 - charInLig) * iti.distance / ligatureLength;
1440
 
                                                }
1441
 
                                                clusterStart = clusterEnd;
1442
 
                                        }
1443
 
                                        if (useGFree) {
1444
 
                                                g_free(utfForm);
1445
 
                                        } else {
1446
 
                                                delete []utfForm;
1447
 
                                        }
1448
 
                                        PLATFORM_ASSERT(i == lenPositions);
1449
 
                                }
1450
 
                        }
1451
 
                        if (len == 1) {
1452
 
                                PFont(font_)->SetCharWidth(*s, positions[0], et);
1453
 
                        }
1454
 
                        return;
1455
 
                }
1456
 
                GdkFont *gf = PFont(font_)->pfont;
1457
 
                bool measure8bit = true;
1458
 
                if (et != singleByte) {
1459
 
                        GdkWChar wctext[maxLengthTextRun];
1460
 
                        if (len >= maxLengthTextRun)
1461
 
                                len = maxLengthTextRun-1;
1462
 
                        int wclen;
1463
 
                        if (et == UTF8) {
1464
 
                                wclen = UTF16FromUTF8(s, len,
1465
 
                                        static_cast<wchar_t *>(static_cast<void *>(wctext)), maxLengthTextRun - 1);
1466
 
                        } else {        // dbcsMode, so convert using current locale
1467
 
                                char sDraw[maxLengthTextRun];
1468
 
                                memcpy(sDraw, s, len);
1469
 
                                sDraw[len] = '\0';
1470
 
                                wclen = gdk_mbstowcs(
1471
 
                                        wctext, sDraw, maxLengthTextRun - 1);
1472
 
                        }
1473
 
                        if (wclen > 0) {
1474
 
                                measure8bit = false;
1475
 
                                wctext[wclen] = L'\0';
1476
 
                                // Map widths back to utf-8 or DBCS input string
1477
 
                                int i = 0;
1478
 
                                for (int iU = 0; iU < wclen; iU++) {
1479
 
                                        int width = gdk_char_width_wc(gf, wctext[iU]);
1480
 
                                        totalWidth += width;
1481
 
                                        int lenChar;
1482
 
                                        if (et == UTF8) {
1483
 
                                                lenChar = UTF8Len(s[i]);
1484
 
                                        } else {
1485
 
                                                lenChar = mblen(s+i, MB_CUR_MAX);
1486
 
                                                if (lenChar < 0)
1487
 
                                                        lenChar = 1;
1488
 
                                        }
1489
 
                                        while (lenChar--) {
1490
 
                                                positions[i++] = totalWidth;
1491
 
                                        }
1492
 
                                }
1493
 
                                while (i < len) {       // In case of problems with lengths
1494
 
                                        positions[i++] = totalWidth;
1495
 
                                }
1496
 
                        }
1497
 
                }
1498
 
                if (measure8bit) {
1499
 
                        // Either Latin1 or conversion failed so treat as Latin1.
1500
 
                        for (int i = 0; i < len; i++) {
1501
 
                                int width = gdk_char_width(gf, s[i]);
1502
 
                                totalWidth += width;
1503
 
                                positions[i] = totalWidth;
1504
 
                        }
1505
 
                }
1506
 
        } else {
1507
 
                // No font so return an ascending range of values
1508
 
                for (int i = 0; i < len; i++) {
1509
 
                        positions[i] = i + 1;
1510
 
                }
1511
 
        }
1512
 
}
1513
 
 
1514
 
int SurfaceImpl::WidthText(Font &font_, const char *s, int len) {
1515
 
        if (font_.GetID()) {
1516
 
                if (PFont(font_)->pfd) {
1517
 
                        char *utfForm = 0;
1518
 
                        pango_layout_set_font_description(layout, PFont(font_)->pfd);
1519
 
                        PangoRectangle pos;
1520
 
                        bool useGFree = false;
1521
 
                        if (et == UTF8) {
1522
 
                                pango_layout_set_text(layout, s, len);
1523
 
                        } else {
1524
 
                                if (et == dbcs) {
1525
 
                                        // Convert to utf8
1526
 
                                        utfForm = UTF8FromDBCS(s, len);
1527
 
                                }
1528
 
                                if (!utfForm) { // DBCS failed so treat as iconv
1529
 
                                        SetConverter(PFont(font_)->characterSet);
1530
 
                                        utfForm = UTF8FromIconv(conv, s, len);
1531
 
                                }
1532
 
                                if (!utfForm) { // g_locale_to_utf8 failed so treat as Latin1
1533
 
                                        utfForm = UTF8FromLatin1(s, len);
1534
 
                                }
1535
 
                                pango_layout_set_text(layout, utfForm, len);
1536
 
                        }
1537
 
#ifdef PANGO_VERSION
1538
 
                        PangoLayoutLine *pangoLine = pango_layout_get_line_readonly(layout,0);
1539
 
#else
1540
 
                        PangoLayoutLine *pangoLine = pango_layout_get_line(layout,0);
1541
 
#endif
1542
 
                        pango_layout_line_get_extents(pangoLine, NULL, &pos);
1543
 
                        if (useGFree) {
1544
 
                                g_free(utfForm);
1545
 
                        } else {
1546
 
                                delete []utfForm;
1547
 
                        }
1548
 
                        return PANGO_PIXELS(pos.width);
1549
 
                }
1550
 
                if (et == UTF8) {
1551
 
                        GdkWChar wctext[maxLengthTextRun];
1552
 
                        size_t wclen = UTF16FromUTF8(s, len, static_cast<wchar_t *>(static_cast<void *>(wctext)),
1553
 
                                sizeof(wctext) / sizeof(GdkWChar) - 1);
1554
 
                        wctext[wclen] = L'\0';
1555
 
                        return gdk_text_width_wc(PFont(font_)->pfont, wctext, wclen);
1556
 
                } else {
1557
 
                        return gdk_text_width(PFont(font_)->pfont, s, len);
1558
 
                }
1559
 
        } else {
1560
 
                return 1;
1561
 
        }
1562
 
}
1563
 
 
1564
 
int SurfaceImpl::WidthChar(Font &font_, char ch) {
1565
 
        if (font_.GetID()) {
1566
 
                if (PFont(font_)->pfd) {
1567
 
                        return WidthText(font_, &ch, 1);
1568
 
                }
1569
 
                return gdk_char_width(PFont(font_)->pfont, ch);
1570
 
        } else {
1571
 
                return 1;
1572
 
        }
1573
 
}
1574
 
 
1575
 
// Three possible strategies for determining ascent and descent of font:
1576
 
// 1) Call gdk_string_extents with string containing all letters, numbers and punctuation.
1577
 
// 2) Use the ascent and descent fields of GdkFont.
1578
 
// 3) Call gdk_string_extents with string as 1 but also including accented capitals.
1579
 
// Smallest values given by 1 and largest by 3 with 2 in between.
1580
 
// Techniques 1 and 2 sometimes chop off extreme portions of ascenders and
1581
 
// descenders but are mostly OK except for accented characters like � which are
1582
 
// rarely used in code.
1583
 
 
1584
 
// This string contains a good range of characters to test for size.
1585
 
//const char largeSizeString[] = "���� `~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890"
1586
 
//                               "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1587
 
#ifndef FAST_WAY
1588
 
const char sizeString[] = "`~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890"
1589
 
                          "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1590
 
#endif
1591
 
 
1592
 
int SurfaceImpl::Ascent(Font &font_) {
1593
 
        if (!(font_.GetID()))
1594
 
                return 1;
1595
 
#ifdef FAST_WAY
1596
 
        FontMutexLock();
1597
 
        int ascent = PFont(font_)->ascent;
1598
 
        if ((ascent == 0) && (PFont(font_)->pfd)) {
1599
 
                PangoFontMetrics *metrics = pango_context_get_metrics(pcontext,
1600
 
                        PFont(font_)->pfd, pango_context_get_language(pcontext));
1601
 
                PFont(font_)->ascent =
1602
 
                        PANGO_PIXELS(pango_font_metrics_get_ascent(metrics));
1603
 
                pango_font_metrics_unref(metrics);
1604
 
                ascent = PFont(font_)->ascent;
1605
 
        }
1606
 
        if ((ascent == 0) && (PFont(font_)->pfont)) {
1607
 
                ascent = PFont(font_)->pfont->ascent;
1608
 
        }
1609
 
        if (ascent == 0) {
1610
 
                ascent = 1;
1611
 
        }
1612
 
        FontMutexUnlock();
1613
 
        return ascent;
1614
 
#else
1615
 
 
1616
 
        gint lbearing;
1617
 
        gint rbearing;
1618
 
        gint width;
1619
 
        gint ascent;
1620
 
        gint descent;
1621
 
 
1622
 
        gdk_string_extents(PFont(font_)->pfont, sizeString,
1623
 
                                           &lbearing, &rbearing, &width, &ascent, &descent);
1624
 
        return ascent;
1625
 
#endif
1626
 
}
1627
 
 
1628
 
int SurfaceImpl::Descent(Font &font_) {
1629
 
        if (!(font_.GetID()))
1630
 
                return 1;
1631
 
#ifdef FAST_WAY
1632
 
 
1633
 
        if (PFont(font_)->pfd) {
1634
 
                PangoFontMetrics *metrics = pango_context_get_metrics(pcontext,
1635
 
                        PFont(font_)->pfd, pango_context_get_language(pcontext));
1636
 
                int descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics));
1637
 
                pango_font_metrics_unref(metrics);
1638
 
                return descent;
1639
 
        }
1640
 
        return PFont(font_)->pfont->descent;
1641
 
#else
1642
 
 
1643
 
        gint lbearing;
1644
 
        gint rbearing;
1645
 
        gint width;
1646
 
        gint ascent;
1647
 
        gint descent;
1648
 
 
1649
 
        gdk_string_extents(PFont(font_)->pfont, sizeString,
1650
 
                                           &lbearing, &rbearing, &width, &ascent, &descent);
1651
 
        return descent;
1652
 
#endif
1653
 
}
1654
 
 
1655
 
int SurfaceImpl::InternalLeading(Font &) {
1656
 
        return 0;
1657
 
}
1658
 
 
1659
 
int SurfaceImpl::ExternalLeading(Font &) {
1660
 
        return 0;
1661
 
}
1662
 
 
1663
 
int SurfaceImpl::Height(Font &font_) {
1664
 
        return Ascent(font_) + Descent(font_);
1665
 
}
1666
 
 
1667
 
int SurfaceImpl::AverageCharWidth(Font &font_) {
1668
 
        return WidthChar(font_, 'n');
1669
 
}
1670
 
 
1671
 
int SurfaceImpl::SetPalette(Palette *, bool) {
1672
 
        // Handled in palette allocation for GTK so this does nothing
1673
 
        return 0;
1674
 
}
1675
 
 
1676
 
void SurfaceImpl::SetClip(PRectangle rc) {
1677
 
        GdkRectangle area = {rc.left, rc.top,
1678
 
                             rc.right - rc.left, rc.bottom - rc.top};
1679
 
        gdk_gc_set_clip_rectangle(gc, &area);
1680
 
}
1681
 
 
1682
 
void SurfaceImpl::FlushCachedState() {}
1683
 
 
1684
 
void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) {
1685
 
        if (unicodeMode_)
1686
 
                et = UTF8;
1687
 
}
1688
 
 
1689
 
void SurfaceImpl::SetDBCSMode(int codePage) {
1690
 
        if (codePage && (codePage != SC_CP_UTF8))
1691
 
                et = dbcs;
1692
 
}
1693
 
 
1694
 
Surface *Surface::Allocate() {
1695
 
        return new SurfaceImpl;
1696
 
}
1697
 
 
1698
 
Window::~Window() {}
1699
 
 
1700
 
void Window::Destroy() {
1701
 
        if (wid)
1702
 
                gtk_widget_destroy(GTK_WIDGET(wid));
1703
 
        wid = 0;
1704
 
}
1705
 
 
1706
 
bool Window::HasFocus() {
1707
 
        return GTK_WIDGET_HAS_FOCUS(wid);
1708
 
}
1709
 
 
1710
 
PRectangle Window::GetPosition() {
1711
 
        // Before any size allocated pretend its 1000 wide so not scrolled
1712
 
        PRectangle rc(0, 0, 1000, 1000);
1713
 
        if (wid) {
1714
 
                rc.left = PWidget(wid)->allocation.x;
1715
 
                rc.top = PWidget(wid)->allocation.y;
1716
 
                if (PWidget(wid)->allocation.width > 20) {
1717
 
                        rc.right = rc.left + PWidget(wid)->allocation.width;
1718
 
                        rc.bottom = rc.top + PWidget(wid)->allocation.height;
1719
 
                }
1720
 
        }
1721
 
        return rc;
1722
 
}
1723
 
 
1724
 
void Window::SetPosition(PRectangle rc) {
1725
 
        GtkAllocation alloc;
1726
 
        alloc.x = rc.left;
1727
 
        alloc.y = rc.top;
1728
 
        alloc.width = rc.Width();
1729
 
        alloc.height = rc.Height();
1730
 
        gtk_widget_size_allocate(PWidget(wid), &alloc);
1731
 
}
1732
 
 
1733
 
void Window::SetPositionRelative(PRectangle rc, Window relativeTo) {
1734
 
        int ox = 0;
1735
 
        int oy = 0;
1736
 
        gdk_window_get_origin(PWidget(relativeTo.wid)->window, &ox, &oy);
1737
 
        ox += rc.left;
1738
 
        if (ox < 0)
1739
 
                ox = 0;
1740
 
        oy += rc.top;
1741
 
        if (oy < 0)
1742
 
                oy = 0;
1743
 
 
1744
 
        /* do some corrections to fit into screen */
1745
 
        int sizex = rc.right - rc.left;
1746
 
        int sizey = rc.bottom - rc.top;
1747
 
        int screenWidth = gdk_screen_width();
1748
 
        int screenHeight = gdk_screen_height();
1749
 
        if (sizex > screenWidth)
1750
 
                ox = 0; /* the best we can do */
1751
 
        else if (ox + sizex > screenWidth)
1752
 
                ox = screenWidth - sizex;
1753
 
        if (oy + sizey > screenHeight)
1754
 
                oy = screenHeight - sizey;
1755
 
 
1756
 
        gtk_window_move(GTK_WINDOW(PWidget(wid)), ox, oy);
1757
 
 
1758
 
        gtk_widget_set_usize(PWidget(wid), sizex, sizey);
1759
 
}
1760
 
 
1761
 
PRectangle Window::GetClientPosition() {
1762
 
        // On GTK+, the client position is the window position
1763
 
        return GetPosition();
1764
 
}
1765
 
 
1766
 
void Window::Show(bool show) {
1767
 
        if (show)
1768
 
                gtk_widget_show(PWidget(wid));
1769
 
}
1770
 
 
1771
 
void Window::InvalidateAll() {
1772
 
        if (wid) {
1773
 
                gtk_widget_queue_draw(PWidget(wid));
1774
 
        }
1775
 
}
1776
 
 
1777
 
void Window::InvalidateRectangle(PRectangle rc) {
1778
 
        if (wid) {
1779
 
                gtk_widget_queue_draw_area(PWidget(wid),
1780
 
                                           rc.left, rc.top,
1781
 
                                           rc.right - rc.left, rc.bottom - rc.top);
1782
 
        }
1783
 
}
1784
 
 
1785
 
void Window::SetFont(Font &) {
1786
 
        // Can not be done generically but only needed for ListBox
1787
 
}
1788
 
 
1789
 
void Window::SetCursor(Cursor curs) {
1790
 
        // We don't set the cursor to same value numerous times under gtk because
1791
 
        // it stores the cursor in the window once it's set
1792
 
        if (curs == cursorLast)
1793
 
                return;
1794
 
 
1795
 
        cursorLast = curs;
1796
 
        GdkCursor *gdkCurs;
1797
 
        switch (curs) {
1798
 
        case cursorText:
1799
 
                gdkCurs = gdk_cursor_new(GDK_XTERM);
1800
 
                break;
1801
 
        case cursorArrow:
1802
 
                gdkCurs = gdk_cursor_new(GDK_LEFT_PTR);
1803
 
                break;
1804
 
        case cursorUp:
1805
 
                gdkCurs = gdk_cursor_new(GDK_CENTER_PTR);
1806
 
                break;
1807
 
        case cursorWait:
1808
 
                gdkCurs = gdk_cursor_new(GDK_WATCH);
1809
 
                break;
1810
 
        case cursorHand:
1811
 
                gdkCurs = gdk_cursor_new(GDK_HAND2);
1812
 
                break;
1813
 
        case cursorReverseArrow:
1814
 
                gdkCurs = gdk_cursor_new(GDK_RIGHT_PTR);
1815
 
                break;
1816
 
        default:
1817
 
                gdkCurs = gdk_cursor_new(GDK_LEFT_PTR);
1818
 
                cursorLast = cursorArrow;
1819
 
                break;
1820
 
        }
1821
 
 
1822
 
        if (PWidget(wid)->window)
1823
 
                gdk_window_set_cursor(PWidget(wid)->window, gdkCurs);
1824
 
        gdk_cursor_destroy(gdkCurs);
1825
 
}
1826
 
 
1827
 
void Window::SetTitle(const char *s) {
1828
 
        gtk_window_set_title(GTK_WINDOW(wid), s);
1829
 
}
1830
 
 
1831
 
/* Returns rectangle of monitor pt is on, both rect and pt are in Window's
1832
 
   gdk window coordinates */
1833
 
PRectangle Window::GetMonitorRect(Point pt) {
1834
 
        gint x_offset, y_offset;
1835
 
        pt = pt;
1836
 
 
1837
 
        gdk_window_get_origin(PWidget(wid)->window, &x_offset, &y_offset);
1838
 
 
1839
 
#if GTK_CHECK_VERSION(2,2,0)
1840
 
        // GTK+ 2.2+
1841
 
        {
1842
 
                GdkScreen* screen;
1843
 
                gint monitor_num;
1844
 
                GdkRectangle rect;
1845
 
 
1846
 
                screen = gtk_widget_get_screen(PWidget(wid));
1847
 
                monitor_num = gdk_screen_get_monitor_at_point(screen, pt.x + x_offset, pt.y + y_offset);
1848
 
                gdk_screen_get_monitor_geometry(screen, monitor_num, &rect);
1849
 
                rect.x -= x_offset;
1850
 
                rect.y -= y_offset;
1851
 
                return PRectangle(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
1852
 
        }
1853
 
#else
1854
 
        return PRectangle(-x_offset, -y_offset, (-x_offset) + gdk_screen_width(),
1855
 
                          (-y_offset) + gdk_screen_height());
1856
 
#endif
1857
 
}
1858
 
 
1859
 
struct ListImage {
1860
 
        const char *xpm_data;
1861
 
        GdkPixbuf *pixbuf;
1862
 
};
1863
 
 
1864
 
static void list_image_free(gpointer, gpointer value, gpointer) {
1865
 
        ListImage *list_image = (ListImage *) value;
1866
 
        if (list_image->pixbuf)
1867
 
                gdk_pixbuf_unref (list_image->pixbuf);
1868
 
        g_free(list_image);
1869
 
}
1870
 
 
1871
 
ListBox::ListBox() {
1872
 
}
1873
 
 
1874
 
ListBox::~ListBox() {
1875
 
}
1876
 
 
1877
 
enum {
1878
 
        PIXBUF_COLUMN,
1879
 
        TEXT_COLUMN,
1880
 
        N_COLUMNS
1881
 
};
1882
 
 
1883
 
class ListBoxX : public ListBox {
1884
 
        WindowID list;
1885
 
        WindowID scroller;
1886
 
        void *pixhash;
1887
 
        GtkCellRenderer* pixbuf_renderer;
1888
 
        XPMSet xset;
1889
 
        int desiredVisibleRows;
1890
 
        unsigned int maxItemCharacters;
1891
 
        unsigned int aveCharWidth;
1892
 
public:
1893
 
        CallBackAction doubleClickAction;
1894
 
        void *doubleClickActionData;
1895
 
 
1896
 
        ListBoxX() : list(0), pixhash(NULL), pixbuf_renderer(0),
1897
 
                desiredVisibleRows(5), maxItemCharacters(0),
1898
 
                aveCharWidth(1), doubleClickAction(NULL), doubleClickActionData(NULL) {
1899
 
        }
1900
 
        virtual ~ListBoxX() {
1901
 
                if (pixhash) {
1902
 
                        g_hash_table_foreach((GHashTable *) pixhash, list_image_free, NULL);
1903
 
                        g_hash_table_destroy((GHashTable *) pixhash);
1904
 
                }
1905
 
        }
1906
 
        virtual void SetFont(Font &font);
1907
 
        virtual void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_);
1908
 
        virtual void SetAverageCharWidth(int width);
1909
 
        virtual void SetVisibleRows(int rows);
1910
 
        virtual int GetVisibleRows() const;
1911
 
        virtual PRectangle GetDesiredRect();
1912
 
        virtual int CaretFromEdge();
1913
 
        virtual void Clear();
1914
 
        virtual void Append(char *s, int type = -1);
1915
 
        virtual int Length();
1916
 
        virtual void Select(int n);
1917
 
        virtual int GetSelection();
1918
 
        virtual int Find(const char *prefix);
1919
 
        virtual void GetValue(int n, char *value, int len);
1920
 
        virtual void RegisterImage(int type, const char *xpm_data);
1921
 
        virtual void ClearRegisteredImages();
1922
 
        virtual void SetDoubleClickAction(CallBackAction action, void *data) {
1923
 
                doubleClickAction = action;
1924
 
                doubleClickActionData = data;
1925
 
        }
1926
 
        virtual void SetList(const char *listText, char separator, char typesep);
1927
 
};
1928
 
 
1929
 
ListBox *ListBox::Allocate() {
1930
 
        ListBoxX *lb = new ListBoxX();
1931
 
        return lb;
1932
 
}
1933
 
 
1934
 
static gboolean ButtonPress(GtkWidget *, GdkEventButton* ev, gpointer p) {
1935
 
        try {
1936
 
                ListBoxX* lb = reinterpret_cast<ListBoxX*>(p);
1937
 
                if (ev->type == GDK_2BUTTON_PRESS && lb->doubleClickAction != NULL) {
1938
 
                        lb->doubleClickAction(lb->doubleClickActionData);
1939
 
                        return TRUE;
1940
 
                }
1941
 
 
1942
 
        } catch (...) {
1943
 
                // No pointer back to Scintilla to save status
1944
 
        }
1945
 
        return FALSE;
1946
 
}
1947
 
 
1948
 
/* Change the active color to the selected color so the listbox uses the color
1949
 
scheme that it would use if it had the focus. */
1950
 
static void StyleSet(GtkWidget *w, GtkStyle*, void*) {
1951
 
        GtkStyle* style;
1952
 
 
1953
 
        g_return_if_fail(w != NULL);
1954
 
 
1955
 
        /* Copy the selected color to active.  Note that the modify calls will cause
1956
 
        recursive calls to this function after the value is updated and w->style to
1957
 
        be set to a new object */
1958
 
        style = gtk_widget_get_style(w);
1959
 
        if (style == NULL)
1960
 
                return;
1961
 
        if (!gdk_color_equal(&style->base[GTK_STATE_SELECTED], &style->base[GTK_STATE_ACTIVE]))
1962
 
                gtk_widget_modify_base(w, GTK_STATE_ACTIVE, &style->base[GTK_STATE_SELECTED]);
1963
 
 
1964
 
        style = gtk_widget_get_style(w);
1965
 
        if (style == NULL)
1966
 
                return;
1967
 
        if (!gdk_color_equal(&style->text[GTK_STATE_SELECTED], &style->text[GTK_STATE_ACTIVE]))
1968
 
                gtk_widget_modify_text(w, GTK_STATE_ACTIVE, &style->text[GTK_STATE_SELECTED]);
1969
 
}
1970
 
 
1971
 
void ListBoxX::Create(Window &, int, Point, int, bool) {
1972
 
        wid = gtk_window_new(GTK_WINDOW_POPUP);
1973
 
 
1974
 
        GtkWidget *frame = gtk_frame_new(NULL);
1975
 
        gtk_widget_show(frame);
1976
 
        gtk_container_add(GTK_CONTAINER(GetID()), frame);
1977
 
        gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
1978
 
        gtk_container_set_border_width(GTK_CONTAINER(frame), 0);
1979
 
 
1980
 
        scroller = gtk_scrolled_window_new(NULL, NULL);
1981
 
        gtk_container_set_border_width(GTK_CONTAINER(scroller), 0);
1982
 
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
1983
 
                                       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1984
 
        gtk_container_add(GTK_CONTAINER(frame), PWidget(scroller));
1985
 
        gtk_widget_show(PWidget(scroller));
1986
 
 
1987
 
        /* Tree and its model */
1988
 
        GtkListStore *store =
1989
 
                gtk_list_store_new(N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING);
1990
 
 
1991
 
        list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1992
 
        g_signal_connect(G_OBJECT(list), "style-set", G_CALLBACK(StyleSet), NULL);
1993
 
 
1994
 
        GtkTreeSelection *selection =
1995
 
                gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
1996
 
        gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
1997
 
        gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
1998
 
        gtk_tree_view_set_reorderable(GTK_TREE_VIEW(list), FALSE);
1999
 
 
2000
 
        /* Columns */
2001
 
        GtkTreeViewColumn *column = gtk_tree_view_column_new();
2002
 
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2003
 
        gtk_tree_view_column_set_title(column, "Autocomplete");
2004
 
 
2005
 
        pixbuf_renderer = gtk_cell_renderer_pixbuf_new();
2006
 
        gtk_cell_renderer_set_fixed_size(pixbuf_renderer, 0, -1);
2007
 
        gtk_tree_view_column_pack_start(column, pixbuf_renderer, FALSE);
2008
 
        gtk_tree_view_column_add_attribute(column, pixbuf_renderer,
2009
 
                                                                                "pixbuf", PIXBUF_COLUMN);
2010
 
 
2011
 
        GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
2012
 
        gtk_cell_renderer_text_set_fixed_height_from_font(GTK_CELL_RENDERER_TEXT(renderer), 1);
2013
 
        gtk_tree_view_column_pack_start(column, renderer, TRUE);
2014
 
        gtk_tree_view_column_add_attribute(column, renderer,
2015
 
                                                                                "text", TEXT_COLUMN);
2016
 
 
2017
 
        gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
2018
 
        if (g_object_class_find_property(G_OBJECT_GET_CLASS(list), "fixed-height-mode"))
2019
 
                g_object_set(G_OBJECT(list), "fixed-height-mode", TRUE, NULL);
2020
 
 
2021
 
        GtkWidget *wid = PWidget(list); // No code inside the G_OBJECT macro
2022
 
        gtk_container_add(GTK_CONTAINER(PWidget(scroller)), wid);
2023
 
        gtk_widget_show(wid);
2024
 
        g_signal_connect(G_OBJECT(wid), "button_press_event",
2025
 
                           G_CALLBACK(ButtonPress), this);
2026
 
        gtk_widget_realize(PWidget(wid));
2027
 
}
2028
 
 
2029
 
void ListBoxX::SetFont(Font &scint_font) {
2030
 
        // Only do for Pango font as there have been crashes for GDK fonts
2031
 
        if (Created() && PFont(scint_font)->pfd) {
2032
 
                // Current font is Pango font
2033
 
                gtk_widget_modify_font(PWidget(list), PFont(scint_font)->pfd);
2034
 
        }
2035
 
}
2036
 
 
2037
 
void ListBoxX::SetAverageCharWidth(int width) {
2038
 
        aveCharWidth = width;
2039
 
}
2040
 
 
2041
 
void ListBoxX::SetVisibleRows(int rows) {
2042
 
        desiredVisibleRows = rows;
2043
 
}
2044
 
 
2045
 
int ListBoxX::GetVisibleRows() const {
2046
 
        return desiredVisibleRows;
2047
 
}
2048
 
 
2049
 
PRectangle ListBoxX::GetDesiredRect() {
2050
 
        // Before any size allocated pretend its 100 wide so not scrolled
2051
 
        PRectangle rc(0, 0, 100, 100);
2052
 
        if (wid) {
2053
 
                int rows = Length();
2054
 
                if ((rows == 0) || (rows > desiredVisibleRows))
2055
 
                        rows = desiredVisibleRows;
2056
 
 
2057
 
                GtkRequisition req;
2058
 
                int height;
2059
 
 
2060
 
                // First calculate height of the clist for our desired visible
2061
 
                // row count otherwise it tries to expand to the total # of rows
2062
 
                // Get cell height
2063
 
                int row_width=0;
2064
 
                int row_height=0;
2065
 
                GtkTreeViewColumn * column =
2066
 
                        gtk_tree_view_get_column(GTK_TREE_VIEW(list), 0);
2067
 
                gtk_tree_view_column_cell_get_size(column, NULL,
2068
 
                        NULL, NULL, &row_width, &row_height);
2069
 
                int ythickness = PWidget(list)->style->ythickness;
2070
 
                height = (rows * row_height
2071
 
                          + 2 * (ythickness
2072
 
                                 + GTK_CONTAINER(PWidget(list))->border_width + 1));
2073
 
                gtk_widget_set_usize(GTK_WIDGET(PWidget(list)), -1, height);
2074
 
 
2075
 
                // Get the size of the scroller because we set usize on the window
2076
 
                gtk_widget_size_request(GTK_WIDGET(scroller), &req);
2077
 
                rc.right = req.width;
2078
 
                rc.bottom = req.height;
2079
 
 
2080
 
                gtk_widget_set_usize(GTK_WIDGET(list), -1, -1);
2081
 
                int width = maxItemCharacters;
2082
 
                if (width < 12)
2083
 
                        width = 12;
2084
 
                rc.right = width * (aveCharWidth + aveCharWidth / 3);
2085
 
                if (Length() > rows)
2086
 
                        rc.right = rc.right + 16;
2087
 
        }
2088
 
        return rc;
2089
 
}
2090
 
 
2091
 
int ListBoxX::CaretFromEdge() {
2092
 
        gint renderer_width, renderer_height;
2093
 
        gtk_cell_renderer_get_fixed_size(pixbuf_renderer, &renderer_width,
2094
 
                                                &renderer_height);
2095
 
        return 4 + renderer_width;
2096
 
}
2097
 
 
2098
 
void ListBoxX::Clear() {
2099
 
        GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
2100
 
        gtk_list_store_clear(GTK_LIST_STORE(model));
2101
 
        maxItemCharacters = 0;
2102
 
}
2103
 
 
2104
 
static void init_pixmap(ListImage *list_image) {
2105
 
        const char *textForm = list_image->xpm_data;
2106
 
        const char * const * xpm_lineform = reinterpret_cast<const char * const *>(textForm);
2107
 
        const char **xpm_lineformfromtext = 0;
2108
 
        // The XPM data can be either in atext form as will be read from a file
2109
 
        // or in a line form (array of char  *) as will be used for images defined in code.
2110
 
        // Test for text form and convert to line form
2111
 
        if ((0 == memcmp(textForm, "/* X", 4)) && (0 == memcmp(textForm, "/* XPM */", 9))) {
2112
 
                // Test done is two parts to avoid possibility of overstepping the memory
2113
 
                // if memcmp implemented strangely. Must be 4 bytes at least at destination.
2114
 
                xpm_lineformfromtext = XPM::LinesFormFromTextForm(textForm);
2115
 
                xpm_lineform = xpm_lineformfromtext;
2116
 
        }
2117
 
 
2118
 
        // Drop any existing pixmap/bitmap as data may have changed
2119
 
        if (list_image->pixbuf)
2120
 
                gdk_pixbuf_unref(list_image->pixbuf);
2121
 
        list_image->pixbuf =
2122
 
                gdk_pixbuf_new_from_xpm_data((const gchar**)xpm_lineform);
2123
 
        delete []xpm_lineformfromtext;
2124
 
}
2125
 
 
2126
 
#define SPACING 5
2127
 
 
2128
 
void ListBoxX::Append(char *s, int type) {
2129
 
        ListImage *list_image = NULL;
2130
 
        if ((type >= 0) && pixhash) {
2131
 
                list_image = (ListImage *) g_hash_table_lookup((GHashTable *) pixhash
2132
 
                             , (gconstpointer) GINT_TO_POINTER(type));
2133
 
        }
2134
 
        GtkTreeIter iter;
2135
 
        GtkListStore *store =
2136
 
                GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
2137
 
        gtk_list_store_append(GTK_LIST_STORE(store), &iter);
2138
 
        if (list_image) {
2139
 
                if (NULL == list_image->pixbuf)
2140
 
                        init_pixmap(list_image);
2141
 
                if (list_image->pixbuf) {
2142
 
                        gtk_list_store_set(GTK_LIST_STORE(store), &iter,
2143
 
                                                                PIXBUF_COLUMN, list_image->pixbuf,
2144
 
                                                                TEXT_COLUMN, s, -1);
2145
 
 
2146
 
                        gint pixbuf_width = gdk_pixbuf_get_width(list_image->pixbuf);
2147
 
                        gint renderer_height, renderer_width;
2148
 
                        gtk_cell_renderer_get_fixed_size(pixbuf_renderer,
2149
 
                                                                &renderer_width, &renderer_height);
2150
 
                        if (pixbuf_width > renderer_width)
2151
 
                                gtk_cell_renderer_set_fixed_size(pixbuf_renderer,
2152
 
                                                                pixbuf_width, -1);
2153
 
                } else {
2154
 
                        gtk_list_store_set(GTK_LIST_STORE(store), &iter,
2155
 
                                                                TEXT_COLUMN, s, -1);
2156
 
                }
2157
 
        } else {
2158
 
                        gtk_list_store_set(GTK_LIST_STORE(store), &iter,
2159
 
                                                                TEXT_COLUMN, s, -1);
2160
 
        }
2161
 
        size_t len = strlen(s);
2162
 
        if (maxItemCharacters < len)
2163
 
                maxItemCharacters = len;
2164
 
}
2165
 
 
2166
 
int ListBoxX::Length() {
2167
 
        if (wid)
2168
 
                return gtk_tree_model_iter_n_children(gtk_tree_view_get_model
2169
 
                                                                                           (GTK_TREE_VIEW(list)), NULL);
2170
 
        return 0;
2171
 
}
2172
 
 
2173
 
void ListBoxX::Select(int n) {
2174
 
        GtkTreeIter iter;
2175
 
        GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
2176
 
        GtkTreeSelection *selection =
2177
 
                gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
2178
 
 
2179
 
        if (n < 0) {
2180
 
                gtk_tree_selection_unselect_all(selection);
2181
 
                return;
2182
 
        }
2183
 
 
2184
 
        bool valid = gtk_tree_model_iter_nth_child(model, &iter, NULL, n) != FALSE;
2185
 
        if (valid) {
2186
 
                gtk_tree_selection_select_iter(selection, &iter);
2187
 
 
2188
 
                // Move the scrollbar to show the selection.
2189
 
                int total = Length();
2190
 
                GtkAdjustment *adj =
2191
 
                        gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(list));
2192
 
                gfloat value = ((gfloat)n / total) * (adj->upper - adj->lower)
2193
 
                                                        + adj->lower - adj->page_size / 2;
2194
 
 
2195
 
                // Get cell height
2196
 
                int row_width;
2197
 
                int row_height;
2198
 
                GtkTreeViewColumn * column =
2199
 
                        gtk_tree_view_get_column(GTK_TREE_VIEW(list), 0);
2200
 
                gtk_tree_view_column_cell_get_size(column, NULL, NULL,
2201
 
                                                                                        NULL, &row_width, &row_height);
2202
 
 
2203
 
                int rows = Length();
2204
 
                if ((rows == 0) || (rows > desiredVisibleRows))
2205
 
                        rows = desiredVisibleRows;
2206
 
                if (rows & 0x1) {
2207
 
                        // Odd rows to display -- We are now in the middle.
2208
 
                        // Align it so that we don't chop off rows.
2209
 
                        value += (gfloat)row_height / 2.0;
2210
 
                }
2211
 
                // Clamp it.
2212
 
                value = (value < 0)? 0 : value;
2213
 
                value = (value > (adj->upper - adj->page_size))?
2214
 
                                        (adj->upper - adj->page_size) : value;
2215
 
 
2216
 
                // Set it.
2217
 
                gtk_adjustment_set_value(adj, value);
2218
 
        } else {
2219
 
                gtk_tree_selection_unselect_all(selection);
2220
 
        }
2221
 
}
2222
 
 
2223
 
int ListBoxX::GetSelection() {
2224
 
        GtkTreeIter iter;
2225
 
        GtkTreeModel *model;
2226
 
        GtkTreeSelection *selection;
2227
 
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
2228
 
        if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
2229
 
                GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
2230
 
                int *indices = gtk_tree_path_get_indices(path);
2231
 
                // Don't free indices.
2232
 
                if (indices)
2233
 
                        return indices[0];
2234
 
        }
2235
 
        return -1;
2236
 
}
2237
 
 
2238
 
int ListBoxX::Find(const char *prefix) {
2239
 
        GtkTreeIter iter;
2240
 
        GtkTreeModel *model =
2241
 
                gtk_tree_view_get_model(GTK_TREE_VIEW(list));
2242
 
        bool valid = gtk_tree_model_get_iter_first(model, &iter) != FALSE;
2243
 
        int i = 0;
2244
 
        while(valid) {
2245
 
                gchar *s;
2246
 
                gtk_tree_model_get(model, &iter, TEXT_COLUMN, &s, -1);
2247
 
                if (s && (0 == strncmp(prefix, s, strlen(prefix)))) {
2248
 
                        g_free(s);
2249
 
                        return i;
2250
 
                }
2251
 
                g_free(s);
2252
 
                valid = gtk_tree_model_iter_next(model, &iter) != FALSE;
2253
 
                i++;
2254
 
        }
2255
 
        return -1;
2256
 
}
2257
 
 
2258
 
void ListBoxX::GetValue(int n, char *value, int len) {
2259
 
        char *text = NULL;
2260
 
        GtkTreeIter iter;
2261
 
        GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
2262
 
        bool valid = gtk_tree_model_iter_nth_child(model, &iter, NULL, n) != FALSE;
2263
 
        if (valid) {
2264
 
                gtk_tree_model_get(model, &iter, TEXT_COLUMN, &text, -1);
2265
 
        }
2266
 
        if (text && len > 0) {
2267
 
                strncpy(value, text, len);
2268
 
                value[len - 1] = '\0';
2269
 
        } else {
2270
 
                value[0] = '\0';
2271
 
        }
2272
 
        g_free(text);
2273
 
}
2274
 
 
2275
 
// g_return_if_fail causes unnecessary compiler warning in release compile.
2276
 
#ifdef _MSC_VER
2277
 
#pragma warning(disable: 4127)
2278
 
#endif
2279
 
 
2280
 
void ListBoxX::RegisterImage(int type, const char *xpm_data) {
2281
 
        g_return_if_fail(xpm_data);
2282
 
 
2283
 
        // Saved and use the saved copy so caller's copy can disappear.
2284
 
        xset.Add(type, xpm_data);
2285
 
        XPM *pxpm = xset.Get(type);
2286
 
        xpm_data = reinterpret_cast<const char *>(pxpm->InLinesForm());
2287
 
 
2288
 
        if (!pixhash) {
2289
 
                pixhash = g_hash_table_new(g_direct_hash, g_direct_equal);
2290
 
        }
2291
 
        ListImage *list_image = (ListImage *) g_hash_table_lookup((GHashTable *) pixhash,
2292
 
                (gconstpointer) GINT_TO_POINTER(type));
2293
 
        if (list_image) {
2294
 
                // Drop icon already registered
2295
 
                if (list_image->pixbuf)
2296
 
                        gdk_pixbuf_unref(list_image->pixbuf);
2297
 
                list_image->pixbuf = NULL;
2298
 
                list_image->xpm_data = xpm_data;
2299
 
        } else {
2300
 
                list_image = g_new0(ListImage, 1);
2301
 
                list_image->xpm_data = xpm_data;
2302
 
                g_hash_table_insert((GHashTable *) pixhash, GINT_TO_POINTER(type),
2303
 
                        (gpointer) list_image);
2304
 
        }
2305
 
}
2306
 
 
2307
 
void ListBoxX::ClearRegisteredImages() {
2308
 
        xset.Clear();
2309
 
}
2310
 
 
2311
 
void ListBoxX::SetList(const char *listText, char separator, char typesep) {
2312
 
        Clear();
2313
 
        int count = strlen(listText) + 1;
2314
 
        char *words = new char[count];
2315
 
        if (words) {
2316
 
                memcpy(words, listText, count);
2317
 
                char *startword = words;
2318
 
                char *numword = NULL;
2319
 
                int i = 0;
2320
 
                for (; words[i]; i++) {
2321
 
                        if (words[i] == separator) {
2322
 
                                words[i] = '\0';
2323
 
                                if (numword)
2324
 
                                        *numword = '\0';
2325
 
                                Append(startword, numword?atoi(numword + 1):-1);
2326
 
                                startword = words + i + 1;
2327
 
                                numword = NULL;
2328
 
                        } else if (words[i] == typesep) {
2329
 
                                numword = words + i;
2330
 
                        }
2331
 
                }
2332
 
                if (startword) {
2333
 
                        if (numword)
2334
 
                                *numword = '\0';
2335
 
                        Append(startword, numword?atoi(numword + 1):-1);
2336
 
                }
2337
 
                delete []words;
2338
 
        }
2339
 
}
2340
 
 
2341
 
Menu::Menu() : mid(0) {}
2342
 
 
2343
 
void Menu::CreatePopUp() {
2344
 
        Destroy();
2345
 
        mid = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
2346
 
}
2347
 
 
2348
 
void Menu::Destroy() {
2349
 
        if (mid)
2350
 
                g_object_unref(G_OBJECT(mid));
2351
 
        mid = 0;
2352
 
}
2353
 
 
2354
 
void Menu::Show(Point pt, Window &) {
2355
 
        int screenHeight = gdk_screen_height();
2356
 
        int screenWidth = gdk_screen_width();
2357
 
        GtkItemFactory *factory = reinterpret_cast<GtkItemFactory *>(mid);
2358
 
        GtkWidget *widget = gtk_item_factory_get_widget(factory, "<main>");
2359
 
        gtk_widget_show_all(widget);
2360
 
        GtkRequisition requisition;
2361
 
        gtk_widget_size_request(widget, &requisition);
2362
 
        if ((pt.x + requisition.width) > screenWidth) {
2363
 
                pt.x = screenWidth - requisition.width;
2364
 
        }
2365
 
        if ((pt.y + requisition.height) > screenHeight) {
2366
 
                pt.y = screenHeight - requisition.height;
2367
 
        }
2368
 
        gtk_item_factory_popup(factory, pt.x - 4, pt.y - 4, 3,
2369
 
                gtk_get_current_event_time());
2370
 
}
2371
 
 
2372
 
ElapsedTime::ElapsedTime() {
2373
 
        GTimeVal curTime;
2374
 
        g_get_current_time(&curTime);
2375
 
        bigBit = curTime.tv_sec;
2376
 
        littleBit = curTime.tv_usec;
2377
 
}
2378
 
 
2379
 
class DynamicLibraryImpl : public DynamicLibrary {
2380
 
protected:
2381
 
        GModule* m;
2382
 
public:
2383
 
        DynamicLibraryImpl(const char *modulePath) {
2384
 
                m = g_module_open(modulePath, G_MODULE_BIND_LAZY);
2385
 
        }
2386
 
 
2387
 
        virtual ~DynamicLibraryImpl() {
2388
 
                if (m != NULL)
2389
 
                        g_module_close(m);
2390
 
        }
2391
 
 
2392
 
        // Use g_module_symbol to get a pointer to the relevant function.
2393
 
        virtual Function FindFunction(const char *name) {
2394
 
                if (m != NULL) {
2395
 
                        gpointer fn_address = NULL;
2396
 
                        gboolean status = g_module_symbol(m, name, &fn_address);
2397
 
                        if (status)
2398
 
                                return static_cast<Function>(fn_address);
2399
 
                        else
2400
 
                                return NULL;
2401
 
                } else
2402
 
                        return NULL;
2403
 
        }
2404
 
 
2405
 
        virtual bool IsValid() {
2406
 
                return m != NULL;
2407
 
        }
2408
 
};
2409
 
 
2410
 
DynamicLibrary *DynamicLibrary::Load(const char *modulePath) {
2411
 
        return static_cast<DynamicLibrary *>( new DynamicLibraryImpl(modulePath) );
2412
 
}
2413
 
 
2414
 
double ElapsedTime::Duration(bool reset) {
2415
 
        GTimeVal curTime;
2416
 
        g_get_current_time(&curTime);
2417
 
        long endBigBit = curTime.tv_sec;
2418
 
        long endLittleBit = curTime.tv_usec;
2419
 
        double result = 1000000.0 * (endBigBit - bigBit);
2420
 
        result += endLittleBit - littleBit;
2421
 
        result /= 1000000.0;
2422
 
        if (reset) {
2423
 
                bigBit = endBigBit;
2424
 
                littleBit = endLittleBit;
2425
 
        }
2426
 
        return result;
2427
 
}
2428
 
 
2429
 
ColourDesired Platform::Chrome() {
2430
 
        return ColourDesired(0xe0, 0xe0, 0xe0);
2431
 
}
2432
 
 
2433
 
ColourDesired Platform::ChromeHighlight() {
2434
 
        return ColourDesired(0xff, 0xff, 0xff);
2435
 
}
2436
 
 
2437
 
const char *Platform::DefaultFont() {
2438
 
#ifdef G_OS_WIN32
2439
 
        return "Lucida Console";
2440
 
#else
2441
 
        return "!Sans";
2442
 
#endif
2443
 
}
2444
 
 
2445
 
int Platform::DefaultFontSize() {
2446
 
#ifdef G_OS_WIN32
2447
 
        return 10;
2448
 
#else
2449
 
        return 12;
2450
 
#endif
2451
 
}
2452
 
 
2453
 
unsigned int Platform::DoubleClickTime() {
2454
 
        return 500;     // Half a second
2455
 
}
2456
 
 
2457
 
bool Platform::MouseButtonBounce() {
2458
 
        return true;
2459
 
}
2460
 
 
2461
 
void Platform::DebugDisplay(const char *s) {
2462
 
        fprintf(stderr, "%s", s);
2463
 
}
2464
 
 
2465
 
bool Platform::IsKeyDown(int) {
2466
 
        // TODO: discover state of keys in GTK+/X
2467
 
        return false;
2468
 
}
2469
 
 
2470
 
long Platform::SendScintilla(
2471
 
    WindowID w, unsigned int msg, unsigned long wParam, long lParam) {
2472
 
        return scintilla_send_message(SCINTILLA(w), msg, wParam, lParam);
2473
 
}
2474
 
 
2475
 
long Platform::SendScintillaPointer(
2476
 
    WindowID w, unsigned int msg, unsigned long wParam, void *lParam) {
2477
 
        return scintilla_send_message(SCINTILLA(w), msg, wParam,
2478
 
                                      reinterpret_cast<sptr_t>(lParam));
2479
 
}
2480
 
 
2481
 
bool Platform::IsDBCSLeadByte(int codePage, char ch) {
2482
 
        // Byte ranges found in Wikipedia articles with relevant search strings in each case
2483
 
        unsigned char uch = static_cast<unsigned char>(ch);
2484
 
        switch (codePage) {
2485
 
                case 932:
2486
 
                        // Shift_jis
2487
 
                        return ((uch >= 0x81) && (uch <= 0x9F)) ||
2488
 
                                ((uch >= 0xE0) && (uch <= 0xEF));
2489
 
                case 936:
2490
 
                        // GBK
2491
 
                        return (uch >= 0x81) && (uch <= 0xFE);
2492
 
                case 950:
2493
 
                        // Big5
2494
 
                        return (uch >= 0x81) && (uch <= 0xFE);
2495
 
                // Korean EUC-KR may be code page 949.
2496
 
        }
2497
 
        return false;
2498
 
}
2499
 
 
2500
 
int Platform::DBCSCharLength(int codePage, const char *s) {
2501
 
        if (codePage == 932 || codePage == 936 || codePage == 950) {
2502
 
                return IsDBCSLeadByte(codePage, s[0]) ? 2 : 1;
2503
 
        } else {
2504
 
                int bytes = mblen(s, MB_CUR_MAX);
2505
 
                if (bytes >= 1)
2506
 
                        return bytes;
2507
 
                else
2508
 
                        return 1;
2509
 
        }
2510
 
}
2511
 
 
2512
 
int Platform::DBCSCharMaxLength() {
2513
 
        return MB_CUR_MAX;
2514
 
        //return 2;
2515
 
}
2516
 
 
2517
 
// These are utility functions not really tied to a platform
2518
 
 
2519
 
int Platform::Minimum(int a, int b) {
2520
 
        if (a < b)
2521
 
                return a;
2522
 
        else
2523
 
                return b;
2524
 
}
2525
 
 
2526
 
int Platform::Maximum(int a, int b) {
2527
 
        if (a > b)
2528
 
                return a;
2529
 
        else
2530
 
                return b;
2531
 
}
2532
 
 
2533
 
//#define TRACE
2534
 
 
2535
 
#ifdef TRACE
2536
 
void Platform::DebugPrintf(const char *format, ...) {
2537
 
        char buffer[2000];
2538
 
        va_list pArguments;
2539
 
        va_start(pArguments, format);
2540
 
        vsprintf(buffer, format, pArguments);
2541
 
        va_end(pArguments);
2542
 
        Platform::DebugDisplay(buffer);
2543
 
}
2544
 
#else
2545
 
void Platform::DebugPrintf(const char *, ...) {}
2546
 
 
2547
 
#endif
2548
 
 
2549
 
// Not supported for GTK+
2550
 
static bool assertionPopUps = true;
2551
 
 
2552
 
bool Platform::ShowAssertionPopUps(bool assertionPopUps_) {
2553
 
        bool ret = assertionPopUps;
2554
 
        assertionPopUps = assertionPopUps_;
2555
 
        return ret;
2556
 
}
2557
 
 
2558
 
void Platform::Assert(const char *c, const char *file, int line) {
2559
 
        char buffer[2000];
2560
 
        sprintf(buffer, "Assertion [%s] failed at %s %d", c, file, line);
2561
 
        strcat(buffer, "\r\n");
2562
 
        Platform::DebugDisplay(buffer);
2563
 
        abort();
2564
 
}
2565
 
 
2566
 
int Platform::Clamp(int val, int minVal, int maxVal) {
2567
 
        if (val > maxVal)
2568
 
                val = maxVal;
2569
 
        if (val < minVal)
2570
 
                val = minVal;
2571
 
        return val;
2572
 
}
2573
 
 
2574
 
void Platform_Initialise() {
2575
 
        FontMutexAllocate();
2576
 
}
2577
 
 
2578
 
void Platform_Finalise() {
2579
 
        FontMutexFree();
2580
 
}