2
/******************************************************************************
3
* MODULE : x_drawables.cpp
4
* DESCRIPTION: Drawables under X
5
* COPYRIGHT : (C) 1999 Joris van der Hoeven
6
*******************************************************************************
7
* This software falls under the GNU general public license and comes WITHOUT
8
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
9
* If you don't have this file, write to the Free Software Foundation, Inc.,
10
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11
******************************************************************************/
13
#include "X/x_window.hpp"
15
#include "image_files.hpp"
16
#include "sys_utils.hpp"
17
#include "analyze.hpp"
18
#include "iterator.hpp"
19
#include "Ghostscript/ghostscript.hpp"
21
extern hashmap<tree,string> ps_bbox;
23
/******************************************************************************
24
* Constructors and destructors
25
******************************************************************************/
27
x_drawable_rep::x_drawable_rep (x_display dis2, int w2, int h2):
28
dis (dis2), w (w2), h (h2)
42
magenta = dis->magenta;
46
light_grey = dis->light_grey;
48
dark_grey = dis->dark_grey;
51
win= (Drawable) XCreatePixmap (dis->dpy, dis->root, w, h, dis->depth);
54
x_drawable_rep::~x_drawable_rep () {
55
if ((w>0) && (h>0)) XFreePixmap (dis->dpy, (Pixmap) win);
59
x_drawable_rep::get_type () {
60
return PS_DEVICE_SCREEN;
63
/******************************************************************************
64
* Conversion between window and postscript coordinates
65
******************************************************************************/
68
x_drawable_rep::encode (SI& x, SI& y) {
74
x_drawable_rep::decode (SI& x, SI& y) {
76
if (x>=0) x= x/pixel; else x= (x-pixel+1)/pixel;
77
if (y>=0) y= -(y/pixel); else y= -((y-pixel+1)/pixel);
80
/******************************************************************************
82
******************************************************************************/
85
x_drawable_rep::set_clipping (SI x1, SI y1, SI x2, SI y2) {
86
outer_round (x1, y1, x2, y2);
87
ps_device_rep::set_clipping (x1, y1, x2, y2);
88
Region region= XCreateRegion ();
96
XUnionRectWithRegion (&r, region, region);
97
XSetRegion (dpy, gc, region);
98
XDestroyRegion (region);
101
/******************************************************************************
102
* Drawing into drawables
103
******************************************************************************/
106
x_drawable_rep::rgb (int r, int g, int b) {
107
return dis->rgb (r, g, b);
111
x_drawable_rep::get_rgb (color col, int& r, int& g, int& b) {
112
dis->get_rgb (col, r, g, b);
116
x_drawable_rep::get_color () {
121
x_drawable_rep::get_background () {
126
x_drawable_rep::set_color (color c) {
127
XSetForeground (dpy, gc, dis->cmap[c]);
132
x_drawable_rep::set_background (color c) {
133
XSetBackground (dpy, gc, dis->cmap[c]);
138
x_drawable_rep::set_line_style (SI lw, int type) { (void) type;
140
XSetLineAttributes (dpy, (GC) gc, 1,
141
LineSolid, CapRound, JoinRound);
143
XSetLineAttributes (dpy, (GC) gc, (lw+thicken) / pixel,
144
LineSolid, CapRound, JoinRound);
148
x_drawable_rep::line (SI x1, SI y1, SI x2, SI y2) {
151
y1--; y2--; // top-left origin to bottom-left origin conversion
152
XDrawLine (dpy, win, gc, x1, y1, x2, y2);
156
x_drawable_rep::clear (SI x1, SI y1, SI x2, SI y2) {
157
x1= max (x1, cx1-ox); y1= max (y1, cy1-oy);
158
x2= min (x2, cx2-ox); y2= min (y2, cy2-oy);
159
// outer_round (x1, y1, x2, y2); might still be needed somewhere
162
if ((x1>=x2) || (y1<=y2)) return;
163
XSetForeground (dpy, gc, dis->cmap[cur_bg]);
164
XFillRectangle (dpy, win, gc, x1, y2, x2-x1, y1-y2);
165
XSetForeground (dpy, gc, dis->cmap[cur_fg]);
169
x_drawable_rep::fill (SI x1, SI y1, SI x2, SI y2) {
170
if ((x2>x1) && ((x2-x1)<pixel)) {
175
if ((y2>y1) && ((y2-y1)<pixel)) {
181
x1= max (x1, cx1-ox); y1= max (y1, cy1-oy);
182
x2= min (x2, cx2-ox); y2= min (y2, cy2-oy);
183
// outer_round (x1, y1, x2, y2); might still be needed somewhere
184
if ((x1>=x2) || (y1>=y2)) return;
188
XFillRectangle (dpy, win, gc, x1, y2, x2-x1, y1-y2);
192
x_drawable_rep::arc (SI x1, SI y1, SI x2, SI y2, int alpha, int delta) {
193
if ((x1>=x2) || (y1>=y2)) return;
196
XDrawArc (dpy, win, gc, x1, y2, x2-x1, y1-y2, alpha, delta);
200
x_drawable_rep::polygon (array<SI> x, array<SI> y) {
202
if ((N(y) != n) || (n<1)) return;
203
STACK_NEW_ARRAY (pnt, XPoint, n);
204
for (i=0; i<n; i++) {
205
SI xx= x[i], yy= y[i];
210
XFillPolygon (dpy, win, gc, pnt, n, Convex, CoordModeOrigin);
211
STACK_DELETE_ARRAY (pnt);
214
/******************************************************************************
215
* Setting up and displaying xpm pixmaps
216
******************************************************************************/
219
x_drawable_rep::xpm_initialize (url file_name) {
220
tree t= xpm_load (file_name);
223
int ok, i=0, j, k, w, h, c, b, x, y;
224
string s= as_string (t[0]);
226
ok= read_int (s, i, w);
228
ok= read_int (s, i, h) && ok;
230
ok= read_int (s, i, c) && ok;
232
ok= read_int (s, i, b) && ok;
233
if ((!ok) || (N(t)<(c+1)) || (c<=0))
234
fatal_error ("Invalid xpm (" * as_string (file_name) * ")",
235
"x_drawable_rep::xpm_initialize");
239
hashmap<string,int> pmcs(0);
240
hashmap<string,int> bmcs(1);
241
for (k=0; k<c; k++) {
242
string s = as_string (t[k+1]);
246
else { name= s(0,b); i=b; }
247
if (k==0) first_name= name;
250
if ((i<N(s)) && (s[i]=='s')) {
253
while ((i<N(s)) && (s[i]!=' ') && (s[i]!='\t')) i++;
256
if ((i<N(s)) && (s[i]=='c')) {
260
while ((i<N(s)) && (s[i]!=' ') && (s[i]!='\t')) i++;
261
def= locase_all (s (j, i));
269
char* _def= as_charp (def);
270
XColor exact, closest;
271
XLookupColor (dis->dpy, dis->cols, _def, &exact, &closest);
272
if (XAllocColor (dis->dpy, dis->cols, &exact))
273
pmcs(name)= exact.pixel;
274
else if (XAllocColor (dis->dpy, dis->cols, &closest))
275
pmcs(name)= closest.pixel;
277
int myc= dis->rgb ((exact.red+128)/256,
278
(exact.green+128)/256,
279
(exact.blue+128)/256);
280
pmcs(name)= dis->cmap[myc];
285
// setup bitmap and pixmap
286
Pixmap pm= XCreatePixmap (dis->dpy, dis->root, w, h, dis->depth);
287
int byte_width= ((w-1)>>3)+1;
288
char* data= new char [byte_width * h];
289
for (i=0; i<(byte_width * h); i++) data[i]=0;
290
for (y=0; y<h; y++) {
291
if (N(t)< (y+c+1)) s= "";
292
else s= as_string (t[y+c+1]);
293
for (x=0; x<w; x++) {
296
if (N(s)<(b*(x+1))) name= first_name;
297
else name= s (b*x, b*(x+1));
300
if (!bmcs->contains (name)) bmc= bmcs[first_name];
301
if (!pmcs->contains (name)) pmc= pmcs[first_name];
302
XSetForeground (dis->dpy, dis->pixmap_gc, pmc);
303
XDrawPoint (dis->dpy, (Drawable) pm, dis->pixmap_gc, x, y);
304
bit= y*byte_width + (x>>3);
305
if (bmc!=0) data[bit]= data[bit] | (1<<(x&7));
308
Pixmap bm= XCreateBitmapFromData (dis->dpy, dis->root, data, w, h);
309
dis->xpm_pixmap (as_string (file_name))= (int) pm;
310
dis->xpm_bitmap (as_string (file_name))= (int) bm;
314
extern bool char_clip;
317
x_drawable_rep::xpm (url file_name, SI x, SI y) {
318
y -= pixel; // counter balance shift in draw_clipped
319
if (!dis->xpm_pixmap->contains (as_string (file_name)))
320
xpm_initialize (file_name);
322
fatal_error ("Shrinking factor should be 1", "x_drawable_rep::xpm");
324
xpm_size (file_name, w, h);
325
Pixmap bm= (Pixmap) dis->xpm_bitmap [as_string (file_name)];
326
Pixmap pm= (Pixmap) dis->xpm_pixmap [as_string (file_name)];
327
int old_clip= char_clip;
329
draw_clipped (pm, bm, w, h, x, y);
333
/******************************************************************************
334
* Invocation of ghostscript
335
******************************************************************************/
337
static int ps_figs_last_gc = 0;
338
static int ps_figs_tot_size= 0;
339
static int ps_figs_max_size= 10000;
340
static hashmap<tree,Pixmap> ps_figs (0);
341
static hashmap<tree,int> ps_figs_w (0);
342
static hashmap<tree,int> ps_figs_h (0);
343
static hashmap<tree,int> ps_figs_time (0);
344
static hashmap<tree,int> ps_figs_nr (0);
347
x_drawable_rep::postscript (
349
SI w, SI h, SI x, SI y,
350
int x1, int y1, int x2, int y2)
352
w= w/pixel; h= h/pixel;
355
if (dis->gswindow == NULL) {
356
widget dummy= text_widget ("ghostscript window");
357
if (ghostscript_bugged ()) {
358
SI max_w= 2 * dis->display_width * PIXEL;
359
SI max_h= 2 * dis->display_height * PIXEL;
360
dummy= glue_widget (false, false, max_w, max_h);
362
dis->gswindow= new x_window_rep (dummy, dis, "ghostscript", 0, 0);
364
if (ghostscript_bugged ()) {
365
SI max_w= 2 * dis->display_width;
366
SI max_h= 2 * dis->display_height;
372
tree lookup= tuple (image->t);
373
lookup << as_string (w ) << as_string (h )
374
<< as_string (x1) << as_string (y1)
375
<< as_string (x2) << as_string (y2);
376
if (ps_figs->contains (lookup)) pm= (Pixmap) ps_figs [lookup];
378
if (DEBUG_AUTO) cout << "TeXmacs] Running ghostscript " << image << "\n";
379
Window gs_win= dis->gswindow->win;
380
pm= XCreatePixmap (dis->dpy, gs_win, w, h, dis->depth);
381
ghostscript_run (dpy, gs_win, pm, image, w, h, x1, y1, x2, y2);
382
if (N(ps_figs_nr) == 0) ps_figs_last_gc= texmacs_time ();
383
ps_figs (lookup)= (int) pm;
384
ps_figs_w (lookup)= w;
385
ps_figs_h (lookup)= h;
386
ps_figs_time (lookup)= texmacs_time ();
387
ps_figs_nr (lookup)= ps_figs_nr [lookup] + 1;
388
ps_figs_tot_size += w*h;
389
if (ps_figs_tot_size > ps_figs_max_size) {
390
dis->postscript_auto_gc ();
391
if (ps_figs_tot_size > ps_figs_max_size)
392
ps_figs_max_size= ps_figs_tot_size << 1;
396
XCopyArea (dpy, (Drawable) pm, win, gc, 0, 0, w, h, x, y-h);
400
x_display_rep::postscript_auto_gc () {
401
int time= texmacs_time ();
402
if (time-ps_figs_last_gc <= 300000) return;
403
ps_figs_last_gc= time;
405
cout << "TeXmacs] Launching garbage collection for unused pictures\n";
407
iterator<tree> it= iterate (ps_figs);
409
tree lookup= it->next();
410
int diff= time- ps_figs_time [lookup];
411
int fact= ps_figs_nr [lookup];
412
fact= fact * fact * fact;
413
if (ps_figs_w [lookup] * ps_figs_h [lookup] < 400) fact= fact * 5;
414
if (ps_figs_w [lookup] * ps_figs_h [lookup] < 6400) fact= fact * 5;
415
if (diff/fact > 60000) {
416
Pixmap pm= (Pixmap) ps_figs [lookup];
417
XFreePixmap (dpy, pm);
418
ps_figs->reset (lookup);
419
ps_figs_w->reset (lookup);
420
ps_figs_h->reset (lookup);
421
ps_figs_time->reset (lookup);
422
ps_bbox->reset (lookup[0]);
428
x_display_rep::postscript_gc (string name) {
430
ps_figs_last_gc= texmacs_time ();
431
iterator<tree> it= iterate (ps_figs);
433
tree lookup= it->next();
434
if (!is_ramdisc (as_url (lookup[0]))) {
435
Pixmap pm= (Pixmap) ps_figs [lookup];
436
XFreePixmap (dpy, pm);
437
ps_figs->reset (lookup);
438
ps_figs_w->reset (lookup);
439
ps_figs_h->reset (lookup);
440
ps_figs_time->reset (lookup);
441
ps_figs_nr->reset (lookup);
442
ps_bbox->reset (lookup[0]);
447
/******************************************************************************
448
* Miscellaneous routines
449
******************************************************************************/
452
x_drawable_rep::next_page () {
456
x_drawable_rep::check_event (int type) {
461
if (event_status) return true;
462
event_status= (XPending (dpy)>0);
465
if (event_status) return true;
466
event_status= XCheckMaskEvent (dpy, KeyPressMask|ButtonPressMask, &ev);
467
if (event_status) XPutBackEvent (dpy, &ev);
470
event_status= XCheckMaskEvent (dpy, PointerMotionMask, &ev);
471
if (event_status) XPutBackEvent (dpy, &ev);
474
event_status= XCheckMaskEvent (dpy, ButtonMotionMask, &ev);
475
if (event_status) XPutBackEvent (dpy, &ev);
478
status= XCheckMaskEvent (dpy, ButtonMotionMask|ButtonReleaseMask, &ev);
479
if (status) XPutBackEvent (dpy, &ev);
488
x_drawable_rep::apply_shadow (SI x1, SI y1, SI x2, SI y2) {
489
if (this != dis->shadow) return;
490
outer_round (x1, y1, x2, y2);
493
dis->shadow_src->encode (x1, y1);
494
dis->shadow_src->encode (x2, y2);
495
dis->shadow_src->shadow_to_window (x1, y1, x2, y2);