1 /** FXScintilla source code edit control
2  *
3  *  PlatFOX.cxx - implementation of platform facilities on the FOX toolkit
4  *
5  *  Copyright 2001-2004 by Gilles Filippini <gilles.filippini@free.fr>
6  *
7  *  Adapted from the Scintilla source PlatGTK.cxx
8  *  Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
9  *
10  *  ====================================================================
11  *
12  *  This file is part of FXScintilla.
13  *
14  *  FXScintilla is free software; you can redistribute it and/or modify
15  *  it under the terms of the GNU Lesser General Public License as published by
16  *  the Free Software Foundation; either version 2.1 of the License, or
17  *  (at your option) any later version.
18  *
19  *  FXScintilla is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU Lesser General Public License for more details.
23  *
24  *  You should have received a copy of the GNU Lesser General Public License
25  *  along with FXScintilla; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  **/
28 
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 
33 #if !defined(WIN32) || defined(__CYGWIN__)
34 # if defined(__CYGWIN__)
35 #  include <windows.h>
36 #  ifdef PIC
37 #   define FOXDLL
38 #  endif
39 # endif
40 # include <sys/time.h>
41 #  include <fx.h>
42 #  include <fxkeys.h>
43 #  include <FXRootWindow.h>
44 #else
45 # if defined(__MINGW32__) && defined(PIC) && !defined(FOXDLL)
46 #   define FOXDLL
47 # endif
48 # pragma warning (disable : 4786)
49 # include <time.h>
50 # include <windows.h>
51 # include <fx.h>
52 # include <fxkeys.h>
53 #endif  // !defined(WIN32) || defined(__CYGWIN__)
54 
55 #include <FX88591Codec.h>
56 
57 #include "Platform.h"
58 #include "Scintilla.h"
59 #include "ScintillaWidget.h"
60 
61 #include <map>
62 using namespace std;
63 
64 // X has a 16 bit coordinate space, so stop drawing here to avoid wrapping
65 static const int maxCoordinate = 32000;
66 
FromLong(long lpoint)67 Point Point::FromLong(long lpoint) {
68   return Point(
69     Platform::LowShortFromLong(lpoint),
70     Platform::HighShortFromLong(lpoint));
71 }
72 
Palette()73 Palette::Palette() {
74   used = 0;
75   allowRealization = false;
76   visual = 0;
77   size = 100;
78   entries = new ColourPair[size];
79 }
80 
~Palette()81 Palette::~Palette() {
82   Release();
83   delete []entries;
84   entries = 0;
85 }
86 
Release()87 void Palette::Release() {
88   used = 0;
89   delete []entries;
90   size = 100;
91   entries = new ColourPair[size];
92 }
93 
94 #if defined(FOX_1_7) && ((FOX_MAJOR>1)||(FOX_MINOR>7)||(FOX_LEVEL>25))
95 # define RGBSWAP(rgb) FXRGB(FXBLUEVAL(rgb),FXGREENVAL(rgb),FXREDVAL(rgb))
96 #else
97 # define RGBSWAP(rgb) (rgb)
98 #endif
99 
100 // This method either adds a colour to the list of wanted colours (want==true)
101 // or retrieves the allocated colour back to the ColourPair.
102 // This is one method to make it easier to keep the code for wanting and retrieving in sync.
WantFind(ColourPair & cp,bool want)103 void Palette::WantFind(ColourPair &cp, bool want) {
104   if (want) {
105     for (int i=0; i < used; i++) {
106       if (entries[i].desired == cp.desired)
107         return;
108     }
109 
110     if (used >= size) {
111       int sizeNew = size * 2;
112       ColourPair *entriesNew = new ColourPair[sizeNew];
113       for (int j=0; j<size; j++) {
114         entriesNew[j] = entries[j];
115       }
116       delete []entries;
117       entries = entriesNew;
118       size = sizeNew;
119     }
120     entries[used].desired = cp.desired;
121     entries[used].allocated.Set(RGBSWAP(cp.desired.AsLong()));
122     used++;
123   } else {
124     for (int i=0; i < used; i++) {
125       if (entries[i].desired == cp.desired) {
126         cp.allocated = entries[i].allocated;
127         return;
128       }
129     }
130     cp.allocated.Set(RGBSWAP(cp.desired.AsLong()));
131   }
132 }
133 
Allocate(Window &)134 void Palette::Allocate(Window & /* w */) {
135 // <FIXME/>
136 }
137 
Font()138 Font::Font() : fid(0) {}
139 
~Font()140 Font::~Font() {}
141 
142 #ifndef WIN32
143 
Create(const char * faceName,int characterSet,int size,bool bold,bool italic,int)144 void Font::Create(const char *faceName, int characterSet,
145   int size, bool bold, bool italic, int) {
146   Release();
147   // If name of the font begins with a '-', assume, that it is
148   // a full fontspec.
149   if (faceName[0] == '-') {
150     fid = new FXFont(FXApp::instance(), faceName);
151   }
152   else {
153         fid = new FXFont(FXApp::instance(), faceName, size,
154           bold ? FXFont::Bold : FXFont::Normal ,
155       italic ? FXFont::Italic : FXFont::Straight,
156       characterSet);
157   }
158   if (!fid) {
159     // Font not available so substitute with the app default font.
160     fid = FXApp::instance()->getNormalFont();
161   }
162   if (fid)
163     fid->create();
164 }
165 
166 #else // WIN32
167 
CharacterSetCode(int characterSet)168 static int CharacterSetCode(int characterSet) {
169   switch (characterSet) {
170   case SC_CHARSET_ANSI:
171     return FONTENCODING_DEFAULT;
172   case SC_CHARSET_DEFAULT:
173     return FONTENCODING_DEFAULT;
174   case SC_CHARSET_BALTIC:
175     return FONTENCODING_BALTIC;
176   case SC_CHARSET_CHINESEBIG5:
177     return FONTENCODING_DEFAULT;
178   case SC_CHARSET_EASTEUROPE:
179     return FONTENCODING_EASTEUROPE;
180   case SC_CHARSET_GB2312:
181     return FONTENCODING_DEFAULT;
182   case SC_CHARSET_GREEK:
183     return FONTENCODING_GREEK;
184   case SC_CHARSET_HANGUL:
185     return FONTENCODING_DEFAULT;
186   case SC_CHARSET_MAC:
187     return FONTENCODING_DEFAULT;
188   case SC_CHARSET_OEM:
189     return FONTENCODING_DEFAULT;
190   case SC_CHARSET_RUSSIAN:
191     return FONTENCODING_RUSSIAN;
192   case SC_CHARSET_CYRILLIC:
193     return FONTENCODING_CYRILLIC;
194   case SC_CHARSET_SHIFTJIS:
195     return FONTENCODING_DEFAULT;
196   case SC_CHARSET_SYMBOL:
197     return FONTENCODING_DEFAULT;
198   case SC_CHARSET_TURKISH:
199     return FONTENCODING_TURKISH;
200   case SC_CHARSET_JOHAB:
201     return FONTENCODING_DEFAULT;
202   case SC_CHARSET_HEBREW:
203     return FONTENCODING_HEBREW;
204   case SC_CHARSET_ARABIC:
205     return FONTENCODING_ARABIC;
206   case SC_CHARSET_VIETNAMESE:
207     return FONTENCODING_CP1258;     /// Windows Vietnam
208   case SC_CHARSET_THAI:
209     return FONTENCODING_THAI;
210   case SC_CHARSET_8859_15:
211     return FONTENCODING_ISO_8859_15;
212   default:
213     return FONTENCODING_DEFAULT;
214   }
215 }
216 
Create(const char * faceName,int characterSet,int size,bool bold,bool italic,int)217 void Font::Create(const char *faceName, int characterSet,
218   int size, bool bold, bool italic, int) {
219   Release();
220   fid = new FXFont(FXApp::instance(), faceName, size,
221           bold ? FXFont::Bold : FXFont::Normal ,
222       italic ? FXFont::Italic : FXFont::Straight,
223       CharacterSetCode(characterSet));
224   if (!fid) {
225     // Font not available so substitute with the app default font.
226     fid = FXApp::instance()->getNormalFont();
227   }
228   if (fid)
229     fid->create();
230 }
231 
232 #endif // WIN32
233 
Release()234 void Font::Release() {
235   if (fid)
236     delete fid;
237   fid = 0;
238 }
239 
240 // ====================================================================
241 // Surface
242 // ====================================================================
243 
244 class SurfaceImpl : public Surface {
245   bool unicodeMode;
246   FXDrawable *drawable;
247   FXImage *ppixmap;
248   static SurfaceImpl *s_dc_owner;
249   FXDCWindow *_dc;
250   FXDCWindow *dc();
251   int x;
252   int y;
253   bool inited;
254   bool createdDC;
255   FX88591Codec asciiCodec;
256   FXString codecBuffer;
257 public:
258   SurfaceImpl();
259   virtual ~SurfaceImpl();
260 
261   void Init(WindowID wid);
262   void Init(SurfaceID sid, WindowID wid);
263   void InitPixMap(int width, int height, Surface *surface_, WindowID wid);
264 
265   void Release();
266   bool Initialised();
267   void PenColour(ColourAllocated fore);
268   void BackColour(ColourAllocated back);
269   int LogPixelsY();
270   int DeviceHeightFont(int points);
271   void MoveTo(int x_, int y_);
272   void LineTo(int x_, int y_);
273   void Polygon(Point *pts, int npts, ColourAllocated fore, ColourAllocated back);
274   void RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back);
275   void FillRectangle(PRectangle rc, ColourAllocated back);
276   void FillRectangle(PRectangle rc, Surface &surfacePattern);
277   void RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back);
278   void AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill,
279     ColourAllocated outline, int alphaOutline, int flags);
280   void Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back);
281   void Copy(PRectangle rc, Point from, Surface &surfaceSource);
282 
283   void DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore);
284   void DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
285   void DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore, ColourAllocated back);
286   void DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore);
287   void MeasureWidths(Font &font_, const char *s, int len, int *positions);
288   int WidthText(Font &font_, const char *s, int len);
289   int WidthChar(Font &font_, char ch);
290   int Ascent(Font &font_);
291   int Descent(Font &font_);
292   int InternalLeading(Font &font_);
293   int ExternalLeading(Font &font_);
294   int Height(Font &font_);
295   int AverageCharWidth(Font &font_);
296 
297   int SetPalette(Palette *pal, bool inBackGround);
298   void SetClip(PRectangle rc);
299   void FlushCachedState();
300 
301   void SetUnicodeMode(bool unicodeMode_);
SetDBCSMode(int)302   virtual void SetDBCSMode(int /* codePage */) {}
303   virtual void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage);
304 };
305 
306 SurfaceImpl * SurfaceImpl::s_dc_owner = NULL;
307 
SurfaceImpl()308 SurfaceImpl::SurfaceImpl() : unicodeMode(false), drawable(0), ppixmap(0), _dc(0),
309 x(0), y(0), inited(false) {}
310 
311 
~SurfaceImpl()312 SurfaceImpl::~SurfaceImpl() {
313   Release();
314 }
315 
dc()316 FXDCWindow * SurfaceImpl::dc()
317 {
318   if (s_dc_owner != this) {
319     if (s_dc_owner) {
320       delete s_dc_owner->_dc;
321       s_dc_owner->_dc = NULL;
322     }
323     s_dc_owner = this;
324     _dc = (drawable) ? new FXDCWindow(drawable) : NULL;
325     // Ask for lines that do not paint the last pixel so is like Win32
326     if (_dc)
327       _dc->setLineCap(CAP_NOT_LAST);
328   }
329   return _dc;
330 
331 }
332 
Release()333 void SurfaceImpl::Release() {
334   drawable = 0;
335   if (_dc) {
336     delete _dc;
337     _dc = 0;
338     s_dc_owner = 0;
339   }
340   if (ppixmap)
341     delete ppixmap;
342   ppixmap = 0;
343   x = 0;
344   y = 0;
345   createdDC = false;
346   inited = false;
347 }
348 
Initialised()349 bool SurfaceImpl::Initialised() {
350   return inited;
351 }
352 
Init(WindowID)353 void SurfaceImpl::Init(WindowID) {
354   Release();
355   inited = true;
356 }
357 
Init(SurfaceID sid,WindowID)358 void SurfaceImpl::Init(SurfaceID sid, WindowID) {
359   Release();
360   drawable = reinterpret_cast<FXDrawable *>(sid);
361   createdDC = true;
362   inited = true;
363 }
364 
InitPixMap(int width,int height,Surface *,WindowID)365 void SurfaceImpl::InitPixMap(int width, int height, Surface*, WindowID) {
366   Release();
367   if (height > 0 && width > 0)
368     ppixmap = new FXImage(FXApp::instance(), NULL, 0, width, height);
369   else
370     ppixmap = NULL;
371   drawable = ppixmap;
372   if (drawable)
373     drawable->create();
374   createdDC = true;
375   inited = true;
376 }
377 
PenColour(ColourAllocated fore)378 void SurfaceImpl::PenColour(ColourAllocated fore) {
379   if (dc()) {
380     ColourDesired cd(fore.AsLong());
381     _dc->setForeground(FXRGB(cd.GetRed(), cd.GetGreen(), cd.GetBlue()));
382   }
383 }
384 
BackColour(ColourAllocated back)385 void SurfaceImpl::BackColour(ColourAllocated back) {
386   if (dc()) {
387     ColourDesired cd(back.AsLong());
388     _dc->setBackground(FXRGB(cd.GetRed(), cd.GetGreen(), cd.GetBlue()));
389   }
390 }
391 
LogPixelsY()392 int SurfaceImpl::LogPixelsY() {
393   return 72;
394 }
395 
DeviceHeightFont(int points)396 int SurfaceImpl::DeviceHeightFont(int points) {
397   int logPix = LogPixelsY();
398   return (points * logPix + logPix / 2) / 72;
399 }
400 
MoveTo(int x_,int y_)401 void SurfaceImpl::MoveTo(int x_, int y_) {
402   x = x_;
403   y = y_;
404 }
405 
LineTo(int x_,int y_)406 void SurfaceImpl::LineTo(int x_, int y_) {
407   if (dc()) {
408     _dc->drawLine(x, y, x_, y_);
409   }
410   x = x_;
411   y = y_;
412 }
413 
Polygon(Point * pts,int npts,ColourAllocated fore,ColourAllocated back)414 void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore,
415                       ColourAllocated back) {
416   if (dc()) {
417     FXPoint gpts[20];
418     if (npts < static_cast<int>((sizeof(gpts)/sizeof(gpts[0])))) {
419       for (int i=0;i<npts;i++) {
420         gpts[i].x = pts[i].x;
421         gpts[i].y = pts[i].y;
422       }
423       gpts[npts].x = pts[0].x;
424       gpts[npts].y = pts[0].y;
425       PenColour(back);
426       _dc->fillPolygon(gpts, npts);
427       PenColour(fore);
428       _dc->drawLines(gpts, npts + 1);
429     }
430   }
431 }
432 
RectangleDraw(PRectangle rc,ColourAllocated fore,ColourAllocated back)433 void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
434   if (dc()) {
435     PenColour(fore);
436     BackColour(back);
437     _dc->drawRectangle(rc.left, rc.top,
438                       rc.right - rc.left + 1, rc.bottom - rc.top + 1);
439   }
440 }
441 
FillRectangle(PRectangle rc,ColourAllocated back)442 void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) {
443   if (dc() && (rc.left < maxCoordinate)) {  // Protect against out of range
444     // GTK+ rectangles include their lower and right edges
445     rc.bottom--;
446     rc.right--;
447     PenColour(back);
448     _dc->fillRectangle(rc.left, rc.top,
449             rc.right - rc.left + 1, rc.bottom - rc.top + 1);
450   }
451 }
452 
FillRectangle(PRectangle rc,Surface & surfacePattern)453 void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {
454   if (static_cast<SurfaceImpl &>(surfacePattern).drawable) {
455     if (dc()) {
456       // Tile pattern over rectangle
457       // Currently assumes 8x8 pattern
458       int widthPat = 8;
459       int heightPat = 8;
460       for (int xTile = rc.left; xTile < rc.right; xTile += widthPat) {
461         int widthx = (xTile + widthPat > rc.right) ? rc.right - xTile : widthPat;
462         for (int yTile = rc.top; yTile < rc.bottom; yTile += heightPat) {
463           int heighty = (yTile + heightPat > rc.bottom) ? rc.bottom - yTile : heightPat;
464           _dc->drawArea(static_cast<SurfaceImpl &>(surfacePattern).drawable,
465                         0, 0,
466                         widthx, heighty,
467                         xTile, yTile);
468         }
469       }
470     }
471   } else {
472     // Something is wrong so try to show anyway
473     // Shows up black because colour not allocated
474     FillRectangle(rc, ColourAllocated(0));
475   }
476 }
477 
RoundedRectangle(PRectangle rc,ColourAllocated fore,ColourAllocated back)478 void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
479   if (((rc.right - rc.left) > 4) && ((rc.bottom - rc.top) > 4)) {
480     // Approximate a round rect with some cut off corners
481     Point pts[] = {
482         Point(rc.left + 2, rc.top),
483         Point(rc.right - 2, rc.top),
484         Point(rc.right, rc.top + 2),
485         Point(rc.right, rc.bottom - 2),
486         Point(rc.right - 2, rc.bottom),
487         Point(rc.left + 2, rc.bottom),
488         Point(rc.left, rc.bottom - 2),
489         Point(rc.left, rc.top + 2),
490     };
491     Polygon(pts, sizeof(pts) / sizeof(pts[0]), fore, back);
492   } else {
493     RectangleDraw(rc, fore, back);
494   }
495 }
496 
497 // Plot a point into a guint32 buffer symetrically to all 4 qudrants
AllFour(FXImage * image,int width,int height,int x,int y,FXColor color)498 static void AllFour(FXImage *image, int width, int height, int x, int y, FXColor color) {
499   image->setPixel(x, y, color);
500   image->setPixel(width-1-x, y, color);
501   image->setPixel(x, height-1-y, color);
502   image->setPixel(width-1-x, height-1-y, color);
503 }
504 
GetRed(unsigned int co)505 static unsigned int GetRed(unsigned int co) {
506   return (co >> 16) & 0xff;
507 }
508 
GetGreen(unsigned int co)509 static unsigned int GetGreen(unsigned int co) {
510   return (co >> 8) & 0xff;
511 }
512 
GetBlue(unsigned int co)513 static unsigned int GetBlue(unsigned int co) {
514   return co & 0xff;
515 }
516 
AlphaRectangle(PRectangle rc,int cornerSize,ColourAllocated fill,int alphaFill,ColourAllocated outline,int alphaOutline,int flags)517 void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill,
518     ColourAllocated outline, int alphaOutline, int flags) {
519   if (dc()) {
520     int width = rc.Width();
521     int height = rc.Height();
522     // Ensure not distorted too much by corners when small
523     cornerSize = Platform::Minimum(cornerSize, (Platform::Minimum(width, height) / 2) - 2);
524     // Make a 32 bit deep image
525     FXImage * image = new FXImage(FXApp::instance(), NULL, IMAGE_OWNED, width, height);
526 
527     FXColor valEmpty = 0;
528     FXColor valFill = FXRGBA(GetRed(fill.AsLong()), GetGreen(fill.AsLong()), GetBlue(fill.AsLong()), alphaFill);
529     FXColor valOutline = FXRGBA(GetRed(outline.AsLong()), GetGreen(outline.AsLong()), GetBlue(outline.AsLong()), alphaOutline);
530     for (int pY=0; pY<height; pY++) {
531       for (int pX=0; pX<width; pX++) {
532         if ((pX==0) || (pX==width-1) || (pY == 0) || (pY == height-1)) {
533           image->setPixel(pX, pY, valOutline);
534         } else {
535           image->setPixel(pX, pY, valFill);
536         }
537       }
538     }
539     for (int c=0;c<cornerSize; c++) {
540       for (int pX=0;pX<c+1; pX++) {
541         AllFour(image, width, height, pX, c-pX, valEmpty);
542       }
543     }
544     for (int pX=1;pX<cornerSize; pX++) {
545       AllFour(image, width, height, pX, cornerSize-pX, valOutline);
546     }
547 
548     // Draw with alpha
549     image->create();
550     _dc->drawImage(image, rc.left, rc.top);
551   }
552 }
553 
554 
Ellipse(PRectangle rc,ColourAllocated fore,ColourAllocated back)555 void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
556   if (dc()) {
557     PenColour(back);
558     _dc->fillArc(rc.left, rc.top,
559           rc.right - rc.left, rc.bottom - rc.top,
560           0, 32767);
561     PenColour(fore);
562     _dc->drawArc(rc.left, rc.top,
563           rc.right - rc.left, rc.bottom - rc.top,
564           0, 32767);
565   }
566 }
567 
Copy(PRectangle rc,Point from,Surface & surfaceSource)568 void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
569   if (dc() && static_cast<SurfaceImpl &>(surfaceSource).drawable) {
570     _dc->drawArea(static_cast<SurfaceImpl &>(surfaceSource).drawable,
571                  from.x, from.y,
572                  rc.right - rc.left, rc.bottom - rc.top ,
573                  rc.left, rc.top);
574   }
575 }
576 
DrawTextBase(PRectangle rc,Font & font_,int ybase,const char * s,int len,ColourAllocated fore)577 void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore)
578 {
579   if (dc()) {
580     PenColour(fore);
581     _dc->setFont(font_.GetID());
582     const int segmentLength = 1000;
583     int xbase = rc.left;
584     if (codecBuffer.length()) { codecBuffer=FXString::null; }
585     if (!unicodeMode) { // Fox uses UTF8 for text drawing, so we must convert any extended ASCII first.
586       for (int p=0; p<len; p++) {
587         if ((FXuchar)(s[p])>126) {
588           codecBuffer.length(asciiCodec.mb2utflen(s,len));
589           asciiCodec.mb2utf(&(codecBuffer.at(0)),codecBuffer.length(),s,len);
590           len=codecBuffer.length();
591           break;
592         }
593       }
594     }
595     while ((len > 0) && (xbase < maxCoordinate)) {
596       int lenDraw = Platform::Minimum(len, segmentLength);
597       _dc->drawText(xbase, ybase, codecBuffer.length()?codecBuffer.text():s, lenDraw);
598       len -= lenDraw;
599       if (len > 0) {
600         xbase += font_.GetID()->getTextWidth(s, lenDraw);
601       }
602       s += lenDraw;
603     }
604   }
605   if (codecBuffer.length()) { codecBuffer=FXString::null; }
606 }
607 
DrawTextNoClip(PRectangle rc,Font & font_,int ybase,const char * s,int len,ColourAllocated fore,ColourAllocated back)608 void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len,
609                        ColourAllocated fore, ColourAllocated back) {
610   if (dc()) {
611     FillRectangle(rc, back);
612     DrawTextBase(rc, font_, ybase, s, len, fore);
613   }
614 }
615 
616 // On GTK+, exactly same as DrawText NoClip
617 // <FIXME> what about FOX ? </FIXME>
DrawTextClipped(PRectangle rc,Font & font_,int ybase,const char * s,int len,ColourAllocated fore,ColourAllocated back)618 void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len,
619                        ColourAllocated fore, ColourAllocated back) {
620   DrawTextNoClip(rc, font_, ybase, s, len, fore, back);
621 }
622 
DrawTextTransparent(PRectangle rc,Font & font_,int ybase,const char * s,int len,ColourAllocated fore)623 void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len,
624                                       ColourAllocated fore) {
625   DrawTextBase(rc, font_, ybase, s, len, fore);
626 }
627 
MeasureWidths(Font & font_,const char * s,int len,int * positions)628 void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) {
629   if (font_.GetID()) {
630     int totalWidth = 0;
631     if (unicodeMode) {
632       const char*p=s;
633       for (FXint i=0; i<len; i++) {
634         int cw=1; // number of bytes in this utf8 character
635         FXuchar c=*p;
636         if (c>127) { // no check for invalid bytes here, there's not much we could do about it anyway.
637           if ((c>=194) && (c<=223)) {
638             cw=2;
639           } else if (c<=239) {
640             cw=3;
641           } else if (c<=244) {
642             cw=4;
643           }
644         }
645         int width = font_.GetID()->getTextWidth(p, cw);
646         totalWidth += width;
647         positions[i] = totalWidth;
648         p+=cw; // this many bytes consumed
649         for (FXint j=1; j<cw; j++) { // assign the same position to each byte for multibyte chars
650           positions[i+1]=positions[i];
651           i++;
652         }
653       }
654     } else {
655       for (int i=0;i<len;i++) {
656         int default_width=font_.GetID()->getTextWidth("8", 1);
657 #ifdef WIN32 // The width of chars > #239 are incorrect on Win32, so use default.
658         int width = ((FXuchar)(s[i])<=239) ? font_.GetID()->getTextWidth(s + i, 1) : default_width;
659 #else
660         int width = font_.GetID()->getTextWidth(s + i, 1);
661 #endif
662         totalWidth += width?width:default_width;
663         positions[i] = totalWidth;
664       }
665     }
666   } else {
667     for (int i=0;i<len;i++) {
668       positions[i] = i + 1;
669     }
670   }
671 }
672 
WidthText(Font & font_,const char * s,int len)673 int SurfaceImpl::WidthText(Font &font_, const char *s, int len) {
674   if (font_.GetID())
675     return font_.GetID()->getTextWidth(s, len);
676   else
677     return 1;
678 }
679 
WidthChar(Font & font_,char ch)680 int SurfaceImpl::WidthChar(Font &font_, char ch) {
681   if (font_.GetID())
682     return font_.GetID()->getTextWidth(&ch, 1);
683   else
684     return 1;
685 }
686 
Ascent(Font & font_)687 int SurfaceImpl::Ascent(Font &font_) {
688   if (!font_.GetID())
689     return 1;
690   return font_.GetID()->getFontAscent();
691 }
692 
Descent(Font & font_)693 int SurfaceImpl::Descent(Font &font_) {
694   if (!font_.GetID())
695     return 1;
696   return font_.GetID()->getFontDescent();
697 }
698 
InternalLeading(Font &)699 int SurfaceImpl::InternalLeading(Font &) {
700   return 0;
701 }
702 
ExternalLeading(Font &)703 int SurfaceImpl::ExternalLeading(Font &) {
704   return 0;
705 }
706 
Height(Font & font_)707 int SurfaceImpl::Height(Font &font_) {
708   if (!font_.GetID())
709     return 1;
710   return font_.GetID()->getFontHeight();
711 }
712 
AverageCharWidth(Font & font_)713 int SurfaceImpl::AverageCharWidth(Font &font_) {
714   if (font_.GetID())
715     return font_.GetID()->getTextWidth("n", 1);
716   else
717     return 1;
718 }
719 
SetPalette(Palette *,bool)720 int SurfaceImpl::SetPalette(Palette *, bool) {
721   // Handled in palette allocation for GTK so this does nothing
722 // <FIXME> What about FOX ? </FIXME>
723   return 0;
724 }
725 
SetClip(PRectangle rc)726 void SurfaceImpl::SetClip(PRectangle rc) {
727   if (dc())
728     _dc->setClipRectangle(rc.left, rc.top,
729                        rc.right - rc.left, rc.bottom - rc.top);
730 }
731 
FlushCachedState()732 void SurfaceImpl::FlushCachedState() {}
733 
SetUnicodeMode(bool unicodeMode_)734 void SurfaceImpl::SetUnicodeMode(bool unicodeMode_) {
735   unicodeMode=unicodeMode_;
736 }
737 
Allocate()738 Surface *Surface::Allocate() {
739   return new SurfaceImpl;
740 }
741 
DrawRGBAImage(PRectangle rc,int width,int height,const unsigned char * pixelsImage)742 void SurfaceImpl::DrawRGBAImage( PRectangle rc, int width, int height,
743                                const unsigned char *pixelsImage) {
744 
745 }
746 
~Window()747 Window::~Window() {}
748 
Destroy()749 void Window::Destroy() {
750   if (wid)
751     delete wid;
752   wid = 0;
753 }
754 
HasFocus()755 bool Window::HasFocus() {
756   return wid->hasFocus();
757 }
758 
GetPosition()759 PRectangle Window::GetPosition() {
760   // Before any size allocated pretend its 1000 wide so not scrolled
761   PRectangle rc(0, 0, 1000, 1000);
762   if (wid) {
763     rc.left = wid->getX();
764     rc.top = wid->getY();
765     rc.right = rc.left + wid->getWidth();
766     rc.bottom = rc.top + wid->getHeight();
767   }
768   return rc;
769 }
770 
SetPosition(PRectangle rc)771 void Window::SetPosition(PRectangle rc) {
772   wid->position(rc.left, rc.top, rc.Width(), rc.Height());
773 }
774 
775 
SetPositionRelative(PRectangle rc,Window relativeTo)776 void Window::SetPositionRelative(PRectangle rc, Window relativeTo) {
777   int ox = relativeTo.GetID()->getX() + rc.left;
778   int oy = relativeTo.GetID()->getY() + rc.top;
779   if (ox < 0)
780     ox = 0;
781   if (oy < 0)
782     oy = 0;
783 
784   /* do some corrections to fit into screen */
785   int sizex = rc.right - rc.left;
786   int sizey = rc.bottom - rc.top;
787   int screenWidth = FXApp::instance()->getRootWindow()->getDefaultWidth();
788   int screenHeight = FXApp::instance()->getRootWindow()->getDefaultHeight();
789   if (sizex > screenWidth)
790     ox = 0; /* the best we can do */
791   else if (ox + sizex > screenWidth)
792     ox = screenWidth - sizex;
793   if (oy + sizey > screenHeight)
794     oy = screenHeight - sizey;
795 
796   wid->position(ox, oy, rc.Width(), rc.Height());
797 }
798 
GetClientPosition()799 PRectangle Window::GetClientPosition() {
800   // On GTK+, the client position is the window position
801   return PRectangle(0, 0, (wid) ? wid->getWidth() - 1 : 1000, (wid) ? wid->getHeight() -1 : 1000);
802 }
803 
Show(bool show)804 void Window::Show(bool show) {
805   if (show) {
806     wid->show();
807     wid->raise();
808   }
809   else
810     wid->hide();
811 }
812 
InvalidateAll()813 void Window::InvalidateAll() {
814   if (wid) {
815     wid->update();
816   }
817 }
818 
InvalidateRectangle(PRectangle rc)819 void Window::InvalidateRectangle(PRectangle rc) {
820   if (wid)
821     wid->update(rc.left, rc.top, rc.right - rc.left + 1, rc.bottom - rc.top + 1);
822 }
823 
SetFont(Font &)824 void Window::SetFont(Font &) {
825   // TODO
826 }
827 
SetCursor(Cursor curs)828 void Window::SetCursor(Cursor curs) {
829   // We don't set the cursor to same value numerous times under FOX because
830   // it stores the cursor in the window once it's set
831   if (curs == cursorLast)
832     return;
833   FXDefaultCursor cursorID;
834   cursorLast = curs;
835 
836   switch (curs) {
837   case cursorText:
838     cursorID = DEF_TEXT_CURSOR;
839     break;
840   case cursorArrow:
841     cursorID = DEF_ARROW_CURSOR;
842     break;
843   case cursorUp:
844     cursorID = DEF_MOVE_CURSOR;
845     break;
846   case cursorWait:
847     cursorID = DEF_SWATCH_CURSOR;
848     break;
849   case cursorHand:
850     // <FIXME/> Should be a hand cursor...
851         cursorID = DEF_HAND_CURSOR; //JKP
852 //    cursorID = DEF_CROSSHAIR_CURSOR;
853     break;
854   case cursorReverseArrow:
855     cursorID = DEF_RARROW_CURSOR;
856     break;
857   default:
858     cursorID = DEF_ARROW_CURSOR;
859     cursorLast = cursorArrow;
860     break;
861   }
862   wid->setDefaultCursor(wid->getApp()->getDefaultCursor(cursorID));
863 }
864 
SetTitle(const char * s)865 void Window::SetTitle(const char *s) {
866   static_cast<FXTopWindow *>(wid)->setTitle(s);
867 }
868 
869 
870 /*** JKP: FIXME: Ugly and not tested !!! ***/
GetMonitorRect(Point pt)871 PRectangle Window::GetMonitorRect(Point pt) {
872   FXRootWindow *rootwin=wid->getApp()->getRootWindow(); //(id->getApp(),id->getVisual());
873   FXint xpos=wid->getX();
874   FXint ypos=wid->getY();
875   return PRectangle(-xpos, -ypos, (-xpos) + rootwin->getDefaultWidth(),
876                     (-ypos) + rootwin->getDefaultHeight());
877 }
878 
879 // ====================================================================
880 // ListBoxFox
881 // ====================================================================
882 
883 class ListBoxFox : public ListBox
884 {
885   FXList * list;
886   map<int, FXXPMIcon *> * pixhash;
887   int desiredVisibleRows;
888   unsigned int maxItemCharacters;
889   unsigned int aveCharWidth;
890 public:
891   CallBackAction doubleClickAction;
892   void *doubleClickActionData;
893 
ListBoxFox()894   ListBoxFox() : list(0), pixhash(NULL), desiredVisibleRows(5), maxItemCharacters(0),
895     doubleClickAction(NULL), doubleClickActionData(NULL) {
896   }
~ListBoxFox()897   virtual ~ListBoxFox() {
898     ClearRegisteredImages();
899   }
900   virtual void Show(bool show=true);
901   virtual void SetFont(Font &font);
902   virtual void Create(Window &parent, int ctrlID, Point location_, int lineHeight_, bool unicodeMode_);
903   virtual void SetAverageCharWidth(int width);
904   virtual void SetVisibleRows(int rows);
905   virtual int GetVisibleRows() const;
906   virtual PRectangle GetDesiredRect();
907   virtual int CaretFromEdge();
908   virtual void Clear();
909   virtual void Append(char *s, int type = -1);
910   virtual int Length();
911   virtual void Select(int n);
912   virtual int GetSelection();
913   virtual int Find(const char *prefix);
914   virtual void GetValue(int n, char *value, int len);
915   virtual void RegisterImage(int type, const char *xpm_data);
916   virtual void ClearRegisteredImages();
SetDoubleClickAction(CallBackAction action,void * data)917   virtual void SetDoubleClickAction(CallBackAction action, void *data) {
918     doubleClickAction = action;
919     doubleClickActionData = data;
920   }
921   virtual void SetList(const char* list, char separator, char typesep);
922   virtual void RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage);
923 };
924 
925 
sListSortFunction(const FXListItem * item1,const FXListItem * item2)926 static int sListSortFunction(const FXListItem* item1, const FXListItem* item2) {
927   return compare(item1->getText(), item2->getText());
928 }
929 
930 class PopupListBox : public FXPopup
931 {
932 FXDECLARE(PopupListBox)
933 protected:
PopupListBox()934   PopupListBox() {}
935 protected:
936   ListBoxFox * listBox;
937   FXList * list;
938 public:
939   enum {
940     ID_LIST = FXPopup::ID_LAST,
941     ID_LAST,
942   };
943 public:
944   long onKeyPress(FXObject *, FXSelector, void *);
945   long onListKeyPress(FXObject *, FXSelector, void *);
946   long onDoubleClicked(FXObject *, FXSelector, void *);
947 public:
948   PopupListBox(FXComposite * p, ListBoxFox * lb);
getList()949   FXList * getList() { return list; }
setFocus()950   virtual void setFocus() {
951     FXPopup::setFocus();
952     list->grabKeyboard();
953   }
killFocus()954   virtual void killFocus() {
955     list->ungrabKeyboard();
956     FXPopup::killFocus();
957   }
958 };
959 
960 FXDEFMAP(PopupListBox) PopupListBoxMap[]={
961   FXMAPFUNC(SEL_KEYPRESS, 0, PopupListBox::onKeyPress),
962   FXMAPFUNC(SEL_KEYPRESS, PopupListBox::ID_LIST, PopupListBox::onListKeyPress),
963   FXMAPFUNC(SEL_DOUBLECLICKED, 0, PopupListBox::onDoubleClicked),
964 };
965 
FXIMPLEMENT(PopupListBox,FXPopup,PopupListBoxMap,ARRAYNUMBER (PopupListBoxMap))966 FXIMPLEMENT(PopupListBox,FXPopup,PopupListBoxMap,ARRAYNUMBER(PopupListBoxMap))
967 
968 PopupListBox::PopupListBox(FXComposite * p, ListBoxFox * lb) :  FXPopup(p), listBox(lb)
969 {
970   list = new FXList(this,
971     this, ID_LIST, LIST_BROWSESELECT|LAYOUT_FILL_X|LAYOUT_FILL_Y|SCROLLERS_TRACK|HSCROLLER_NEVER);
972   list->setSortFunc(sListSortFunction);
973 }
974 
onKeyPress(FXObject * sender,FXSelector sel,void * ptr)975 long PopupListBox::onKeyPress(FXObject * sender, FXSelector sel, void * ptr)
976 {
977   return FXPopup::onKeyPress(sender, sel, ptr);
978 }
979 
onListKeyPress(FXObject * sender,FXSelector sel,void * ptr)980 long PopupListBox::onListKeyPress(FXObject * sender, FXSelector sel, void * ptr)
981 {
982   list->setTarget(NULL);
983   list->onKeyPress(sender, sel, ptr);
984   FXEvent * event = (FXEvent *)ptr;
985 
986   switch(event->code) {
987     case KEY_Page_Up:
988     case KEY_KP_Page_Up:
989     case KEY_Page_Down:
990     case KEY_KP_Page_Down:
991     case KEY_Up:
992     case KEY_KP_Up:
993     case KEY_Down:
994     case KEY_KP_Down:
995     case KEY_Home:
996     case KEY_KP_Home:
997     case KEY_End:
998     case KEY_KP_End:
999       break;
1000     default:
1001       getOwner()->handle(this, MKUINT(0, SEL_KEYPRESS), ptr);
1002   }
1003   list->setTarget(this);
1004   return 1;
1005 }
1006 
onDoubleClicked(FXObject *,FXSelector,void *)1007 long PopupListBox::onDoubleClicked(FXObject *, FXSelector, void *)
1008 {
1009   if (listBox->doubleClickAction) {
1010     listBox->doubleClickAction(listBox->doubleClickActionData);
1011   }
1012   return 1;
1013 }
1014 
1015 // ====================================================================
1016 
Create(Window & parent,int,Point,int,bool)1017 void ListBoxFox::Create(Window & parent, int, Point, int, bool) {
1018   wid = new PopupListBox(static_cast<FXComposite *>(parent.GetID()), this);
1019   wid->create();
1020   list = (static_cast<PopupListBox *>(wid))->getList();
1021 }
1022 
SetFont(Font & scint_font)1023 void ListBoxFox::SetFont(Font &scint_font) {
1024   list->setFont(scint_font.GetID());
1025 }
1026 
SetAverageCharWidth(int width)1027 void ListBoxFox::SetAverageCharWidth(int width) {
1028     aveCharWidth = width;
1029 }
1030 
SetVisibleRows(int rows)1031 void ListBoxFox::SetVisibleRows(int rows) {
1032   list->setNumVisible(rows);
1033 }
1034 
GetVisibleRows() const1035 int ListBoxFox::GetVisibleRows() const {
1036   return list->getNumVisible();
1037 }
1038 
GetDesiredRect()1039 PRectangle ListBoxFox::GetDesiredRect() {
1040   // Before any size allocated pretend its 100 wide so not scrolled
1041   PRectangle rc(0, 0, 100, 100);
1042   if (wid) {
1043     // Height
1044     int rows = Length();
1045     if ((rows == 0) || (rows > desiredVisibleRows))
1046       rows = desiredVisibleRows;
1047     list->setNumVisible(rows);
1048     rc.bottom = wid->getHeight();
1049     // Width
1050     int width = maxItemCharacters;
1051     if (width < 12)
1052       width = 12;
1053     rc.right = width * (aveCharWidth+aveCharWidth/3);
1054     if (Length() > rows)
1055       rc.right += list->verticalScrollBar()->getWidth();
1056 
1057     // <FIXME/>
1058 /*    int rows = Length();
1059     if ((rows == 0) || (rows > desiredVisibleRows))
1060       rows = desiredVisibleRows;
1061 
1062     GtkRequisition req;
1063     int height;
1064 
1065     // First calculate height of the clist for our desired visible row count otherwise it tries to expand to the total # of rows
1066     height = (rows * GTK_CLIST(list)->row_height
1067               + rows + 1
1068               + 2 * (list->style->klass->ythickness
1069                      + GTK_CONTAINER(list)->border_width));
1070     gtk_widget_set_usize(GTK_WIDGET(list), -1, height);
1071 
1072     // Get the size of the scroller because we set usize on the window
1073     gtk_widget_size_request(GTK_WIDGET(scroller), &req);
1074     rc.right = req.width;
1075     rc.bottom = req.height;
1076 
1077     gtk_widget_set_usize(GTK_WIDGET(list), -1, -1);
1078     int width = maxItemCharacters;
1079     if (width < 12)
1080       width = 12;
1081     rc.right = width * (aveCharWidth+aveCharWidth/3);
1082     if (Length() > rows)
1083       rc.right = rc.right + 16;*/
1084   }
1085   return rc;
1086 
1087 }
1088 
Show(bool show)1089 void ListBoxFox::Show(bool show) {
1090   if (show) {
1091     (static_cast<FXPopup *>(wid))->popup(NULL, wid->getX(), wid->getY(),
1092                       wid->getWidth(), wid->getHeight());
1093     list->selectItem(0);
1094   }
1095 }
1096 
CaretFromEdge()1097 int ListBoxFox::CaretFromEdge() {
1098   // <FIXME/> return 4 + GetWidth();
1099   return 0;
1100 }
1101 
Clear()1102 void ListBoxFox::Clear() {
1103   list->clearItems();
1104   maxItemCharacters = 0;
1105 }
1106 
Append(char * s,int type)1107 void ListBoxFox::Append(char *s, int type) {
1108   FXXPMIcon * icon = NULL;
1109   if ((type >= 0) && pixhash) {
1110     map<int, FXXPMIcon *>::iterator it = pixhash->find(type);
1111     if (it != pixhash->end())
1112       icon = (*it).second;
1113   }
1114   list->appendItem(s, icon);
1115   size_t len = strlen(s);
1116   if (maxItemCharacters < len)
1117           maxItemCharacters = len;
1118   if (list->getNumItems() <= desiredVisibleRows)
1119     list->setNumVisible(list->getNumItems());
1120   list->sortItems();
1121 }
1122 
Length()1123 int ListBoxFox::Length() {
1124   if (wid)
1125     return list->getNumItems();
1126   return 0;
1127 }
1128 
Select(int n)1129 void ListBoxFox::Select(int n) {
1130   // Case n==-1 handled by FXList
1131   list->setCurrentItem(n, true);
1132 }
1133 
GetSelection()1134 int ListBoxFox::GetSelection() {
1135   // Returns -1 when no current item
1136   return list->getCurrentItem();
1137 }
1138 
Find(const char * prefix)1139 int ListBoxFox::Find(const char *prefix) {
1140   int count = Length();
1141   for (int i = 0; i < count; i++) {
1142     FXString text = list->getItemText(i);
1143     const char* s = text.text();
1144     if (s && (0 == strncmp(prefix, s, strlen(prefix)))) {
1145       return i;
1146     }
1147   }
1148   return - 1;
1149 }
1150 
GetValue(int n,char * value,int len)1151 void ListBoxFox::GetValue(int n, char *value, int len) {
1152   FXString text = list->getItemText(n);
1153   if (text.length() && len > 0) {
1154     strncpy(value, text.text(), len);
1155     value[len - 1] = '\0';
1156   } else {
1157     value[0] = '\0';
1158   }
1159 }
1160 
RegisterImage(int type,const char * xpm_data)1161 void ListBoxFox::RegisterImage(int type, const char *xpm_data)
1162 {
1163   FXXPMIcon * icon = new FXXPMIcon(FXApp::instance(), &xpm_data);
1164   icon->create();
1165   if (!pixhash)
1166     pixhash = new map<int, FXXPMIcon *>;
1167   FXXPMIcon * old = (*pixhash)[type];
1168   if (old)
1169     delete old;
1170   (*pixhash)[type] = icon;
1171 }
1172 
ClearRegisteredImages()1173 void ListBoxFox::ClearRegisteredImages()
1174 {
1175   if (pixhash) {
1176     map<int, FXXPMIcon *>::iterator it;
1177     for (it = pixhash->begin(); it != pixhash->end(); it++) {
1178       delete (*it).second;
1179     }
1180     delete pixhash;
1181   }
1182 }
1183 
SetList(const char * items,char separator,char typesep)1184 void ListBoxFox::SetList(const char* items, char separator, char typesep) {
1185   Clear();
1186   int count = strlen(items) + 1;
1187   char *words = new char[count];
1188   if (words) {
1189     memcpy(words, items, count);
1190     char *startword = words;
1191     char *numword = NULL;
1192     int i = 0;
1193     for (; words[i]; i++) {
1194       if (words[i] == separator) {
1195         words[i] = '\0';
1196         if (numword)
1197           *numword = '\0';
1198         Append(startword, numword?atoi(numword + 1):-1);
1199         startword = words + i + 1;
1200         numword = NULL;
1201       } else if (words[i] == typesep) {
1202         numword = words + i;
1203       }
1204     }
1205     if (startword) {
1206       if (numword)
1207         *numword = '\0';
1208       Append(startword, numword?atoi(numword + 1):-1);
1209     }
1210     delete []words;
1211   }
1212 }
1213 
RegisterRGBAImage(int type,int width,int height,const unsigned char * pixelsImage)1214 void ListBoxFox::RegisterRGBAImage(int type, int width, int height, const unsigned char *pixelsImage) {
1215 
1216 }
1217 
1218 
1219 // ====================================================================
1220 // ListBox
1221 // ====================================================================
1222 
ListBox()1223 ListBox::ListBox()
1224 {
1225 }
1226 
~ListBox()1227 ListBox::~ListBox()
1228 {
1229 }
1230 
Allocate()1231 ListBox * ListBox::Allocate()
1232 {
1233   return new ListBoxFox();
1234 }
1235 
1236 
1237 // ====================================================================
1238 // Menu
1239 // ====================================================================
1240 
Menu()1241 Menu::Menu() : mid(0) {}
1242 
1243 
CreatePopUp()1244 void Menu::CreatePopUp() {
1245   Destroy();
1246   mid = new FXMenuPane(FXApp::instance()->getCursorWindow());
1247 }
1248 
Destroy()1249 void Menu::Destroy() {
1250   if (mid)
1251     delete mid;
1252   mid = 0;
1253 }
1254 
Show(Point pt,Window &)1255 void Menu::Show(Point pt, Window &) {
1256   int screenHeight = FXApp::instance()->getRootWindow()->getDefaultHeight();
1257   int screenWidth = FXApp::instance()->getRootWindow()->getDefaultWidth();
1258   mid->create();
1259   if ((pt.x + mid->getWidth()) > screenWidth) {
1260     pt.x = screenWidth - mid->getWidth();
1261   }
1262   if ((pt.y + mid->getHeight()) > screenHeight) {
1263     pt.y = screenHeight - mid->getHeight();
1264   }
1265   mid->popup(NULL, pt.x - 4, pt.y);
1266   FXApp::instance()->runModalWhileShown(mid);
1267 }
1268 
1269 #ifndef WIN32
1270 
ElapsedTime()1271 ElapsedTime::ElapsedTime() {
1272   timeval curTime;
1273   gettimeofday(&curTime, NULL);
1274   bigBit = curTime.tv_sec;
1275   littleBit = curTime.tv_usec;
1276 }
1277 
Duration(bool reset)1278 double ElapsedTime::Duration(bool reset) {
1279   timeval curTime;
1280   gettimeofday(&curTime, NULL);
1281   long endBigBit = curTime.tv_sec;
1282   long endLittleBit = curTime.tv_usec;
1283   double result = 1000000.0 * (endBigBit - bigBit);
1284   result += endLittleBit - littleBit;
1285   result /= 1000000.0;
1286   if (reset) {
1287     bigBit = endBigBit;
1288     littleBit = endLittleBit;
1289   }
1290   return result;
1291 }
1292 
1293 #else  // WIN32
1294 
1295 static bool initialisedET = false;
1296 static bool usePerformanceCounter = false;
1297 static LARGE_INTEGER frequency;
1298 
ElapsedTime()1299 ElapsedTime::ElapsedTime() {
1300   if (!initialisedET) {
1301     usePerformanceCounter = ::QueryPerformanceFrequency(&frequency);
1302     initialisedET = true;
1303   }
1304   if (usePerformanceCounter) {
1305     LARGE_INTEGER timeVal;
1306     ::QueryPerformanceCounter(&timeVal);
1307     bigBit = timeVal.HighPart;
1308     littleBit = timeVal.LowPart;
1309   } else {
1310     bigBit = clock();
1311   }
1312 }
1313 
Duration(bool reset)1314 double ElapsedTime::Duration(bool reset) {
1315   double result;
1316   long endBigBit;
1317   long endLittleBit;
1318 
1319   if (usePerformanceCounter) {
1320     LARGE_INTEGER lEnd;
1321     ::QueryPerformanceCounter(&lEnd);
1322     endBigBit = lEnd.HighPart;
1323     endLittleBit = lEnd.LowPart;
1324     LARGE_INTEGER lBegin;
1325     lBegin.HighPart = bigBit;
1326     lBegin.LowPart = littleBit;
1327     double elapsed = lEnd.QuadPart - lBegin.QuadPart;
1328     result = elapsed / static_cast<double>(frequency.QuadPart);
1329   } else {
1330     endBigBit = clock();
1331     endLittleBit = 0;
1332     double elapsed = endBigBit - bigBit;
1333     result = elapsed / CLOCKS_PER_SEC;
1334   }
1335   if (reset) {
1336     bigBit = endBigBit;
1337     littleBit = endLittleBit;
1338   }
1339   return result;
1340 }
1341 #endif  // WIN32
1342 
1343 // ====================================================================
1344 // Dynamic library handling.
1345 // - fxdllXxx API with Fox >= 1.2
1346 // ====================================================================
1347 
1348 // Fox >= 1.2 has dynamic librarie handling
1349 
1350 
1351 #include <FXDLL.h>
1352 
1353 #ifdef FOX_1_6
1354 class DynamicLibraryImpl : public DynamicLibrary {
1355 protected:
1356   void * m;
1357 public:
DynamicLibraryImpl(const char * modulePath)1358   DynamicLibraryImpl(const char *modulePath) {
1359     m = fxdllOpen(modulePath);
1360   }
1361 
~DynamicLibraryImpl()1362   virtual ~DynamicLibraryImpl() {
1363     if (m != NULL)
1364       fxdllClose(m);
1365   }
1366 
1367   // Use lt_dlsym to get a pointer to the relevant function.
FindFunction(const char * name)1368   virtual Function FindFunction(const char *name) {
1369     if (m != NULL) {
1370       return fxdllSymbol(m, name);
1371     } else
1372       return NULL;
1373   }
1374 
IsValid()1375   virtual bool IsValid() {
1376     return m != NULL;
1377   }
1378 };
1379 #else
1380 class DynamicLibraryImpl : public DynamicLibrary {
1381 protected:
1382   FXDLL*dll;
1383 public:
DynamicLibraryImpl(const char * modulePath)1384   DynamicLibraryImpl(const char *modulePath) {
1385       dll=new FXDLL();
1386     dll->load(modulePath);
1387   }
1388 
~DynamicLibraryImpl()1389   virtual ~DynamicLibraryImpl() {
1390     dll->unload();
1391     delete dll;
1392   }
1393 
1394 
1395   // Use lt_dlsym to get a pointer to the relevant function.
FindFunction(const char * name)1396   virtual Function FindFunction(const char *name) {
1397     if (dll->loaded()) {
1398       return dll->address(name);
1399     } else
1400       return NULL;
1401   }
1402 
IsValid()1403   virtual bool IsValid() {
1404     return dll->loaded();
1405   }
1406 };
1407 #endif
1408 
1409 
Load(const char * modulePath)1410 DynamicLibrary *DynamicLibrary::Load(const char *modulePath) {
1411   return static_cast<DynamicLibrary *>( new DynamicLibraryImpl(modulePath) );
1412 }
1413 
1414 
1415 // ====================================================================
1416 // Platform
1417 // ====================================================================
1418 
Chrome()1419 ColourDesired Platform::Chrome() {
1420   return ColourDesired(0xe0, 0xe0, 0xe0);
1421 }
1422 
ChromeHighlight()1423 ColourDesired Platform::ChromeHighlight() {
1424   return ColourDesired(0xff, 0xff, 0xff);
1425 }
1426 
DefaultFont()1427 const char *Platform::DefaultFont() {
1428   static FXString fontName;
1429   fontName = FXApp::instance()->getNormalFont()->getName();
1430   return fontName.text();
1431 }
1432 
DefaultFontSize()1433 int Platform::DefaultFontSize() {
1434   // Warning: FOX gives the font size in deci-point
1435   return FXApp::instance()->getNormalFont()->getSize() / 10;
1436 }
1437 
DoubleClickTime()1438 unsigned int Platform::DoubleClickTime() {
1439   return 500;   // Half a second
1440 }
1441 
MouseButtonBounce()1442 bool Platform::MouseButtonBounce() {
1443   return true; // <FIXME/> same as gtk?
1444 }
1445 
DebugDisplay(const char * s)1446 void Platform::DebugDisplay(const char *s) {
1447   printf("%s", s);
1448 }
1449 
IsKeyDown(int)1450 bool Platform::IsKeyDown(int) {
1451   // TODO: discover state of keys in GTK+/X
1452   return false;
1453 }
1454 
1455 /* These methods are now implemented in ScintillaFOX.cxx
1456 long Platform::SendScintilla(WindowID w, unsigned int msg,
1457                              unsigned long wParam, long lParam) {
1458   return static_cast<FXScintilla *>(w)->sendMessage(msg, wParam, lParam);
1459 }
1460 long Platform::SendScintillaPointer(WindowID w, unsigned int msg,
1461                                     unsigned long wParam, void *lParam) {
1462   return static_cast<FXScintilla *>(w)->
1463     sendMessage(msg, wParam, reinterpret_cast<sptr_t>(lParam));
1464 }
1465 */
1466 
IsDBCSLeadByte(int,char)1467 bool Platform::IsDBCSLeadByte(int /*codePage*/, char /*ch*/) {
1468   return false;
1469 }
1470 
DBCSCharLength(int,const char * s)1471 int Platform::DBCSCharLength(int /*codePage*/, const char *s) {
1472   int bytes = mblen(s, MB_CUR_MAX);
1473   if (bytes >= 1)
1474     return bytes;
1475   else
1476     return 1;
1477 }
1478 
DBCSCharMaxLength()1479 int Platform::DBCSCharMaxLength() {
1480   return MB_CUR_MAX;
1481 }
1482 
1483 // These are utility functions not really tied to a platform
1484 
Minimum(int a,int b)1485 int Platform::Minimum(int a, int b) {
1486   if (a < b)
1487     return a;
1488   else
1489     return b;
1490 }
1491 
Maximum(int a,int b)1492 int Platform::Maximum(int a, int b) {
1493   if (a > b)
1494     return a;
1495   else
1496     return b;
1497 }
1498 
1499 //#define TRACE
1500 
1501 #ifdef TRACE
DebugPrintf(const char * format,...)1502 void Platform::DebugPrintf(const char *format, ...) {
1503   char buffer[2000];
1504   va_list pArguments;
1505   va_start(pArguments, format);
1506   vsprintf(buffer, format, pArguments);
1507   va_end(pArguments);
1508   Platform::DebugDisplay(buffer);
1509 }
1510 #else
DebugPrintf(const char *,...)1511 void Platform::DebugPrintf(const char *, ...) {
1512 }
1513 #endif
1514 
1515 // Not supported for GTK+
1516 static bool assertionPopUps = true;
1517 
ShowAssertionPopUps(bool assertionPopUps_)1518 bool Platform::ShowAssertionPopUps(bool assertionPopUps_) {
1519   bool ret = assertionPopUps;
1520   assertionPopUps = assertionPopUps_;
1521   return ret;
1522 }
1523 
Assert(const char * c,const char * file,int line)1524 void Platform::Assert(const char *c, const char *file, int line) {
1525   char buffer[2000];
1526   sprintf(buffer, "Assertion [%s] failed at %s %d", c, file, line);
1527   strcat(buffer, "\r\n");
1528   Platform::DebugDisplay(buffer);
1529   abort();
1530 }
1531 
Clamp(int val,int minVal,int maxVal)1532 int Platform::Clamp(int val, int minVal, int maxVal) {
1533   if (val > maxVal)
1534     val = maxVal;
1535   if (val < minVal)
1536     val = minVal;
1537   return val;
1538 }
1539