wxPostScriptDC::wxPostScriptDC ()
{
m_pstream = (ofstream*) NULL;
-
+
m_currentRed = 0;
m_currentGreen = 0;
m_currentBlue = 0;
-
+
m_pageNumber = 0;
-
+
m_clipping = FALSE;
-
+
m_underlinePosition = 0.0;
m_underlineThickness = 0.0;
wxPostScriptDC::wxPostScriptDC (const wxString& file, bool interactive, wxWindow *parent)
{
m_pstream = (ofstream*) NULL;
-
+
m_currentRed = 0;
m_currentGreen = 0;
m_currentBlue = 0;
-
+
m_pageNumber = 0;
-
+
m_clipping = FALSE;
-
+
m_underlinePosition = 0.0;
m_underlineThickness = 0.0;
{
m_ok = TRUE;
}
-
+
return m_ok;
}
{
return m_ok;
}
-
+
bool wxPostScriptDC::PrinterDialog(wxWindow *parent)
{
- wxPostScriptPrintDialog dialog( parent, _("Printer Settings"), wxPoint(150, 150), wxSize(400, 400),
+ wxPostScriptPrintDialog dialog( parent, _("Printer Settings"), wxPoint(150, 150), wxSize(400, 400),
wxDEFAULT_DIALOG_STYLE | wxDIALOG_MODAL );
m_ok = (dialog.ShowModal () == wxID_OK);
if (!m_ok) return FALSE;
- if ((m_filename == "") &&
- (wxThePrintSetupData->GetPrinterMode() == PS_PREVIEW ||
+ if ((m_filename == "") &&
+ (wxThePrintSetupData->GetPrinterMode() == PS_PREVIEW ||
wxThePrintSetupData->GetPrinterMode() == PS_PRINTER))
{
// steve, 05.09.94
void wxPostScriptDC::SetClippingRegion (long x, long y, long w, long h)
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (m_clipping) return;
wxDC::SetClippingRegion( x, y, w, h );
-
+
m_clipping = TRUE;
- *m_pstream << "gsave\n"
- << "newpath\n"
+ *m_pstream << "gsave\n"
+ << "newpath\n"
<< XLOG2DEV(x) << " " << YLOG2DEV(y) << " moveto\n"
<< XLOG2DEV(x+w) << " " << YLOG2DEV(y) << " lineto\n"
<< XLOG2DEV(x+w) << " " << YLOG2DEV(y+h) << " lineto\n"
void wxPostScriptDC::DestroyClippingRegion()
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
wxDC::DestroyClippingRegion();
-
+
if (m_clipping)
{
m_clipping = FALSE;
void wxPostScriptDC::DrawLine (long x1, long y1, long x2, long y2)
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (m_pen.GetStyle() == wxTRANSPARENT) return;
-
+
SetPen( m_pen );
-
+
*m_pstream << "newpath\n"
<< XLOG2DEV(x1) << " " << YLOG2DEV (y1) << " moveto\n"
<< XLOG2DEV(x2) << " " << YLOG2DEV (y2) << " lineto\n"
<< "stroke\n";
-
+
CalcBoundingBox( x1, y1 );
CalcBoundingBox( x2, y2 );
}
void wxPostScriptDC::DrawArc (long x1, long y1, long x2, long y2, long xc, long yc)
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
long dx = x1 - xc;
long dy = y1 - yc;
long radius = (long) sqrt(dx*dx+dy*dy);
double alpha1, alpha2;
- if (x1 == x2 && y1 == y2)
+ if (x1 == x2 && y1 == y2)
{
alpha1 = 0.0;
alpha2 = 360.0;
- } else if (radius == 0.0)
+ } else if (radius == 0.0)
{
alpha1 = alpha2 = 0.0;
- } else
+ } else
{
alpha1 = (x1 - xc == 0) ?
(y1 - yc < 0) ? 90.0 : -90.0 :
while (alpha1 > 360) alpha1 -= 360; // 0 and 360 degree
while (alpha2 > 360) alpha2 -= 360;
- if (m_brush.GetStyle() != wxTRANSPARENT)
+ if (m_brush.GetStyle() != wxTRANSPARENT)
{
SetBrush( m_brush );
*m_pstream << "newpath\n"
<< "closepath\n"
<< "fill\n";
}
-
- if (m_pen.GetStyle() != wxTRANSPARENT)
+
+ if (m_pen.GetStyle() != wxTRANSPARENT)
{
SetPen( m_pen );
*m_pstream << "newpath\n"
<< alpha2 << " ellipse\n"
<< "stroke\n";
}
-
+
CalcBoundingBox( xc-radius, yc-radius );
CalcBoundingBox( xc+radius, yc+radius );
}
void wxPostScriptDC::DrawEllipticArc(long x,long y,long w,long h,double sa,double ea)
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (sa>=360 || sa<=-360) sa=sa-int(sa/360)*360;
if (ea>=360 || ea<=-360) ea=ea-int(ea/360)*360;
if (sa<0) sa+=360;
if (ea<0) ea+=360;
-
+
if (sa==ea)
{
DrawEllipse(x,y,w,h);
{
SetBrush( m_brush );
- *m_pstream << "newpath\n"
- << XLOG2DEV(x+w/2) << " " << YLOG2DEV(y+h/2) << " "
- << XLOG2DEVREL(w/2) << " " << YLOG2DEVREL(h/2) << " "
+ *m_pstream << "newpath\n"
+ << XLOG2DEV(x+w/2) << " " << YLOG2DEV(y+h/2) << " "
+ << XLOG2DEVREL(w/2) << " " << YLOG2DEVREL(h/2) << " "
<< int(sa) <<" "<< int(ea) << " true ellipticarc\n";
CalcBoundingBox( x ,y );
CalcBoundingBox( x+w, y+h );
}
-
+
if (m_pen.GetStyle () != wxTRANSPARENT)
{
SetPen( m_pen );
- *m_pstream << "newpath\n"
- << XLOG2DEV(x+w/2) << " " << YLOG2DEV(y+h/2) << " "
- << XLOG2DEVREL(w/2) << " " << XLOG2DEVREL(h/2) << " "
+ *m_pstream << "newpath\n"
+ << XLOG2DEV(x+w/2) << " " << YLOG2DEV(y+h/2) << " "
+ << XLOG2DEVREL(w/2) << " " << XLOG2DEVREL(h/2) << " "
<< int(sa) <<" "<< int(ea) << " false ellipticarc\n";
CalcBoundingBox( x, y );
void wxPostScriptDC::DrawPoint (long x, long y)
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (m_pen.GetStyle() == wxTRANSPARENT) return;
-
+
SetPen (m_pen);
-
+
*m_pstream << "newpath\n"
<< XLOG2DEV(x) << " " << YLOG2DEV (y) << " moveto\n"
<< XLOG2DEV(x+1) << " " << YLOG2DEV (y) << " lineto\n"
<< "stroke\n";
-
+
CalcBoundingBox( x, y );
}
void wxPostScriptDC::DrawPolygon (int n, wxPoint points[], long xoffset, long yoffset, int WXUNUSED(fillStyle))
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (n <= 0) return;
-
+
if (m_brush.GetStyle () != wxTRANSPARENT)
{
SetBrush( m_brush );
-
+
*m_pstream << "newpath\n";
long xx = XLOG2DEV(points[0].x + xoffset);
if (m_pen.GetStyle () != wxTRANSPARENT)
{
SetPen( m_pen );
-
+
*m_pstream << "newpath\n";
long xx = XLOG2DEV(points[0].x + xoffset);
void wxPostScriptDC::DrawLines (int n, wxPoint points[], long xoffset, long yoffset)
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (m_pen.GetStyle() == wxTRANSPARENT)
return;
if (n <= 0)
return;
-
+
SetPen (m_pen);
-
+
int i;
for ( i =0; i<n ; i++ )
{
*m_pstream << "newpath\n"
<< XLOG2DEV(points[0].x+xoffset) << " "
<< YLOG2DEV(points[0].y+yoffset) << " moveto\n";
-
- for (i = 1; i < n; i++)
+
+ for (i = 1; i < n; i++)
{
*m_pstream << XLOG2DEV(points[i].x+xoffset) << " "
<< YLOG2DEV(points[i].y+yoffset) << " lineto\n";
}
-
+
*m_pstream << "stroke\n";
}
void wxPostScriptDC::DrawRectangle (long x, long y, long width, long height)
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (m_brush.GetStyle () != wxTRANSPARENT)
{
SetBrush( m_brush );
CalcBoundingBox( x, y );
CalcBoundingBox( x + width, y + height );
}
-
+
if (m_pen.GetStyle () != wxTRANSPARENT)
{
SetPen (m_pen);
void wxPostScriptDC::DrawRoundedRectangle (long x, long y, long width, long height, double radius)
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (radius < 0.0)
{
// Now, a negative radius is interpreted to mean
smallest = height;
radius = (-radius * smallest);
}
-
+
long rad = (long) radius;
if (m_brush.GetStyle () != wxTRANSPARENT)
{
SetBrush( m_brush );
-
+
// Draw rectangle anticlockwise
*m_pstream << "newpath\n"
<< XLOG2DEV(x + rad) << " " << YLOG2DEV(y + rad) << " " << XLOG2DEVREL(rad) << " 90 180 arc\n"
CalcBoundingBox( x, y );
CalcBoundingBox( x + width, y + height );
}
-
+
if (m_pen.GetStyle () != wxTRANSPARENT)
{
SetPen (m_pen);
-
+
// Draw rectangle anticlockwise
*m_pstream << "newpath\n"
<< XLOG2DEV(x + rad) << " " << YLOG2DEV(y + rad) << " " << XLOG2DEVREL(rad) << " 90 180 arc\n"
void wxPostScriptDC::DrawEllipse (long x, long y, long width, long height)
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (m_brush.GetStyle () != wxTRANSPARENT)
{
SetBrush (m_brush);
- *m_pstream << "newpath\n"
- << XLOG2DEV(x + width / 2) << " " << YLOG2DEV(y + height / 2) << " "
- << XLOG2DEV(width / 2) << " " << YLOG2DEVREL(height / 2) << " 0 360 ellipse\n"
+ *m_pstream << "newpath\n"
+ << XLOG2DEV(x + width / 2) << " " << YLOG2DEV(y + height / 2) << " "
+ << XLOG2DEV(width / 2) << " " << YLOG2DEVREL(height / 2) << " 0 360 ellipse\n"
<< "fill\n";
CalcBoundingBox( x - width, y - height );
CalcBoundingBox( x + width, y + height );
}
-
+
if (m_pen.Ok() && m_pen.GetStyle () != wxTRANSPARENT)
{
SetPen (m_pen);
- *m_pstream << "newpath\n"
- << XLOG2DEV(x + width / 2) << " " << YLOG2DEV(y + height / 2) << " "
- << XLOG2DEV(width / 2) << " " << YLOG2DEVREL(height / 2) << " 0 360 ellipse\n"
+ *m_pstream << "newpath\n"
+ << XLOG2DEV(x + width / 2) << " " << YLOG2DEV(y + height / 2) << " "
+ << XLOG2DEV(width / 2) << " " << YLOG2DEVREL(height / 2) << " 0 360 ellipse\n"
<< "stroke\n";
CalcBoundingBox( x - width, y - height );
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
if (!bitmap.Ok()) return;
-
+
wxImage image( bitmap );
-
+
if (!image.Ok()) return;
-
+
int ww = XLOG2DEVREL(image.GetWidth());
int hh = YLOG2DEVREL(image.GetHeight());
-
+
image = image.Scale( ww, hh );
-
+
if (!image.Ok()) return;
-
+
int xx = XLOG2DEV(x);
int yy = YLOG2DEV(y + bitmap.GetHeight());
-
+
*m_pstream << "/origstate save def\n"
<< "20 dict begin\n"
<< "/pix " << ww << " string def\n"
<< "[" << ww << " 0 0 " << (-hh) << " 0 " << hh << "]\n"
<< "{currentfile pix readhexstring pop}\n"
<< "false 3 colorimage\n";
-
+
for (int j = 0; j < hh; j++)
{
for (int i = 0; i < ww; i++)
*m_pstream << "end\n";
*m_pstream << "origstate restore\n";
-
+
}
void wxPostScriptDC::SetFont( const wxFont& font )
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (!font.Ok()) return;
-
+
m_font = font;
const char *name;
char buf[100];
strcpy (buf, name);
strcat (buf, style);
-
+
*m_pstream << buf << " reencodeISO def\n";
*m_pstream << buf << " findfont\n";
*m_pstream << YLOG2DEVREL(m_font.GetPointSize()) << " scalefont setfont\n";
void wxPostScriptDC::SetPen( const wxPen& pen )
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (!pen.Ok()) return;
-
+
int oldStyle = m_pen.GetStyle();
m_pen = pen;
/*
Line style - WRONG: 2nd arg is OFFSET
-
+
Here, I'm afraid you do not conceive meaning of parameters of 'setdash'
operator correctly. You should look-up this in the Red Book: the 2nd parame-
ter is not number of values in the array of the first one, but an offset
case wxTRANSPARENT:
default: psdash = "[] 0"; break;
}
-
+
if (oldStyle != m_pen.GetStyle())
{
*m_pstream << psdash << " setdash\n";
green = (unsigned char) 0;
blue = (unsigned char) 0;
}
-
+
// setgray here ?
}
void wxPostScriptDC::SetBrush( const wxBrush& brush )
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (!brush.Ok()) return;
-
+
m_brush = brush;
// Brush colour
green = (unsigned char) 255;
blue = (unsigned char) 255;
}
-
+
// setgray here ?
}
void wxPostScriptDC::DrawText( const wxString& text, long x, long y, bool WXUNUSED(use16bit) )
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
SetFont( m_font );
if (m_textForegroundColour.Ok ())
blue = (unsigned char) 0;
}
}
-
+
// maybe setgray here ?
-
+
if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue))
{
long redPS = (long) (((int) red) / 255.0);
long by = y + (long)floor( float(size) * 2.0 / 3.0 ); // approximate baseline
*m_pstream << XLOG2DEV(x) << " " << YLOG2DEV(by) << " moveto\n";
-
+
*m_pstream << "(";
int len = strlen ((char *)(const char *)text);
int i;
long uy = (long)(y + size - m_underlinePosition);
long w, h;
GetTextExtent(text, &w, &h);
-
+
*m_pstream << "gsave " << XLOG2DEV(x) << " " << YLOG2DEV(uy)
<< " moveto\n"
<< (long)m_underlineThickness << " setlinewidth "
<< XLOG2DEV(x + w) << " " << YLOG2DEV(uy)
<< " lineto stroke grestore\n";
}
-
+
CalcBoundingBox( x, y );
CalcBoundingBox( x + size * text.Length() * 2/3 , y );
}
void wxPostScriptDC::DrawSpline( wxList *points )
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
SetPen( m_pen );
double a, b, c, d, x1, y1, x2, y2, x3, y3;
wxNode *node = points->First();
p = (wxPoint *)node->Data();
- x1 = p->x;
+ x1 = p->x;
y1 = p->y;
node = node->Next();
p = (wxPoint *)node->Data();
- c = p->x;
+ c = p->x;
d = p->y;
x3 = a = (double)(x1 + c) / 2;
y3 = b = (double)(y1 + d) / 2;
- *m_pstream << "newpath "
- << XLOG2DEV((long)x1) << " " << YLOG2DEV((long)y1) << " moveto "
+ *m_pstream << "newpath "
+ << XLOG2DEV((long)x1) << " " << YLOG2DEV((long)y1) << " moveto "
<< XLOG2DEV((long)x3) << " " << YLOG2DEV((long)y3) << " lineto\n";
-
+
CalcBoundingBox( (long)x1, (long)y1 );
CalcBoundingBox( (long)x3, (long)y3 );
{
q = (wxPoint *)node->Data();
- x1 = x3;
+ x1 = x3;
y1 = y3;
- x2 = c;
+ x2 = c;
y2 = d;
- c = q->x;
+ c = q->x;
d = q->y;
x3 = (double)(x2 + c) / 2;
y3 = (double)(y2 + d) / 2;
- *m_pstream << XLOG2DEV((long)x1) << " " << YLOG2DEV((long)y1) << " "
+ *m_pstream << XLOG2DEV((long)x1) << " " << YLOG2DEV((long)y1) << " "
<< XLOG2DEV((long)x2) << " " << YLOG2DEV((long)y2) << " "
<< XLOG2DEV((long)x3) << " " << YLOG2DEV((long)y3) << " DrawSplineSection\n";
CalcBoundingBox( (long)x1, (long)y1 );
CalcBoundingBox( (long)x3, (long)y3 );
}
-
+
/*
At this point, (x2,y2) and (c,d) are the position of the
next-to-last and last point respectively, in the point list
void wxPostScriptDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
m_signX = (xLeftRight ? 1 : -1);
m_signY = (yBottomUp ? 1 : -1);
-
+
// FIXME there is no such function in MSW
#ifndef __WXMSW__
ComputeScaleAndOrigin();
void wxPostScriptDC::SetDeviceOrigin( long x, long y )
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
int h = 0;
int w = 0;
GetSize( &w, &h );
-
+
wxDC::SetDeviceOrigin( x, h-y );
}
void wxPostScriptDC::GetSize(int* width, int* height) const
{
const char *paperType = wxThePrintSetupData->GetPaperName();
-
+
if (!paperType) paperType = _("A4 210 x 297 mm");
wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(paperType);
-
+
if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(_("A4 210 x 297 mm"));
-
+
if (paper)
{
if (width) *width = paper->widthPixels;
bool wxPostScriptDC::StartDoc (const wxString& message)
{
wxCHECK_MSG( m_ok, FALSE, "invalid postscript dc" );
-
+
if (m_filename == "")
{
m_filename = wxGetTempFileName("ps");
}
m_pstream = new ofstream (wxThePrintSetupData->GetPrinterFile());
-
+
if (!m_pstream || !m_pstream->good())
{
wxMessageBox (_("Cannot open file!"), _("Error"), wxOK);
m_ok = FALSE;
return FALSE;
}
-
+
m_ok = TRUE;
SetBrush( *wxBLACK_BRUSH );
// set origin according to paper size
SetDeviceOrigin( 0,0 );
-
+
wxPageNumber = 1;
m_pageNumber = 1;
m_title = message;
void wxPostScriptDC::EndDoc ()
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
if (m_clipping)
{
m_clipping = FALSE;
}
char *header_file = wxGetTempFileName("ps");
-
+
m_pstream = new ofstream( header_file );
*m_pstream << "%!PS-Adobe-2.0\n"; /* PostScript magic strings */
void wxPostScriptDC::StartPage ()
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
*m_pstream << "%%Page: " << (wxPageNumber++) << "\n";
-
+
// *m_pstream << "matrix currentmatrix\n";
// Added by Chris Breeze
// Each page starts with an "initgraphics" which resets the
// transformation and so we need to reset the origin
// (and rotate the page for landscape printing)
-
+
/*
m_scaleFactor = 1.0;
m_logicalOriginX = 0;
m_logicalOriginY = 0;
*/
- // Output scaling
- long translate_x, translate_y;
- double scale_x, scale_y;
- wxThePrintSetupData->GetPrinterTranslation(&translate_x, &translate_y);
- wxThePrintSetupData->GetPrinterScaling(&scale_x, &scale_y);
+ // Output scaling
+ long translate_x, translate_y;
+ double scale_x, scale_y;
+ wxThePrintSetupData->GetPrinterTranslation(&translate_x, &translate_y);
+ wxThePrintSetupData->GetPrinterScaling(&scale_x, &scale_y);
- if (wxThePrintSetupData->GetPrinterOrientation() == PS_LANDSCAPE)
- {
- translate_y -= m_maxY;
- *m_pstream << "90 rotate\n";
- }
+ if (wxThePrintSetupData->GetPrinterOrientation() == PS_LANDSCAPE)
+ {
+ translate_y -= m_maxY;
+ *m_pstream << "90 rotate\n";
+ }
- *m_pstream << scale_x << " " << scale_y << " scale\n";
- *m_pstream << translate_x << " " << translate_y << " translate\n";
+ *m_pstream << scale_x << " " << scale_y << " scale\n";
+ *m_pstream << translate_x << " " << translate_y << " translate\n";
}
void wxPostScriptDC::EndPage ()
{
wxCHECK_RET( m_ok && m_pstream, "invalid postscript dc" );
-
+
*m_pstream << "showpage\n";
}
-bool wxPostScriptDC::Blit( long xdest, long ydest,
+bool wxPostScriptDC::Blit( long xdest, long ydest,
long fwidth, long fheight,
- wxDC *source,
- long xsrc, long ysrc,
+ wxDC *source,
+ long xsrc, long ysrc,
int rop, bool WXUNUSED(useMask) )
{
wxCHECK_MSG( m_ok && m_pstream, FALSE, "invalid postscript dc" );
-
+
wxCHECK_MSG( source, FALSE, "invalid source dc" );
-
+
/* blit into a bitmap */
-
- wxBitmap bitmap( fwidth, fheight );
+
+ wxBitmap bitmap( (int)fwidth, (int)fheight );
wxMemoryDC memDC;
memDC.SelectObject(bitmap);
memDC.Blit(0, 0, fwidth, fheight, source, xsrc, ysrc, rop); /* TODO: Blit transparently? */
/* draw bitmap. scaling and positioning is done there */
DrawBitmap( bitmap, xdest, ydest );
-
+
return TRUE;
}
bool WXUNUSED(use16) )
{
wxFont *fontToUse = theFont;
-
+
if (!fontToUse) fontToUse = (wxFont*) &m_font;
wxCHECK_RET( fontToUse, "GetTextExtent: no font defined" );
/* Provide a VERY rough estimate (avoid using it).
* Produces accurate results for mono-spaced font
* such as Courier (aka wxMODERN) */
-
+
int height = 12;
if (fontToUse)
{
- height = fontToUse->GetPointSize();
+ height = fontToUse->GetPointSize();
}
*x = strlen (string) * height * 72 / 120;
- *y = (long) (height * 1.32); /* allow for descender */
+ *y = (long) (height * 1.32); /* allow for descender */
if (descent) *descent = 0;
if (externalLeading) *externalLeading = 0;
#else
- /* method for calculating string widths in postscript:
- / read in the AFM (adobe font metrics) file for the
- / actual font, parse it and extract the character widths
- / and also the descender. this may be improved, but for now
- / it works well. the AFM file is only read in if the
- / font is changed. this may be chached in the future.
- / calls to GetTextExtent with the font unchanged are rather
- / efficient!!!
- /
- / for each font and style used there is an AFM file necessary.
- / currently i have only files for the roman font family.
- / I try to get files for the other ones!
- /
- / CAVE: the size of the string is currently always calculated
- / in 'points' (1/72 of an inch). this should later on be
- / changed to depend on the mapping mode.
- / CAVE: the path to the AFM files must be set before calling this
- / function. this is usually done by a call like the following:
- / wxSetAFMPath("d:\\wxw161\\afm\\");
- /
- / example:
- /
- / wxPostScriptDC dc(NULL, TRUE);
- / if (dc.Ok()){
- / wxSetAFMPath("d:\\wxw161\\afm\\");
- / dc.StartDoc("Test");
- / dc.StartPage();
- / long w,h;
- / dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL));
- / dc.GetTextExtent("Hallo",&w,&h);
- / dc.EndPage();
- / dc.EndDoc();
- / }
- /
- / by steve (stefan.hammes@urz.uni-heidelberg.de)
- / created: 10.09.94
- / updated: 14.05.95 */
+ /* method for calculating string widths in postscript:
+ / read in the AFM (adobe font metrics) file for the
+ / actual font, parse it and extract the character widths
+ / and also the descender. this may be improved, but for now
+ / it works well. the AFM file is only read in if the
+ / font is changed. this may be chached in the future.
+ / calls to GetTextExtent with the font unchanged are rather
+ / efficient!!!
+ /
+ / for each font and style used there is an AFM file necessary.
+ / currently i have only files for the roman font family.
+ / I try to get files for the other ones!
+ /
+ / CAVE: the size of the string is currently always calculated
+ / in 'points' (1/72 of an inch). this should later on be
+ / changed to depend on the mapping mode.
+ / CAVE: the path to the AFM files must be set before calling this
+ / function. this is usually done by a call like the following:
+ / wxSetAFMPath("d:\\wxw161\\afm\\");
+ /
+ / example:
+ /
+ / wxPostScriptDC dc(NULL, TRUE);
+ / if (dc.Ok()){
+ / wxSetAFMPath("d:\\wxw161\\afm\\");
+ / dc.StartDoc("Test");
+ / dc.StartPage();
+ / long w,h;
+ / dc.SetFont(new wxFont(10, wxROMAN, wxNORMAL, wxNORMAL));
+ / dc.GetTextExtent("Hallo",&w,&h);
+ / dc.EndPage();
+ / dc.EndDoc();
+ / }
+ /
+ / by steve (stefan.hammes@urz.uni-heidelberg.de)
+ / created: 10.09.94
+ / updated: 14.05.95 */
/* these static vars are for storing the state between calls */
static int lastFamily= INT_MIN;
char *name = (char*) NULL;
switch (Family)
- {
- case wxMODERN:
- {
- if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "CourBoO";
- else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "CourBo";
- else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "Cour0";
- else name = "Cour";
- }
- break;
- case wxROMAN:
- {
- if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "TimesBoO";
- else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "TimesBo";
- else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "TimesO";
- else if name = "TimesRo"; /* no typo */
- }
- break;
- default:
- {
- if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "HelvBoO";
- else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "HelvBo";
- else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "Helv0";
- else name = "Helv";
- }
- break;
- }
+ {
+ case wxMODERN:
+ {
+ if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "CourBoO";
+ else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "CourBo";
+ else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "Cour0";
+ else name = "Cour";
+ }
+ break;
+ case wxROMAN:
+ {
+ if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "TimesBoO";
+ else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "TimesBo";
+ else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "TimesO";
+ else if name = "TimesRo"; /* no typo */
+ }
+ break;
+ default:
+ {
+ if ((Style == wxITALIC) && (Weight == wxBOLD)) name = "HelvBoO";
+ else if ((Style != wxITALIC) && (Weight == wxBOLD)) name = "HelvBo";
+ else if ((Style == wxITALIC) && (Weight != wxBOLD)) name = "Helv0";
+ else name = "Helv";
+ }
+ break;
+ }
/* get the directory of the AFM files */
char afmName[256];
afmName[0] = 0;
if (wxGetAFMPath()) strcpy( afmName, wxGetAFMPath() );
- /* 2. open and process the file
- / a short explanation of the AFM format:
- / we have for each character a line, which gives its size
- / e.g.:
- /
- / C 63 ; WX 444 ; N question ; B 49 -14 395 676 ;
- /
- / that means, we have a character with ascii code 63, and width
- / (444/1000 * fontSize) points.
- / the other data is ignored for now!
- /
- / when the font has changed, we read in the right AFM file and store the
- / character widths in an array, which is processed below (see point 3.). */
+ /* 2. open and process the file
+ / a short explanation of the AFM format:
+ / we have for each character a line, which gives its size
+ / e.g.:
+ /
+ / C 63 ; WX 444 ; N question ; B 49 -14 395 676 ;
+ /
+ / that means, we have a character with ascii code 63, and width
+ / (444/1000 * fontSize) points.
+ / the other data is ignored for now!
+ /
+ / when the font has changed, we read in the right AFM file and store the
+ / character widths in an array, which is processed below (see point 3.). */
/* new elements JC Sun Aug 25 23:21:44 MET DST 1996 */
for (int i=0; i<256; i++) lastWidths[i] = 500; /* an approximate value */
lastDescender = -150; /* dito. */
}
- else
- {
+ else
+ {
/* init the widths array */
for(int i=0; i<256; i++) lastWidths[i] = INT_MIN;
/* some variables for holding parts of a line */
int ascii,cWidth;
/* read in the file and parse it */
while(fgets(line,sizeof(line),afmFile)!=NULL)
- {
+ {
/* A.) check for descender definition */
if (strncmp(line,"Descender",9)==0)
- {
+ {
if ((sscanf(line,"%s%d",descString,&lastDescender)!=2) ||
- (strcmp(descString,"Descender")!=0))
- {
- wxLogDebug( "AFM-file '%s': line '%s' has error (bad descender)\n", afmName,line );
+ (strcmp(descString,"Descender")!=0))
+ {
+ wxLogDebug( "AFM-file '%s': line '%s' has error (bad descender)\n", afmName,line );
}
}
/* JC 1.) check for UnderlinePosition */
else if(strncmp(line,"UnderlinePosition",17)==0)
- {
+ {
if ((sscanf(line,"%s%lf",upString,&UnderlinePosition)!=2) ||
- (strcmp(upString,"UnderlinePosition")!=0))
- {
- wxLogDebug( "AFM-file '%s': line '%s' has error (bad UnderlinePosition)\n", afmName, line );
+ (strcmp(upString,"UnderlinePosition")!=0))
+ {
+ wxLogDebug( "AFM-file '%s': line '%s' has error (bad UnderlinePosition)\n", afmName, line );
}
}
- /* JC 2.) check for UnderlineThickness */
+ /* JC 2.) check for UnderlineThickness */
else if(strncmp(line,"UnderlineThickness",18)==0)
- {
+ {
if ((sscanf(line,"%s%lf",utString,&UnderlineThickness)!=2) ||
- (strcmp(utString,"UnderlineThickness")!=0))
- {
- wxLogDebug( "AFM-file '%s': line '%s' has error (bad UnderlineThickness)\n", afmName, line );
+ (strcmp(utString,"UnderlineThickness")!=0))
+ {
+ wxLogDebug( "AFM-file '%s': line '%s' has error (bad UnderlineThickness)\n", afmName, line );
}
}
- /* JC 3.) check for EncodingScheme */
+ /* JC 3.) check for EncodingScheme */
else if(strncmp(line,"EncodingScheme",14)==0)
- {
+ {
if ((sscanf(line,"%s%s",utString,encString)!=2) ||
- (strcmp(utString,"EncodingScheme")!=0))
- {
- wxLogDebug("AFM-file '%s': line '%s' has error (bad EncodingScheme)\n", afmName, line );
+ (strcmp(utString,"EncodingScheme")!=0))
+ {
+ wxLogDebug("AFM-file '%s': line '%s' has error (bad EncodingScheme)\n", afmName, line );
}
else if (strncmp(encString, "AdobeStandardEncoding", 21))
{
- wxLogDebug( "AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)\n",
- afmName,line, encString);
+ wxLogDebug( "AFM-file '%s': line '%s' has error (unsupported EncodingScheme %s)\n",
+ afmName,line, encString);
}
}
/* B.) check for char-width */
else if(strncmp(line,"C ",2)==0)
- {
+ {
if (sscanf(line,"%s%d%s%s%d",cString,&ascii,semiString,WXString,&cWidth)!=5)
- {
+ {
wxLogDebug("AFM-file '%s': line '%s' has an error (bad character width)\n",afmName,line);
}
if(strcmp(cString,"C")!=0 || strcmp(semiString,";")!=0 || strcmp(WXString,"WX")!=0)
- {
+ {
wxLogDebug("AFM-file '%s': line '%s' has a format error\n",afmName,line);
}
/* printf(" char '%c'=%d has width '%d'\n",ascii,ascii,cWidth); */
if (ascii>=0 && ascii<256)
- {
+ {
lastWidths[ascii] = cWidth; /* store width */
}
- else
- {
- /* MATTHEW: this happens a lot; don't print an error */
+ else
+ {
+ /* MATTHEW: this happens a lot; don't print an error */
/* wxLogDebug("AFM-file '%s': ASCII value %d out of range\n",afmName,ascii); */
}
}
fclose(afmFile);
}
/* hack to compute correct values for german 'Umlaute'
- / the correct way would be to map the character names
- / like 'adieresis' to corresp. positions of ISOEnc and read
- / these values from AFM files, too. Maybe later ... */
+ / the correct way would be to map the character names
+ / like 'adieresis' to corresp. positions of ISOEnc and read
+ / these values from AFM files, too. Maybe later ... */
lastWidths[196] = lastWidths['A']; // Ä
lastWidths[228] = lastWidths['a']; // ä
lastWidths[214] = lastWidths['O']; // Ö
m_underlineThickness = m_underlineThickness * fontToUse->GetPointSize() / 1000.0f * m_scaleFactor;
/* 3. now the font metrics are read in, calc size this
- / is done by adding the widths of the characters in the
- / string. they are given in 1/1000 of the size! */
+ / is done by adding the widths of the characters in the
+ / string. they are given in 1/1000 of the size! */
long widthSum=0;
long height=Size; /* by default */
for(p=(unsigned char *)(const char *)string; *p; p++)
{
if(lastWidths[*p]== INT_MIN)
- {
+ {
wxLogDebug("GetTextExtent: undefined width for character '%c' (%d)\n", *p,*p);
widthSum += (long)(lastWidths[' ']/1000.0F * Size); /* assume space */
}
- else
- {
+ else
+ {
widthSum += (long)((lastWidths[*p]/1000.0F)*Size);
}
}
-
+
/* add descender to height (it is usually a negative value) */
if (lastDescender!=INT_MIN)
{
if (descent)
{
if(lastDescender!=INT_MIN)
- {
+ {
*descent = (long)(((-lastDescender)/1000.0F) * Size); /* MATTHEW: forgot scale */
}
- else
- {
- *descent = 0;
+ else
+ {
+ *descent = 0;
}
}
void wxPostScriptDC::GetSizeMM(long *width, long *height) const
{
const char *paperType = wxThePrintSetupData->GetPaperName();
-
+
if (!paperType) paperType = _("A4 210 x 297 mm");
wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(paperType);
-
+
if (!paper) paper = wxThePrintPaperDatabase->FindPaperType(_("A4 210 x 297 mm"));
-
+
if (paper)
{
if (width) *width = paper->widthMM;
print_modes[2] = _("Preview Only");
-
+
wxButton *okBut = new wxButton (this, wxID_OK, _("OK"), wxPoint(5, 5));
(void) new wxButton (this, wxID_CANCEL, _("Cancel"), wxPoint(40, 5));
okBut->SetDefault();
wxGetResource ("wxWindows", "PSView", &wxThePrintSetupData->previewCommand);
features = (wxThePrintSetupData->GetPrintPreviewCommand() &&
- *wxThePrintSetupData->GetPrintPreviewCommand()) ? 3 : 2;
-
+ *wxThePrintSetupData->GetPrintPreviewCommand()) ? 3 : 2;
+
wxRadioBox *radio1 = new wxRadioBox(this, wxID_PRINTER_MODES, _("PostScript:"),
wxPoint(150, yPos),
wxSize(-1,-1), features,
- print_modes, features, wxRA_SPECIFY_ROWS);
+ print_modes, features, wxRA_SPECIFY_ROWS);
#ifdef __WXMSW__
radio1->Enable(0, FALSE);
(void) new wxStaticText(this, -1, _("Y Translation"), wxPoint(220, yPos));
sprintf (buf, "%.2ld", wx_printer_translate_y);
/* wxTextCtrl *text4 = */ (void) new wxTextCtrl(this, wxID_PRINTER_Y_TRANS, buf, wxPoint(320, yPos), wxSize(100, -1));
-
+
Fit ();
delete[] orientation;
/////////////////////////////////////////////////////////////////////////////
-// Name: thread.cpp
-// Purpose: wxThread Implementation for Posix threads
+// Name: threadpsx.cpp
+// Purpose: wxThread (Posix) Implementation
// Author: Original from Wolfram Gloger/Guilhem Lavaux
-// Modified by: Robert Roebling
+// Modified by:
// Created: 04/22/98
// RCS-ID: $Id$
-// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998)
+// Copyright: (c) Wolfram Gloger (1996, 1997)
+// Guilhem Lavaux (1998)
+// Robert Roebling (1999)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__
-#pragma implementation "thread.h"
+ #pragma implementation "thread.h"
#endif
-#include "wx/defs.h"
-
-#if wxUSE_THREADS
-
-#include "wx/module.h"
-#include "wx/thread.h"
-#include "wx/utils.h"
-#include "wx/log.h"
-
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-
-// for select()
-#include <sys/time.h>
-#include <sys/types.h>
-#ifdef __sgi
-#include <bstring.h>
+#ifdef __linux__
+ #include <sched.h>
#endif
-//--------------------------------------------------------------------
-// constants
-//--------------------------------------------------------------------
+#include "wx/thread.h"
+#include "wx/module.h"
+#include "wx/utils.h"
+#include "wx/log.h"
+#include "wx/intl.h"
+#include "wx/dynarray.h"
-enum thread_state
+enum thread_state
{
- STATE_IDLE = 0,
- STATE_RUNNING,
- STATE_PAUSING,
- STATE_PAUSED,
- STATE_CANCELED,
- STATE_EXITED
+ STATE_NEW, // didn't start execution yet (=> RUNNING)
+ STATE_RUNNING,
+ STATE_PAUSED,
+ STATE_CANCELED,
+ STATE_EXITED
};
-//--------------------------------------------------------------------
-// global data
-//--------------------------------------------------------------------
-
-static pthread_t p_mainid;
-
-wxMutex *wxMainMutex = (wxMutex*) NULL; /* controls access to all GUI functions */
+WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
-/* TODO for Xt */
+// -----------------------------------------------------------------------------
+// global data
+// -----------------------------------------------------------------------------
-static int p_thrd_pipe[2] = { -1, -1 };
+// we keep the list of all threads created by the application to be able to
+// terminate them on exit if there are some left - otherwise the process would
+// be left in memory
+static wxArrayThread gs_allThreads;
-//-------------------------------------------------------------------------
-// global functions
-//-------------------------------------------------------------------------
+// the id of the main thread
+static pthread_t gs_tidMain;
-static void wxThreadGuiInit()
-{
-/* TODO for Xt */
-}
+// the key for the pointer to the associated wxThread object
+static pthread_key_t gs_keySelf;
-static void wxThreadGuiExit()
-{
-/* TODO for Xt */
-}
+// this mutex must be acquired before any call to a GUI function
+static wxMutex *gs_mutexGui;
-void wxMutexGuiEnter()
-{
- if (wxMainMutex)
- wxMainMutex->Lock();
-}
-
-void wxMutexGuiLeave()
-{
- if (wxMainMutex)
- wxMainMutex->Unlock();
-}
+//--------------------------------------------------------------------
+// common GUI thread code
+//--------------------------------------------------------------------
//--------------------------------------------------------------------
// wxMutex (Posix implementation)
//--------------------------------------------------------------------
-class wxMutexInternal
+class wxMutexInternal
{
public:
pthread_mutex_t p_mutex;
wxMutex::wxMutex()
{
p_internal = new wxMutexInternal;
- pthread_mutex_init(&(p_internal->p_mutex), NULL);
+ pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) NULL );
m_locked = 0;
}
wxMutex::~wxMutex()
{
if (m_locked > 0)
- wxLogDebug( "wxMutex warning: freeing a locked mutex (%d locks)\n", m_locked );
+ wxLogDebug("Freeing a locked mutex (%d locks)", m_locked);
- pthread_mutex_destroy(&(p_internal->p_mutex));
+ pthread_mutex_destroy( &(p_internal->p_mutex) );
delete p_internal;
}
wxMutexError wxMutex::Lock()
{
- int err;
-
- err = pthread_mutex_lock(&(p_internal->p_mutex));
+ int err = pthread_mutex_lock( &(p_internal->p_mutex) );
if (err == EDEADLK)
+ {
+ wxLogDebug("Locking this mutex would lead to deadlock!");
+
return wxMUTEX_DEAD_LOCK;
-
+ }
+
m_locked++;
+
return wxMUTEX_NO_ERROR;
}
wxMutexError wxMutex::TryLock()
{
- int err;
-
if (m_locked)
+ {
return wxMUTEX_BUSY;
-
- err = pthread_mutex_trylock(&(p_internal->p_mutex));
- switch (err)
+ }
+
+ int err = pthread_mutex_trylock( &(p_internal->p_mutex) );
+ switch (err)
{
case EBUSY: return wxMUTEX_BUSY;
}
+
m_locked++;
+
return wxMUTEX_NO_ERROR;
}
wxMutexError wxMutex::Unlock()
{
if (m_locked > 0)
+ {
m_locked--;
+ }
else
+ {
+ wxLogDebug("Unlocking not locked mutex.");
+
return wxMUTEX_UNLOCKED;
-
- pthread_mutex_unlock(&(p_internal->p_mutex));
+ }
+
+ pthread_mutex_unlock( &(p_internal->p_mutex) );
+
return wxMUTEX_NO_ERROR;
}
// wxCondition (Posix implementation)
//--------------------------------------------------------------------
-class wxConditionInternal
+class wxConditionInternal
{
public:
pthread_cond_t p_condition;
wxCondition::wxCondition()
{
p_internal = new wxConditionInternal;
- pthread_cond_init(&(p_internal->p_condition), NULL);
+ pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL );
}
wxCondition::~wxCondition()
{
- pthread_cond_destroy(&(p_internal->p_condition));
+ pthread_cond_destroy( &(p_internal->p_condition) );
+
delete p_internal;
}
void wxCondition::Wait(wxMutex& mutex)
{
- pthread_cond_wait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex));
+ pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) );
}
bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
{
struct timespec tspec;
- tspec.tv_sec = time(NULL)+sec;
+ tspec.tv_sec = time(0L)+sec;
tspec.tv_nsec = nsec;
return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
}
void wxCondition::Signal()
{
- pthread_cond_signal(&(p_internal->p_condition));
+ pthread_cond_signal( &(p_internal->p_condition) );
}
void wxCondition::Broadcast()
{
- pthread_cond_broadcast(&(p_internal->p_condition));
+ pthread_cond_broadcast( &(p_internal->p_condition) );
}
//--------------------------------------------------------------------
// wxThread (Posix implementation)
//--------------------------------------------------------------------
-class wxThreadInternal
+class wxThreadInternal
{
public:
- wxThreadInternal() { state = STATE_IDLE; }
- ~wxThreadInternal() {}
- static void *PthreadStart(void *ptr);
- pthread_t thread_id;
- int state;
- int prio;
- int defer_destroy;
+ wxThreadInternal();
+ ~wxThreadInternal();
+
+ // thread entry function
+ static void *PthreadStart(void *ptr);
+
+ // thread actions
+ // start the thread
+ wxThreadError Run();
+ // ask the thread to terminate
+ void Cancel();
+ // wake up threads waiting for our termination
+ void SignalExit();
+ // go to sleep until Resume() is called
+ void Pause();
+ // resume the thread
+ void Resume();
+
+ // accessors
+ // priority
+ int GetPriority() const { return m_prio; }
+ void SetPriority(int prio) { m_prio = prio; }
+ // state
+ thread_state GetState() const { return m_state; }
+ void SetState(thread_state state) { m_state = state; }
+ // id
+ pthread_t GetId() const { return thread_id; }
+ // "cancelled" flag
+ bool WasCancelled() const { return m_cancelled; }
+
+//private: -- should be!
+ pthread_t thread_id;
+
+private:
+ thread_state m_state; // see thread_state enum
+ int m_prio; // in wxWindows units: from 0 to 100
+
+ // set when the thread should terminate
+ bool m_cancelled;
+
+ // this (mutex, cond) pair is used to synchronize the main thread and this
+ // thread in several situations:
+ // 1. The thread function blocks until condition is signaled by Run() when
+ // it's initially created - this allows create thread in "suspended"
+ // state
+ // 2. The Delete() function blocks until the condition is signaled when the
+ // thread exits.
+ wxMutex m_mutex;
+ wxCondition m_cond;
+
+ // another (mutex, cond) pair for Pause()/Resume() usage
+ //
+ // VZ: it's possible that we might reuse the mutex and condition from above
+ // for this too, but as I'm not at all sure that it won't create subtle
+ // problems with race conditions between, say, Pause() and Delete() I
+ // prefer this may be a bit less efficient but much safer solution
+ wxMutex m_mutexSuspend;
+ wxCondition m_condSuspend;
};
void *wxThreadInternal::PthreadStart(void *ptr)
{
wxThread *thread = (wxThread *)ptr;
+ wxThreadInternal *pthread = thread->p_internal;
- // Call the main entry
- pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ if ( pthread_setspecific(gs_keySelf, thread) != 0 )
+ {
+ wxLogError(_("Can not start thread: error writing TLS."));
+
+ return (void *)-1;
+ }
+
+ // wait for the condition to be signaled from Run()
+ // mutex state: currently locked by the thread which created us
+ pthread->m_cond.Wait(pthread->m_mutex);
+
+ // mutex state: locked again on exit of Wait()
+
+ // call the main entry
void* status = thread->Entry();
+ // terminate the thread
thread->Exit(status);
+ wxFAIL_MSG("wxThread::Exit() can't return.");
+
return NULL;
}
-wxThreadError wxThread::Create()
+wxThreadInternal::wxThreadInternal()
{
- pthread_attr_t a;
- int min_prio, max_prio, p;
- struct sched_param sp;
+ m_state = STATE_NEW;
+ m_cancelled = FALSE;
- if (p_internal->state != STATE_IDLE)
- return wxTHREAD_RUNNING;
+ // this mutex is locked during almost all thread lifetime - it will only be
+ // unlocked in the very end
+ m_mutex.Lock();
- // Change thread priority
- pthread_attr_init(&a);
- pthread_attr_getschedpolicy(&a, &p);
+ // this mutex is used in Pause()/Resume() and is also locked all the time
+ // unless the thread is paused
+ m_mutexSuspend.Lock();
+}
- min_prio = sched_get_priority_min(p);
- max_prio = sched_get_priority_max(p);
+wxThreadInternal::~wxThreadInternal()
+{
+ m_mutexSuspend.Unlock();
- pthread_attr_getschedparam(&a, &sp);
- sp.sched_priority = min_prio +
- (p_internal->prio*(max_prio-min_prio))/100;
- pthread_attr_setschedparam(&a, &sp);
+ // note that m_mutex will be unlocked by the thread which waits for our
+ // termination
+}
- // this is the point of no return
- p_internal->state = STATE_RUNNING;
- if (pthread_create(&p_internal->thread_id, &a,
- wxThreadInternal::PthreadStart, (void *)this) != 0)
- {
- p_internal->state = STATE_IDLE;
- pthread_attr_destroy(&a);
- return wxTHREAD_NO_RESOURCE;
- }
- pthread_attr_destroy(&a);
+wxThreadError wxThreadInternal::Run()
+{
+ wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
+ "thread may only be started once after successful Create()" );
+
+ // the mutex was locked on Create(), so we will be able to lock it again
+ // only when the thread really starts executing and enters the wait -
+ // otherwise we might signal the condition before anybody is waiting for it
+ wxMutexLocker lock(m_mutex);
+ m_cond.Signal();
+
+ m_state = STATE_RUNNING;
return wxTHREAD_NO_ERROR;
+
+ // now the mutex is unlocked back - but just to allow Wait() function to
+ // terminate by relocking it, so the net result is that the worker thread
+ // starts executing and the mutex is still locked
+}
+
+void wxThreadInternal::Cancel()
+{
+ // if the thread we're waiting for is waiting for the GUI mutex, we will
+ // deadlock so make sure we release it temporarily
+ if ( wxThread::IsMain() )
+ wxMutexGuiLeave();
+
+ // nobody ever writes this variable so it's safe to not use any
+ // synchronization here
+ m_cancelled = TRUE;
+
+ // entering Wait() releases the mutex thus allowing SignalExit() to acquire
+ // it and to signal us its termination
+ m_cond.Wait(m_mutex);
+
+ // mutex is still in the locked state - relocked on exit from Wait(), so
+ // unlock it - we don't need it any more, the thread has already terminated
+ m_mutex.Unlock();
+
+ // reacquire GUI mutex
+ if ( wxThread::IsMain() )
+ wxMutexGuiEnter();
}
-void wxThread::SetPriority(int prio)
+void wxThreadInternal::SignalExit()
{
- if (p_internal->state == STATE_RUNNING)
- return;
+ // as mutex is currently locked, this will block until some other thread
+ // (normally the same which created this one) unlocks it by entering Wait()
+ m_mutex.Lock();
- if (prio > 100) prio = 100;
-
- if (prio < 0) prio = 0;
-
- p_internal->prio = prio;
+ // wake up all the threads waiting for our termination
+ m_cond.Broadcast();
+
+ // after this call mutex will be finally unlocked
+ m_mutex.Unlock();
}
-int wxThread::GetPriority() const
+void wxThreadInternal::Pause()
{
- return p_internal->prio;
+ wxCHECK_RET( m_state == STATE_PAUSED,
+ "thread must first be paused with wxThread::Pause()." );
+
+ // wait until the condition is signaled from Resume()
+ m_condSuspend.Wait(m_mutexSuspend);
}
-void wxThread::DeferDestroy(bool on)
+void wxThreadInternal::Resume()
{
- if (on)
- pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
- else
- pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ wxCHECK_RET( m_state == STATE_PAUSED,
+ "can't resume thread which is not suspended." );
+
+ // we will be able to lock this mutex only when Pause() starts waiting
+ wxMutexLocker lock(m_mutexSuspend);
+ m_condSuspend.Signal();
+
+ SetState(STATE_RUNNING);
+}
+
+// -----------------------------------------------------------------------------
+// static functions
+// -----------------------------------------------------------------------------
+
+wxThread *wxThread::This()
+{
+ return (wxThread *)pthread_getspecific(gs_keySelf);
+}
+
+bool wxThread::IsMain()
+{
+ return (bool)pthread_equal(pthread_self(), gs_tidMain);
+}
+
+void wxThread::Yield()
+{
+ sched_yield();
+}
+
+void wxThread::Sleep(unsigned long milliseconds)
+{
+ wxUsleep(milliseconds);
+}
+
+// -----------------------------------------------------------------------------
+// creating thread
+// -----------------------------------------------------------------------------
+
+wxThread::wxThread()
+{
+ // add this thread to the global list of all threads
+ gs_allThreads.Add(this);
+
+ p_internal = new wxThreadInternal();
}
-wxThreadError wxThread::Destroy()
+wxThreadError wxThread::Create()
{
- int res = 0;
+ if (p_internal->GetState() != STATE_NEW)
+ return wxTHREAD_RUNNING;
+
+ // set up the thread attribute: right now, we only set thread priority
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
- if (p_internal->state == STATE_RUNNING)
+ int prio;
+ if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 )
+ {
+ wxLogError(_("Can not retrieve thread scheduling policy."));
+ }
+
+ int min_prio = sched_get_priority_min(prio),
+ max_prio = sched_get_priority_max(prio);
+
+ if ( min_prio == -1 || max_prio == -1 )
+ {
+ wxLogError(_("Can not get priority range for scheduling policy %d."),
+ prio);
+ }
+ else
{
- res = pthread_cancel(p_internal->thread_id);
- if (res == 0)
- p_internal->state = STATE_CANCELED;
+ struct sched_param sp;
+ pthread_attr_getschedparam(&attr, &sp);
+ sp.sched_priority = min_prio +
+ (p_internal->GetPriority()*(max_prio-min_prio))/100;
+ pthread_attr_setschedparam(&attr, &sp);
+ }
+
+ // create the new OS thread object
+ int rc = pthread_create(&p_internal->thread_id, &attr,
+ wxThreadInternal::PthreadStart,
+ (void *)this);
+ pthread_attr_destroy(&attr);
+
+ if ( rc != 0 )
+ {
+ p_internal->SetState(STATE_EXITED);
+ return wxTHREAD_NO_RESOURCE;
}
return wxTHREAD_NO_ERROR;
}
+wxThreadError wxThread::Run()
+{
+ return p_internal->Run();
+}
+
+// -----------------------------------------------------------------------------
+// misc accessors
+// -----------------------------------------------------------------------------
+
+void wxThread::SetPriority(unsigned int prio)
+{
+ wxCHECK_RET( (WXTHREAD_MIN_PRIORITY <= prio) &&
+ (prio <= WXTHREAD_MAX_PRIORITY), "invalid thread priority" );
+
+ wxCriticalSectionLocker lock(m_critsect);
+
+ switch ( p_internal->GetState() )
+ {
+ case STATE_NEW:
+ // thread not yet started, priority will be set when it is
+ p_internal->SetPriority(prio);
+ break;
+
+ case STATE_RUNNING:
+ case STATE_PAUSED:
+ {
+ struct sched_param sparam;
+ sparam.sched_priority = prio;
+
+ if ( pthread_setschedparam(p_internal->GetId(),
+ SCHED_OTHER, &sparam) != 0 )
+ {
+ wxLogError(_("Failed to set thread priority %d."), prio);
+ }
+ }
+ break;
+
+ case STATE_EXITED:
+ default:
+ wxFAIL_MSG("impossible to set thread priority in this state");
+ }
+}
+
+unsigned int wxThread::GetPriority() const
+{
+ wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
+
+ return p_internal->GetPriority();
+}
+
+unsigned long wxThread::GetID() const
+{
+ return (unsigned long)p_internal->thread_id;
+}
+
+// -----------------------------------------------------------------------------
+// pause/resume
+// -----------------------------------------------------------------------------
+
wxThreadError wxThread::Pause()
{
- if (p_internal->state != STATE_RUNNING)
+ wxCriticalSectionLocker lock(m_critsect);
+
+ if ( p_internal->GetState() != STATE_RUNNING )
+ {
+ wxLogDebug("Can't pause thread which is not running.");
+
return wxTHREAD_NOT_RUNNING;
+ }
- if (!p_internal->defer_destroy)
- return wxTHREAD_MISC_ERROR;
+ p_internal->SetState(STATE_PAUSED);
- p_internal->state = STATE_PAUSING;
return wxTHREAD_NO_ERROR;
}
wxThreadError wxThread::Resume()
{
- if (p_internal->state == STATE_PAUSING || p_internal->state == STATE_PAUSED)
- p_internal->state = STATE_RUNNING;
+ wxCriticalSectionLocker lock(m_critsect);
- return wxTHREAD_NO_ERROR;
+ if ( p_internal->GetState() == STATE_PAUSED )
+ {
+ p_internal->Resume();
+
+ return wxTHREAD_NO_ERROR;
+ }
+ else
+ {
+ wxLogDebug("Attempt to resume a thread which is not paused.");
+
+ return wxTHREAD_MISC_ERROR;
+ }
}
-void *wxThread::Join()
+// -----------------------------------------------------------------------------
+// exiting thread
+// -----------------------------------------------------------------------------
+
+wxThread::ExitCode wxThread::Delete()
{
- void* status = 0;
+ m_critsect.Enter();
+ thread_state state = p_internal->GetState();
+ m_critsect.Leave();
- if (p_internal->state != STATE_IDLE)
+ switch ( state )
{
- bool do_unlock = wxThread::IsMain();
+ case STATE_NEW:
+ case STATE_EXITED:
+ // nothing to do
+ break;
- while (p_internal->state == STATE_RUNNING)
- wxYield();
+ case STATE_PAUSED:
+ // resume the thread first
+ Resume();
- if (do_unlock) wxMainMutex->Unlock();
-
- pthread_join(p_internal->thread_id, &status);
-
- if (do_unlock) wxMainMutex->Lock();
+ // fall through
- p_internal->state = STATE_IDLE;
+ default:
+ // set the flag telling to the thread to stop and wait
+ p_internal->Cancel();
}
-
- return status;
+
+ return NULL;
}
-unsigned long wxThread::GetID() const
+wxThreadError wxThread::Kill()
{
- return p_internal->thread_id;
+ switch ( p_internal->GetState() )
+ {
+ case STATE_NEW:
+ case STATE_EXITED:
+ return wxTHREAD_NOT_RUNNING;
+
+ default:
+ if ( pthread_cancel(p_internal->GetId()) != 0 )
+ {
+ wxLogError(_("Failed to terminate a thread."));
+
+ return wxTHREAD_MISC_ERROR;
+ }
+
+ return wxTHREAD_NO_ERROR;
+ }
}
void wxThread::Exit(void *status)
{
- wxThread* ptr = this;
+ // first call user-level clean up code
+ OnExit();
+
+ // next wake up the threads waiting for us (OTOH, this function won't return
+ // until someone waited for us!)
+ p_internal->SignalExit();
-/* THREAD_SEND_EXIT_MSG(ptr); TODO for Xt */
-
- p_internal->state = STATE_EXITED;
+ p_internal->SetState(STATE_EXITED);
+
+ // delete both C++ thread object and terminate the OS thread object
+ delete this;
pthread_exit(status);
}
-void wxThread::TestDestroy()
+// also test whether we were paused
+bool wxThread::TestDestroy()
{
- if (p_internal->state == STATE_PAUSING)
+ wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
+
+ if ( p_internal->GetState() == STATE_PAUSED )
{
- p_internal->state = STATE_PAUSED;
- while (p_internal->state == STATE_PAUSED)
- {
- pthread_testcancel();
- usleep(1);
- }
+ // leave the crit section or the other threads will stop too if they try
+ // to call any of (seemingly harmless) IsXXX() functions while we sleep
+ m_critsect.Leave();
+
+ p_internal->Pause();
+
+ // enter it back before it's finally left in lock object dtor
+ m_critsect.Enter();
}
- pthread_testcancel();
+
+ return p_internal->WasCancelled();
}
-bool wxThread::IsMain()
+wxThread::~wxThread()
{
- return (bool)pthread_equal(pthread_self(), p_mainid);
+ // remove this thread from the global array
+ gs_allThreads.Remove(this);
}
+// -----------------------------------------------------------------------------
+// state tests
+// -----------------------------------------------------------------------------
+
bool wxThread::IsRunning() const
{
- return (p_internal->state == STATE_RUNNING);
-}
+ wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
-bool wxThread::IsAlive() const
-{
- return (p_internal->state == STATE_RUNNING) ||
- (p_internal->state == STATE_PAUSING) ||
- (p_internal->state == STATE_PAUSED);
+ return p_internal->GetState() == STATE_RUNNING;
}
-wxThread::wxThread()
+bool wxThread::IsAlive() const
{
- p_internal = new wxThreadInternal();
-}
+ wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
-wxThread::~wxThread()
-{
- Destroy();
- Join();
- delete p_internal;
-}
+ switch ( p_internal->GetState() )
+ {
+ case STATE_RUNNING:
+ case STATE_PAUSED:
+ return TRUE;
-// The default callback just joins the thread and throws away the result.
-void wxThread::OnExit()
-{
- Join();
+ default:
+ return FALSE;
+ }
}
//--------------------------------------------------------------------
-// wxThreadModule
+// wxThreadModule
//--------------------------------------------------------------------
class wxThreadModule : public wxModule
IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
-bool wxThreadModule::OnInit()
+bool wxThreadModule::OnInit()
{
- wxMainMutex = new wxMutex();
- wxThreadGuiInit();
- p_mainid = pthread_self();
- wxMainMutex->Lock();
+ if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 )
+ {
+ wxLogError(_("Thread module initialization failed: "
+ "failed to create pthread key."));
+
+ return FALSE;
+ }
+
+ gs_mutexGui = new wxMutex();
+ //wxThreadGuiInit();
+ gs_tidMain = pthread_self();
+ gs_mutexGui->Lock();
return TRUE;
}
void wxThreadModule::OnExit()
{
- wxMainMutex->Unlock();
- wxThreadGuiExit();
- delete wxMainMutex;
-};
+ wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" );
-#endif
- // wxUSE_THREADS
+ // terminate any threads left
+ size_t count = gs_allThreads.GetCount();
+ if ( count != 0u )
+ wxLogDebug("Some threads were not terminated by the application.");
+
+ for ( size_t n = 0u; n < count; n++ )
+ {
+ gs_allThreads[n]->Delete();
+ }
+
+ // destroy GUI mutex
+ gs_mutexGui->Unlock();
+ //wxThreadGuiExit();
+ delete gs_mutexGui;
+
+ // and free TLD slot
+ (void)pthread_key_delete(gs_keySelf);
+}
+
+void wxMutexGuiEnter()
+{
+ gs_mutexGui->Lock();
+}
+
+void wxMutexGuiLeave()
+{
+ gs_mutexGui->Unlock();
+}