Some menu shuffling.
[grace.git] / src / xutil.c
blobd9ee594cab219b8854127e33c00fd776533d6d86
1 /*
2 * Grace - GRaphing, Advanced Computation and Exploration of data
3 *
4 * Home page: http://plasma-gate.weizmann.ac.il/Grace/
5 *
6 * Copyright (c) 1991-1995 Paul J Turner, Portland, OR
7 * Copyright (c) 1996-2004 Grace Development Team
8 *
9 * Maintained by Evgeny Stambulchik
12 * All Rights Reserved
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program 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 General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <config.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <errno.h>
35 #include <X11/Xlib.h>
36 #include <X11/cursorfont.h>
38 #include "defines.h"
39 #include "globals.h"
41 #include "utils.h"
42 #include "files.h"
43 #include "core_utils.h"
44 #include "plotone.h"
46 #include "motifinc.h"
47 #include "protos.h"
49 extern XtAppContext app_con;
51 extern Input_buffer *ib_tbl;
52 extern int ib_tblsize;
54 static GC gcxor;
56 static void resize_drawables(unsigned int w, unsigned int h);
58 long x11_allocate_color(GUI *gui, const RGB *rgb)
60 X11Stuff *xstuff = gui->xstuff;
61 XColor xc;
63 xc.pixel = 0;
64 xc.flags = DoRed | DoGreen | DoBlue;
66 xc.red = rgb->red << (16 - GRACE_BPP);
67 xc.green = rgb->green << (16 - GRACE_BPP);
68 xc.blue = rgb->blue << (16 - GRACE_BPP);
70 if (XAllocColor(xstuff->disp, xstuff->cmap, &xc)) {
71 return xc.pixel;
72 } else
73 if (gui->install_cmap != CMAP_INSTALL_NEVER &&
74 gui->private_cmap == FALSE) {
75 xstuff->cmap = XCopyColormapAndFree(xstuff->disp, xstuff->cmap);
76 gui->private_cmap = TRUE;
78 /* try to allocate the same color in the private colormap */
79 return x11_allocate_color(gui, rgb);
80 } else {
81 return -1;
85 void set_wait_cursor(void)
87 if (grace->gui->xstuff->disp == NULL) {
88 return;
91 DefineDialogCursor(grace->gui->xstuff->wait_cursor);
94 void unset_wait_cursor(void)
96 X11Stuff *xstuff = grace->gui->xstuff;
97 if (xstuff->disp == NULL) {
98 return;
101 UndefineDialogCursor();
102 if (xstuff->cur_cursor >= 0) {
103 set_cursor(grace->gui, xstuff->cur_cursor);
107 void set_cursor(GUI *gui, int c)
109 X11Stuff *xstuff = gui->xstuff;
110 if (xstuff->disp == NULL || xstuff->cur_cursor == c) {
111 return;
114 XUndefineCursor(xstuff->disp, xstuff->xwin);
115 xstuff->cur_cursor = c;
116 switch (c) {
117 case 0:
118 XDefineCursor(xstuff->disp, xstuff->xwin, xstuff->line_cursor);
119 break;
120 case 1:
121 XDefineCursor(xstuff->disp, xstuff->xwin, xstuff->find_cursor);
122 break;
123 case 2:
124 XDefineCursor(xstuff->disp, xstuff->xwin, xstuff->text_cursor);
125 break;
126 case 3:
127 XDefineCursor(xstuff->disp, xstuff->xwin, xstuff->kill_cursor);
128 break;
129 case 4:
130 XDefineCursor(xstuff->disp, xstuff->xwin, xstuff->move_cursor);
131 break;
132 case 5:
133 XDefineCursor(xstuff->disp, xstuff->xwin, xstuff->drag_cursor);
134 break;
135 default:
136 xstuff->cur_cursor = -1;
137 break;
139 XFlush(xstuff->disp);
142 void init_cursors(GUI *gui)
144 X11Stuff *xstuff = gui->xstuff;
146 xstuff->wait_cursor = XCreateFontCursor(xstuff->disp, XC_watch);
147 xstuff->line_cursor = XCreateFontCursor(xstuff->disp, XC_crosshair);
148 xstuff->find_cursor = XCreateFontCursor(xstuff->disp, XC_dotbox);
149 xstuff->text_cursor = XCreateFontCursor(xstuff->disp, XC_xterm);
150 xstuff->kill_cursor = XCreateFontCursor(xstuff->disp, XC_pirate);
151 xstuff->move_cursor = XCreateFontCursor(xstuff->disp, XC_fleur);
152 xstuff->drag_cursor = XCreateFontCursor(xstuff->disp, XC_hand2);
154 xstuff->cur_cursor = -1;
159 * put a string in the title bar
161 void update_app_title(const Quark *pr)
163 GUI *gui = gui_from_quark(pr);
164 static char *ts_save = NULL;
165 char *ts;
166 static int dstate_save = 0;
167 int dstate;
169 if (!pr || !gui->inwin) {
170 return;
173 dstate = quark_dirtystate_get(pr);
174 ts = mybasename(project_get_docname(pr));
175 if (ts_save == NULL || strcmp(ts_save, ts) != 0 || dstate != dstate_save) {
176 char *buf1, *buf2;
177 ts_save = copy_string(ts_save, ts);
178 dstate_save = dstate;
179 buf1 = copy_string(NULL, "Grace: ");
180 buf1 = concat_strings(buf1, ts);
181 buf2 = copy_string(NULL, ts);
182 if (dstate) {
183 buf2 = concat_strings(buf2, "*");
184 buf1 = concat_strings(buf1, " (modified)");
186 XtVaSetValues(app_shell, XtNtitle, buf1, XtNiconName, buf2, NULL);
187 xfree(buf1);
188 xfree(buf2);
192 void page_zoom_inout(Grace *grace, int inout)
194 if (!gui_is_page_free(grace->gui)) {
195 if (inout > 0) {
196 grace->gui->zoom *= ZOOM_STEP;
197 } else
198 if (inout < 0) {
199 grace->gui->zoom /= ZOOM_STEP;
200 } else {
201 grace->gui->zoom = 1.0;
203 xdrawgraph(grace->project, TRUE);
204 set_left_footer(NULL);
209 * Auxiliary routines for simultaneous drawing on display and pixmap
211 static void aux_XDrawLine(GUI *gui, int x1, int y1, int x2, int y2)
213 X11Stuff *xstuff = gui->xstuff;
214 XDrawLine(xstuff->disp, xstuff->xwin, gcxor, x1, y1, x2, y2);
215 if (xstuff->bufpixmap != (Pixmap) NULL) {
216 XDrawLine(xstuff->disp, xstuff->bufpixmap, gcxor, x1, y1, x2, y2);
220 static void aux_XDrawRectangle(GUI *gui, int x1, int y1, int x2, int y2)
222 X11Stuff *xstuff = gui->xstuff;
223 XDrawRectangle(xstuff->disp, xstuff->xwin, gcxor, x1, y1, x2, y2);
224 if (xstuff->bufpixmap != (Pixmap) NULL) {
225 XDrawRectangle(xstuff->disp, xstuff->bufpixmap, gcxor, x1, y1, x2, y2);
229 static void aux_XFillRectangle(GUI *gui, int x, int y, unsigned int width, unsigned int height)
231 X11Stuff *xstuff = gui->xstuff;
232 XFillRectangle(xstuff->disp, xstuff->xwin, gcxor, x, y, width, height);
233 if (xstuff->bufpixmap != (Pixmap) NULL) {
234 XFillRectangle(xstuff->disp, xstuff->bufpixmap, gcxor, x, y, width, height);
240 * draw the graph focus indicators
242 void draw_focus(Quark *gr)
244 short ix1, iy1, ix2, iy2;
245 view v;
246 VPoint vp;
247 GUI *gui = gui_from_quark(gr);
249 if (gui->draw_focus_flag == TRUE) {
250 graph_get_viewport(gr, &v);
251 vp.x = v.xv1;
252 vp.y = v.yv1;
253 x11_VPoint2dev(&vp, &ix1, &iy1);
254 vp.x = v.xv2;
255 vp.y = v.yv2;
256 x11_VPoint2dev(&vp, &ix2, &iy2);
257 aux_XFillRectangle(gui, ix1 - 5, iy1 - 5, 10, 10);
258 aux_XFillRectangle(gui, ix1 - 5, iy2 - 5, 10, 10);
259 aux_XFillRectangle(gui, ix2 - 5, iy2 - 5, 10, 10);
260 aux_XFillRectangle(gui, ix2 - 5, iy1 - 5, 10, 10);
262 gui->xstuff->f_x1 = ix1;
263 gui->xstuff->f_x2 = ix2;
264 gui->xstuff->f_y1 = iy1;
265 gui->xstuff->f_y2 = iy2;
267 gui->xstuff->f_v = v;
272 * rubber band line (optionally erasing previous one)
274 void select_line(GUI *gui, int x1, int y1, int x2, int y2, int erase)
276 static int x1_old, y1_old, x2_old, y2_old;
278 if (erase) {
279 aux_XDrawLine(gui, x1_old, y1_old, x2_old, y2_old);
281 x1_old = x1;
282 y1_old = y1;
283 x2_old = x2;
284 y2_old = y2;
285 aux_XDrawLine(gui, x1, y1, x2, y2);
288 static int region_need_erasing = FALSE;
290 * draw an xor'ed box (optionally erasing previous one)
292 void select_region(GUI *gui, int x1, int y1, int x2, int y2, int erase)
294 static int x1_old, y1_old, dx_old, dy_old;
295 int dx = x2 - x1;
296 int dy = y2 - y1;
298 if (dx < 0) {
299 iswap(&x1, &x2);
300 dx = -dx;
302 if (dy < 0) {
303 iswap(&y1, &y2);
304 dy = -dy;
306 if (erase && region_need_erasing) {
307 aux_XDrawRectangle(gui, x1_old, y1_old, dx_old, dy_old);
309 x1_old = x1;
310 y1_old = y1;
311 dx_old = dx;
312 dy_old = dy;
313 aux_XDrawRectangle(gui, x1, y1, dx, dy);
314 region_need_erasing = TRUE;
317 void select_vregion(GUI *gui, int x1, int x2, int erase)
319 X11Stuff *xstuff = gui->xstuff;
321 select_region(gui, x1, xstuff->f_y1, x2, xstuff->f_y2, erase);
324 void select_hregion(GUI *gui, int y1, int y2, int erase)
326 X11Stuff *xstuff = gui->xstuff;
328 select_region(gui, xstuff->f_x1, y1, xstuff->f_x2, y2, erase);
332 * slide an xor'ed bbox shifted by shift_*, (optionally erasing previous one)
334 void slide_region(GUI *gui, view bb, int shift_x, int shift_y, int erase)
336 short x1, x2, y1, y2;
337 VPoint vp;
339 vp.x = bb.xv1;
340 vp.y = bb.yv1;
341 x11_VPoint2dev(&vp, &x1, &y1);
342 x1 += shift_x;
343 y1 += shift_y;
345 vp.x = bb.xv2;
346 vp.y = bb.yv2;
347 x11_VPoint2dev(&vp, &x2, &y2);
348 x2 += shift_x;
349 y2 += shift_y;
351 select_region(gui, x1, y1, x2, y2, erase);
354 void resize_region(GUI *gui, view bb, int on_focus,
355 int shift_x, int shift_y, int erase)
357 short x1, x2, y1, y2;
358 VPoint vp;
360 vp.x = bb.xv1;
361 vp.y = bb.yv1;
362 x11_VPoint2dev(&vp, &x1, &y1);
363 vp.x = bb.xv2;
364 vp.y = bb.yv2;
365 x11_VPoint2dev(&vp, &x2, &y2);
367 switch (on_focus) {
368 case 1:
369 x1 += shift_x;
370 y1 += shift_y;
371 break;
372 case 2:
373 x1 += shift_x;
374 y2 += shift_y;
375 break;
376 case 3:
377 x2 += shift_x;
378 y2 += shift_y;
379 break;
380 case 4:
381 x2 += shift_x;
382 y1 += shift_y;
383 break;
384 default:
385 return;
388 select_region(gui, x1, y1, x2, y2, erase);
391 static int crosshair_erase = FALSE;
392 static int cursor_oldx, cursor_oldy;
395 void reset_crosshair(GUI *gui, int clear)
397 X11Stuff *xstuff = gui->xstuff;
398 crosshair_erase = FALSE;
399 if (clear) {
400 aux_XDrawLine(gui, xstuff->f_x1, cursor_oldy, xstuff->f_x2, cursor_oldy);
401 aux_XDrawLine(gui, cursor_oldx, xstuff->f_y1, cursor_oldx, xstuff->f_y2);
406 * draw a crosshair cursor
408 void crosshair_motion(GUI *gui, int x, int y)
410 X11Stuff *xstuff = gui->xstuff;
412 /* Erase the previous crosshair */
413 if (crosshair_erase == TRUE) {
414 aux_XDrawLine(gui, xstuff->f_x1, cursor_oldy, xstuff->f_x2, cursor_oldy);
415 aux_XDrawLine(gui, cursor_oldx, xstuff->f_y1, cursor_oldx, xstuff->f_y2);
418 if (x < xstuff->f_x1 || x > xstuff->f_x2 ||
419 y < xstuff->f_y2 || y > xstuff->f_y1) {
420 crosshair_erase = FALSE;
421 return;
424 /* Draw the new crosshair */
425 aux_XDrawLine(gui, xstuff->f_x1, y, xstuff->f_x2, y);
426 aux_XDrawLine(gui, x, xstuff->f_y1, x, xstuff->f_y2);
427 crosshair_erase = TRUE;
428 cursor_oldx = x;
429 cursor_oldy = y;
432 void sync_canvas_size(Grace *grace)
434 X11Stuff *xstuff = grace->gui->xstuff;
435 unsigned int w, h;
437 Device_entry *d = get_device_props(grace->rt->canvas, grace->rt->tdevice);
439 GetDimensions(xstuff->canvas, &w, &h);
441 set_page_dimensions(grace, w*72.0/d->pg.dpi, h*72.0/d->pg.dpi, TRUE);
446 * expose/resize proc
448 void expose_resize(Widget w, XtPointer client_data, XtPointer call_data)
450 Grace *grace = (Grace *) client_data;
451 static int inc = FALSE;
452 XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct *) call_data;
454 #if defined(DEBUG)
455 if (get_debuglevel(grace) == 7) {
456 printf("Call to expose_resize(); reason == %d\n", cbs->reason);
458 #endif
460 /* HACK */
461 if (!grace->gui->inwin) {
462 return;
465 if (!inc) {
466 inc = TRUE;
468 update_all();
469 xdrawgraph(grace->project, TRUE);
471 return;
474 if (cbs->reason == XmCR_EXPOSE) {
475 x11_redraw(cbs->window,
476 cbs->event->xexpose.x,
477 cbs->event->xexpose.y,
478 cbs->event->xexpose.width,
479 cbs->event->xexpose.height);
480 } else {
481 if (gui_is_page_free(grace->gui)) {
482 sync_canvas_size(grace);
483 update_all();
484 xdrawgraph(grace->project, TRUE);
490 * redraw all
492 void xdrawgraph(const Quark *q, int force)
494 Quark *project = get_parent_project(q);
495 Grace *grace = grace_from_quark(q);
497 if (grace && grace->gui->inwin && (force || grace->gui->auto_redraw)) {
498 X11Stuff *xstuff = grace->gui->xstuff;
499 Quark *gr = graph_get_current(project);
500 Device_entry *d = get_device_props(grace->rt->canvas, grace->rt->tdevice);
501 Page_geometry *pg = &d->pg;
502 float dpi = grace->gui->zoom*xstuff->dpi;
504 set_wait_cursor();
506 if (dpi != pg->dpi) {
507 int wpp, hpp;
508 project_get_page_dimensions(project, &wpp, &hpp);
510 pg->width = (unsigned long) (wpp*dpi/72);
511 pg->height = (unsigned long) (hpp*dpi/72);
512 pg->dpi = dpi;
515 resize_drawables(pg->width, pg->height);
517 select_device(grace->rt->canvas, grace->rt->tdevice);
518 drawgraph(project);
520 if (quark_is_active(gr)) {
521 draw_focus(gr);
523 reset_crosshair(grace->gui, FALSE);
524 region_need_erasing = FALSE;
526 x11_redraw(xstuff->xwin, 0, 0, xstuff->win_w, xstuff->win_h);
528 XFlush(xstuff->disp);
530 unset_wait_cursor();
535 void x11_redraw(Window window, int x, int y, int width, int height)
537 X11Stuff *xstuff = grace->gui->xstuff;
538 if (grace->gui->inwin == TRUE && xstuff->bufpixmap != (Pixmap) NULL) {
539 XCopyArea(xstuff->disp, xstuff->bufpixmap, window, xstuff->gc, x, y, width, height, x, y);
543 static void resize_drawables(unsigned int w, unsigned int h)
545 X11Stuff *xstuff = grace->gui->xstuff;
547 if (w == 0 || h == 0) {
548 return;
551 if (xstuff->bufpixmap == (Pixmap) NULL) {
552 xstuff->bufpixmap = XCreatePixmap(xstuff->disp, xstuff->root, w, h, xstuff->depth);
553 } else if (xstuff->win_w != w || xstuff->win_h != h) {
554 XFreePixmap(xstuff->disp, xstuff->bufpixmap);
555 xstuff->bufpixmap = XCreatePixmap(xstuff->disp, xstuff->root, w, h, xstuff->depth);
558 if (xstuff->bufpixmap == (Pixmap) NULL) {
559 errmsg("Can't allocate buffer pixmap");
560 xstuff->win_w = 0;
561 xstuff->win_h = 0;
562 } else {
563 xstuff->win_w = w;
564 xstuff->win_h = h;
567 xstuff->win_scale = MIN2(xstuff->win_w, xstuff->win_h);
569 if (!gui_is_page_free(grace->gui)) {
570 SetDimensions(xstuff->canvas, xstuff->win_w, xstuff->win_h);
574 static void xmonitor_rti(XtPointer ib, int *ptrFd, XtInputId *ptrId)
576 set_wait_cursor();
578 monitor_input(grace, (Input_buffer *) ib, 1, 1);
580 unset_wait_cursor();
583 void xregister_rti(Input_buffer *ib)
585 if (grace->gui->inwin && ib) {
586 /* the screen has been initialized : we can register the buffer */
587 ib->id = (unsigned long) XtAppAddInput(app_con,
588 ib->fd,
589 (XtPointer) XtInputReadMask,
590 xmonitor_rti,
591 (XtPointer) ib);
595 void xunregister_rti(const Input_buffer *ib)
597 if (grace->gui->inwin && ib) {
598 /* the screen has been initialized : we can remove the buffer */
599 XtRemoveInput((XtInputId) ib->id);
604 * for the goto point feature
606 void setpointer(VPoint vp)
608 X11Stuff *xstuff = grace->gui->xstuff;
609 short x, y;
611 x11_VPoint2dev(&vp, &x, &y);
613 /* Make sure we remain inside the DA widget dimensions */
614 x = MAX2(x, 0);
615 x = MIN2(x, xstuff->win_w);
616 y = MAX2(y, 0);
617 y = MIN2(y, xstuff->win_h);
619 XWarpPointer(xstuff->disp, None, xstuff->xwin, 0, 0, 0, 0, x, y);
622 char *display_name(GUI *gui)
624 return DisplayString(gui->xstuff->disp);
627 #define BUFSIZE 1024
628 static int HandleXError(Display *dpy, XErrorEvent *event)
630 char buffer[BUFSIZE], mesg[BUFSIZE], *output;
632 char *mtype = "XlibMessage";
634 XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", buffer, BUFSIZE);
635 output = copy_string(NULL, buffer);
636 output = concat_strings(output, ":");
638 XGetErrorText(dpy, event->error_code, buffer, BUFSIZE);
639 output = concat_strings(output, buffer);
640 output = concat_strings(output, "\n");
642 XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", mesg,
643 BUFSIZE);
644 sprintf(buffer, mesg, event->request_code);
645 output = concat_strings(output, buffer);
647 if (event->request_code < 128) {
648 char number[32];
649 sprintf(number, "%d", event->request_code);
650 XGetErrorDatabaseText(dpy, "XRequest", number, "", mesg, BUFSIZE);
651 sprintf(buffer, " (%s)\n", mesg);
652 output = concat_strings(output, buffer);
655 switch (event->error_code) {
656 case (BadWindow):
657 case (BadPixmap):
658 case (BadCursor):
659 case (BadFont):
660 case (BadDrawable):
661 case (BadColor):
662 case (BadGC):
663 case (BadIDChoice):
664 case (BadValue):
665 case (BadAtom):
666 if (event->error_code == BadValue) {
667 XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x", mesg,
668 BUFSIZE);
669 } else if (event->error_code == BadAtom) {
670 XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x", mesg,
671 BUFSIZE);
672 } else {
673 XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
674 mesg, BUFSIZE);
676 output = concat_strings(output, " ");
677 sprintf(buffer, mesg, event->resourceid);
678 output = concat_strings(output, buffer);
679 output = concat_strings(output, "\n");
680 break;
681 } /* switch() */
683 XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", mesg,
684 BUFSIZE);
685 sprintf(buffer, mesg, event->serial);
686 output = concat_strings(output, " ");
687 output = concat_strings(output, buffer);
688 output = concat_strings(output, ".");
690 emergency_exit(grace, TRUE, output);
691 xfree(output);
693 /* return value is ignored anyway */
694 return 0;
698 * Interrupt handler for X IO errors
700 static int HandleXIOError(Display *d)
702 char msg[BUFSIZE];
703 if (errno == EPIPE) {
704 sprintf(msg, "X connection to %s broken (server error - EPIPE).",
705 DisplayString(d));
706 } else {
707 sprintf(msg, "Fatal IO error on X server %s.", DisplayString(d));
710 emergency_exit(grace, FALSE, msg);
712 /* Ideally, we don't reach this anyway ... */
713 return 1;
716 void installXErrorHandler(void)
718 XSetErrorHandler(HandleXError);
719 XSetIOErrorHandler(HandleXIOError);
722 int x11_init(Grace *grace)
724 X11Stuff *xstuff = grace->gui->xstuff;
725 XGCValues gc_val;
726 long mrsize;
727 int max_path_limit;
729 xstuff->screennumber = DefaultScreen(xstuff->disp);
730 xstuff->root = RootWindow(xstuff->disp, xstuff->screennumber);
732 xstuff->gc = DefaultGC(xstuff->disp, xstuff->screennumber);
734 xstuff->depth = DisplayPlanes(xstuff->disp, xstuff->screennumber);
736 /* init colormap */
737 xstuff->cmap = DefaultColormap(xstuff->disp, xstuff->screennumber);
738 /* redefine colormap, if needed */
739 if (grace->gui->install_cmap == CMAP_INSTALL_ALWAYS) {
740 xstuff->cmap = XCopyColormapAndFree(xstuff->disp, xstuff->cmap);
741 grace->gui->private_cmap = TRUE;
744 /* set GCs */
745 if (grace->gui->invert) {
746 gc_val.function = GXinvert;
747 } else {
748 gc_val.function = GXxor;
750 gcxor = XCreateGC(xstuff->disp, xstuff->root, GCFunction, &gc_val);
752 /* XExtendedMaxRequestSize() appeared in X11R6 */
753 #if XlibSpecificationRelease > 5
754 mrsize = XExtendedMaxRequestSize(xstuff->disp);
755 #else
756 mrsize = 0;
757 #endif
758 if (mrsize <= 0) {
759 mrsize = XMaxRequestSize(xstuff->disp);
761 max_path_limit = (mrsize - 3)/2;
762 if (max_path_limit < get_max_path_limit(grace->rt->canvas)) {
763 char buf[128];
764 sprintf(buf,
765 "Setting max drawing path length to %d (limited by the X server)",
766 max_path_limit);
767 errmsg(buf);
768 set_max_path_limit(grace->rt->canvas, max_path_limit);
771 xstuff->dpi = rint(MM_PER_INCH*DisplayWidth(xstuff->disp, xstuff->screennumber)/
772 DisplayWidthMM(xstuff->disp, xstuff->screennumber));
774 return RETURN_SUCCESS;
778 static int x11_convx(double x)
780 X11Stuff *xstuff = grace->gui->xstuff;
781 return ((int) rint(xstuff->win_scale * x));
784 static int x11_convy(double y)
786 X11Stuff *xstuff = grace->gui->xstuff;
787 return ((int) rint(xstuff->win_h - xstuff->win_scale * y));
790 void x11_VPoint2dev(const VPoint *vp, short *x, short *y)
792 *x = x11_convx(vp->x);
793 *y = x11_convy(vp->y);
797 * x11_dev2VPoint - given (x,y) in screen coordinates, return the
798 * viewport coordinates
800 void x11_dev2VPoint(short x, short y, VPoint *vp)
802 X11Stuff *xstuff = grace->gui->xstuff;
803 if (xstuff->win_scale == 0) {
804 vp->x = (double) 0.0;
805 vp->y = (double) 0.0;
806 } else {
807 vp->x = (double) x / xstuff->win_scale;
808 vp->y = (double) (xstuff->win_h - y) / xstuff->win_scale;
812 Pixmap char_to_pixmap(Widget w, int font, char c, int csize)
814 X11Stuff *xstuff = grace->gui->xstuff;
815 CPixmap *pm;
816 Pixmap pixmap = 0;
817 int height, width, hshift, vshift;
818 float fsize = 0.8*(float)csize;
820 pm = canvas_raster_char(font, c, fsize, &vshift, &hshift);
822 if (pm != NULL && pm->bits != NULL) {
823 long bg, fg;
824 Pixmap ptmp;
826 vshift = csize - vshift - 4;
827 height = pm->height;
828 width = pm->width;
830 ptmp = XCreateBitmapFromData(xstuff->disp, xstuff->root,
831 pm->bits, width, height);
832 pixmap = XCreatePixmap(xstuff->disp, xstuff->root,
833 csize, csize, xstuff->depth);
835 XtVaGetValues(w, XmNbackground, &bg, XmNforeground, &fg, NULL);
836 XSetForeground(xstuff->disp, xstuff->gc, bg);
837 XFillRectangle(xstuff->disp, pixmap, xstuff->gc, 0, 0, csize, csize);
839 XSetBackground(xstuff->disp, xstuff->gc, bg);
840 XSetForeground(xstuff->disp, xstuff->gc, fg);
841 XCopyPlane(xstuff->disp, ptmp, pixmap, xstuff->gc, 0, 0,
842 width, height, hshift, vshift, 1);
844 XFreePixmap(xstuff->disp, ptmp);
845 canvas_cpixmap_free(pm);
848 return pixmap;