2 * Grace - GRaphing, Advanced Computation and Exploration of data
4 * Home page: http://plasma-gate.weizmann.ac.il/Grace/
6 * Copyright (c) 1991-1995 Paul J Turner, Portland, OR
7 * Copyright (c) 1996-2004 Grace Development Team
9 * Maintained by Evgeny Stambulchik
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.
36 #include <X11/cursorfont.h>
43 #include "core_utils.h"
49 extern XtAppContext app_con
;
51 extern Input_buffer
*ib_tbl
;
52 extern int ib_tblsize
;
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
;
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
)) {
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
);
85 void set_wait_cursor(void)
87 if (grace
->gui
->xstuff
->disp
== NULL
) {
91 DefineDialogCursor(grace
->gui
->xstuff
->wait_cursor
);
94 void unset_wait_cursor(void)
96 X11Stuff
*xstuff
= grace
->gui
->xstuff
;
97 if (xstuff
->disp
== NULL
) {
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
) {
114 XUndefineCursor(xstuff
->disp
, xstuff
->xwin
);
115 xstuff
->cur_cursor
= c
;
118 XDefineCursor(xstuff
->disp
, xstuff
->xwin
, xstuff
->line_cursor
);
121 XDefineCursor(xstuff
->disp
, xstuff
->xwin
, xstuff
->find_cursor
);
124 XDefineCursor(xstuff
->disp
, xstuff
->xwin
, xstuff
->text_cursor
);
127 XDefineCursor(xstuff
->disp
, xstuff
->xwin
, xstuff
->kill_cursor
);
130 XDefineCursor(xstuff
->disp
, xstuff
->xwin
, xstuff
->move_cursor
);
133 XDefineCursor(xstuff
->disp
, xstuff
->xwin
, xstuff
->drag_cursor
);
136 xstuff
->cur_cursor
= -1;
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
;
166 static int dstate_save
= 0;
169 if (!pr
|| !gui
->inwin
) {
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
) {
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
);
183 buf2
= concat_strings(buf2
, "*");
184 buf1
= concat_strings(buf1
, " (modified)");
186 XtVaSetValues(app_shell
, XtNtitle
, buf1
, XtNiconName
, buf2
, NULL
);
192 void page_zoom_inout(Grace
*grace
, int inout
)
194 if (!gui_is_page_free(grace
->gui
)) {
196 grace
->gui
->zoom
*= ZOOM_STEP
;
199 grace
->gui
->zoom
/= ZOOM_STEP
;
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
;
247 GUI
*gui
= gui_from_quark(gr
);
249 if (gui
->draw_focus_flag
== TRUE
) {
250 graph_get_viewport(gr
, &v
);
253 x11_VPoint2dev(&vp
, &ix1
, &iy1
);
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
;
279 aux_XDrawLine(gui
, x1_old
, y1_old
, x2_old
, y2_old
);
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
;
306 if (erase
&& region_need_erasing
) {
307 aux_XDrawRectangle(gui
, x1_old
, y1_old
, dx_old
, dy_old
);
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
;
341 x11_VPoint2dev(&vp
, &x1
, &y1
);
347 x11_VPoint2dev(&vp
, &x2
, &y2
);
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
;
362 x11_VPoint2dev(&vp
, &x1
, &y1
);
365 x11_VPoint2dev(&vp
, &x2
, &y2
);
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
;
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
;
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
;
432 void sync_canvas_size(Grace
*grace
)
434 X11Stuff
*xstuff
= grace
->gui
->xstuff
;
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
);
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
;
455 if (get_debuglevel(grace
) == 7) {
456 printf("Call to expose_resize(); reason == %d\n", cbs
->reason
);
461 if (!grace
->gui
->inwin
) {
469 xdrawgraph(grace
->project
, TRUE
);
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
);
481 if (gui_is_page_free(grace
->gui
)) {
482 sync_canvas_size(grace
);
484 xdrawgraph(grace
->project
, TRUE
);
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
;
506 if (dpi
!= pg
->dpi
) {
508 project_get_page_dimensions(project
, &wpp
, &hpp
);
510 pg
->width
= (unsigned long) (wpp
*dpi
/72);
511 pg
->height
= (unsigned long) (hpp
*dpi
/72);
515 resize_drawables(pg
->width
, pg
->height
);
517 select_device(grace
->rt
->canvas
, grace
->rt
->tdevice
);
520 if (quark_is_active(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
);
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) {
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");
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
)
578 monitor_input(grace
, (Input_buffer
*) ib
, 1, 1);
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
,
589 (XtPointer
) XtInputReadMask
,
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
;
611 x11_VPoint2dev(&vp
, &x
, &y
);
613 /* Make sure we remain inside the DA widget dimensions */
615 x
= MIN2(x
, xstuff
->win_w
);
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
);
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
,
644 sprintf(buffer
, mesg
, event
->request_code
);
645 output
= concat_strings(output
, buffer
);
647 if (event
->request_code
< 128) {
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
) {
666 if (event
->error_code
== BadValue
) {
667 XGetErrorDatabaseText(dpy
, mtype
, "Value", "Value 0x%x", mesg
,
669 } else if (event
->error_code
== BadAtom
) {
670 XGetErrorDatabaseText(dpy
, mtype
, "AtomID", "AtomID 0x%x", mesg
,
673 XGetErrorDatabaseText(dpy
, mtype
, "ResourceID", "ResourceID 0x%x",
676 output
= concat_strings(output
, " ");
677 sprintf(buffer
, mesg
, event
->resourceid
);
678 output
= concat_strings(output
, buffer
);
679 output
= concat_strings(output
, "\n");
683 XGetErrorDatabaseText(dpy
, mtype
, "ErrorSerial", "Error Serial #%d", mesg
,
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
);
693 /* return value is ignored anyway */
698 * Interrupt handler for X IO errors
700 static int HandleXIOError(Display
*d
)
703 if (errno
== EPIPE
) {
704 sprintf(msg
, "X connection to %s broken (server error - EPIPE).",
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 ... */
716 void installXErrorHandler(void)
718 XSetErrorHandler(HandleXError
);
719 XSetIOErrorHandler(HandleXIOError
);
722 int x11_init(Grace
*grace
)
724 X11Stuff
*xstuff
= grace
->gui
->xstuff
;
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
);
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
;
745 if (grace
->gui
->invert
) {
746 gc_val
.function
= GXinvert
;
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
);
759 mrsize
= XMaxRequestSize(xstuff
->disp
);
761 max_path_limit
= (mrsize
- 3)/2;
762 if (max_path_limit
< get_max_path_limit(grace
->rt
->canvas
)) {
765 "Setting max drawing path length to %d (limited by the X server)",
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;
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
;
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
) {
826 vshift
= csize
- vshift
- 4;
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
);