2 static char *RCSid() { return RCSid("$Id: gplt_x11.c,v 1.167.2.11 2009/04/10 04:37:00 sfeam Exp $"); }
6 #define MOUSE_ALL_WINDOWS 1
8 /* GNUPLOT - gplt_x11.c */
11 * Copyright 1986 - 1993, 1998, 2004 Thomas Williams, Colin Kelley
13 * Permission to use, copy, and distribute this software and its
14 * documentation for any purpose with or without fee is hereby granted,
15 * provided that the above copyright notice appear in all copies and
16 * that both that copyright notice and this permission notice appear
17 * in supporting documentation.
19 * Permission to modify the software is granted, but not the right to
20 * distribute the complete modified source code. Modifications are to
21 * be distributed as patches to the released version. Permission to
22 * distribute binaries produced by compiling modified sources is granted,
24 * 1. distribute the corresponding source modifications from the
25 * released version in the form of a patch file along with the binaries,
26 * 2. add special version identification to distinguish your version
27 * in addition to the base release version number,
28 * 3. provide your name and address as the primary contact for the
29 * support of your modified version, and
30 * 4. retain our contact information in regard to use of the base
32 * Permission to distribute the released version of the source code along
33 * with corresponding source modifications in the form of a patch file is
34 * granted with same provisions 2 through 4 for binary distributions.
36 * This software is provided "as is" without express or implied warranty
37 * to the extent permitted by applicable law.
42 * (a) make EXPORT_SELECTION the default and specify NOEXPORT to undefine
43 * (b) append X11 terminal number to resource name
44 * (c) change cursor for active terminal
47 /*-----------------------------------------------------------------------------
48 * gnuplot_x11 - X11 outboard terminal driver for gnuplot 3.3
50 * Requires installation of companion inboard x11 driver in gnuplot/term.c
53 * Chris Peterson (MIT)
54 * Dana Chee (Bellcore)
55 * Arthur Smith (Cornell)
56 * Hendri Hondorp (University of Twente, The Netherlands)
57 * Bill Kucharski (Solbourne)
58 * Charlie Kline (University of Illinois)
59 * Yehavi Bourvine (Hebrew University of Jerusalem, Israel)
60 * Russell Lang (Monash University, Australia)
61 * O'Reilly & Associates: X Window System - Volumes 1 & 2
63 * This code is provided as is and with no warranties of any kind.
65 * drd: change to allow multiple windows to be maintained independently
67 *---------------------------------------------------------------------------*/
69 /* drd : export the graph via ICCCM primary selection. well... not quite
70 * ICCCM since we dont support full list of targets, but this
71 * is a start. define EXPORT_SELECTION if you want this feature
74 /*lph: add a "feature" to undefine EXPORT_SELECTION
75 The following makes EXPORT_SELECTION the default and
76 defining NOEXPORT over-rides the default
79 /* Petr Mikulik and Johannes Zellner: added mouse support (October 1999)
80 * Implementation and functionality is based on os2/gclient.c; see mousing.c
81 * Pieter-Tjerk de Boer <ptdeboer@cs.utwente.nl>: merged two versions
82 * of mouse patches. (November 1999) (See also mouse.[ch]).
85 /* X11 support for Petr Mikulik's pm3d
86 * by Johannes Zellner <johannes@zellner.org>
87 * (November 1999 - January 2000, Oct. 2000)
90 /* Polyline support May 2003
91 * Ethan Merritt <merritt@u.washington.edu>
94 /* Dynamically created windows July 2003
95 * Across-pipe title text and close command October 2003
96 * Dan Sebald <daniel.sebald@ieee.org>
99 /* Daniel Sebald: added X11 support for images. (27 February 2003)
102 /* Shigeharu Takeno <shige@iee.niit.ac.jp> February 2005
103 * Support for multi-byte fonts based, with permission, on the "gnuplot+"
104 * patches by Masahito Yamaga <ma@yama-ga.com>
109 #include "gp_types.h"
110 #include "term_api.h"
111 #include "gplt_x11.h"
113 #ifdef EXPORT_SELECTION
114 # undef EXPORT_SELECTION
115 #endif /* EXPORT SELECTION */
117 # define EXPORT_SELECTION XA_PRIMARY
118 #endif /* NOEXPORT */
121 #if !(defined(VMS) || defined(CRIPPLED_SELECT))
125 #if defined(VMS) && defined(CRIPPLED_SELECT)
126 Error. Incompatible options.
130 #include <X11/Xlib.h>
131 #include <X11/Xresource.h>
132 #include <X11/Xutil.h>
133 #include <X11/Xatom.h>
134 #include <X11/keysym.h>
135 #ifdef USE_X11_MULTIBYTE
136 # include <X11/Xlocale.h>
140 #include "getcolor.h"
143 # include <X11/cursorfont.h>
145 # define XC_crosshair 34
150 #ifdef HAVE_SYS_BSDTYPES_H
151 # include <sys/bsdtypes.h>
154 #if defined(HAVE_SYS_SYSTEMINFO_H) && defined(HAVE_SYSINFO)
155 # include <sys/systeminfo.h>
156 # define SYSINFO_METHOD "sysinfo"
157 # define GP_SYSTEMINFO(host) sysinfo (SI_HOSTNAME, (host), MAXHOSTNAMELEN)
159 # define SYSINFO_METHOD "gethostname"
160 # define GP_SYSTEMINFO(host) gethostname ((host), MAXHOSTNAMELEN)
161 #endif /* HAVE_SYS_SYSTEMINFO_H && HAVE_SYSINFO */
165 # define INCL_DOSPROCESS
166 # define INCL_DOSSEMAPHORES
169 # include "gpexecute.h"
174 static unsigned long gnuplotXID = 0; /* WINDOWID of gnuplot */
176 #ifdef MOUSE_ALL_WINDOWS
177 # include "axis.h" /* Just to pick up FIRST_X_AXIS enums */
178 typedef struct axis_scale_t {
186 #endif /* USE_MOUSE */
189 /* for gethostname ... */
191 /* for __XOS2RedirRoot */
192 #include <X11/Xlibint.h>
198 # include <starlet.h>
200 # define EXIT(status) sys$delprc(0, 0) /* VMS does not drop itself */
203 # define EXIT(status) \
205 gp_exec_event(GE_pending, 0, 0, 0, 0, 0); \
211 # define EXIT(status) exit(status)
212 # endif /* PIPE_IPC */
216 # define EINTR E_ILLFNC
222 typedef struct cmap_t {
223 struct cmap_t *prev_cmap; /* Linked list pointers and number */
224 struct cmap_t *next_cmap;
226 unsigned long colors[Ncolors]; /* line colors as pixel values */
227 unsigned long rgbcolors[Ncolors]; /* line colors in rgb format */
228 unsigned long xorpixel; /* line colors */
231 unsigned long *pixels; /* pm3d colors */
234 /* always allocate a default colormap (done in preset()) */
235 static cmap_t default_cmap;
237 /* information about one window/plot */
238 typedef struct plot_struct {
241 unsigned int posn_flags;
243 unsigned int width, height; /* window size */
244 unsigned int gheight; /* height of the part of the window that
245 * contains the graph (i.e., excluding the
246 * status line at the bottom if mouse is
249 int ncommands, max_commands;
253 int button; /* buttons which are currently pressed */
254 char str[0xff]; /* last displayed string */
256 Time time; /* time stamp of previous event */
257 int lwidth; /* this and the following 6 lines declare */
258 int type; /* variables used during drawing in exec_cmd() */
261 double angle; /* Text rotation angle in degrees */
264 TBOOLEAN mouse_on; /* is mouse bar on? */
265 TBOOLEAN ruler_on; /* is ruler on? */
266 TBOOLEAN ruler_lineto_on; /* is line between ruler and mouse cursor on? */
267 int ruler_x, ruler_y; /* coordinates of ruler */
268 int ruler_lineto_x, ruler_lineto_y; /* draw line from ruler to current mouse pos */
269 TBOOLEAN zoombox_on; /* is zoombox on? */
270 int zoombox_x1, zoombox_y1, zoombox_x2, zoombox_y2; /* coordinates of zoombox as last drawn */
271 char zoombox_str1a[64], zoombox_str1b[64], zoombox_str2a[64], zoombox_str2b[64]; /* strings to be drawn at corners of zoombox ; 1/2 indicate corner; a/b indicate above/below */
272 TBOOLEAN resizing; /* TRUE while waiting for an acknowledgement of resize */
274 /* points to the cmap which is currently used for drawing.
275 * This is always the default colormap, if not in pm3d.
278 #if defined(USE_MOUSE) && defined(MOUSE_ALL_WINDOWS)
279 /* This array holds per-axis scaling information sufficient to reconstruct
280 * plot coordinates of a mouse click. It is a snapshot of the contents of
281 * gnuplot's axis_array structure at the time the plot was drawn.
284 int axis_mask; /* Bits set to show which axes are active */
285 axis_scale_t axis_scale[2*SECOND_AXES];
287 /* Last text position - used by enhanced text mode */
289 /* Saved text position - used by enhanced text mode */
291 /* Last rgb color that was set */
292 unsigned long current_rgb;
294 struct plot_struct *prev_plot; /* Linked list pointers and number */
295 struct plot_struct *next_plot;
299 static plot_struct *Add_Plot_To_Linked_List __PROTO((int));
300 static void Remove_Plot_From_Linked_List __PROTO((Window));
301 static plot_struct *Find_Plot_In_Linked_List_By_Number __PROTO((int));
302 static plot_struct *Find_Plot_In_Linked_List_By_Window __PROTO((Window));
303 static plot_struct *Find_Plot_In_Linked_List_By_CMap __PROTO((cmap_t *));
305 static struct plot_struct *current_plot = NULL;
306 static struct plot_struct *plot_list_start = NULL;
308 static void x11_setfill __PROTO((GC *gc, int style, TBOOLEAN poly));
310 /* information about window/plot to be removed */
311 typedef struct plot_remove_struct {
312 Window plot_window_to_remove;
313 struct plot_remove_struct *next_remove;
315 } plot_remove_struct;
317 static void Add_Plot_To_Remove_FIFO_Queue __PROTO((Window));
318 static void Process_Remove_FIFO_Queue __PROTO((void));
320 static struct plot_remove_struct *remove_fifo_queue_start = NULL;
321 static int process_remove_fifo_queue = 0;
323 static cmap_t *Add_CMap_To_Linked_List __PROTO((void));
324 static void Remove_CMap_From_Linked_List __PROTO((cmap_t *));
325 static cmap_t *Find_CMap_In_Linked_List __PROTO((cmap_t *));
326 static int cmaps_differ __PROTO((cmap_t *, cmap_t *));
328 /* current_cmap always points to a valid colormap. At start up
329 * it is the default colormap. When a palette command comes
330 * across the pipe, the current_cmap is set to point at the
331 * resulting colormap which ends up in the linked list of colormaps.
332 * The current_cmap should never be removed from the linked list
333 * even if all windows are deleted, because that colormap will be
334 * used for the next plot.
336 static struct cmap_t *current_cmap = NULL;
337 static struct cmap_t *cmap_list_start = NULL;
339 /* These might work better as fuctions, but defines will do for now. */
340 #define ERROR_NOTICE(str) "\nGNUPLOT (gplt_x11): " str
341 #define ERROR_NOTICE_NEWLINE(str) "\n " str
343 enum { NOT_AVAILABLE = -1 };
346 static char selection[SEL_LEN] = "";
350 # define GRAPH_HEIGHT(plot) ((plot)->gheight)
351 # define PIXMAP_HEIGHT(plot) ((plot)->gheight + vchar)
352 /* note: PIXMAP_HEIGHT is the height of the plot including the status line,
353 even if the latter is not enabled right now */
355 # define GRAPH_HEIGHT(plot) ((plot)->height)
356 # define PIXMAP_HEIGHT(plot) ((plot)->height)
359 static void CmapClear __PROTO((cmap_t *));
360 static void RecolorWindow __PROTO((plot_struct *));
361 static void FreeColors __PROTO((cmap_t *));
362 static void ReleaseColormap __PROTO((cmap_t *));
363 static unsigned long *ReallocColors __PROTO((cmap_t *, int));
364 static void PaletteMake __PROTO((t_sm_palette *));
365 static void PaletteSetColor __PROTO((plot_struct *, double));
366 static int GetVisual __PROTO((int, Visual **, int *));
367 static void scan_palette_from_buf __PROTO((void));
369 #if defined(WITH_IMAGE)
370 static unsigned short BitMaskDetails __PROTO((unsigned long mask, unsigned short *left_shift, unsigned short *right_shift));
372 #if defined(WITH_IMAGE) || defined(BINARY_X11_POLYGON)
373 TBOOLEAN swap_endian = 0; /* For binary data. */
374 /* Petr's byte swapping routine. */
376 byteswap(char* data, int datalen)
378 char tmp, *dest = data + datalen - 1;
379 if (datalen < 2) return;
380 while (dest > data) {
386 /* Additional macros that should be more efficient when data size is known. */
389 #define byteswap2(x) \
390 byteswap_char = ((char *)x)[0]; \
391 ((char *)x)[0] = ((char *)x)[1]; \
392 ((char *)x)[1] = byteswap_char;
393 #define byteswap4(x) \
394 byteswap_char = ((char *)x)[0]; \
395 ((char *)x)[0] = ((char *)x)[3]; \
396 ((char *)x)[3] = byteswap_char; \
397 byteswap_char = ((char *)x)[1]; \
398 ((char *)x)[1] = ((char *)x)[2]; \
399 ((char *)x)[2] = byteswap_char
402 static void store_command __PROTO((char *, plot_struct *));
403 static void prepare_plot __PROTO((plot_struct *, int));
404 static void delete_plot __PROTO((plot_struct *));
406 static int record __PROTO((void));
407 static void process_event __PROTO((XEvent *)); /* from Xserver */
408 static void process_configure_notify_event __PROTO((XEvent *event));
410 static void mainloop __PROTO((void));
412 static void display __PROTO((plot_struct *));
413 static void UpdateWindow __PROTO((plot_struct *));
415 static int ErrorHandler __PROTO((Display *, XErrorEvent *));
416 static void DrawRuler __PROTO((plot_struct *));
417 static void EventuallyDrawMouseAddOns __PROTO((plot_struct *));
418 static void DrawBox __PROTO((plot_struct *));
419 static void DrawLineToRuler __PROTO((plot_struct *));
420 static void AnnotatePoint __PROTO((plot_struct *, int, int, const char[], const char[]));
421 static long int SetTime __PROTO((plot_struct *, Time));
422 static unsigned long AllocateXorPixel __PROTO((cmap_t *));
423 static void GetGCXor __PROTO((plot_struct *, GC *));
424 static void GetGCXorDashed __PROTO((plot_struct *, GC *));
426 static void GetGCBlackAndWhite __PROTO((plot_struct *, GC *, Pixmap, int));
427 static int SplitAt __PROTO((char **, int, char *, char));
428 static void xfree __PROTO((void *));
430 static void EraseCoords __PROTO((plot_struct *));
431 static void DrawCoords __PROTO((plot_struct *, const char *));
432 static void DisplayCoords __PROTO((plot_struct *, const char *));
434 static TBOOLEAN is_meta __PROTO((KeySym));
435 static char* getMultiTabConsoleSwitchCommand __PROTO((unsigned long *));
436 #endif /* USE_MOUSE */
438 static void DrawRotated __PROTO((plot_struct *, Display *, GC,
439 int, int, const char *, int));
440 static int DrawRotatedErrorHandler __PROTO((Display *, XErrorEvent *));
441 static void exec_cmd __PROTO((plot_struct *, char *));
443 static void reset_cursor __PROTO((void));
445 static void preset __PROTO((int, char **));
446 static char *pr_GetR __PROTO((XrmDatabase, char *));
447 static void pr_color __PROTO((cmap_t *));
448 static void pr_dashes __PROTO((void));
449 static void pr_encoding __PROTO((void));
450 static void pr_font __PROTO((char *));
451 static void pr_geometry __PROTO((char *));
452 static void pr_pointsize __PROTO((void));
453 static void pr_width __PROTO((void));
454 static void pr_window __PROTO((plot_struct *));
455 static void ProcessEvents __PROTO((Window));
456 static void pr_raise __PROTO((void));
457 static void pr_persist __PROTO((void));
458 static void pr_feedback __PROTO((void));
459 static void pr_ctrlq __PROTO((void));
460 static void pr_fastrotate __PROTO((void));
462 #ifdef EXPORT_SELECTION
463 static void export_graph __PROTO((plot_struct *));
464 static void handle_selection_event __PROTO((XEvent *));
465 static void pr_exportselection __PROTO((void));
468 #if defined(USE_MOUSE) && defined(MOUSE_ALL_WINDOWS)
469 static void mouse_to_coords __PROTO((plot_struct *, XEvent *,
470 double *, double *, double *, double *));
471 static double mouse_to_axis __PROTO((int, axis_scale_t *));
474 static char *FallbackFont = "fixed";
475 #ifdef USE_X11_MULTIBYTE
476 static char *FallbackFontMB =
477 "mbfont:*-medium-r-normal--14-*;*-medium-r-normal--16-*";
478 # define FontSetSep ';'
479 static int usemultibyte = 0;
480 static int multibyte_fonts_usable=1;
481 static int fontset_transsep __PROTO((char *, char *, int));
482 #endif /* USE_X11_MULTIBYTE */
483 static int gpXTextWidth __PROTO((XFontStruct *, const char *, int));
484 static int gpXTextHeight __PROTO((XFontStruct *));
485 static void gpXSetFont __PROTO((Display *, GC, Font));
486 static void gpXDrawImageString __PROTO((Display *, Drawable, GC, int, int, const char *, int));
487 static void gpXDrawString __PROTO((Display *, Drawable, GC, int, int, const char *, int));
488 static void gpXFreeFont __PROTO((Display *, XFontStruct *));
489 static XFontStruct *gpXLoadQueryFont __PROTO((Display *, char *));
490 static char *gpFallbackFont __PROTO((void));
491 static int gpXGetFontascent __PROTO((XFontStruct *cfont));
493 enum set_encoding_id encoding = S_ENC_DEFAULT; /* EAM - mirrored from core code by 'QE' */
494 static char default_font[64] = { '\0' };
495 static char default_encoding[16] = { '\0' };
498 static unsigned int widths[Nwidths] = { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
501 static char dashes[Ndashes][5];
503 t_sm_palette sm_palette = {
504 -1, /* colorFormulae */
505 SMPAL_COLOR_MODE_NONE, /* colorMode */
506 0, 0, 0, /* formula[RGB] */
508 0, /* use_maxcolors */
510 (rgb_color *) 0, /* color */
512 0, /* gradient_num */
513 (gradient_struct *) 0 /* gradient */
514 /* Afunc, Bfunc and Cfunc can't be initialised here */
517 static int have_pm3d = 1;
518 static int num_colormaps = 0;
519 static unsigned int maximal_possible_colors = 0x100;
520 static unsigned int minimal_possible_colors;
522 /* the following visual names must match the
523 * definitions in X.h in this order ! I hope
524 * this is standard (joze) */
525 static char *visual_name[] = {
538 static Visual *vis = (Visual *) 0;
539 static GC gc = (GC) 0;
540 static GC *current_gc = (GC *) 0;
541 static GC gc_xor = (GC) 0;
542 static GC gc_xor_dashed = (GC) 0;
543 static GC fill_gc = (GC) 0;
544 static XFontStruct *font = NULL;
545 #ifdef USE_X11_MULTIBYTE
546 static XFontSet mbfont = NULL;
548 static int do_raise = yes, persist = no;
549 static TBOOLEAN fast_rotate = TRUE;
550 static int feedback = yes;
551 static int ctrlq = no;
552 static int dashedlines = no;
553 #ifdef EXPORT_SELECTION
554 static TBOOLEAN exportselection = TRUE;
556 static Cursor cursor;
557 static Cursor cursor_default;
559 static Cursor cursor_exchange;
560 static Cursor cursor_sizing;
561 static Cursor cursor_zooming;
562 #ifndef TITLE_BAR_DRAWING_MSG
563 static Cursor cursor_waiting;
564 static Cursor cursor_save;
565 static int button_pressed = 0;
569 static int windows_open = 0;
571 static int gX = 100, gY = 100;
572 static unsigned int gW = 640, gH = 450;
573 static unsigned int gFlags = PSize;
575 static unsigned int BorderWidth = 2;
576 static unsigned int dep; /* depth */
577 static long max_request_size;
579 static Bool Mono = 0, Gray = 0, Rv = 0, Clear = 0;
580 static char X_Name[64] = "gnuplot";
581 static char X_Class[64] = "Gnuplot";
583 static int cx = 0, cy = 0;
585 /* Font characteristics held locally but sent back via pipe to x11.trm */
586 static int vchar, hchar;
588 /* Speficy negative values as indicator of uninitialized state */
589 static double xscale = -1.;
590 static double yscale = -1.;
591 double pointsize = -1.;
592 /* Avoid a crash upon using uninitialized variables from
593 above and avoid unnecessary calls to display().
594 Probably this is not the best fix ... */
595 #define Call_display(plot) if (xscale<0.) display(plot);
596 #define X(x) (int) ((x) * xscale)
597 #define Y(y) (int) ((4095-(y)) * yscale)
598 #define RevX(x) (((x)+0.5)/xscale)
599 #define RevY(y) (4095-((y)+0.5)/yscale)
600 /* note: the 0.5 term in RevX(x) and RevY(y) compensates for the round-off in X(x) and Y(y) */
602 #if defined(WITH_IMAGE) || defined(BINARY_X11_POLYGON)
603 #define Nbuf X11_COMMAND_BUFFER_LENGTH
607 static char buf[Nbuf];
608 static int buffered_input_available = 0;
610 static FILE *X11_ipc;
612 /* when using an ICCCM-compliant window manager, we can ask it
613 * to send us an event when user chooses 'close window'. We do this
614 * by setting WM_DELETE_WINDOW atom in property WM_PROTOCOLS
617 static Atom WM_PROTOCOLS, WM_DELETE_WINDOW;
619 static XPoint Diamond[5], Triangle[4];
620 static XSegment Plus[2], Cross[2], Star[4];
622 /* pixmaps used for filled boxes (ULIG) */
623 /* FIXME EAM - These data structures are a duplicate of the ones in bitmap.c */
625 /* pattern stipples for pattern fillstyle */
626 #define stipple_pattern_width 8
627 #define stipple_pattern_height 8
628 #define stipple_pattern_num 8
629 static const char stipple_pattern_bits[stipple_pattern_num][8] = {
630 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } /* no fill */
631 , { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x41 } /* cross-hatch (1) */
632 , { 0x88, 0x55, 0x22, 0x55, 0x88, 0x55, 0x22, 0x55 } /* double crosshatch(2) */
633 , { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /* solid fill (3) */
634 , { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 } /* diagonal stripes (4) */
635 , { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 } /* diagonal stripes (5) */
636 , { 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88 } /* diagonal stripes (6) */
637 , { 0x88, 0x88, 0x44, 0x44, 0x22, 0x22, 0x11, 0x11 } /* diagonal stripes (7) */
640 static Pixmap stipple_pattern[stipple_pattern_num];
641 static int stipple_initialized = 0;
644 static XPoint *polyline = NULL;
645 static int polyline_space = 0;
646 static int polyline_size = 0;
653 main(int argc, char *argv[])
661 /* malloc large blocks, otherwise problems with fragmented mem */
665 /* close open file handles */
669 #ifdef USE_X11_MULTIBYTE
670 if (setlocale(LC_ALL, "")==NULL || XSupportsLocale()==False)
671 multibyte_fonts_usable=0;
672 setlocale(LC_NUMERIC, "C"); /* HBB 20050525 */
673 #endif /* USE_X11_MULTIBYTE */
676 /* set up the alternative cursor */
677 cursor_default = XCreateFontCursor(dpy, XC_crosshair);
678 cursor = cursor_default;
680 /* create cursors for the splot actions */
681 cursor_exchange = XCreateFontCursor(dpy, XC_exchange);
682 cursor_sizing = XCreateFontCursor(dpy, XC_sizing);
683 /* arrow, top_left_arrow, left_ptr, sb_left_arrow, sb_right_arrow,
684 * plus, pencil, draft_large, right_ptr, draft_small */
685 cursor_zooming = XCreateFontCursor(dpy, XC_draft_small);
686 #ifndef TITLE_BAR_DRAWING_MSG
687 cursor_waiting = XCreateFontCursor(dpy, XC_watch);
688 cursor_save = (Cursor)0;
693 /* set up nonblocking stdout */
694 getfl = fcntl(1, F_GETFL); /* get current flags */
695 fcntl(1, F_SETFL, getfl | O_NONBLOCK);
696 signal(SIGPIPE, pipe_died_handler);
701 polyline_space = 100;
702 polyline = calloc(polyline_space, sizeof(XPoint));
703 if (!polyline) fprintf(stderr, "Panic: cannot allocate polyline\n");
709 FPRINTF((stderr, "waiting for %d windows\n", windows_open));
712 /* HBB 20030519: Some programs executing gnuplot -persist may
713 * be waiting for all default handles to be closed before they
714 * consider the sub-process finished. Emacs, e.g., does. So,
715 * unless this is a DEBUG build, drop our connection to stderr
716 * now. Using Freopen() ensures that debug fprintf()s won't
718 freopen("/dev/null", "w", stderr);
721 /* read x events until all windows have been quit */
722 while (windows_open > 0) {
724 XNextEvent(dpy, &event);
725 process_event(&event);
730 FPRINTF((stderr, "exiting\n"));
735 /*-----------------------------------------------------------------------------
736 * mainloop processing - process X events and input from gnuplot
738 * Three different versions of main loop processing are provided to support
739 * three different platforms.
741 * DEFAULT_X11: use select() for both X events and input on stdin
742 * from gnuplot inboard driver
744 * CRIPPLED_SELECT: use select() to service X events and check during
745 * select timeout for temporary plot file created
748 * VMS: use XNextEvent to service X events and AST to
749 * service input from gnuplot inboard driver on stdin
750 *---------------------------------------------------------------------------*/
756 * DEFAULT_X11 mainloop
761 int nf, cn = ConnectionNumber(dpy), in;
762 SELECT_TYPE_ARG1 nfds;
763 struct timeval timeout, *timer = (struct timeval *) 0;
767 int usleep_count = 0;
769 out = fileno(stdout);
773 in = fileno(X11_ipc);
777 nfds = ((cn > out) ? cn : out) + 1;
780 nfds = ((cn > in) ? cn : in) + 1;
783 /* Added by Robert Eckardt, RobertE@beta.TP2.Ruhr-Uni-Bochum.de */
784 timeout.tv_sec = 0; /* select() in ISC2.2 needs timeout */
785 timeout.tv_usec = 300000; /* otherwise input from gnuplot is */
786 timer = &timeout; /* suspended til next X event. */
787 #endif /* ISC22 (0.3s are short enough not to be noticed */
791 /* XNextEvent does an XFlush() before waiting. But here.
792 * we must ensure that the queue is flushed, since we
793 * dont call XNextEvent until an event arrives. (I have
794 * twice wasted quite some time over this issue, so now
795 * I am making sure of it !
803 /* Don't wait for events if we know that input is
804 * already sitting in a buffer. Also don't wait for
805 * input to become available.
807 if (buffered_input_available) {
812 timer = (struct timeval *) 0;
817 if (buffered_output_pending && !pipe_died) {
818 /* check, if stdout becomes writable */
822 /* Make sure this loop does not monopolize CPU if the pipe is jammed */
823 if (++usleep_count > 10) {
830 nf = select(nfds, SELECT_TYPE_ARG234 &tset, 0, 0, SELECT_TYPE_ARG5 timer);
835 perror("gnuplot_x11: select failed");
843 /* used to use CheckMaskEvent() but that cannot receive
844 * maskable events such as ClientMessage. So now we do
845 * one event, then return to the select.
846 * And that almost works, except that under some Xservers
847 * running without a window manager (e.g. Hummingbird Exceed under Win95)
848 * a bogus ConfigureNotify is sent followed by a valid ConfigureNotify
849 * when the window is maximized. The two events are queued, apparently
850 * in a single I/O because select() above doesn't see the second, valid
851 * event. This little loop fixes the problem by flushing the
852 * event queue completely.
856 XNextEvent(dpy, &xe);
858 } while (XPending(dpy));
861 if (FD_ISSET(in, &tset) || buffered_input_available) {
862 if (!record()) /* end of input */
866 if (!pipe_died && (FD_ISSET(out, &tset) || buffered_output_pending)) {
867 gp_exec_event(GE_pending, 0, 0, 0, 0, 0);
870 /* A method in which the ErrorHandler can queue plots to be
871 removed from the linked list. This prevents the situation
872 that could arise if the ErrorHandler directly removed
873 plots and some other part of the program were utilizing
874 a pointer to a plot that was destroyed. */
875 if (process_remove_fifo_queue) {
876 Process_Remove_FIFO_Queue();
881 #elif defined(CRIPPLED_SELECT)
883 char X11_ipcpath[32];
886 * CRIPPLED_SELECT mainloop
891 SELECT_TYPE_ARG1 nf, nfds, cn = ConnectionNumber(dpy);
892 struct timeval timeout, *timer;
894 unsigned long all = (unsigned long) (-1L);
900 sprintf(X11_ipcpath, "/tmp/Gnuplot_%d", getppid());
904 XFlush(dpy); /* see above */
909 /* Don't wait for events if we know that input is
910 * already sitting in a buffer. Also don't wait for
911 * input to become available.
913 if (buffered_input_available) {
918 timer = (struct timeval *) 0;
922 nfds = (cn > in) ? cn + 1 : in + 1;
924 nf = select(nfds, SELECT_TYPE_ARG234 &tset, 0, 0, SELECT_TYPE_ARG5 timer);
929 perror("gnuplot_x11: select failed");
936 if (FD_ISSET(cn, &tset)) {
937 while (XCheckMaskEvent(dpy, all, &xe)) {
941 if ((X11_ipc = fopen(X11_ipcpath, "r"))) {
951 /*-----------------------------------------------------------------------------
952 * VMS mainloop - Yehavi Bourvine - YEHAVI@VMS.HUJI.AC.IL
953 *---------------------------------------------------------------------------*/
955 /* In VMS there is no decent Select(). hence, we have to loop inside
956 * XGetNextEvent for getting the next X window event. In order to get input
957 * from the master we assign a channel to SYS$INPUT and use AST's in order to
958 * receive data. In order to exit the mainloop, we need to somehow make
959 * XNextEvent return from within the ast. We do this with a XSendEvent() to
961 * This needs a window to send the message to, so we create an unmapped window
962 * for this purpose. Event type XClientMessage is perfect for this, but it
963 * appears that such messages come from elsewhere (motif window manager,
964 * perhaps ?) So we need to check fairly carefully that it is the ast event
965 * that has been received.
969 char STDIIN[] = "SYS$INPUT:";
970 short STDIINchannel, STDIINiosb[4];
975 char STDIINbuffer[64];
980 int status = sys$qio(0, STDIINchannel, IO$_READVBLK, STDIINiosb, record,
981 0, STDIINbuffer, sizeof(STDIINbuffer) - 1, 0, 0, 0, 0);
982 if ((status & 0x1) == 0)
986 Window message_window;
991 /* dummy unmapped window for receiving internally-generated terminate
994 message_window = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 1, 0, 0);
996 STDIINdesc.size = strlen(STDIIN);
998 STDIINdesc.address = STDIIN;
999 status = sys$assign(&STDIINdesc, &STDIINchannel, 0, 0, 0);
1000 if ((status & 0x1) == 0)
1006 XNextEvent(dpy, &xe);
1007 if (xe.type == ClientMessage && xe.xclient.window == message_window) {
1008 if (xe.xclient.message_type == None && xe.xclient.format == 8 && strcmp(xe.xclient.data.b, "die gnuplot die") == 0) {
1009 FPRINTF((stderr, "quit message from ast\n"));
1012 FPRINTF((stderr, "Bogus XClientMessage event from window manager ?\n"));
1018 #else /* !(DEFAULT_X11 || CRIPPLED_SELECT || VMS */
1019 # error You lose. No mainloop.
1020 #endif /* !(DEFAULT_X11 || CRIPPLED_SELECT || VMS */
1022 /* delete a window / plot */
1024 delete_plot(plot_struct *plot)
1028 FPRINTF((stderr, "Delete plot %d\n", plot->plot_number));
1030 for (i = 0; i < plot->ncommands; ++i)
1031 free(plot->commands[i]);
1032 plot->ncommands = 0;
1034 free(plot->commands);
1035 plot->commands = NULL;
1036 plot->max_commands = 0;
1039 /* Free up memory for window title. */
1040 if (plot->titlestring) {
1041 free(plot->titlestring);
1042 plot->titlestring = 0;
1046 FPRINTF((stderr, "Destroy window 0x%x\n", plot->window));
1047 XDestroyWindow(dpy, plot->window);
1048 plot->window = None;
1052 if (stipple_initialized) { /* ULIG */
1054 for (i = 0; i < stipple_pattern_num; i++)
1055 XFreePixmap(dpy, stipple_pattern[i]);
1056 stipple_initialized = 0;
1060 XFreePixmap(dpy, plot->pixmap);
1061 plot->pixmap = None;
1063 /* Release the colormap here to free color resources, but only
1064 * if this plot is using a colormap not used by another plot
1065 * and is not using the current colormap.
1067 if (plot->cmap != current_cmap && !Find_Plot_In_Linked_List_By_CMap(plot->cmap))
1068 Remove_CMap_From_Linked_List(plot->cmap);
1069 /* but preserve geometry */
1073 /* prepare the plot structure */
1075 prepare_plot(plot_struct *plot, int term_number)
1079 for (i = 0; i < plot->ncommands; ++i)
1080 free(plot->commands[i]);
1081 plot->ncommands = 0;
1083 if (!plot->posn_flags) {
1084 /* first time this window has been used - use default or -geometry
1087 plot->posn_flags = gFlags;
1092 plot->pixmap = None;
1095 plot->resizing = FALSE;
1096 plot->str[0] = '\0';
1097 plot->zoombox_on = FALSE;
1100 if (!plot->window) {
1101 plot->cmap = current_cmap; /* color space */
1102 RecolorWindow(plot);
1106 * set all mouse parameters
1107 * to a well-defined state.
1110 plot->mouse_on = TRUE;
1111 plot->x = NOT_AVAILABLE;
1112 plot->y = NOT_AVAILABLE;
1113 if (plot->str[0] != '\0') {
1114 /* if string was non-empty last time, initialize it as almost empty: one space, to prevent window resize */
1116 plot->str[1] = '\0';
1118 plot->time = 0; /* XXX how should we initialize this ? XXX */
1122 /* We don't know that it is the same window as before, so we reset the
1123 * cursors for all windows and then define the cursor for the active
1126 plot->angle = 0; /* default is horizontal */
1128 XDefineCursor(dpy, plot->window, cursor);
1131 /* store a command in a plot structure */
1133 store_command(char *buffer, plot_struct *plot)
1137 /* binary can't be printed as string */
1138 #if defined(WITH_IMAGE) && defined(BINARY_X11_POLYGON)
1139 if (*buffer == X11_GR_IMAGE || *buffer == X11_GR_FILLED_POLYGON || *buffer == X11_GR_SET_COLOR)
1142 if (*buffer == X11_GR_IMAGE)
1144 #ifdef BINARY_X11_POLYGON
1145 if (*buffer != X11_GR_FILLED_POLYGON && *buffer != X11_GR_SET_COLOR)
1148 #if defined(WITH_IMAGE) || defined(BINARY_X11_POLYGON)
1149 {FPRINTF((stderr, "Store in %d : %c\n", plot->plot_number, *buffer));}
1152 {FPRINTF((stderr, "Store in %d : %s", plot->plot_number, buffer));}
1154 if (plot->ncommands >= plot->max_commands) {
1155 plot->max_commands = plot->max_commands * 2 + 1;
1156 plot->commands = (plot->commands)
1157 ? (char **) realloc(plot->commands, plot->max_commands * sizeof(char *))
1158 : (char **) malloc(sizeof(char *));
1160 p = (char *) malloc((unsigned) strlen(buffer) + 1);
1161 if (!plot->commands || !p) {
1162 fputs("gnuplot: can't get memory. X11 aborted.\n", stderr);
1165 plot->commands[plot->ncommands++] = strcpy(p, buffer);
1170 static int read_input __PROTO((void));
1173 * Handle input. Use read instead of fgets because stdio buffering
1174 * causes trouble when combined with calls to select.
1179 static int rdbuf_size = 10 * Nbuf;
1180 static char rdbuf[10 * Nbuf];
1181 static int total_chars;
1182 static int rdbuf_offset;
1183 static int buf_offset;
1184 static int partial_read = 0;
1185 int fd = fileno(X11_ipc);
1190 if (!buffered_input_available) {
1191 total_chars = read(fd, rdbuf, rdbuf_size);
1192 buffered_input_available = 1;
1195 if (total_chars == 0)
1197 if (total_chars < 0)
1201 if (rdbuf_offset < total_chars) {
1202 while (rdbuf_offset < total_chars && buf_offset < Nbuf) {
1203 char c = rdbuf[rdbuf_offset++];
1204 buf[buf_offset++] = c;
1209 if (buf_offset == Nbuf) {
1210 fputs("\ngplt_x11.c: buffer overflow in read_input!\n"
1211 " X11 aborted.\n", stderr);
1214 buf[buf_offset] = NUL;
1217 if (rdbuf_offset == total_chars) {
1218 buffered_input_available = 0;
1219 if (buf[buf_offset - 1] != '\n')
1223 return partial_read;
1226 static void read_input_line __PROTO((void));
1229 * Handle a whole input line, issuing an error message if a complete
1230 * read does not appear after a few tries.
1236 for (i_read = 1; read_input() == 1; i_read++) {
1238 fprintf(stderr, "\ngplt_x11.c: A complete buffer instruction is not appearing across\n"
1239 " link. Check for system overload or driver error.\n");
1244 * This function builds back a palette from what x11.trm has written
1245 * into the pipe. It cheats: SMPAL_COLOR_MODE_FUNCTIONS for user defined
1246 * formulaes to transform gray into the three color components is not
1247 * implemented. If this had to be done, one would have to include all
1248 * the code for evaluating functions here too, and, even worse: how to
1249 * transmit all function definition from gnuplot to here!
1250 * To avoid this, the following is done: For grayscale, and rgbformulae
1251 * everything is easy. Gradients are more difficult: Each gradient point
1252 * is encoded in a 8-byte string (which does not include any '\n' and
1253 * transmitted here. Here the gradient is rebuilt.
1254 * Form user defined formulae x11.trm builds a special gradient: The gray
1255 * values are equally spaced and are not transmitted, only the 6 bytes for
1256 * the rgbcolor are sent. These are assembled into a gradient which is
1257 * than used in the palette.
1259 * This function belongs completely into record(), but is quiet large so it
1260 * became a function of its own.
1263 scan_palette_from_buf(void)
1267 if (4 != sscanf( buf+2, "%c %c %c %d", &cm, &pos, &mod,
1268 &(tpal.use_maxcolors) ) ) {
1269 fprintf( stderr, "%s:%d error in setting palette.\n",
1270 __FILE__, __LINE__);
1275 tpal.colorMode = cm;
1276 tpal.positive = pos;
1278 tpal.gradient = NULL;
1280 /* function palettes are transmitted as approximated gradients: */
1281 if (tpal.colorMode == SMPAL_COLOR_MODE_FUNCTIONS)
1282 tpal.colorMode = SMPAL_COLOR_MODE_GRADIENT;
1284 switch( tpal.colorMode ) {
1285 case SMPAL_COLOR_MODE_GRAY:
1287 if (1 != sscanf( buf, "%lf", &(tpal.gamma) )) {
1288 fprintf( stderr, "%s:%d error in setting palette.\n",
1289 __FILE__, __LINE__);
1293 case SMPAL_COLOR_MODE_RGB:
1295 if (3 != sscanf( buf, "%d %d %d", &(tpal.formulaR),
1296 &(tpal.formulaG), &(tpal.formulaB) )) {
1297 fprintf( stderr, "%s:%d error in setting palette.\n",
1298 __FILE__, __LINE__);
1302 case SMPAL_COLOR_MODE_GRADIENT: {
1305 if (1 != sscanf( buf, "%d", &(tpal.gradient_num) )) {
1306 fprintf( stderr, "%s:%d error in setting palette.\n",
1307 __FILE__, __LINE__);
1310 tpal.gradient = (gradient_struct*)
1311 malloc( tpal.gradient_num * sizeof(gradient_struct) );
1312 assert(tpal.gradient);
1313 for( i=0; i<tpal.gradient_num; i++ ) {
1314 /* this %50 *must* match the amount of gradient structs
1315 written to the pipe by x11.trm! */
1319 str_to_gradient_entry( &(buf[8*(i%50)]), &(tpal.gradient[i]) );
1323 case SMPAL_COLOR_MODE_FUNCTIONS:
1324 fprintf( stderr, "%s:%d ooops: No function palettes for x11!\n",
1325 __FILE__, __LINE__ );
1328 fprintf( stderr, "%s:%d ooops: Unknown colorMode '%c'.\n",
1329 __FILE__, __LINE__, (char)(tpal.colorMode) );
1330 tpal.colorMode = SMPAL_COLOR_MODE_GRAY;
1336 free(tpal.gradient);
1341 * record - record new plot from gnuplot inboard X11 driver (Unix)
1343 static struct plot_struct *plot = NULL;
1348 int status = read_input();
1355 case 'G': /* enter graphics mode */
1359 sscanf(buf, "G%d", &plot_number);
1362 sscanf(buf, "G%d %lu %li", &plot_number, &gnuplotXID, &ppidGnu);
1364 sscanf(buf, "G%d %lu", &plot_number, &gnuplotXID);
1367 FPRINTF((stderr, "plot for window number %d\n", plot_number));
1368 if (!(plot = Find_Plot_In_Linked_List_By_Number(plot_number)))
1369 plot = Add_Plot_To_Linked_List(plot_number);
1371 prepare_plot(plot, plot_number);
1372 current_plot = plot;
1374 if (!input_from_PM_Terminal) { /* get shared memory */
1375 sprintf(mouseShareMemName, "\\SHAREMEM\\GP%i_Mouse_Input", (int) ppidGnu);
1376 if (DosGetNamedSharedMem(&input_from_PM_Terminal, mouseShareMemName, PAG_WRITE))
1377 DosBeep(1440L, 1000L); /* indicates error */
1382 #ifdef TITLE_BAR_DRAWING_MSG
1383 /* show a message in the wm's title bar that the
1384 * graph will be redrawn. This might be useful
1385 * for slow redrawing (large plots). The title
1386 * string is reset to the default at the end of
1387 * display(). We should make this configurable!
1392 char *added_text = " drawing ...";
1393 int orig_len = (plot->titlestring ? strlen(plot->titlestring) : 0);
1394 if (msg = (char *) malloc(orig_len + strlen(added_text) + 1)) {
1395 strcpy(msg, plot->titlestring);
1396 strcat(msg, added_text);
1397 XStoreName(dpy, plot->window, msg);
1400 XStoreName(dpy, plot->window, added_text + 1);
1404 if (!button_pressed) {
1405 cursor_save = cursor;
1406 cursor = cursor_waiting;
1408 XDefineCursor(dpy, plot->window, cursor);
1413 /* return 1; To do: Should a "return" be here? Gnuplot usually sends 'G' followed by other commands. So perhaps not needed. DJS */
1416 case 'N': /* just update the plot number */
1419 if (strcspn(buf+1, " \n") && sscanf(buf, "N%d", &itmp))
1420 current_plot = Add_Plot_To_Linked_List(itmp);
1424 case 'C': /* close the plot with given number */
1427 if (strcspn(buf+1, " \n") && sscanf(buf, "C%d", &itmp)) {
1429 if ((psp = Find_Plot_In_Linked_List_By_Number(itmp)))
1430 Remove_Plot_From_Linked_List(psp->window);
1431 } else if (current_plot) {
1432 Remove_Plot_From_Linked_List(current_plot->window);
1437 case '^': /* raise the plot with given number or the whole group */
1440 if (strcspn(buf+1," \n") && sscanf(buf, "^%d", &itmp)) {
1442 if ((psp = Find_Plot_In_Linked_List_By_Number(itmp))) {
1443 XRaiseWindow(dpy, psp->window);
1446 /* Find end of list, i.e., first created. */
1447 plot_struct *psp = plot_list_start;
1448 while (psp != NULL) {
1449 if (psp->next_plot == NULL) break;
1450 psp = psp->next_plot;
1452 while (psp != NULL) {
1453 XRaiseWindow(dpy, psp->window);
1454 psp = psp->prev_plot;
1460 case 'v': /* lower the plot with given number or the whole group */
1463 if (strcspn(buf+1," \n") && sscanf(buf, "v%d", &itmp)) {
1465 if ((psp = Find_Plot_In_Linked_List_By_Number(itmp))) {
1466 XLowerWindow(dpy, psp->window);
1468 } else if (current_plot) {
1469 plot_struct *psp = plot_list_start;
1470 while (psp != NULL) {
1471 XLowerWindow(dpy, psp->window);
1472 psp = psp->next_plot;
1478 case 'n': /* update the plot name (title) */
1481 current_plot = Add_Plot_To_Linked_List(0);
1484 if (current_plot->titlestring)
1485 free(current_plot->titlestring);
1486 if ((current_plot->titlestring = (char *) malloc(strlen(buf+1) + 1) )) {
1487 strcpy(current_plot->titlestring, buf+1);
1488 cp = current_plot->titlestring;
1491 if (current_plot->window)
1492 XStoreName(dpy, current_plot->window, cp);
1497 case 'E': /* leave graphics mode / suspend */
1501 if (plot == current_plot)
1502 gp_exec_event(GE_plotdone, 0, 0, 0, 0, 0); /* notify main program */
1505 case 'R': /* leave x11 mode */
1509 case X11_GR_MAKE_PALETTE:
1511 scan_palette_from_buf();
1514 /* (DJS 28sep2004) Possibly remove. Not sure this is useful for anything.
1515 * What gnuplot command would issue this? When would gnuplot know it is OK to
1516 * release a palette inside gnuplot_x11? I see no X11_GR_RELEASE_PALETTE
1517 * or 'e' inside x11.trm.
1519 * Plots and colormaps are independent in new scheme, so the line below
1520 * "if (plot)" is outdated. Also, sm_palette is a global, static structure.
1521 * sm_palette.gradient should be set to NULL after freeing the memory.
1523 case X11_GR_RELEASE_PALETTE:
1525 FPRINTF((stderr, "X11_GR_RELEASE_PALETTE\n"));
1527 ReleaseColormap(plot);
1528 sm_palette.colorMode = SMPAL_COLOR_MODE_NONE;
1529 free( sm_palette.gradient );
1533 #if defined(WITH_IMAGE) || defined(BINARY_X11_POLYGON)
1534 case X11_GR_CHECK_ENDIANESS:
1536 /* Initialize variable in case short happens to be longer than two bytes. */
1537 unsigned short tmp = (unsigned short) ENDIAN_VALUE;
1538 ((char *)&tmp)[0] = buf[1];
1539 ((char *)&tmp)[1] = buf[2];
1540 if (tmp == (unsigned short) ENDIAN_VALUE) swap_endian = 0;
1541 else swap_endian = 1;
1546 case 'X': /* tell the driver about do_raise / persist */
1548 int tmp_do_raise = UNSET, tmp_persist = UNSET;
1549 int tmp_dashed = UNSET, tmp_ctrlq = UNSET;
1550 sscanf(buf, "X%d%d%d%d", &tmp_do_raise, &tmp_persist, &tmp_dashed, &tmp_ctrlq);
1551 if (UNSET != tmp_do_raise)
1552 do_raise = tmp_do_raise;
1553 if (UNSET != tmp_persist)
1554 persist = tmp_persist;
1555 if (UNSET != tmp_dashed)
1556 dashedlines = tmp_dashed;
1557 if (UNSET != tmp_ctrlq)
1562 case 's': /* set window geometry */
1565 sscanf(&buf[2], "%s", strtmp);
1566 pr_geometry(strtmp);
1578 sscanf(buf, "u%4d%4d%4d", &c, &x, &y);
1581 case -4: /* switch off line between ruler and mouse cursor */
1582 DrawLineToRuler(plot);
1583 plot->ruler_lineto_on = FALSE;
1585 case -3: /* switch on line between ruler and mouse cursor */
1586 if (plot->ruler_on && plot->ruler_lineto_on)
1588 plot->ruler_lineto_x = X(x);
1589 plot->ruler_lineto_y = Y(y);
1590 plot->ruler_lineto_on = TRUE;
1591 DrawLineToRuler(plot);
1593 case -2: /* warp pointer */
1594 XWarpPointer(dpy, None /* src_w */ ,
1595 plot->window /* dest_w */ , 0, 0, 0, 0, X(x), Y(y));
1596 case -1: /* zoombox */
1597 plot->zoombox_x1 = plot->zoombox_x2 = X(x);
1598 plot->zoombox_y1 = plot->zoombox_y2 = Y(y);
1599 plot->zoombox_on = TRUE;
1602 case 0: /* standard cross-hair cursor */
1603 cursor = cursor_default;
1604 XDefineCursor(dpy, plot->window, cursor);
1606 case 1: /* cursor during rotation */
1607 cursor = cursor_exchange;
1608 XDefineCursor(dpy, plot->window, cursor);
1610 case 2: /* cursor during scaling */
1611 cursor = cursor_sizing;
1612 XDefineCursor(dpy, plot->window, cursor);
1614 case 3: /* cursor during zooming */
1615 cursor = cursor_zooming;
1616 XDefineCursor(dpy, plot->window, cursor);
1619 if (c >= 0 && plot->zoombox_on) {
1620 /* erase zoom box */
1622 plot->zoombox_on = FALSE;
1624 if (c >= 0 && plot->ruler_lineto_on) {
1625 /* erase line from ruler to cursor */
1626 DrawLineToRuler(plot);
1627 plot->ruler_lineto_on = FALSE;
1640 if (sscanf(buf, "t%4d", &where) != 1)
1642 buf[strlen(buf) - 1] = 0; /* remove trailing \n */
1646 DisplayCoords(plot, buf + 5);
1649 second = strchr(buf + 5, '\r');
1650 if (second == NULL) {
1651 *(plot->zoombox_str1a) = '\0';
1652 *(plot->zoombox_str1b) = '\0';
1657 if (plot->zoombox_on)
1659 strcpy(plot->zoombox_str1a, buf + 5);
1660 strcpy(plot->zoombox_str1b, second);
1661 if (plot->zoombox_on)
1665 second = strchr(buf + 5, '\r');
1666 if (second == NULL) {
1667 *(plot->zoombox_str2a) = '\0';
1668 *(plot->zoombox_str2b) = '\0';
1673 if (plot->zoombox_on)
1675 strcpy(plot->zoombox_str2a, buf + 5);
1676 strcpy(plot->zoombox_str2b, second);
1677 if (plot->zoombox_on)
1692 DrawRuler(plot); /* erase previous ruler */
1693 sscanf(buf, "r%4d%4d", &x, &y);
1695 DrawLineToRuler(plot);
1696 plot->ruler_on = FALSE;
1698 plot->ruler_on = TRUE;
1701 plot->ruler_lineto_x = X(x);
1702 plot->ruler_lineto_y = Y(y);
1703 DrawLineToRuler(plot);
1705 DrawRuler(plot); /* draw new one */
1715 int len = strlen(buf + 1) - 1; /* discard newline '\n' */
1716 memcpy(selection, buf + 1, len < SEL_LEN ? len : SEL_LEN);
1718 selection[len + 1 < SEL_LEN ? len + 1 : SEL_LEN - 1] = '\0';
1719 XStoreBytes(dpy, buf + 1, len);
1721 #ifdef EXPORT_SELECTION
1722 if (plot && exportselection)
1730 /* Set default font immediately and return size info through pipe */
1731 if (buf[1] == 'G') {
1732 int scaled_hchar, scaled_vchar;
1733 char *c = &(buf[strlen(buf)-1]);
1734 while (*c <= ' ') *c-- = '\0';
1735 strncpy(default_font, &buf[2], strlen(&buf[2])+1);
1738 /* EAM FIXME - this is all out of order; initialization doesnt */
1739 /* happen until term->graphics() is called. */
1740 xscale = (plot->width > 0) ? plot->width / 4096. : gW / 4096.;
1741 yscale = (plot->height > 0) ? plot->height / 4096. : gH / 4096.;
1742 scaled_hchar = (1.0/xscale) * hchar;
1743 scaled_vchar = (1.0/yscale) * vchar;
1744 FPRINTF((stderr, "gplt_x11: preset default font to %s hchar = %d vchar = %d \n",
1745 default_font, scaled_hchar, scaled_vchar));
1746 gp_exec_event(GE_fontprops, plot->width, plot->height,
1747 scaled_hchar, scaled_vchar, 0);
1755 store_command(buf, plot);
1759 if (feof(X11_ipc) || ferror(X11_ipc))
1768 * record - record new plot from gnuplot inboard X11 driver (VMS)
1770 static struct plot_struct *plot = NULL;
1775 if ((STDIINiosb[0] & 0x1) == 0)
1776 EXIT(STDIINiosb[0]);
1777 STDIINbuffer[STDIINiosb[1]] = '\0';
1778 strcpy(buf, STDIINbuffer);
1781 case 'G': /* enter graphics mode */
1783 int plot_number = atoi(buf + 1); /* 0 if none specified */
1784 FPRINTF((stderr, "plot for window number %d\n", plot_number));
1785 if (!(plot = Find_Plot_In_Linked_List_By_Number(plot_number)))
1786 plot = Add_Plot_To_Linked_List(plot_number);
1788 prepare_plot(plot, plot_number);
1789 current_plot = plot;
1792 case 'E': /* leave graphics mode */
1796 case 'R': /* exit x11 mode */
1797 FPRINTF((stderr, "received R - sending ClientMessage\n"));
1799 sys$cancel(STDIINchannel);
1800 /* this is ridiculous - cook up an event to ourselves,
1801 * in order to get the mainloop() out of the XNextEvent() call
1802 * it seems that window manager can also send clientmessages,
1803 * so put a checksum into the message
1806 XClientMessageEvent event;
1807 event.type = ClientMessage;
1808 event.send_event = True;
1809 event.display = dpy;
1810 event.window = message_window;
1811 event.message_type = None;
1813 strcpy(event.data.b, "die gnuplot die");
1814 XSendEvent(dpy, message_window, False, 0, (XEvent *) & event);
1817 return; /* no ast */
1820 store_command(buf, plot);
1828 DrawRotatedErrorHandler(Display * display, XErrorEvent * error_event)
1830 return 0; /* do nothing */
1834 DrawRotated(plot_struct *plot, Display *dpy, GC gc, int xdest, int ydest,
1835 const char *str, int len)
1837 Window w = plot->window;
1838 Drawable d = plot->pixmap;
1839 double angle = plot->angle;
1840 enum JUSTIFY just = plot->jmode;
1842 double src_x, src_y;
1843 double dest_x, dest_y;
1844 int width = gpXTextWidth(font, str, len);
1846 double src_cen_x = (double)width * 0.5;
1847 double src_cen_y = (double)height * 0.5;
1848 static const double deg2rad = .01745329251994329576; /* atan2(1, 1) / 45.0; */
1849 double sa = sin(angle * deg2rad);
1850 double ca = cos(angle * deg2rad);
1851 int dest_width = (double)height * fabs(sa) + (double)width * fabs(ca) + 2;
1852 int dest_height = (double)width * fabs(sa) + (double)height * fabs(ca) + 2;
1853 double dest_cen_x = (double)dest_width * 0.5;
1854 double dest_cen_y = (double)dest_height * 0.5;
1855 char* data = (char*) malloc(dest_width * dest_height * sizeof(char));
1856 Pixmap pixmap_src = XCreatePixmap(dpy, root, (unsigned int)width, (unsigned int)height, 1);
1860 unsigned long fgpixel = 0;
1861 unsigned long bgpixel = 0;
1862 XWindowAttributes win_attrib;
1863 int xscr, yscr, xoff, yoff;
1864 unsigned int scr_width, scr_height;
1865 XErrorHandler prevErrorHandler;
1867 unsigned long gcFunctionMask = GCFunction;
1869 int gcCurrentFunction = 0;
1872 /* bitmapGC is static, so that is has to be initialized only once */
1873 static GC bitmapGC = (GC) 0;
1875 /* eventually initialize bitmapGC */
1876 if ((GC)0 == bitmapGC) {
1877 bitmapGC = XCreateGC(dpy, pixmap_src, 0, (XGCValues *) 0);
1878 XSetForeground(dpy, bitmapGC, 1);
1879 XSetBackground(dpy, bitmapGC, 0);
1882 s = XGetGCValues(dpy, gc, gcFunctionMask|GCForeground|GCBackground, &gcValues);
1885 fgpixel = gcValues.foreground;
1886 bgpixel = gcValues.background;
1887 gcCurrentFunction = gcValues.function; /* save current function */
1890 /* set font for the bitmap GC */
1892 gpXSetFont(dpy, bitmapGC, font->fid);
1894 /* draw string to the source bitmap */
1895 gpXDrawImageString(dpy, pixmap_src, bitmapGC, 0, gpXGetFontascent(font), str, len);
1897 /* create XImage's of depth 1 */
1898 /* source from pixmap */
1899 image_src = XGetImage(dpy, pixmap_src, 0, 0, (unsigned int)width, (unsigned int)height,
1900 1, XYPixmap /* ZPixmap, XYBitmap */ );
1904 memset((void*)data, 0, (size_t)dest_width * dest_height);
1905 image_dest = XCreateImage(dpy, vis, 1, XYBitmap,
1906 0, data, (unsigned int)dest_width, (unsigned int)dest_height, 8, 0);
1907 #define RotateX(_x, _y) (( (_x) * ca + (_y) * sa + dest_cen_x))
1908 #define RotateY(_x, _y) ((-(_x) * sa + (_y) * ca + dest_cen_y))
1909 /* copy & rotate from source --> dest */
1910 for (y = 0, src_y = -src_cen_y; y < height; y++, src_y++) {
1911 for (x = 0, src_x = -src_cen_x; x < width; x++, src_x++) {
1912 /* TODO: move some operations outside the inner loop (joze) */
1913 dest_x = rint(RotateX(src_x, src_y));
1914 dest_y = rint(RotateY(src_x, src_y));
1915 if (dest_x >= 0 && dest_x < dest_width && dest_y >= 0 && dest_y < dest_height)
1916 XPutPixel(image_dest, (int)dest_x, (int)dest_y, XGetPixel(image_src, x, y));
1920 src_cen_y = 0; /* EAM 29-Sep-2002 - vertical justification has already been done */
1925 xdest -= RotateX(-src_cen_x, src_cen_y);
1926 ydest -= RotateY(-src_cen_x, src_cen_y);
1929 xdest -= RotateX(0, src_cen_y);
1930 ydest -= RotateY(0, src_cen_y);
1933 xdest -= RotateX(src_cen_x, src_cen_y);
1934 ydest -= RotateY(src_cen_x, src_cen_y);
1942 /* This default method is a lot faster, but may corrupt the colors
1943 * underneath the rotated text if the X display Visual is PseudoColor.
1946 assert(s); /* Previous success in reading XGetGCValues() */
1947 /* Force pixels of new text to black, background unchanged */
1948 gcValues.function = GXand;
1949 gcValues.background = WhitePixel(dpy, scr);
1950 gcValues.foreground = BlackPixel(dpy, scr);
1951 XChangeGC(dpy, gc, gcFunctionMask|GCBackground|GCForeground, &gcValues);
1952 XPutImage(dpy, d, gc, image_dest, 0, 0, xdest, ydest, dest_width, dest_height);
1954 /* Force pixels of new text to color, background unchanged */
1955 gcValues.function = GXor;
1956 gcValues.background = BlackPixel(dpy, scr);
1957 gcValues.foreground = fgpixel;
1958 XChangeGC(dpy, gc, gcFunctionMask|GCBackground|GCForeground, &gcValues);
1959 XPutImage(dpy, d, gc, image_dest, 0, 0, xdest, ydest, dest_width, dest_height);
1962 /* Slow but sure version - grab the current screen area where the new
1963 * text will go and substitute in the pixels of the new text one by one.
1964 * NB: selected by X Resource
1965 * gnuplot*fastrotate: off
1967 assert(s); /* Previous success in reading XGetGCValues() */
1968 gcValues.function = GXcopy;
1969 XChangeGC(dpy, gc, gcFunctionMask, &gcValues);
1970 s = XGetWindowAttributes(dpy, w, &win_attrib);
1971 /* compute screen coords that are within the current window */
1972 xscr = (xdest<0)? 0 : xdest;
1973 yscr = (ydest<0)? 0 : ydest;;
1974 scr_width = dest_width; scr_height = dest_height;
1975 if (xscr + dest_width > win_attrib.width)
1976 scr_width = win_attrib.width - xscr;
1977 if (yscr + dest_height > win_attrib.height)
1978 scr_height = win_attrib.height - yscr;
1979 xoff = xscr - xdest;
1980 yoff = yscr - ydest;
1983 prevErrorHandler = XSetErrorHandler(DrawRotatedErrorHandler);
1985 image_scr = XGetImage(dpy, d, xscr, yscr, scr_width,
1986 scr_height, AllPlanes, XYPixmap);
1987 if (image_scr != 0){
1988 /* copy from 1 bit bitmap image of text to the full depth image of screen*/
1989 for (y = 0; y < scr_height; y++){
1990 for (x = 0; x < scr_width; x++){
1991 if (XGetPixel(image_dest, x + xoff, y + yoff)){
1992 XPutPixel(image_scr, x, y, fgpixel);
1996 /* copy the rotated image to the drawable d */
1997 XPutImage(dpy, d, gc, image_scr, 0, 0, xscr, yscr, scr_width, scr_height);
1999 XDestroyImage(image_scr);
2001 XSetErrorHandler(prevErrorHandler);
2002 } /* End slow rotatation code */
2004 /* free resources */
2005 XFreePixmap(dpy, pixmap_src);
2006 XDestroyImage(image_src);
2007 XDestroyImage(image_dest);
2010 /* restore original state of gc */
2011 gcValues.function = gcCurrentFunction;
2012 gcValues.background = bgpixel;
2013 XChangeGC(dpy, gc, gcFunctionMask|GCBackground, &gcValues);
2018 * exec_cmd - execute drawing command from inboard driver
2021 exec_cmd(plot_struct *plot, char *command)
2023 int x, y, sw, sl, sj;
2027 /* binary can't be printed as string */
2028 #if defined(WITH_IMAGE) && defined(BINARY_X11_POLYGON)
2029 if (*buffer == X11_GR_IMAGE || *buffer == X11_GR_FILLED_POLYGON || *buffer == X11_GR_SET_COLOR)
2032 if (*buffer == X11_GR_IMAGE)
2034 #ifdef BINARY_X11_POLYGON
2035 if (*buffer == X11_GR_FILLED_POLYGON && *buffer == X11_GR_SET_COLOR)
2038 #if defined(WITH_IMAGE) || defined(BINARY_X11_POLYGON)
2039 {FPRINTF((stderr, "(display) buffer = |%c|\n", *buffer));}
2042 {FPRINTF((stderr, "(display) buffer = |%s|\n", buffer));}
2045 /* X11_vector(x, y) - draw vector */
2046 if (*buffer == 'V') {
2047 sscanf(buffer, "V%4d%4d", &x, &y);
2048 if (polyline_size == 0) {
2049 polyline[polyline_size].x = X(cx);
2050 polyline[polyline_size].y = Y(cy);
2052 if (++polyline_size >= polyline_space) {
2053 polyline_space += 100;
2054 polyline = realloc(polyline, polyline_space * sizeof(XPoint));
2055 if (!polyline) fprintf(stderr, "Panic: cannot realloc polyline\n");
2057 polyline[polyline_size].x = X(x);
2058 polyline[polyline_size].y = Y(y);
2061 /* Limit the number of vertices in any single polyline */
2062 if (polyline_size > max_request_size) {
2063 FPRINTF((stderr, "(display) dumping polyline size %d\n", polyline_size));
2064 XDrawLines(dpy, plot->pixmap, *current_gc,
2065 polyline, polyline_size+1, CoordModeOrigin);
2069 } else if (polyline_size > 0) {
2070 FPRINTF((stderr, "(display) dumping polyline size %d\n", polyline_size));
2071 XDrawLines(dpy, plot->pixmap, *current_gc,
2072 polyline, polyline_size+1, CoordModeOrigin);
2076 /* X11_vector(x, y) - draw vector */
2077 if (*buffer == 'V') {
2078 sscanf(buffer, "V%4d%4d", &x, &y);
2079 XDrawLine(dpy, plot->pixmap, *current_gc, X(cx), Y(cy), X(x), Y(y));
2084 /* X11_move(x, y) - move */
2086 sscanf(buffer, "M%4d%4d", &cx, &cy);
2088 /* change default font (QD) encoding (QE) or current font (QF) */
2089 else if (*buffer == 'Q') {
2091 switch (buffer[1]) {
2093 /* Strip out just the font name */
2094 c = &(buffer[strlen(buffer)-1]);
2095 while (*c <= ' ') *c-- = '\0';
2096 pr_font(&buffer[2]);
2098 gpXSetFont(dpy, gc, font->fid);
2101 /* Save the requested font encoding */
2104 sscanf(buffer, "QE%d", &tmp);
2105 encoding = (enum set_encoding_id)tmp;
2107 FPRINTF((stderr, "gnuplot_x11: changing encoding to %d\n", encoding));
2110 /* Save the request default font */
2111 c = &(buffer[strlen(buffer)-1]);
2112 while (*c <= ' ') *c-- = '\0';
2113 strncpy(default_font, &buffer[2], strlen(&buffer[2])+1);
2114 FPRINTF((stderr, "gnuplot_x11: exec_cmd() set default_font to \"%s\"\n", default_font));
2119 /* X11_put_text(x, y, str) - draw text */
2120 else if (*buffer == 'T') {
2121 /* Enhanced text mode added November 2003 - Ethan A Merritt */
2122 int x_offset=0, y_offset=0, v_offset=0;
2124 switch (buffer[1]) {
2126 case 'j': /* Set start for right-justified enhanced text */
2127 sscanf(buffer+2, "%4d%4d", &x_offset, &y_offset);
2128 plot->xLast = x_offset - (plot->xLast - x_offset);
2129 plot->yLast = y_offset - (vchar/3) / yscale;
2131 case 'k': /* Set start for center-justified enhanced text */
2132 sscanf(buffer+2, "%4d%4d", &x_offset, &y_offset);
2133 plot->xLast = x_offset - 0.5*(plot->xLast - x_offset);
2134 plot->yLast = y_offset - (vchar/3) / yscale;
2136 case 'l': /* Set start for left-justified enhanced text */
2137 sscanf(buffer+2, "%4d%4d", &x_offset, &y_offset);
2138 plot->xLast = x_offset;
2139 plot->yLast = y_offset - (vchar/3) / yscale;
2141 case 'o': /* Enhanced mode print with no update */
2142 case 'c': /* Enhanced mode print with update to center */
2143 case 'u': /* Enhanced mode print with update */
2144 case 's': /* Enhanced mode update with no print */
2145 sscanf(buffer+2, "%4d%4d", &x_offset, &y_offset);
2146 /* EAM FIXME - This code has only been tested for x_offset == 0 */
2147 if (plot->angle != 0) {
2149 xtmp += x_offset * cos((double)(plot->angle) * 0.01745);
2150 xtmp -= y_offset * sin((double)(plot->angle) * 0.01745) * yscale/xscale;
2151 ytmp += x_offset * sin((double)(plot->angle) * 0.01745) * xscale/yscale;
2152 ytmp += y_offset * cos((double)(plot->angle) * 0.01745);
2156 x = plot->xLast + x_offset;
2157 y = plot->yLast + y_offset;
2161 case 'p': /* Push (Save) position for later use */
2162 plot->xSave = plot->xLast;
2163 plot->ySave = plot->yLast;
2165 case 'r': /* Pop (Restore) saved position */
2166 plot->xLast = plot->xSave;
2167 plot->yLast = plot->ySave;
2170 sscanf(buffer, "T%4d%4d", &x, &y);
2171 v_offset = vchar/3; /* Why is this??? */
2176 sl = strlen(str) - 1;
2177 sw = gpXTextWidth(font, str, sl);
2179 /* EAM - May 2002 Modify to allow colored text.
2180 * 1) do not force foreground of gc to be black
2181 * 2) write text to (*current_gc), rather than to gc, so that text color can be set
2182 * using pm3d mappings.
2185 switch (plot->jmode) {
2198 if (sl == 0) /* Pointless to draw empty string */
2200 else if (buffer[1] == 's') /* Enhanced text mode reserve space only */
2202 else if (plot->angle != 0) {
2204 DrawRotated(plot, dpy, *current_gc, X(x), Y(y), str, sl);
2206 /* horizontal text */
2207 gpXDrawString(dpy, plot->pixmap, *current_gc,
2208 X(x) + sj, Y(y) + v_offset, str, sl);
2211 /* Update current text position */
2212 if (buffer[1] == 'c') {
2213 plot->xLast = RevX(X(x) + sj + sw/2) - x_offset;
2214 plot->yLast = y - y_offset;
2215 } else if (buffer[1] != 'o') {
2216 plot->xLast = RevX(X(x) + sj + sw) - x_offset;
2217 plot->yLast = y - y_offset;
2218 if (plot->angle != 0) { /* This correction is not perfect */
2219 plot->yLast += RevX(sw) * sin((plot->angle) * 0.01745) * xscale/yscale;
2220 plot->xLast -= RevX(sw) * (1.0 - cos((plot->angle) * 0.01745));
2224 } else if (*buffer == 'F') { /* fill box */
2225 int style, xtmp, ytmp, w, h;
2227 if (sscanf(buffer + 1, "%4d%4d%4d%4d%4d", &style, &xtmp, &ytmp, &w, &h) == 5) {
2228 x11_setfill(&gc, style, FALSE);
2230 /* gnuplot has origin at bottom left, but X uses top left
2231 * There may be an off-by-one (or more) error here.
2233 ytmp += h; /* top left corner of rectangle to be filled */
2236 XFillRectangle(dpy, plot->pixmap, gc, X(xtmp), Y(ytmp), w + 1, h + 1);
2237 /* reset everything */
2238 XSetForeground(dpy, gc, plot->cmap->colors[plot->lt + 3]);
2239 XSetFillStyle(dpy, gc, FillSolid);
2242 /* X11_justify_text(mode) - set text justification mode */
2243 else if (*buffer == 'J')
2244 sscanf(buffer, "J%4d", (int *) &plot->jmode);
2246 else if (*buffer == 'A')
2247 sscanf(buffer + 1, "%lf", &plot->angle);
2249 /* X11_linewidth(plot->lwidth) - set line width */
2250 else if (*buffer == 'W')
2251 sscanf(buffer + 1, "%4d", &plot->user_width);
2253 /* X11_linetype(plot->type) - set line type */
2254 else if (*buffer == 'L') {
2255 sscanf(buffer, "L%4d", &plot->lt);
2256 plot->lt = (plot->lt % 8) + 2;
2258 if (plot->lt < 0) /* LT_NODRAW, LT_BACKGROUND, LT_UNDEFINED */
2261 else { /* Fixme: no mechanism to hold width or dashstyle for LT_BACKGROUND */
2262 /* default width is 0 {which X treats as 1} */
2263 plot->lwidth = widths[plot->lt] ? plot->user_width * widths[plot->lt] : plot->user_width;
2265 if ((dashedlines && dashes[plot->lt][0])
2266 || (plot->lt == LT_AXIS+2 && dashes[LT_AXIS+2][0])) {
2267 plot->type = LineOnOffDash;
2268 XSetDashes(dpy, gc, 0, dashes[plot->lt], strlen(dashes[plot->lt]));
2270 plot->type = LineSolid;
2274 XSetForeground(dpy, gc, plot->cmap->colors[plot->lt + 3]);
2275 XSetLineAttributes(dpy, gc, plot->lwidth, plot->type, CapButt, JoinBevel);
2276 plot->current_rgb = plot->cmap->rgbcolors[plot->lt + 3];
2279 /* X11_point(number) - draw a point */
2280 else if (*buffer == 'P') {
2282 sscanf(buffer + 1, "%d %d %d", &point, &x, &y);
2284 /* set point size */
2285 plot->px = (int) (x * xscale * pointsize);
2286 plot->py = (int) (y * yscale * pointsize);
2287 } else if (point == -1) {
2289 XDrawPoint(dpy, plot->pixmap, *current_gc, X(x), Y(y));
2291 unsigned char fill = 0;
2292 unsigned char upside_down_fill = 0;
2293 short upside_down_sign = 1;
2294 int delta = (plot->px + plot->py + 1)/2;
2296 /* Force line type to solid, with round ends */
2297 XSetLineAttributes(dpy, *current_gc, plot->lwidth, LineSolid, CapRound, JoinRound);
2299 switch (point % 13) {
2300 case 0: /* do plus */
2301 Plus[0].x1 = (short) X(x) - delta;
2302 Plus[0].y1 = (short) Y(y);
2303 Plus[0].x2 = (short) X(x) + delta;
2304 Plus[0].y2 = (short) Y(y);
2305 Plus[1].x1 = (short) X(x);
2306 Plus[1].y1 = (short) Y(y) - delta;
2307 Plus[1].x2 = (short) X(x);
2308 Plus[1].y2 = (short) Y(y) + delta;
2310 XDrawSegments(dpy, plot->pixmap, *current_gc, Plus, 2);
2313 Cross[0].x1 = (short) X(x) - delta;
2314 Cross[0].y1 = (short) Y(y) - delta;
2315 Cross[0].x2 = (short) X(x) + delta;
2316 Cross[0].y2 = (short) Y(y) + delta;
2317 Cross[1].x1 = (short) X(x) - delta;
2318 Cross[1].y1 = (short) Y(y) + delta;
2319 Cross[1].x2 = (short) X(x) + delta;
2320 Cross[1].y2 = (short) Y(y) - delta;
2322 XDrawSegments(dpy, plot->pixmap, *current_gc, Cross, 2);
2324 case 2: /* do star */
2325 Star[0].x1 = (short) X(x) - delta;
2326 Star[0].y1 = (short) Y(y);
2327 Star[0].x2 = (short) X(x) + delta;
2328 Star[0].y2 = (short) Y(y);
2329 Star[1].x1 = (short) X(x);
2330 Star[1].y1 = (short) Y(y) - delta;
2331 Star[1].x2 = (short) X(x);
2332 Star[1].y2 = (short) Y(y) + delta;
2333 Star[2].x1 = (short) X(x) - delta;
2334 Star[2].y1 = (short) Y(y) - delta;
2335 Star[2].x2 = (short) X(x) + delta;
2336 Star[2].y2 = (short) Y(y) + delta;
2337 Star[3].x1 = (short) X(x) - delta;
2338 Star[3].y1 = (short) Y(y) + delta;
2339 Star[3].x2 = (short) X(x) + delta;
2340 Star[3].y2 = (short) Y(y) - delta;
2342 XDrawSegments(dpy, plot->pixmap, *current_gc, Star, 4);
2344 case 3: /* do box */
2345 XDrawRectangle(dpy, plot->pixmap, *current_gc, X(x) - delta, Y(y) - delta,
2346 (delta + delta), (delta + delta));
2347 XDrawPoint(dpy, plot->pixmap, *current_gc, X(x), Y(y));
2349 case 4: /* filled box */
2350 XFillRectangle(dpy, plot->pixmap, *current_gc, X(x) - delta, Y(y) - delta,
2351 (delta + delta), (delta + delta));
2353 case 5: /* circle */
2354 XDrawArc(dpy, plot->pixmap, *current_gc, X(x) - delta, Y(y) - delta,
2355 2 * delta, 2 * delta, 0, 23040 /* 360 * 64 */);
2356 XDrawPoint(dpy, plot->pixmap, *current_gc, X(x), Y(y));
2358 case 6: /* filled circle */
2359 XFillArc(dpy, plot->pixmap, *current_gc, X(x) - delta, Y(y) - delta,
2360 2 * delta, 2 * delta, 0, 23040 /* 360 * 64 */);
2362 case 10: /* filled upside-down triangle */
2363 upside_down_fill = 1;
2365 case 9: /* do upside-down triangle */
2366 upside_down_sign = (short)-1;
2367 case 8: /* filled triangle */
2370 case 7: /* do triangle */
2372 short temp_x, temp_y;
2374 temp_x = (short) (1.33 * (double) delta + 0.5);
2375 temp_y = (short) (1.33 * (double) delta + 0.5);
2377 Triangle[0].x = (short) X(x);
2378 Triangle[0].y = (short) Y(y) - upside_down_sign * temp_y;
2379 Triangle[1].x = (short) temp_x;
2380 Triangle[1].y = (short) upside_down_sign * 2 * delta;
2381 Triangle[2].x = (short) -(2 * temp_x);
2382 Triangle[2].y = (short) 0;
2383 Triangle[3].x = (short) temp_x;
2384 Triangle[3].y = (short) -(upside_down_sign * 2 * delta);
2386 if ((upside_down_sign == 1 && fill) || upside_down_fill) {
2387 XFillPolygon(dpy, plot->pixmap, *current_gc,
2388 Triangle, 4, Convex, CoordModePrevious);
2390 XDrawLines(dpy, plot->pixmap, *current_gc, Triangle, 4, CoordModePrevious);
2391 XDrawPoint(dpy, plot->pixmap, *current_gc, X(x), Y(y));
2395 case 12: /* filled diamond */
2398 case 11: /* do diamond */
2399 Diamond[0].x = (short) X(x) - delta;
2400 Diamond[0].y = (short) Y(y);
2401 Diamond[1].x = (short) delta;
2402 Diamond[1].y = (short) -delta;
2403 Diamond[2].x = (short) delta;
2404 Diamond[2].y = (short) delta;
2405 Diamond[3].x = (short) -delta;
2406 Diamond[3].y = (short) delta;
2407 Diamond[4].x = (short) -delta;
2408 Diamond[4].y = (short) -delta;
2411 * Should really do a check with XMaxRequestSize()
2415 XFillPolygon(dpy, plot->pixmap, *current_gc,
2416 Diamond, 5, Convex, CoordModePrevious);
2418 XDrawLines(dpy, plot->pixmap, *current_gc, Diamond, 5, CoordModePrevious);
2419 XDrawPoint(dpy, plot->pixmap, *current_gc, X(x), Y(y));
2424 /* Restore original line style */
2425 XSetLineAttributes(dpy, *current_gc, plot->lwidth, plot->type, CapButt, JoinBevel);
2428 else if (*buffer == X11_GR_SET_LINECOLOR) {
2430 sscanf(buffer + 1, "%4d", <);
2432 if (lt < 0) /* LT_NODRAW, LT_BACKGROUND, LT_UNDEFINED */
2434 XSetForeground(dpy, gc, plot->cmap->colors[lt + 3]);
2435 plot->current_rgb = plot->cmap->rgbcolors[lt + 3];
2437 } else if (*buffer == X11_GR_SET_RGBCOLOR) {
2440 sscanf(buffer + 1, "%x", &rgb255color);
2441 xcolor.red = (double)(0xffff) * (double)((rgb255color >> 16) & 0xff) /255.;
2442 xcolor.green = (double)(0xffff) * (double)((rgb255color >> 8) & 0xff) /255.;
2443 xcolor.blue = (double)(0xffff) * (double)(rgb255color & 0xff) /255.;
2444 FPRINTF((stderr, "gplt_x11: got request for color %d %d %d\n",
2445 xcolor.red, xcolor.green, xcolor.blue));
2446 if (XAllocColor(dpy, plot->cmap->colormap, &xcolor)) {
2447 XSetForeground(dpy, gc, xcolor.pixel);
2448 plot->current_rgb = rgb255color;
2450 FPRINTF((stderr, " failed to allocate color\n"));
2453 } else if (*buffer == X11_GR_SET_COLOR) { /* set color */
2454 if (have_pm3d) { /* ignore, if your X server is not supported */
2455 #ifndef BINARY_X11_POLYGON
2457 sscanf(buffer + 1, "%lf", &gray);
2458 PaletteSetColor(plot, gray);
2461 /* This command will fit within a single buffer so it doesn't
2462 * need to be so elaborate.
2464 unsigned char *iptr;
2466 unsigned i_remaining;
2468 TBOOLEAN code_detected = 0;
2470 iptr = (unsigned char *) &gray;
2471 i_remaining = sizeof(gray);
2473 /* Decode and reconstruct the data. */
2474 for (bptr = buffer + 1; i_remaining; ) {
2475 unsigned char uctmp = *bptr++;
2476 if (code_detected) {
2478 *iptr++ = uctmp - 1 + SET_COLOR_TRANSLATION_CHAR;
2482 if ( uctmp == SET_COLOR_CODE_CHAR ) {
2486 *iptr++ = uctmp + SET_COLOR_TRANSLATION_CHAR;
2493 byteswap((char *)&gray, sizeof(gray));
2496 PaletteSetColor(plot, (double)gray);
2500 } else if (*buffer == X11_GR_FILLED_POLYGON) { /* filled polygon */
2501 if (have_pm3d) { /* ignore, if your X server is not supported */
2503 #ifndef BINARY_X11_POLYGON
2505 static XPoint *points = NULL;
2506 static int st_npoints = 0;
2507 static int saved_npoints = -1, saved_i = -1; /* HBB 20010919 */
2508 int i, npoints, style;
2509 char *ptr = buffer + 1;
2511 sscanf(ptr, "%4d", &npoints);
2515 sscanf(ptr, "%4d", &style);
2518 /* HBB 20010919: Implement buffer overflow protection by
2519 * breaking up long lines */
2520 if (npoints == -1) {
2521 /* This is a continuation line. */
2522 if (saved_npoints < 100) {
2523 fprintf(stderr, "gnuplot_x11: filled_polygon() protocol error\n");
2526 /* Continue filling at end of previous list: */
2528 npoints = saved_npoints;
2530 saved_npoints = npoints;
2535 if (npoints > st_npoints) {
2536 XPoint *new_points = realloc(points, sizeof(XPoint) * npoints);
2537 st_npoints = npoints;
2539 perror("gnuplot_x11: exec_cmd()->points");
2542 points = new_points;
2545 while (*ptr != 'x' && i < npoints) { /* not end-of-line marker */
2546 sscanf(ptr, "%4d%4d", &x, &y);
2554 /* only do the call if list is complete by now */
2556 XColor xcolor, bgnd;
2559 #else /* BINARY_X11_POLYGON */
2561 static TBOOLEAN transferring = 0;
2562 static unsigned char *iptr;
2563 static int int_cache[2];
2564 #define style int_cache[1]
2565 #define npoints int_cache[0]
2566 static unsigned i_remaining;
2567 unsigned short i_buffer;
2569 static TBOOLEAN code_detected = 0;
2570 static XPoint *points = NULL;
2571 static int st_npoints = 0;
2573 /* The first value read will be the number of points or the number of
2574 * points followed by style. Set up parameters to point to npoints.
2576 if (!transferring) {
2577 iptr = (unsigned char *) &npoints;
2578 i_remaining = sizeof(int_cache);
2581 i_buffer = BINARY_MAX_CHAR_PER_TRANSFER;
2583 /* Decode and reconstruct the data. */
2584 for (bptr = &buffer[1]; i_buffer && i_remaining; i_buffer--) {
2586 unsigned char uctmp = *bptr++;
2588 if (code_detected) {
2590 *iptr++ = uctmp - 1 + FILLED_POLYGON_TRANSLATION_CHAR;
2593 if ( uctmp == FILLED_POLYGON_CODE_CHAR ) {
2596 *iptr++ = uctmp + FILLED_POLYGON_TRANSLATION_CHAR;
2601 if(!i_remaining && !transferring) {
2602 /* The number of points was just read. Now set up points array and continue. */
2604 byteswap((char *)&npoints, sizeof(npoints));
2605 byteswap((char *)&style, sizeof(style));
2607 if (npoints > st_npoints) {
2608 XPoint *new_points = realloc(points, npoints*2*sizeof(int));
2609 st_npoints = npoints;
2611 perror("gnuplot_x11: exec_cmd()->points");
2614 points = new_points;
2616 i_remaining = npoints*2*sizeof(int);
2617 iptr = (unsigned char *) points;
2628 /* If the byte order needs to be swapped, do so. */
2631 for (i--; i >= 0; i--) {
2632 byteswap((char *)&((int *)points)[i], sizeof(int));
2636 /* Convert the ints to XPoint format. This looks like it tramples
2637 * on itself, but the XPoint x and y are smaller than an int.
2639 for (i=0; i < npoints; i++) {
2640 points[i].x = X( ((int *)points)[2*i] );
2641 points[i].y = Y( ((int *)points)[2*i+1] );
2644 #endif /* BINARY_X11_POLYGON */
2646 /* Load selected pattern or fill into a separate gc */
2648 fill_gc = XCreateGC(dpy, plot->window, 0, 0);
2649 XCopyGC(dpy, *current_gc, ~0, fill_gc);
2651 x11_setfill(&fill_gc, style, TRUE);
2653 XFillPolygon(dpy, plot->pixmap, fill_gc, points, npoints,
2654 Nonconvex, CoordModeOrigin);
2656 #ifndef BINARY_X11_POLYGON
2658 /* Flag this continuation line as closed */
2659 saved_npoints = saved_i = -1;
2661 /* Store how far we got: */
2665 #else /* BINARY_X11_POLYGON */
2671 #endif /* BINARY_X11_POLYGON */
2677 else if (*buffer == X11_GR_IMAGE) { /* image */
2679 static unsigned char *iptr;
2680 static TBOOLEAN transferring = 0;
2681 static unsigned short *image;
2683 static int pixel_1_1_x, pixel_1_1_y, pixel_M_N_x, pixel_M_N_y;
2684 static int visual_1_1_x, visual_1_1_y, visual_M_N_x, visual_M_N_y;
2685 static int color_mode;
2686 static unsigned i_remaining;
2688 /* ignore, if your X server is not supported */
2692 /* These might work better as fuctions, but defines will do for now. */
2693 #define ERROR_NOTICE(str) "\nGNUPLOT (gplt_x11): " str
2694 #define ERROR_NOTICE_NEWLINE(str) "\n " str
2696 if (!transferring) {
2698 /* Get variables. */
2699 if (11 != sscanf( &buffer[1], "%x %x %x %x %x %x %x %x %x %x %x", &M, &N, &pixel_1_1_x,
2700 &pixel_1_1_y, &pixel_M_N_x, &pixel_M_N_y, &visual_1_1_x, &visual_1_1_y,
2701 &visual_M_N_x, &visual_M_N_y, &color_mode)) {
2702 fprintf(stderr, ERROR_NOTICE("Couldn't read image parameters correctly.\n\n"));
2705 /* Number of symbols depends upon whether it is color or palette lookup. */
2706 i_remaining = M*N*sizeof(image[0]);
2707 if (color_mode == IC_RGB) i_remaining *= 3;
2710 fprintf(stderr, ERROR_NOTICE("Image of size zero.\n\n"));
2712 image = (unsigned short *) malloc(i_remaining);
2714 iptr = (unsigned char *) image;
2717 fprintf(stderr, ERROR_NOTICE("Cannot allocate memory for image.\n\n"));
2724 unsigned short i_buffer;
2726 static TBOOLEAN code_detected = 0;
2728 i_buffer = BINARY_MAX_CHAR_PER_TRANSFER;
2730 /* Decode and reconstruct the data. */
2731 for (bptr = &buffer[1]; i_buffer && i_remaining; i_buffer--) {
2732 unsigned char uctmp = *bptr++;
2733 if (code_detected) {
2735 *iptr++ = uctmp - 1 + IMAGE_TRANSLATION_CHAR;
2738 if (uctmp == IMAGE_CODE_CHAR) {
2741 *iptr++ = uctmp + IMAGE_TRANSLATION_CHAR;
2749 /* Expand or contract the image into a new image and place this on the screen. */
2751 static unsigned short R_msb_mask=0, R_rshift, R_lshift;
2752 static unsigned short G_msb_mask, G_rshift, G_lshift;
2753 static unsigned short B_msb_mask, B_rshift, B_lshift;
2754 static unsigned long prev_red_mask, prev_green_mask, prev_blue_mask;
2755 #define LET_XPUTPIXEL_SWAP_BYTES 1
2756 #if !LET_XPUTPIXEL_SWAP_BYTES
2757 static TBOOLEAN swap_image_bytes = FALSE;
2759 TBOOLEAN create_image = FALSE;
2760 #define SINGLE_PALETTE_BIT_SHIFT 0 /* Discard over time, 16aug2004 */
2761 #if SINGLE_PALETTE_BIT_SHIFT
2762 static int prev_allocated=0;
2763 static short palette_bit_shift=0;
2768 /* If the byte order needs to be swapped, do so. */
2771 if (color_mode == IC_RGB) {i *= 3;}
2772 for (i--; i >= 0; i--) {
2773 /* The assumption is that image data through the pipe is 16 bits. */
2774 byteswap2(&image[i]);
2778 if (color_mode == IC_PALETTE) {
2780 #if SINGLE_PALETTE_BIT_SHIFT
2781 /* If the palette size is 2 to some power then a single bit shift would work.
2782 * The multiply/shift method doesn't seem noticably slower and generally works
2783 * with any size pallete. Keep this around for the time being in case some
2784 * use for it comes up.
2786 /* Initialize the palette shift, or if the palette size changes then update the shift. */
2787 if (!palette_bit_shift || (plot->cmap->allocated != prev_allocated)) {
2788 short i_bits, n_colors;
2789 prev_allocated = plot->cmap->allocated;
2790 for (palette_bit_shift = 16, n_colors = 1; palette_bit_shift > 0; palette_bit_shift--) {
2791 if (n_colors >= plot->cmap->allocated) {break;}
2797 create_image = TRUE;
2801 switch( vis->class ) {
2803 static char *display_error_text_after = " display class cannot use component"
2804 ERROR_NOTICE_NEWLINE("data. Try palette mode.\n\n");
2808 /* This algorithm for construction of pixel values from the RGB components
2809 * doesn't look to be the most portable. However, it tries to be. It
2810 * gets the red/green/blue masks from the X11 information and generates
2811 * appropriate shifts and masks from that. The X11 documentation mentions
2812 * something about using the masks in some odd way to generate an index
2813 * for a color table. It all seemed like a bother for no benefit however.
2814 * Certainly we don't want to have only a few bits of color, and we don't
2815 * want to have some huge color table. My feeling on the matter is to
2816 * just pack bits according to the masks that X11 indicates. If someone
2817 * finds they have a peculiar display type that doesn't work, that can be
2818 * considered when and if it happens.
2821 /* Get the color mask information and compute the proper bit shifts, but only upon
2822 * first call or if the masks change. I'm not sure if it is necessary to check if
2823 * the masks changed, but I left it in as a safeguard in case there is some strange
2824 * system out there somewhere.
2826 if (!R_msb_mask || (vis->red_mask != prev_red_mask) ||
2827 (vis->green_mask != prev_green_mask) || (vis->blue_mask != prev_blue_mask)) {
2828 short R_bits, G_bits, B_bits, min_bits;
2829 prev_red_mask = vis->red_mask;
2830 prev_green_mask = vis->green_mask;
2831 prev_blue_mask = vis->blue_mask;
2832 R_msb_mask = BitMaskDetails(vis->red_mask, &R_rshift, &R_lshift);
2833 G_msb_mask = BitMaskDetails(vis->green_mask, &G_rshift, &G_lshift);
2834 B_msb_mask = BitMaskDetails(vis->blue_mask, &B_rshift, &B_lshift);
2836 /* Graphics info in case strange behavior occurs in a particular system.
2838 FPRINTF((stderr, "\n\nvis->visualid: 0x%x vis->class: %d vis->bits_per_rgb: %d\n",
2839 (int)vis->visualid, vis->class, vis->bits_per_rgb));
2840 FPRINTF((stderr, "vis->red_mask: %lx vis->green_mask: %lx vis->blue_mask: %lx\n",
2841 vis->red_mask, vis->green_mask, vis->blue_mask));
2842 FPRINTF((stderr, "ImageByteOrder: %d\n\n", ImageByteOrder(dpy)));
2844 R_bits = 32-R_rshift-R_lshift;
2845 G_bits = 32-G_rshift-G_lshift;
2846 B_bits = 32-B_rshift-B_lshift;
2847 min_bits = GPMIN(GPMIN(R_bits, G_bits), B_bits);
2848 if (R_bits > min_bits) {
2849 R_msb_mask >>= (R_bits-min_bits);
2850 R_lshift += (R_bits-min_bits);
2853 if (G_bits > min_bits) {
2854 G_msb_mask >>= (G_bits-min_bits);
2855 G_lshift += (G_bits-min_bits);
2858 if (B_bits > min_bits) {
2859 B_msb_mask >>= (B_bits-min_bits);
2860 B_lshift += (B_bits-min_bits);
2863 R_rshift = 16-R_bits;
2864 G_rshift = 16-G_bits;
2865 B_rshift = 16-B_bits;
2867 #if !LET_XPUTPIXEL_SWAP_BYTES
2868 /* Now deal with the byte order issue. */
2869 if (ImageByteOrder(dpy)) {
2870 /* If the bit field for each channel is 8 bits, the masks can be rearranged instead
2871 * of having to actually perform a byte order swap on the image data.
2873 if ((R_bits == 8) && (G_bits == 8) && (B_bits == 8)) {
2874 R_lshift = 24 - R_lshift;
2875 G_lshift = 24 - G_lshift;
2876 B_lshift = 24 - B_lshift;
2877 swap_image_bytes = FALSE;
2879 swap_image_bytes = TRUE;
2882 swap_image_bytes = FALSE;
2887 create_image = TRUE;
2891 fprintf(stderr, ERROR_NOTICE("PseudoColor"));
2892 fprintf(stderr, display_error_text_after);
2896 fprintf(stderr, ERROR_NOTICE("GrayScale"));
2897 fprintf(stderr, display_error_text_after);
2901 fprintf(stderr, ERROR_NOTICE("StaticColor"));
2902 fprintf(stderr, display_error_text_after);
2906 fprintf(stderr, ERROR_NOTICE("StaticGray"));
2907 fprintf(stderr, display_error_text_after);
2911 fprintf(stderr, ERROR_NOTICE("DirectColor display class currently")
2912 ERROR_NOTICE_NEWLINE("not supported.\n\n"));
2916 fprintf(stderr, ERROR_NOTICE("Unknown X11 display class.\n\n"));
2925 int M_pixel, N_pixel;
2927 int pixel_1_1_x_plot, pixel_1_1_y_plot, pixel_M_N_x_plot, pixel_M_N_y_plot;
2928 int view_1_1_x_plot, view_1_1_y_plot, view_M_N_x_plot, view_M_N_y_plot;
2929 int final_1_1_x_plot, final_1_1_y_plot;
2930 int i_start, j_start;
2933 /* Compute the image extent with sanity check. */
2934 pixel_1_1_x_plot = X(pixel_1_1_x);
2935 pixel_M_N_x_plot = X(pixel_M_N_x);
2936 M_pixel = pixel_M_N_x_plot - pixel_1_1_x_plot;
2939 itmp = pixel_1_1_x_plot;
2940 pixel_1_1_x_plot = pixel_M_N_x_plot;
2941 pixel_M_N_x_plot = itmp;
2943 pixel_1_1_y_plot = Y(pixel_1_1_y);
2944 pixel_M_N_y_plot = Y(pixel_M_N_y);
2945 N_pixel = pixel_M_N_y_plot - pixel_1_1_y_plot;
2948 itmp = pixel_1_1_y_plot;
2949 pixel_1_1_y_plot = pixel_M_N_y_plot;
2950 pixel_M_N_y_plot = itmp;
2953 /* Compute the visual extent of the plot with sanity check. */
2954 view_1_1_x_plot = X(visual_1_1_x);
2955 view_M_N_x_plot = X(visual_M_N_x);
2956 if (view_M_N_x_plot < view_1_1_x_plot) {
2957 itmp = view_1_1_x_plot;
2958 view_1_1_x_plot = view_M_N_x_plot;
2959 view_M_N_x_plot = itmp;
2961 view_1_1_y_plot = Y(visual_1_1_y);
2962 view_M_N_y_plot = Y(visual_M_N_y);
2963 if (view_M_N_y_plot < view_1_1_y_plot) {
2964 itmp = view_1_1_y_plot;
2965 view_1_1_y_plot = view_M_N_y_plot;
2966 view_M_N_y_plot = itmp;
2969 /* Determine parameters for the image that will be built and put on screen. */
2970 itmp = view_1_1_x_plot - pixel_1_1_x_plot;
2972 i_start = itmp; final_1_1_x_plot = view_1_1_x_plot;
2974 i_start = 0; final_1_1_x_plot = pixel_1_1_x_plot;
2976 itmp = pixel_M_N_x_plot - view_M_N_x_plot;
2978 M_view = M_pixel - itmp - i_start;
2980 M_view = M_pixel - i_start;
2983 itmp = view_1_1_y_plot - pixel_1_1_y_plot;
2985 j_start = itmp; final_1_1_y_plot = view_1_1_y_plot;
2987 j_start = 0; final_1_1_y_plot = pixel_1_1_y_plot;
2989 itmp = pixel_M_N_y_plot - view_M_N_y_plot;
2991 N_view = N_pixel - itmp - j_start;
2993 N_view = N_pixel - j_start;
2996 if ((M_view > 0) && (N_view > 0)) {
2999 short sample_data_size;
3002 /* Determine if 2 bytes is sufficient or 4 bytes are necessary for color image data. */
3004 sample_data_size = 4;
3006 sample_data_size = 2;
3009 /* Expand or compress the original image to the pixels it will occupy on the screen. */
3010 sample_data = (char *) malloc(M_view*N_view*sample_data_size);
3016 /* Create an initialized image object. */
3017 image_dest = XCreateImage(dpy, vis, dep, ZPixmap, 0, sample_data, M_view, N_view,
3018 8*sample_data_size, M_view*sample_data_size);
3020 /* Fill in the output image data by decimating or repeating the input image data. */
3021 for (j_view=0; j_view < N_view; j_view++) {
3022 int j = ((j_view+j_start) * N) / N_pixel;
3023 int row_start = j*M;
3024 for (i_view=0; i_view < M_view; i_view++) {
3025 int i = ((i_view+i_start) * M) / M_pixel;
3026 if (color_mode == IC_PALETTE) {
3028 #if SINGLE_PALETTE_BIT_SHIFT
3029 /* If the palette size is 2 to some power then a single bit shift would work.
3030 * The multiply/shift method doesn't seem noticably slower and generally works
3031 * with any size pallete. Keep this around for the time being in case some
3032 * use for it comes up.
3034 unsigned long pixel = plot->cmap->pixels[image[row_start + i]>>palette_bit_shift];
3036 /* The methods below avoid using floating point. The basic idea is to multiply
3037 * the palette size by the "normalized" data coming across the pipe. (I think
3038 * some DSP people call this Q1 or Q0 format, or something like that.) Following
3039 * this multiplication by division by 2^16 gives the final answer. Most moderately
3040 * advanced CPUs have bit shifting. The first method uses this. However, a bit
3041 * shift isn't necessary because we can just take the top word of a two word
3042 * number and we've effectively divided by 2^16. The second method uses this.
3043 * However, my guess is that C compilers more effeciently translate the first
3044 * method with the bit shift than the second method which pulls out the top word.
3045 * (There is one instruction less for the shift version than the word selection
3046 * version on gcc for x86.)
3049 unsigned long pixel;
3050 unsigned short index = (plot->cmap->allocated * (unsigned long) image[row_start + i]) >> 16;
3051 pixel = plot->cmap->pixels[index];
3053 unsigned long index;
3054 unsigned long pixel;
3055 index = plot->cmap->allocated * (unsigned long) image[row_start + i];
3056 pixel = plot->cmap->pixels[((unsigned short *)&index)[1]];
3059 XPutPixel(image_dest, i_view, j_view, pixel);
3061 int index3 = 3*(row_start + i);
3062 unsigned long pixel = ((unsigned int)((image[index3++]>>R_rshift)&R_msb_mask)) << R_lshift;
3063 pixel |= ((unsigned int)((image[index3++]>>G_rshift)&G_msb_mask)) << G_lshift;
3064 pixel |= ((unsigned int)((image[index3]>>B_rshift)&B_msb_mask)) << B_lshift;
3065 XPutPixel(image_dest, i_view, j_view, pixel);
3070 #if !LET_XPUTPIXEL_SWAP_BYTES
3071 /* Swap the image byte order if necessary. */
3072 if (swap_image_bytes) {
3073 int i_swap = M_view*N_view - 1;
3074 if (sample_data_size == 2) {
3075 for (; i_swap >= 0; i_swap--) {
3076 byteswap2(&(((unsigned short *)sample_data)[i_swap]));
3079 for (; i_swap >= 0; i_swap--) {
3080 byteswap4(&(((unsigned int *)sample_data)[i_swap]));
3086 /* Copy the image to the drawable d. */
3087 XPutImage(dpy, plot->pixmap, gc, image_dest, 0, 0,
3088 final_1_1_x_plot, final_1_1_y_plot, M_view, N_view);
3090 /* Free resources. */
3091 XDestroyImage(image_dest);
3093 /* XDestroyImage frees the sample_data memory, so no "free" here. */
3096 fprintf(stderr, ERROR_NOTICE("Could not allocate memory for image.\n\n"));
3102 /* image was not used as part of X resource, so must "free" here. */
3109 #endif /* WITH_IMAGE */
3110 #if defined(USE_MOUSE) && defined(MOUSE_ALL_WINDOWS)
3111 /* Axis scaling information to save for later mouse clicks */
3112 else if (*buffer == 'S') {
3113 int axis, axis_mask;
3115 sscanf(&buffer[1], "%d %d", &axis, &axis_mask);
3117 plot->almost2d = axis_mask;
3118 } else if (axis < 0) {
3119 plot->axis_mask = axis_mask;
3120 } else if (axis < 2*SECOND_AXES) {
3121 sscanf(&buffer[1], "%d %lg %d %lg %lg", &axis,
3122 &(plot->axis_scale[axis].min), &(plot->axis_scale[axis].term_lower),
3123 &(plot->axis_scale[axis].term_scale), &(plot->axis_scale[axis].logbase));
3124 FPRINTF((stderr, "gnuplot_x11: axis %d scaling %14.3lg %14d %14.3lg %14.3lg\n",
3125 axis, plot->axis_scale[axis].min, plot->axis_scale[axis].term_lower,
3126 plot->axis_scale[axis].term_scale, plot->axis_scale[axis].logbase));
3131 fprintf(stderr, "gnuplot_x11: unknown command <%s>\n", buffer);
3136 * display - display a stored plot
3139 display(plot_struct *plot)
3143 FPRINTF((stderr, "Display %d ; %d commands\n", plot->plot_number, plot->ncommands));
3145 if (plot->ncommands == 0)
3148 /* set scaling factor between internal driver & window geometry */
3149 xscale = plot->width / 4096.0;
3150 yscale = GRAPH_HEIGHT(plot) / 4096.0;
3152 /* initial point sizes, until overridden with P7xxxxyyyy */
3153 plot->px = (int) (xscale * pointsize);
3154 plot->py = (int) (yscale * pointsize);
3156 /* create new pixmap & GC */
3157 if (!plot->pixmap) {
3158 FPRINTF((stderr, "Create pixmap %d : %dx%dx%d\n", plot->plot_number, plot->width, PIXMAP_HEIGHT(plot), dep));
3159 plot->pixmap = XCreatePixmap(dpy, root, plot->width, PIXMAP_HEIGHT(plot), dep);
3165 gc = XCreateGC(dpy, plot->pixmap, 0, (XGCValues *) 0);
3168 gpXSetFont(dpy, gc, font->fid);
3170 XSetFillStyle(dpy, gc, FillSolid);
3172 /* initialize stipple for filled boxes (ULIG) */
3173 if (!stipple_initialized) {
3175 for (i = 0; i < stipple_pattern_num; i++)
3176 stipple_pattern[i] =
3177 XCreateBitmapFromData(dpy, plot->pixmap, stipple_pattern_bits[i],
3178 stipple_pattern_width, stipple_pattern_height);
3179 stipple_initialized = 1;
3182 /* set pixmap background */
3183 XSetForeground(dpy, gc, plot->cmap->colors[0]);
3184 XFillRectangle(dpy, plot->pixmap, gc, 0, 0, plot->width, PIXMAP_HEIGHT(plot) + vchar);
3185 XSetBackground(dpy, gc, plot->cmap->colors[0]);
3190 /* top the window but don't put keyboard or mouse focus into it. */
3192 XMapRaised(dpy, plot->window);
3194 /* momentarily clear the window first if requested */
3196 XClearWindow(dpy, plot->window);
3199 /* loop over accumulated commands from inboard driver */
3200 for (n = 0; n < plot->ncommands; n++) {
3201 exec_cmd(plot, plot->commands[n]);
3204 #ifdef EXPORT_SELECTION
3205 if (exportselection)
3211 #ifdef TITLE_BAR_DRAWING_MSG
3213 /* restore default window title */
3214 char *cp = plot->titlestring;
3216 XStoreName(dpy, plot->window, cp);
3219 if (!button_pressed) {
3220 cursor = cursor_save ? cursor_save : cursor_default;
3221 cursor_save = (Cursor)0;
3222 XDefineCursor(dpy, plot->window, cursor);
3229 UpdateWindow(plot_struct * plot)
3234 if (None == plot->window) {
3238 if (!plot->pixmap) {
3239 /* create a black background pixmap */
3240 FPRINTF((stderr, "Create pixmap %d : %dx%dx%d\n", plot->plot_number, plot->width, PIXMAP_HEIGHT(plot), dep));
3241 plot->pixmap = XCreatePixmap(dpy, root, plot->width, PIXMAP_HEIGHT(plot), dep);
3244 gc = XCreateGC(dpy, plot->pixmap, 0, (XGCValues *) 0);
3246 gpXSetFont(dpy, gc, font->fid);
3247 /* set pixmap background */
3248 XSetForeground(dpy, gc, plot->cmap->colors[0]);
3249 XFillRectangle(dpy, plot->pixmap, gc, 0, 0, plot->width, PIXMAP_HEIGHT(plot) + vchar);
3250 XSetBackground(dpy, gc, plot->cmap->colors[0]);
3252 XSetWindowBackgroundPixmap(dpy, plot->window, plot->pixmap);
3253 XClearWindow(dpy, plot->window);
3256 EventuallyDrawMouseAddOns(plot);
3260 /* XXX discard expose events. This is a kludge for
3261 * preventing the event dispatcher calling UpdateWindow()
3262 * and the latter again generating expose events, which
3263 * again would trigger the event dispatcher ... (joze) XXX */
3264 while (XCheckWindowEvent(dpy, plot->window, ExposureMask, &event))
3271 CmapClear(cmap_t * cmap_ptr)
3273 cmap_ptr->total = (int) 0;
3274 cmap_ptr->allocated = (int) 0;
3275 cmap_ptr->pixels = (unsigned long *) 0;
3279 RecolorWindow(plot_struct * plot)
3281 if (None != plot->window) {
3282 XSetWindowColormap(dpy, plot->window, plot->cmap->colormap);
3283 XSetWindowBackground(dpy, plot->window, plot->cmap->colors[0]);
3284 XSetWindowBorder(dpy, plot->window, plot->cmap->colors[1]);
3287 XFreeGC(dpy, gc_xor);
3289 GetGCXor(plot, &gc_xor); /* recreate gc_xor */
3296 * free all *pm3d* colors (*not* the line colors cmap->colors)
3297 * of a plot_struct's colormap. This could be either a private
3298 * or the default colormap. Note, that the line colors are not
3299 * free'd nor even touched.
3302 FreeColors(cmap_t *cmp)
3304 if (cmp->total && cmp->pixels) {
3305 if (cmp->allocated) {
3306 FPRINTF((stderr, "freeing palette colors\n"));
3307 XFreeColors(dpy, cmp->colormap, cmp->pixels,
3308 cmp->allocated, 0 /* XXX ??? XXX */ );
3316 * free pm3d colors and eventually a private colormap.
3317 * set the plot_struct's colormap to the default colormap
3318 * and the line `colors' to the line colors of the default
3322 ReleaseColormap(cmap_t *cmp)
3324 if (cmp && cmp != current_cmap) {
3326 FPRINTF((stderr, "releasing private colormap\n"));
3327 if (cmp->colormap && cmp->colormap != current_cmap->colormap) {
3328 XFreeColormap(dpy, cmp->colormap);
3334 static unsigned long *
3335 ReallocColors(cmap_t *cmap, int n)
3339 cmap->pixels = (unsigned long *)
3340 malloc(sizeof(unsigned long) * cmap->total);
3341 return cmap->pixels;
3345 * check if the display supports the visual of type `class'.
3347 * If multiple visuals of `class' are supported, try to get
3348 * the one with the highest depth.
3350 * If visual class and depth are equal to the default visual
3351 * class and depth, the latter is preferred.
3353 * modifies: best, depth
3355 * returns 1 if a visual which matches the request
3356 * could be found else 0.
3359 GetVisual(int class, Visual ** visual, int *depth)
3361 XVisualInfo *visualsavailable;
3363 long vinfo_mask = VisualClassMask;
3366 vinfo.class = class;
3370 visualsavailable = XGetVisualInfo(dpy, vinfo_mask, &vinfo, &nvisuals);
3372 if (visualsavailable && nvisuals > 0) {
3374 for (i = 0; i < nvisuals; i++) {
3375 if (visualsavailable[i].depth > *depth) {
3376 *visual = visualsavailable[i].visual;
3377 *depth = visualsavailable[i].depth;
3380 XFree(visualsavailable);
3381 if (*visual && (*visual)->class == (DefaultVisual(dpy, scr))->class && *depth == DefaultDepth(dpy, scr)) {
3382 /* prefer the default visual */
3383 *visual = DefaultVisual(dpy, scr);
3386 return nvisuals > 0;
3390 PaletteMake(t_sm_palette * tpal)
3394 char *save_title = (char *) 0;
3396 /* The information retained in a linked list is the cmap_t structure.
3397 * That colormap structure doesn't contain the palette specifications
3398 * t_sm_palette used to generate the colormap. Therefore, the making
3399 * of the colormap must be carried all the way through before we can
3400 * determine if it is unique from the other colormaps in the linked list.
3402 * Rather than create and initialize a colormap outside of the list, we'll
3403 * just put a new one in the list, and if it isn't unique remove it later.
3406 cmap_t *new_cmap = Add_CMap_To_Linked_List();
3408 /* Continue until valid palette is built. May require multiple passes. */
3413 if (tpal->use_maxcolors > 0) {
3414 max_colors = tpal->use_maxcolors;
3416 max_colors = maximal_possible_colors;
3419 FPRINTF((stderr, "(PaletteMake) tpal->use_maxcolors = %d\n",
3420 tpal->use_maxcolors));
3422 /* free old gradient table */
3423 if (sm_palette.gradient) {
3424 free( sm_palette.gradient );
3425 sm_palette.gradient = NULL;
3426 sm_palette.gradient_num = 0;
3429 sm_palette.colorMode = tpal->colorMode;
3430 sm_palette.positive = tpal->positive;
3431 sm_palette.use_maxcolors = tpal->use_maxcolors;
3432 sm_palette.cmodel = tpal->cmodel;
3434 switch( sm_palette.colorMode ) {
3435 case SMPAL_COLOR_MODE_GRAY:
3436 sm_palette.gamma = tpal->gamma;
3438 case SMPAL_COLOR_MODE_RGB:
3439 sm_palette.formulaR = tpal->formulaR;
3440 sm_palette.formulaG = tpal->formulaG;
3441 sm_palette.formulaB = tpal->formulaB;
3443 case SMPAL_COLOR_MODE_FUNCTIONS:
3444 fprintf( stderr, "Ooops: no SMPAL_COLOR_MODE_FUNCTIONS here!\n" );
3446 case SMPAL_COLOR_MODE_GRADIENT:
3447 sm_palette.gradient_num = tpal->gradient_num;
3448 /* Take over the memory from tpal. */
3449 sm_palette.gradient = tpal->gradient;
3450 tpal->gradient = NULL;
3453 fprintf(stderr,"%s:%d ooops: Unknown color mode '%c'.\n",
3454 __FILE__, __LINE__, (char)(sm_palette.colorMode) );
3458 max_colors = maximal_possible_colors;
3459 FPRINTF((stderr, "(PaletteMake) tpal=NULL\n"));
3462 if (minimal_possible_colors < max_colors)
3463 min_colors = minimal_possible_colors;
3465 min_colors = max_colors / (num_colormaps > 1 ? 2 : 8);
3469 if (current_plot->window) {
3471 char *added_text = " allocating colors ...";
3472 int orig_len = (current_plot->titlestring ? strlen(current_plot->titlestring) : 0);
3473 XFetchName(dpy, current_plot->window, &save_title);
3474 if ((msg = (char *) malloc(orig_len + strlen(added_text) + 1))) {
3475 if (current_plot->titlestring)
3476 strcpy(msg, current_plot->titlestring);
3479 strcat(msg, added_text);
3480 XStoreName(dpy, current_plot->window, msg);
3485 if (!num_colormaps) {
3486 XFree(XListInstalledColormaps(dpy, current_plot->window, &num_colormaps));
3487 FPRINTF((stderr, "(PaletteMake) num_colormaps = %d\n", num_colormaps));
3493 /* EventuallyChangeVisual(plot); */
3496 * start with trying to allocate max_colors. This should
3497 * always succeed with TrueColor visuals >= 16bit. If it
3498 * fails (for example for a PseudoColor visual of depth 8),
3499 * try it with half of the colors. Proceed until min_colors
3500 * is reached. If this fails we should probably install a
3502 * Note that I make no difference for different
3503 * visual types here. (joze)
3505 for ( /* EMPTY */ ; max_colors >= min_colors; max_colors /= 2) {
3508 double fact = 1.0 / (double)(max_colors-1);
3511 ReallocColors(new_cmap, max_colors);
3513 for (new_cmap->allocated = 0; new_cmap->allocated < max_colors; new_cmap->allocated++) {
3515 double gray = (double) new_cmap->allocated * fact;
3517 rgb1_from_gray( gray, &color );
3518 xcolor.red = 0xffff * color.r + 0.5;
3519 xcolor.green = 0xffff * color.g + 0.5;
3520 xcolor.blue = 0xffff * color.b + 0.5;
3522 if (XAllocColor(dpy, new_cmap->colormap, &xcolor)) {
3523 new_cmap->pixels[new_cmap->allocated] = xcolor.pixel;
3525 FPRINTF((stderr, "failed at color %d\n", new_cmap->allocated));
3530 if (new_cmap->allocated == max_colors) {
3531 break; /* success! */
3534 /* reduce the number of max_colors to at
3535 * least less than new_cmap->allocated */
3536 while (max_colors > new_cmap->allocated && max_colors >= min_colors) {
3541 FPRINTF((stderr, "(PaletteMake) allocated = %d\n", new_cmap->allocated));
3542 FPRINTF((stderr, "(PaletteMake) max_colors = %d\n", max_colors));
3543 FPRINTF((stderr, "(PaletteMake) min_colors = %d\n", min_colors));
3545 if (new_cmap->allocated < min_colors && tpal) {
3546 /* create a private colormap on second pass. */
3547 FPRINTF((stderr, "switching to private colormap\n"));
3554 /* Now check the uniqueness of the new colormap against all the other
3555 * colormaps in the linked list.
3558 cmap_t *cmp = cmap_list_start;
3560 while (cmp != NULL) {
3561 if ((cmp != new_cmap) && !cmaps_differ(cmp, new_cmap))
3563 cmp = cmp->next_cmap;
3567 /* Found a match. Discard the newly created colormap. (Could
3568 * have simply discarded the old one and combined parts of
3569 * code similar to these if statements, but we'll avoid removing
3570 * old blocks of memory so that it is more likely that heap
3571 * memory will remain more tidy.
3573 Remove_CMap_From_Linked_List(new_cmap);
3575 current_plot->cmap = cmp;
3576 RecolorWindow(current_plot);
3580 /* Unique and truely new colormap. Make it the current map. */
3582 current_plot->cmap = new_cmap;
3583 RecolorWindow(current_plot);
3585 /* If no other plots using colormap, then can be removed. */
3586 if (!Find_Plot_In_Linked_List_By_CMap(current_cmap))
3587 Remove_CMap_From_Linked_List(current_cmap);
3588 current_cmap = new_cmap;
3594 /* Restore window title (current_plot and current_plot->window are
3595 * valid, otherwise would not have been able to get save_title.
3597 XStoreName(dpy, current_plot->window, save_title);
3604 PaletteSetColor(plot_struct * plot, double gray)
3606 if (plot->cmap->allocated) {
3609 gray = floor(gray * plot->cmap->allocated) / (plot->cmap->allocated - 1);
3610 index = gray * (plot->cmap->allocated - 1);
3611 if (index >= plot->cmap->allocated)
3612 index = plot->cmap->allocated -1;
3614 XSetForeground(dpy, gc, plot->cmap->pixels[index]);
3615 plot->current_rgb = plot->cmap->pixels[index];
3622 ErrorHandler(Display * display, XErrorEvent * error_event)
3624 /* Don't remove directly. Main program might be using the memory. */
3625 (void) display; /* avoid -Wunused warnings */
3626 Add_Plot_To_Remove_FIFO_Queue((Window) error_event->resourceid);
3627 gp_exec_event(GE_reset, 0, 0, 0, 0, 0);
3632 DrawRuler(plot_struct * plot)
3634 if (plot->ruler_on) {
3635 int x = X(plot->ruler_x);
3636 int y = Y(plot->ruler_y);
3638 /* create a gc for `rubberbanding' (well ...) */
3639 GetGCXor(plot, &gc_xor);
3642 XDrawLine(dpy, plot->window, gc_xor, x, 0, x, GRAPH_HEIGHT(plot));
3643 /* horizontal line */
3644 XDrawLine(dpy, plot->window, gc_xor, 0, y, plot->width, y);
3649 EventuallyDrawMouseAddOns(plot_struct * plot)
3652 DrawLineToRuler(plot);
3653 if (plot->zoombox_on)
3655 DrawCoords(plot, plot->str);
3663 * draw a line using the gc with the GXxor function.
3664 * This can be used to turn on *and off* a line between
3665 * the current mouse pointer and the ruler.
3668 DrawLineToRuler(plot_struct * plot)
3670 if (plot->ruler_on == FALSE || plot->ruler_lineto_on == FALSE)
3672 if (plot->ruler_lineto_x < 0)
3675 GetGCXor(plot, &gc_xor);
3677 XDrawLine(dpy, plot->window, gc_xor,
3678 X(plot->ruler_x), Y(plot->ruler_y),
3679 plot->ruler_lineto_x, plot->ruler_lineto_y);
3686 * draw a box using the gc with the GXxor function.
3687 * This can be used to turn on *and off* a box. The
3688 * corners of the box are annotated with the strings
3689 * stored in the plot structure.
3692 DrawBox(plot_struct * plot)
3696 int X0 = plot->zoombox_x1;
3697 int Y0 = plot->zoombox_y1;
3698 int X1 = plot->zoombox_x2;
3699 int Y1 = plot->zoombox_y2;
3701 if (!gc_xor_dashed) {
3702 GetGCXorDashed(plot, &gc_xor_dashed);
3720 XDrawRectangle(dpy, plot->window, gc_xor_dashed, X0, Y0, width, height);
3722 if (plot->zoombox_str1a[0] || plot->zoombox_str1b[0])
3723 AnnotatePoint(plot, plot->zoombox_x1, plot->zoombox_y1, plot->zoombox_str1a, plot->zoombox_str1b);
3724 if (plot->zoombox_str2a[0] || plot->zoombox_str2b[0])
3725 AnnotatePoint(plot, plot->zoombox_x2, plot->zoombox_y2, plot->zoombox_str2a, plot->zoombox_str2b);
3730 * draw the strings xstr and ystr centered horizontally
3731 * and vertically at the point x, y. Use the GXxor
3732 * as usually, so that we can also remove the coords
3736 AnnotatePoint(plot_struct * plot, int x, int y, const char xstr[], const char ystr[])
3741 xlen = strlen(xstr);
3742 xwidth = gpXTextWidth(font, xstr, xlen);
3744 ylen = strlen(ystr);
3745 ywidth = gpXTextWidth(font, ystr, ylen);
3747 /* horizontal centering disabled (joze) */
3750 GetGCXor(plot, &gc_xor);
3752 gpXDrawString(dpy, plot->window, gc_xor, x, y - 3, xstr, xlen);
3753 gpXDrawString(dpy, plot->window, gc_xor, x, y + vchar, ystr, ylen);
3756 /* returns the time difference to the last click in milliseconds */
3758 SetTime(plot_struct *plot, Time t)
3760 long int diff = t - plot->time;
3762 FPRINTF((stderr, "(SetTime) difftime = %ld\n", diff));
3765 return diff > 0 ? diff : 0;
3768 static unsigned long
3769 AllocateXorPixel(cmap_t *cmap_ptr)
3771 unsigned long pixel;
3774 xcolor.pixel = cmap_ptr->colors[0]; /* background color */
3775 XQueryColor(dpy, cmap_ptr->colormap, &xcolor);
3777 if (xcolor.red + xcolor.green + xcolor.blue < 0xffff) {
3778 /* it is admittedly somehow arbitrary to call
3779 * everything with a gray value < 0xffff a
3780 * dark background. Try to use the background's
3781 * complement for drawing which will always
3782 * result in white when using xor. */
3783 xcolor.red = ~xcolor.red;
3784 xcolor.green = ~xcolor.green;
3785 xcolor.blue = ~xcolor.blue;
3786 if (XAllocColor(dpy, cmap_ptr->colormap, &xcolor)) {
3787 /* use white foreground for dark backgrounds */
3788 pixel = xcolor.pixel;
3790 /* simple xor if we've run out of colors. */
3791 pixel = WhitePixel(dpy, scr);
3794 /* use the background itself for drawing.
3795 * xoring two same colors will always result
3796 * in black. This color is already allocated. */
3797 pixel = xcolor.pixel;
3799 cmap_ptr->xorpixel = pixel;
3804 GetGCXor(plot_struct * plot, GC * ret)
3807 unsigned long mask = 0;
3809 values.foreground = AllocateXorPixel(plot->cmap);
3811 #ifdef USE_X11_MULTIBYTE
3813 mask = GCForeground | GCFunction;
3814 values.function = GXxor;
3818 mask = GCForeground | GCFunction | GCFont;
3819 values.function = GXxor;
3820 values.font = font->fid;
3823 *ret = XCreateGC(dpy, plot->window, mask, &values);
3827 GetGCXorDashed(plot_struct * plot, GC * gc)
3830 XSetLineAttributes(dpy, *gc, 0, /* line width, X11 treats 0 as a `thin' line */
3831 LineOnOffDash, /* also: LineDoubleDash */
3832 CapNotLast, /* also: CapButt, CapRound, CapProjecting */
3833 JoinMiter /* also: JoinRound, JoinBevel */ );
3838 * returns the newly created gc
3839 * pixmap: where the gc will be used
3840 * mode == 0 --> black on white
3841 * mode == 1 --> white on black
3843 /* FIXME HBB 20020225: This function is not used anywhere ??? */
3845 GetGCBlackAndWhite(plot_struct * plot, GC * ret, Pixmap pixmap, int mode)
3848 unsigned long mask = 0;
3850 mask = GCForeground | GCBackground | GCFont | GCFunction;
3853 values.foreground = BlackPixel(dpy, scr);
3854 values.background = WhitePixel(dpy, scr);
3856 values.foreground = plot->cmap->colors[1];
3857 values.background = plot->cmap->colors[0];
3864 values.foreground = WhitePixel(dpy, scr);
3865 values.background = BlackPixel(dpy, scr);
3867 values.foreground = plot->cmap->colors[0];
3868 values.background = plot->cmap->colors[1];
3871 values.function = GXcopy;
3872 values.font = font->fid;
3874 *ret = XCreateGC(dpy, pixmap, mask, &values);
3878 * split a string at `splitchar'.
3880 /* FIXME HBB 20020225: This function is not used anywhere ??? */
3882 SplitAt(char **args, int maxargs, char *buf, char splitchar)
3886 while (*buf != '\0' && argc < maxargs) {
3888 if ((*buf == splitchar))
3891 if (!(*buf)) /* don't count the terminating NULL */
3894 /* Save the argument. */
3898 /* Skip over the argument */
3899 while ((*buf != '\0') && (*buf != splitchar))
3903 *args = '\0'; /* terminate */
3907 /* FIXME HBB 20020225: This function is not used anywhere ??? */
3916 /* erase the last displayed position string */
3918 EraseCoords(plot_struct * plot)
3920 DrawCoords(plot, plot->str);
3926 DrawCoords(plot_struct * plot, const char *str)
3929 GetGCXor(plot, &gc_xor);
3933 gpXDrawString(dpy, plot->window, gc_xor, 1, plot->gheight + vchar - 1, str, strlen(str));
3937 /* display text (e.g. mouse position) in the lower left corner of the window. */
3939 DisplayCoords(plot_struct * plot, const char *s)
3941 /* first, erase old text */
3946 if (plot->height > plot->gheight) {
3947 /* and window has space for text? then make it smaller, unless we're already doing a resize: */
3948 if (!plot->resizing) {
3949 XResizeWindow(dpy, plot->window, plot->width, plot->gheight);
3950 plot->resizing = TRUE;
3954 /* so we do have new text */
3955 if (plot->height == plot->gheight) {
3956 /* window not large enough? then make it larger, unless we're already doing a resize: */
3957 if (!plot->resizing) {
3958 XResizeWindow(dpy, plot->window, plot->width, plot->gheight + vchar);
3959 plot->resizing = TRUE;
3964 /* finally, draw the new text: */
3965 DrawCoords(plot, s);
3967 /* and save it, for later erasing: */
3968 strcpy(plot->str, s);
3975 /* CJK keyboards may have these meta keys */
3976 if (0xFF20 <= mod && mod <= 0xFF3F)
3979 /* Everyone else may have these meta keys */
3996 /* It returns NULL if we are not running in any known (=implemented) multitab
3998 * Otherwise it returns a command to be executed in order to switch to the
3999 * appropriate tab of a multitab console.
4000 * In addition, it may return non-zero newGnuplotXID in order to overwrite zero
4001 * value of gnuplotXID (because Konsole's in KDE <3.2 don't set WINDOWID contrary
4002 * to all other xterm's).
4003 * Currently implemented for:
4005 * Note: if the returned command is !NULL, then it must be free()'d by the caller.
4008 getMultiTabConsoleSwitchCommand(unsigned long *newGnuplotXID)
4010 #ifdef HAVE_STRDUP /* We assume that any machine missing strdup is too old for KDE */
4011 char *cmd = NULL; /* result */
4012 char *ptr = getenv("KONSOLE_DCOP_SESSION"); /* Try KDE's Konsole first. */
4015 /* We are in KDE's Konsole, or in a terminal window detached from a Konsole.
4016 * In order to active a tab:
4017 * 1. get environmental variable KONSOLE_DCOP_SESSION: it includes konsole id and session name
4019 * $WINDOWID is defined and it equals
4020 * `dcop konsole-3152 konsole-mainwindow#1 getWinID`
4021 * (KDE 3.2) or when $WINDOWID is undefined (KDE 3.1), then run commands
4022 * dcop konsole-3152 konsole activateSession session-2; \
4023 * dcop konsole-3152 konsole-mainwindow#1 raise
4024 * Note: by $WINDOWID we mean gnuplot's text console WINDOWID.
4025 * Missing: focus is not transferred unless $WINDOWID is defined (should be fixed in KDE 3.2).
4027 * Implementation and tests on KDE 3.1.4: Petr Mikulik.
4029 char *konsole_name = NULL;
4030 *newGnuplotXID = 0; /* don't change gnuplotXID by default */
4031 /* use 'while' instead of 'if' to easily break out (aka catch exception) */
4036 ptr = strchr(ptr, '(');
4037 /* the string for tab nb 4 looks like 'DCOPRef(konsole-2866, session-4)' */
4038 if (!ptr) return NULL;
4039 konsole_name = strdup(ptr+1);
4040 konsole_tab = strchr(konsole_name, ',');
4041 if (!konsole_tab) break;
4043 ptr = strchr(konsole_tab, ')');
4045 /* Not necessary to define DCOP_RAISE: returning newly known
4046 * newGnuplotXID instead is sufficient.
4048 /* #define DCOP_RAISE */
4050 cmd = malloc(2*strlen(konsole_name) + strlen(konsole_tab) + 128);
4052 cmd = malloc(strlen(konsole_name) + strlen(konsole_tab) + 64);
4054 sprintf(cmd, "dcop %s konsole-mainwindow#1 getWinID 2>/dev/null", konsole_name);
4055 /* is 2>/dev/null portable among various shells? */
4056 p = popen(cmd, "r");
4058 fscanf(p, "%lu", &w);
4061 if (gnuplotXID) { /* $WINDOWID is known */
4062 if (w != gnuplotXID) break;
4063 /* `dcop getWinID`==$WINDOWID thus we are running in a window detached from Konsole */
4066 /* $WINDOWID has not been known (KDE 3.1), thus set it up */
4069 /* not necessary: returning newly known newGnuplotXID instead is sufficient */
4070 sprintf(cmd, "dcop %s konsole-mainwindow#1 raise;", konsole_name);
4071 sprintf(cmd+strlen(cmd), "dcop %s konsole activateSession %s", konsole_name, konsole_tab);
4073 sprintf(cmd, "dcop %s konsole activateSession %s", konsole_name, konsole_tab);
4082 /* now test for GNOME multitab console */
4083 /* ... if somebody bothers to implement it ... */
4085 #endif /* HAVE_STRDUP */
4086 /* we are not running in any known (implemented) multitab console */
4093 /*---------------------------------------------------------------------------
4094 * reset all cursors (since we dont have a record of the previous terminal #)
4095 *---------------------------------------------------------------------------*/
4100 plot_struct *plot = plot_list_start;
4104 FPRINTF((stderr, "Window for plot %d exists\n", plot->plot_number));
4105 XUndefineCursor(dpy, plot->window);
4107 plot = plot->next_plot;
4110 FPRINTF((stderr, "Cursors reset\n"));
4114 /*-----------------------------------------------------------------------------
4115 * resize - rescale last plot if window resized
4116 *---------------------------------------------------------------------------*/
4120 /* the status of the shift, ctrl and alt keys
4122 static int modifier_mask = 0;
4124 static void update_modifiers __PROTO((unsigned int));
4127 update_modifiers(unsigned int state)
4131 old_mod_mask = modifier_mask;
4132 modifier_mask = ((state & ShiftMask) ? Mod_Shift : 0)
4133 | ((state & ControlMask) ? Mod_Ctrl : 0)
4134 | ((state & Mod1Mask) ? Mod_Alt : 0);
4135 if (old_mod_mask != modifier_mask) {
4136 gp_exec_event(GE_modifier, 0, 0, modifier_mask, 0, 0);
4143 process_configure_notify_event(XEvent *event)
4146 int force_redraw = 0;
4148 /* Filter down to the last ConfigureNotify event */
4150 while (XCheckTypedWindowEvent(dpy, event->xany.window, ConfigureNotify, event))
4153 plot = Find_Plot_In_Linked_List_By_Window(event->xconfigure.window);
4155 int w = event->xconfigure.width, h = event->xconfigure.height;
4157 /* store settings in case window is closed then recreated */
4158 /* but: don't do this if both x and y are 0, since some
4159 * (all?) systems set these to zero when only resizing
4160 * (not moving) the window. This does mean that a move to
4161 * (0, 0) won't be registered: can we solve that? */
4162 if (event->xconfigure.x != 0 || event->xconfigure.y != 0) {
4163 plot->x = event->xconfigure.x;
4164 plot->y = event->xconfigure.y;
4165 plot->posn_flags = (plot->posn_flags & ~PPosition) | USPosition;
4168 /* first, check whether we were waiting for completion of a resize */
4169 if (plot->resizing) {
4170 /* it seems to be impossible to distinguish between a
4171 * resize caused by our call to XResizeWindow(), and a
4172 * resize started by the user/windowmanager; but we can
4173 * make a good guess which can only fail if the user
4174 * resizes the window while we're also resizing it
4176 if (w == plot->width
4177 && (h == plot->gheight || h == plot->gheight + vchar)) {
4178 /* most likely, it's a resize for showing/hiding the status line.
4179 * Test whether the height is now correct; if not, start another resize. */
4180 plot->resizing = FALSE;
4181 if (w == plot->width
4182 && h == plot->gheight + (plot->str[0] ? vchar : 0)) {
4183 /* Was successful, status line can be drawn without rescaling plot. */
4187 /* Possibly, a resize attempt _failed_ because window manager denied it.
4188 Resizing again goes into a vicious endless loop!
4189 (Seen with fluxbox-1.0.0 and a tab group of gnuplot windows.) */
4190 /* Instead of just appending the status line, redraw/scale the plot. */
4191 force_redraw = TRUE;
4197 if (w > 1 && h > 1 && (force_redraw || w != plot->width || h != plot->height)) {
4202 /* Make sure that unsigned number doesn't underflow. */
4204 plot->gheight = (vchar > plot->height) ? 0 : plot->height - vchar;
4206 plot->gheight = plot->height;
4208 plot->posn_flags = (plot->posn_flags & ~PSize) | USSize;
4210 if (stipple_initialized) {
4212 for (i = 0; i < stipple_pattern_num; i++)
4213 XFreePixmap(dpy, stipple_pattern[i]);
4214 stipple_initialized = 0;
4218 /* it is the wrong size now */
4219 FPRINTF((stderr, "Free pixmap %d\n", 0));
4220 XFreePixmap(dpy, plot->pixmap);
4221 plot->pixmap = None;
4229 process_event(XEvent *event)
4233 char key_sequence[8];
4235 FPRINTF((stderr, "Event 0x%x\n", event->type));
4237 switch (event->type) {
4238 case ConfigureNotify:
4239 process_configure_notify_event(event);
4243 plot = Find_Plot_In_Linked_List_By_Window(event->xkey.window);
4245 /* Unlike XKeycodeToKeysym, XLookupString applies the current */
4246 /* shift, ctrl, alt, and meta modifiers to yield a character. */
4247 /* keysym = XKeycodeToKeysym(dpy, event->xkey.keycode, 0); */
4248 XLookupString((XKeyEvent *)event, key_sequence, sizeof(key_sequence), &keysym, NULL);
4251 update_modifiers(event->xkey.state);
4256 static int cmd_tried = 0;
4257 static char *cmd = NULL;
4258 static unsigned long newGnuplotXID = 0;
4260 /* If the "-ctrlq" resource is set, ignore ' ' unless control key is also pressed */
4261 if (ctrlq && !(modifier_mask & Mod_Ctrl))
4265 cmd = getMultiTabConsoleSwitchCommand(&newGnuplotXID);
4268 /* overwrite gnuplotXID (re)set after x11.trm:X11_options() */
4269 if (newGnuplotXID) gnuplotXID = newGnuplotXID;
4270 if (cmd) system(cmd);
4273 XMapRaised(dpy, gnuplotXID);
4274 XSetInputFocus(dpy, gnuplotXID, 0 /*revert */ , CurrentTime);
4278 case 'm': /* Toggle mouse display, but only if we control the window here */
4279 if (((plot != current_plot) && (!modifier_mask))
4284 plot->mouse_on = !(plot->mouse_on);
4285 DisplayCoords(plot, plot->mouse_on ? " " : "");
4291 /* If the "-ctrlq" resource is set, ignore q unless control key is also pressed */
4292 if (ctrlq && !(modifier_mask & Mod_Ctrl)) {
4293 FPRINTF((stderr, "ignoring q, modifier_mask = %o\n", modifier_mask));
4297 /* close X window */
4298 Remove_Plot_From_Linked_List(event->xkey.window);
4302 } /* switch (keysym) */
4305 if (is_meta(keysym))
4310 #define KNOWN_KEYSYMS(gp_keysym) \
4311 if (plot == current_plot) { \
4312 gp_exec_event(GE_keypress, \
4313 (int)RevX(event->xkey.x), (int)RevY(event->xkey.y), \
4314 gp_keysym, 0, plot->plot_number); \
4316 gp_exec_event(GE_keypress_old, \
4317 (int)RevX(event->xkey.x), (int)RevY(event->xkey.y), \
4318 gp_keysym, 0, plot->plot_number); \
4322 /* Prevent hysteresis if redraw cannot keep up with rate of keystrokes */
4323 #define DRAIN_KEYSTROKES(key) \
4324 if (plot == current_plot) { \
4325 while (XCheckTypedWindowEvent(dpy, \
4326 event->xany.window, KeyPress, event)); \
4330 KNOWN_KEYSYMS(GP_BackSpace);
4332 KNOWN_KEYSYMS(GP_Tab);
4334 KNOWN_KEYSYMS(GP_Linefeed);
4336 KNOWN_KEYSYMS(GP_Clear);
4338 KNOWN_KEYSYMS(GP_Return);
4340 KNOWN_KEYSYMS(GP_Pause);
4341 case XK_Scroll_Lock:
4342 KNOWN_KEYSYMS(GP_Scroll_Lock);
4345 KNOWN_KEYSYMS(GP_Sys_Req);
4348 KNOWN_KEYSYMS(GP_Escape);
4350 KNOWN_KEYSYMS(GP_Insert);
4352 KNOWN_KEYSYMS(GP_Delete);
4354 KNOWN_KEYSYMS(GP_Home);
4356 DRAIN_KEYSTROKES(XK_Left);
4357 KNOWN_KEYSYMS(GP_Left);
4359 DRAIN_KEYSTROKES(XK_Up);
4360 KNOWN_KEYSYMS(GP_Up);
4362 DRAIN_KEYSTROKES(XK_Right);
4363 KNOWN_KEYSYMS(GP_Right);
4365 DRAIN_KEYSTROKES(XK_Down);
4366 KNOWN_KEYSYMS(GP_Down);
4367 case XK_Prior: /* XXX */
4368 KNOWN_KEYSYMS(GP_PageUp);
4369 case XK_Next: /* XXX */
4370 KNOWN_KEYSYMS(GP_PageDown);
4372 KNOWN_KEYSYMS(GP_End);
4374 KNOWN_KEYSYMS(GP_Begin);
4376 KNOWN_KEYSYMS(GP_KP_Space);
4378 KNOWN_KEYSYMS(GP_KP_Tab);
4380 KNOWN_KEYSYMS(GP_KP_Enter);
4382 KNOWN_KEYSYMS(GP_KP_F1);
4384 KNOWN_KEYSYMS(GP_KP_F2);
4386 KNOWN_KEYSYMS(GP_KP_F3);
4388 KNOWN_KEYSYMS(GP_KP_F4);
4391 KNOWN_KEYSYMS(GP_KP_Home);
4395 KNOWN_KEYSYMS(GP_KP_Left);
4399 KNOWN_KEYSYMS(GP_KP_Up);
4403 KNOWN_KEYSYMS(GP_KP_Right);
4407 KNOWN_KEYSYMS(GP_KP_Down);
4409 #ifdef XK_KP_Page_Up
4411 KNOWN_KEYSYMS(GP_KP_Page_Up);
4413 #ifdef XK_KP_Page_Down
4414 case XK_KP_Page_Down:
4415 KNOWN_KEYSYMS(GP_KP_Page_Down);
4419 KNOWN_KEYSYMS(GP_KP_End);
4423 KNOWN_KEYSYMS(GP_KP_Begin);
4427 KNOWN_KEYSYMS(GP_KP_Insert);
4431 KNOWN_KEYSYMS(GP_KP_Delete);
4434 KNOWN_KEYSYMS(GP_KP_Equal);
4435 case XK_KP_Multiply:
4436 KNOWN_KEYSYMS(GP_KP_Multiply);
4438 KNOWN_KEYSYMS(GP_KP_Add);
4439 case XK_KP_Separator:
4440 KNOWN_KEYSYMS(GP_KP_Separator);
4441 case XK_KP_Subtract:
4442 KNOWN_KEYSYMS(GP_KP_Subtract);
4444 KNOWN_KEYSYMS(GP_KP_Decimal);
4446 KNOWN_KEYSYMS(GP_KP_Divide);
4449 KNOWN_KEYSYMS(GP_KP_0);
4451 KNOWN_KEYSYMS(GP_KP_1);
4453 KNOWN_KEYSYMS(GP_KP_2);
4455 KNOWN_KEYSYMS(GP_KP_3);
4457 KNOWN_KEYSYMS(GP_KP_4);
4459 KNOWN_KEYSYMS(GP_KP_5);
4461 KNOWN_KEYSYMS(GP_KP_6);
4463 KNOWN_KEYSYMS(GP_KP_7);
4465 KNOWN_KEYSYMS(GP_KP_8);
4467 KNOWN_KEYSYMS(GP_KP_9);
4470 KNOWN_KEYSYMS(GP_F1);
4472 KNOWN_KEYSYMS(GP_F2);
4474 KNOWN_KEYSYMS(GP_F3);
4476 KNOWN_KEYSYMS(GP_F4);
4478 KNOWN_KEYSYMS(GP_F5);
4480 KNOWN_KEYSYMS(GP_F6);
4482 KNOWN_KEYSYMS(GP_F7);
4484 KNOWN_KEYSYMS(GP_F8);
4486 KNOWN_KEYSYMS(GP_F9);
4488 KNOWN_KEYSYMS(GP_F10);
4490 KNOWN_KEYSYMS(GP_F11);
4492 KNOWN_KEYSYMS(GP_F12);
4495 KNOWN_KEYSYMS((int) keysym);
4502 update_modifiers(event->xkey.state);
4503 keysym = XKeycodeToKeysym(dpy, event->xkey.keycode, 0);
4504 if (is_meta(keysym)) {
4505 plot = Find_Plot_In_Linked_List_By_Window(event->xkey.window);
4506 cursor = cursor_default;
4508 XDefineCursor(dpy, plot->window, cursor);
4514 if (event->xclient.message_type == WM_PROTOCOLS &&
4515 event->xclient.format == 32 && event->xclient.data.l[0] == WM_DELETE_WINDOW) {
4516 Remove_Plot_From_Linked_List(event->xclient.window);
4517 /* EAM FIXME - may have to generate GE_reset event here also */
4523 plot = Find_Plot_In_Linked_List_By_Window(event->xconfigure.window);
4524 if (plot == current_plot) {
4525 gp_exec_event(GE_reset, 0, 0, 0, 0, 0);
4531 * we need to handle expose events here, because
4532 * there might stuff like rulers which has to
4533 * be redrawn. Well. It's not really hard to handle
4534 * this. Note that the x and y fields are not used
4535 * to update the pointer pos because the pointer
4536 * might be on another window which generates the
4537 * expose events. (joze)
4540 /* Check for any ConfigureNotify events further down in the X11
4541 * event queue. If one is found, handle it first and let the
4542 * expose event that is generated be handled later.
4543 * Jay Painter Nov 2003.
4545 if (XCheckTypedWindowEvent(dpy, event->xany.window, ConfigureNotify, event)) {
4546 process_configure_notify_event(event);
4549 while (XCheckTypedWindowEvent(dpy, event->xany.window, Expose, event));
4551 plot = Find_Plot_In_Linked_List_By_Window(event->xexpose.window);
4558 plot = Find_Plot_In_Linked_List_By_Window(event->xcrossing.window);
4561 if (plot == current_plot) {
4563 gp_exec_event(GE_motion, (int) RevX(event->xcrossing.x), (int) RevY(event->xcrossing.y), 0, 0, 0);
4565 if (plot->zoombox_on) {
4567 plot->zoombox_x2 = event->xcrossing.x;
4568 plot->zoombox_y2 = event->xcrossing.y;
4571 if (plot->ruler_on) {
4572 DrawLineToRuler(plot);
4573 plot->ruler_lineto_x = event->xcrossing.x;
4574 plot->ruler_lineto_y = event->xcrossing.y;
4575 DrawLineToRuler(plot);
4579 update_modifiers(event->xmotion.state);
4580 plot = Find_Plot_In_Linked_List_By_Window(event->xmotion.window);
4585 int root_x, root_y, pos_x, pos_y;
4586 unsigned int keys_buttons;
4587 if (!XQueryPointer(dpy, event->xmotion.window, &root, &child, &root_x, &root_y, &pos_x, &pos_y, &keys_buttons))
4590 if (plot == current_plot
4596 gp_exec_event(GE_motion, (int) RevX(pos_x), (int) RevY(pos_y), 0, 0, 0);
4597 #if defined(USE_MOUSE) && defined(MOUSE_ALL_WINDOWS)
4598 } else if (plot->axis_mask && plot->mouse_on && plot->almost2d) {
4599 /* This is not the active plot window, but we can still update the mouse coords */
4600 char mouse_format[60];
4601 char *m = mouse_format;
4602 double x, y, x2, y2;
4605 mouse_to_coords(plot, event, &x, &y, &x2, &y2);
4606 if (plot->axis_mask & (1<<FIRST_X_AXIS)) {
4607 sprintf(m, "x= %10g %c", x, '\0');
4610 if (plot->axis_mask & (1<<SECOND_X_AXIS)) {
4611 sprintf(m, "x2= %10g %c", x2, '\0');
4614 if (plot->axis_mask & (1<<FIRST_Y_AXIS)) {
4615 sprintf(m, "y= %10g %c", y, '\0');
4618 if (plot->axis_mask & (1<<SECOND_Y_AXIS)) {
4619 sprintf(m, "y2= %10g %c", y2, '\0');
4622 DisplayCoords(plot, mouse_format);
4623 } else if (!plot->mouse_on) {
4624 DisplayCoords(plot, "");
4628 if (plot->zoombox_on) {
4630 plot->zoombox_x2 = pos_x;
4631 plot->zoombox_y2 = pos_y;
4634 if (plot->ruler_on && plot->ruler_lineto_on) {
4635 DrawLineToRuler(plot);
4636 plot->ruler_lineto_x = event->xcrossing.x;
4637 plot->ruler_lineto_y = event->xcrossing.y;
4638 DrawLineToRuler(plot);
4643 update_modifiers(event->xbutton.state);
4644 #ifndef TITLE_BAR_DRAWING_MSG
4645 button_pressed |= (1 << event->xbutton.button);
4647 plot = Find_Plot_In_Linked_List_By_Window(event->xbutton.window);
4651 if (plot == current_plot) {
4653 gp_exec_event(GE_buttonpress, (int) RevX(event->xbutton.x), (int) RevY(event->xbutton.y), event->xbutton.button, 0, 0);
4658 #ifndef TITLE_BAR_DRAWING_MSG
4659 button_pressed &= ~(1 << event->xbutton.button);
4661 plot = Find_Plot_In_Linked_List_By_Window(event->xbutton.window);
4664 if (plot == current_plot) {
4666 long int doubleclick = SetTime(plot, event->xbutton.time);
4668 update_modifiers(event->xbutton.state);
4670 gp_exec_event(GE_buttonrelease,
4671 (int) RevX(event->xbutton.x), (int) RevY(event->xbutton.y),
4672 event->xbutton.button, (int) doubleclick, 0);
4676 #if defined(USE_MOUSE) && defined(MOUSE_ALL_WINDOWS)
4677 /* This causes gnuplot_x11 to pass mouse clicks back from all plot windows,
4678 * not just the current plot. But who should we notify that a click has
4679 * happened, and how? The fprintf to stderr is just for debugging. */
4680 else if (plot->axis_mask) {
4681 double x, y, x2, y2;
4682 mouse_to_coords(plot, event, &x, &y, &x2, &y2);
4683 fprintf(stderr, "gnuplot_x11 %d: mouse button %1d from window %d at %g %g\n",
4684 __LINE__, event->xbutton.button, (plot ? plot->plot_number : 0), x, y);
4690 #endif /* USE_MOUSE */
4691 #ifdef EXPORT_SELECTION
4692 case SelectionNotify:
4694 case SelectionRequest:
4695 if (exportselection)
4696 handle_selection_event(event);
4703 /*-----------------------------------------------------------------------------
4704 * preset - determine options, open display, create window
4705 *---------------------------------------------------------------------------*/
4707 #define On(v) ( !strcmp(v, "on") || !strcmp(v, "true") || \
4708 !strcmp(v, "On") || !strcmp(v, "True") || \
4709 !strcmp(v, "ON") || !strcmp(v, "TRUE") )
4711 #define On(v) ( !strncasecmp(v, "on", 2) || !strncasecmp(v, "true", 4) )
4713 #define AppDefDir "/usr/lib/X11/app-defaults"
4714 #ifndef MAXHOSTNAMELEN
4715 #define MAXHOSTNAMELEN 64
4718 static XrmDatabase dbCmd, dbApp, dbDef, dbEnv, db = (XrmDatabase) 0;
4720 static char *type[20];
4721 static XrmValue value;
4723 static XrmOptionDescRec options[] = {
4724 {"-mono", ".mono", XrmoptionNoArg, (XPointer) "on"},
4725 {"-gray", ".gray", XrmoptionNoArg, (XPointer) "on"},
4726 {"-clear", ".clear", XrmoptionNoArg, (XPointer) "on"},
4727 {"-tvtwm", ".tvtwm", XrmoptionNoArg, (XPointer) "on"},
4728 {"-pointsize", ".pointsize", XrmoptionSepArg, (XPointer) NULL},
4729 {"-display", ".display", XrmoptionSepArg, (XPointer) NULL},
4730 {"-name", ".name", XrmoptionSepArg, (XPointer) NULL},
4731 {"-geometry", "*geometry", XrmoptionSepArg, (XPointer) NULL},
4732 {"-background", "*background", XrmoptionSepArg, (XPointer) NULL},
4733 {"-bg", "*background", XrmoptionSepArg, (XPointer) NULL},
4734 {"-foreground", "*foreground", XrmoptionSepArg, (XPointer) NULL},
4735 {"-fg", "*foreground", XrmoptionSepArg, (XPointer) NULL},
4736 {"-bordercolor", "*bordercolor", XrmoptionSepArg, (XPointer) NULL},
4737 {"-bd", "*bordercolor", XrmoptionSepArg, (XPointer) NULL},
4738 {"-borderwidth", ".borderWidth", XrmoptionSepArg, (XPointer) NULL},
4739 {"-bw", ".borderWidth", XrmoptionSepArg, (XPointer) NULL},
4740 {"-font", "*font", XrmoptionSepArg, (XPointer) NULL},
4741 {"-fn", "*font", XrmoptionSepArg, (XPointer) NULL},
4742 {"-reverse", "*reverseVideo", XrmoptionNoArg, (XPointer) "on"},
4743 {"-rv", "*reverseVideo", XrmoptionNoArg, (XPointer) "on"},
4744 {"+rv", "*reverseVideo", XrmoptionNoArg, (XPointer) "off"},
4745 {"-iconic", "*iconic", XrmoptionNoArg, (XPointer) "on"},
4746 {"-synchronous", "*synchronous", XrmoptionNoArg, (XPointer) "on"},
4747 {"-xnllanguage", "*xnllanguage", XrmoptionSepArg, (XPointer) NULL},
4748 {"-selectionTimeout", "*selectionTimeout", XrmoptionSepArg, (XPointer) NULL},
4749 {"-title", ".title", XrmoptionSepArg, (XPointer) NULL},
4750 {"-xrm", NULL, XrmoptionResArg, (XPointer) NULL},
4751 {"-raise", "*raise", XrmoptionNoArg, (XPointer) "on"},
4752 {"-noraise", "*raise", XrmoptionNoArg, (XPointer) "off"},
4753 {"-feedback", "*feedback", XrmoptionNoArg, (XPointer) "on"},
4754 {"-nofeedback", "*feedback", XrmoptionNoArg, (XPointer) "off"},
4755 {"-ctrlq", "*ctrlq", XrmoptionNoArg, (XPointer) "on"},
4756 {"-dashed", "*dashed", XrmoptionNoArg, (XPointer) "on"},
4757 {"-solid", "*dashed", XrmoptionNoArg, (XPointer) "off"},
4758 {"-persist", "*persist", XrmoptionNoArg, (XPointer) "on"}
4761 #define Nopt (sizeof(options) / sizeof(options[0]))
4764 preset(int argc, char *argv[])
4770 char *ldisplay = (char *) 0;
4772 char *ldisplay = getenv("DISPLAY");
4774 char *home = getenv("HOME");
4775 char *server_defaults, *env, buffer[256];
4777 Visual *TrueColor_vis, *PseudoColor_vis, *StaticGray_vis, *GrayScale_vis;
4778 int TrueColor_depth, PseudoColor_depth, StaticGray_depth, GrayScale_depth;
4782 FPRINTF((stderr, "(preset) \n"));
4784 /* avoid bus error when env vars are not set */
4785 if (ldisplay == NULL)
4790 /*---set to ignore ^C and ^Z----------------------------------------------*/
4792 signal(SIGINT, SIG_IGN);
4794 signal(SIGTSTP, SIG_IGN);
4797 /*---prescan arguments for "-name"----------------------------------------*/
4799 while (++Argv, --Argc > 0) {
4800 if (!strcmp(*Argv, "-name") && Argc > 1) {
4801 strncpy(X_Name, Argv[1], sizeof(X_Name) - 1);
4802 strncpy(X_Class, Argv[1], sizeof(X_Class) - 1);
4804 X_Name[sizeof(X_Name) - 1] = NUL;
4805 X_Class[sizeof(X_Class) - 1] = NUL;
4806 if (X_Class[0] >= 'a' && X_Class[0] <= 'z')
4813 /*---parse command line---------------------------------------------------*/
4816 XrmParseCommand(&dbCmd, options, Nopt, X_Name, &Argc, Argv);
4819 if (!strcmp(Argv[1], "-noevents")) {
4823 fprintf(stderr, "\n\
4824 gnuplot: bad option: %s\n\
4825 gnuplot: X11 aborted.\n", Argv[1]);
4831 if (pr_GetR(dbCmd, ".display"))
4832 ldisplay = (char *) value.addr;
4834 /*---open display---------------------------------------------------------*/
4837 XSetErrorHandler(ErrorHandler);
4839 dpy = XOpenDisplay(ldisplay);
4841 fprintf(stderr, "\n\
4842 gnuplot: unable to open display '%s'\n\
4843 gnuplot: X11 aborted.\n", ldisplay);
4846 scr = DefaultScreen(dpy);
4847 root = DefaultRootWindow(dpy);
4848 server_defaults = XResourceManagerString(dpy);
4849 vis = DefaultVisual(dpy, scr);
4850 dep = DefaultDepth(dpy, scr);
4851 default_cmap.colormap = DefaultColormap(dpy, scr);
4852 current_cmap = &default_cmap;
4853 max_request_size = XMaxRequestSize(dpy) / 2;
4856 /**** atoms we will need later ****/
4858 WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
4859 WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
4862 /*---get application defaults--(subset of Xt processing)------------------*/
4865 strcpy(buffer, "DECW$USER_DEFAULTS:GNUPLOT_X11.INI");
4867 /* for XFree86 ... */
4869 char appdefdir[MAXPATHLEN];
4871 __XOS2RedirRoot("/XFree86/lib/X11/app-defaults"),
4873 sprintf(buffer, "%s/%s", appdefdir, "Gnuplot");
4876 strcpy(buffer, AppDefDir);
4877 strcat(buffer, "/");
4878 strcat(buffer, "Gnuplot");
4881 dbApp = XrmGetFileDatabase(buffer);
4882 XrmMergeDatabases(dbApp, &db);
4884 /*---get server or ~/.Xdefaults-------------------------------------------*/
4886 if (server_defaults)
4887 dbDef = XrmGetStringDatabase(server_defaults);
4890 strcpy(buffer, "DECW$USER_DEFAULTS:DECW$XDEFAULTS.DAT");
4892 strcpy(buffer, home);
4893 strcat(buffer, "/.Xdefaults");
4895 dbDef = XrmGetFileDatabase(buffer);
4897 XrmMergeDatabases(dbDef, &db);
4899 /*---get XENVIRONMENT or ~/.Xdefaults-hostname---------------------------*/
4902 if ((env = getenv("XENVIRONMENT")) != NULL)
4903 dbEnv = XrmGetFileDatabase(env);
4905 char *p = NULL, host[MAXHOSTNAMELEN];
4907 if (GP_SYSTEMINFO(host) < 0) {
4908 fprintf(stderr, "gnuplot: %s failed. X11 aborted.\n", SYSINFO_METHOD);
4911 if ((p = strchr(host, '.')) != NULL)
4913 strcpy(buffer, home);
4914 strcat(buffer, "/.Xdefaults-");
4915 strcat(buffer, host);
4916 dbEnv = XrmGetFileDatabase(buffer);
4918 XrmMergeDatabases(dbEnv, &db);
4919 #endif /* not VMS */
4921 /*---merge command line options-------------------------------------------*/
4923 XrmMergeDatabases(dbCmd, &db);
4925 /*---set geometry, font, colors, line widths, dash styles, point size-----*/
4927 /* a specific visual can be forced by the X resource visual */
4928 db_string = pr_GetR(db, ".visual") ? (char *) value.addr : (char *) 0;
4930 Visual *visual = (Visual *) 0;
4931 int depth = (int) 0;
4932 char **ptr = visual_name;
4934 for (i = 0; *ptr; i++, ptr++) {
4935 if (!strcmp(db_string, *ptr)) {
4937 if (DirectColor == i) {
4938 fprintf(stderr, "DirectColor not supported by pm3d, using default.\n");
4941 if (GetVisual(i, &visual, &depth)) {
4944 if (vis != DefaultVisual(dpy, scr)) {
4945 /* this will be the default colormap */
4946 default_cmap.colormap = XCreateColormap(dpy, root, vis, AllocNone);
4949 fprintf(stderr, "%s not supported by %s, using default.\n", *ptr, ldisplay);
4956 if (DirectColor == vis->class) {
4961 /* removed this message as it is annoying
4962 * when using gnuplot in a pipe (joze) */
4963 if (vis->class < (sizeof(visual_name) / sizeof(char **)) - 1) {
4964 fprintf(stderr, "Using %s at depth %d.\n", visual_name[vis->class], dep);
4967 CmapClear(&default_cmap);
4969 /* set default of maximal_possible_colors */
4971 maximal_possible_colors = 0x200;
4972 } else if (dep > 8) {
4973 maximal_possible_colors = 0x100;
4975 /* will be something like PseudoColor * 8 */
4976 maximal_possible_colors = 240; /* leave 16 for line colors */
4979 /* check database for maxcolors */
4980 db_string = pr_GetR(db, ".maxcolors") ? (char *) value.addr : (char *) 0;
4983 if (sscanf(db_string, "%d", &itmp)) {
4985 fprintf(stderr, "\nmaxcolors must be strictly positive.\n");
4986 } else if (itmp > pow((double) 2, (double) dep)) {
4987 fprintf(stderr, "\noops, cannot use this many colors on a %d bit deep display.\n", dep);
4989 maximal_possible_colors = itmp;
4992 fprintf(stderr, "\nunable to parse '%s' as integer\n", db_string);
4996 /* setting a default for minimal_possible_colors */
4997 minimal_possible_colors = maximal_possible_colors / (num_colormaps > 1 ? 2 : 8); /* 0x20 / 30 */
4998 /* check database for mincolors */
4999 db_string = pr_GetR(db, ".mincolors") ? (char *) value.addr : (char *) 0;
5002 if (sscanf(db_string, "%d", &itmp)) {
5004 fprintf(stderr, "\nmincolors must be strictly positive.\n");
5005 } else if (itmp > pow((double) 2, (double) dep)) {
5006 fprintf(stderr, "\noops, cannot use this many colors on a %d bit deep display.\n", dep);
5007 } else if (itmp > maximal_possible_colors) {
5008 fprintf(stderr, "\nmincolors must be <= %d\n", maximal_possible_colors);
5010 minimal_possible_colors = itmp;
5013 fprintf(stderr, "\nunable to parse '%s' as integer\n", db_string);
5018 pr_encoding(); /* check for global default encoding */
5019 pr_font(NULL); /* set current font to default font */
5020 pr_color(&default_cmap); /* set colors for default colormap */
5029 #ifdef EXPORT_SELECTION
5030 pr_exportselection();
5035 /*-----------------------------------------------------------------------------
5036 * pr_GetR - get resource from database using "-name" option (if any)
5037 *---------------------------------------------------------------------------*/
5040 pr_GetR(XrmDatabase xrdb, char *resource)
5042 char name[128], class[128], *rc;
5044 strcpy(name, X_Name);
5045 strcat(name, resource);
5046 strcpy(class, X_Class);
5047 strcat(class, resource);
5048 rc = XrmGetResource(xrdb, name, class, type, &value)
5049 ? (char *) value.addr : (char *) 0;
5053 /*-----------------------------------------------------------------------------
5054 * pr_color - determine color values
5055 *---------------------------------------------------------------------------*/
5057 static const char color_keys[Ncolors][30] = {
5058 "background", "bordercolor", "text", "border", "axis",
5059 "line1", "line2", "line3", "line4",
5060 "line5", "line6", "line7", "line8"
5062 static char color_values[Ncolors][30] = {
5063 "white", "black", "black", "black", "black",
5064 "red", "green", "blue", "magenta",
5065 "cyan", "sienna", "orange", "coral"
5067 static char color_values_rv[Ncolors][30] = {
5068 "black", "white", "white", "white", "white",
5069 "red", "green", "blue", "magenta",
5070 "cyan", "sienna", "orange", "coral"
5072 static char gray_values[Ncolors][30] = {
5073 "black", "white", "white", "gray50", "gray50",
5074 "gray100", "gray60", "gray80", "gray40",
5075 "gray90", "gray50", "gray70", "gray30"
5079 pr_color(cmap_t * cmap_ptr)
5081 unsigned long black = BlackPixel(dpy, scr), white = WhitePixel(dpy, scr);
5082 char option[20], color[30], *v, *ctype;
5084 double intensity = -1;
5087 if (pr_GetR(db, ".mono") && On(value.addr))
5089 if (pr_GetR(db, ".gray") && On(value.addr))
5091 if (pr_GetR(db, ".reverseVideo") && On(value.addr))
5094 if (!Gray && (vis->class == GrayScale || vis->class == StaticGray))
5099 ctype = (Gray) ? "Gray" : "Color";
5101 if (current_cmap != cmap_ptr) {
5102 /* for private colormaps: make sure
5103 * that pixel 0 gets black (joze) */
5107 XAllocColor(dpy, cmap_ptr->colormap, &xcolor);
5110 for (n = 0; n < Ncolors; n++) {
5111 strcpy(option, ".");
5112 strcat(option, color_keys[n]);
5114 strcat(option, ctype);
5115 v = pr_GetR(db, option) ? (char *) value.addr
5116 : ((Gray) ? gray_values[n]
5117 : (Rv ? color_values_rv[n] : color_values[n]));
5119 if (sscanf(v, "%30[^, ], %lf", color, &intensity) == 2) {
5120 if (intensity < 0 || intensity > 1) {
5121 fprintf(stderr, "\ngnuplot: invalid color intensity in '%s'\n", color);
5129 if (!XParseColor(dpy, cmap_ptr->colormap, color, &xcolor)) {
5130 fprintf(stderr, "\ngnuplot: unable to parse '%s'. Using black.\n", color);
5131 cmap_ptr->colors[n] = black;
5133 xcolor.red *= intensity;
5134 xcolor.green *= intensity;
5135 xcolor.blue *= intensity;
5136 if (XAllocColor(dpy, cmap_ptr->colormap, &xcolor)) {
5137 cmap_ptr->colors[n] = xcolor.pixel;
5138 cmap_ptr->rgbcolors[n] = ((xcolor.red>>8 & 0xff) << 16)
5139 + ((xcolor.green>>8 & 0xff) << 8)
5142 fprintf(stderr, "\ngnuplot: can't allocate '%s'. Using black.\n", v);
5143 cmap_ptr->colors[n] = black;
5148 cmap_ptr->colors[0] = (Rv) ? black : white;
5149 for (n = 1; n < Ncolors; n++)
5150 cmap_ptr->colors[n] = (Rv) ? white : black;
5154 /* create the xor GC just for allocating the xor value
5155 * before a palette is created. This way the xor foreground
5156 * will be available. */
5157 AllocateXorPixel(cmap_ptr);
5162 /*-----------------------------------------------------------------------------
5163 * pr_dashes - determine line dash styles
5164 *---------------------------------------------------------------------------*/
5166 static const char dash_keys[Ndashes][10] = {
5168 "line1", "line2", "line3", "line4", "line5", "line6", "line7", "line8"
5171 static char dash_mono[Ndashes][10] = {
5173 "0", "42", "13", "44", "15", "4441", "42", "13"
5176 static char dash_color[Ndashes][10] = {
5178 "0", "0", "0", "0", "0", "0", "0", "0"
5185 char option[20], *v;
5187 if (pr_GetR(db, ".dashed")) {
5188 dashedlines = (!strncasecmp(value.addr, "on", 2) || !strncasecmp(value.addr, "true", 4));
5191 for (n = 0; n < Ndashes; n++) {
5192 strcpy(option, ".");
5193 strcat(option, dash_keys[n]);
5194 strcat(option, "Dashes");
5195 v = pr_GetR(db, option)
5196 ? (char *) value.addr : ((Mono) ? dash_mono[n] : dash_color[n]);
5198 if (l == 1 && *v == '0') {
5199 dashes[n][0] = (unsigned char) 0;
5202 for (ok = 0, j = 0; j < l; j++) {
5203 if (v[j] >= '1' && v[j] <= '9')
5206 if (ok != l || (ok != 2 && ok != 4)) {
5207 fprintf(stderr, "gnuplot: illegal dashes value %s:%s\n",
5209 dashes[n][0] = (unsigned char) 0;
5212 for (j = 0; j < l; j++) {
5213 dashes[n][j] = (unsigned char) (v[j] - '0');
5215 dashes[n][l] = (unsigned char) 0;
5219 /*-----------------------------------------------------------------------------
5220 * pr_font - determine font
5221 *---------------------------------------------------------------------------*/
5223 /* wrapper functions */
5224 int gpXTextWidth (XFontStruct *cfont, const char *str, int count)
5226 #ifdef USE_X11_MULTIBYTE
5228 return XmbTextEscapement(mbfont, str, count);
5230 return XTextWidth(cfont, str, count);
5233 int gpXTextHeight (XFontStruct *cfont)
5235 #ifdef USE_X11_MULTIBYTE
5236 static XFontSetExtents *extents;
5238 extents = XExtentsOfFontSet(mbfont);
5239 return extents->max_logical_extent.height;
5242 return cfont->ascent + cfont->descent;
5245 void gpXSetFont (Display *disp, GC gc, Font fontid)
5247 #ifdef USE_X11_MULTIBYTE
5250 XSetFont(disp, gc, fontid);
5253 void gpXDrawImageString (Display *disp, Drawable d, GC gc, int x, int y,
5254 const char *str, int len)
5256 #ifdef USE_X11_MULTIBYTE
5258 XmbDrawImageString(disp, d, mbfont, gc, x, y, str, len);
5262 XDrawImageString(disp, d, gc, x, y, str, len);
5265 void gpXDrawString (Display *disp, Drawable d, GC gc, int x, int y,
5266 const char *str, int len)
5268 #ifdef USE_X11_MULTIBYTE
5270 XmbDrawString(disp, d, mbfont, gc, x, y, str, len);
5274 XDrawString(disp, d, gc, x, y, str, len);
5277 void gpXFreeFont(Display *disp, XFontStruct *cfont)
5279 #ifndef USE_X11_MULTIBYTE
5281 XFreeFont(disp, cfont);
5284 XFreeFont(disp, font);
5288 XFreeFontSet(disp, mbfont);
5294 XFontStruct *gpXLoadQueryFont (Display *disp, char *fontname)
5296 #ifndef USE_X11_MULTIBYTE
5297 return XLoadQueryFont(disp, fontname);
5299 static char **miss, *def;
5300 static TBOOLEAN first_time = TRUE;
5305 return XLoadQueryFont(disp, fontname);
5307 fontset_transsep(tmpfname, fontname, 256-1);
5308 mbfont = XCreateFontSet(disp, tmpfname, &miss, &n_miss, &def);
5310 /* This test seemed to make sense for Japanese locales, which only */
5311 /* claim to require a small number of character sets. But it is */
5312 /* highly likely to fail for more generic locales like en_US.UTF-8 */
5313 /* that claim to "require" about 2 dozen obscure character sets. */
5314 /* EAM - do not fail the request; just continue after a warning. */
5318 XFreeFontSet(disp, mbfont);
5323 fprintf(stderr,"gnuplot_x11: Some character sets not available\n");
5326 while (n_miss-- > 0)
5327 FPRINTF((stderr,"Missing charset: %s\n", miss[n_miss]));
5329 XFreeStringList(miss);
5337 char *gpFallbackFont(void)
5339 #ifdef USE_X11_MULTIBYTE
5341 return FallbackFontMB;
5343 return FallbackFont;
5346 int gpXGetFontascent(XFontStruct *cfont)
5348 #ifndef USE_X11_MULTIBYTE
5349 return cfont->ascent;
5351 static XFontStruct **eachfonts;
5356 if(!usemultibyte) return font->ascent;
5357 n_fonts = XFontsOfFontSet(mbfont, &eachfonts, &fontnames);
5358 for (i = 0; i < n_fonts; i++) {
5359 if (eachfonts[i]->ascent > max_ascent)
5360 max_ascent = eachfonts[i]->ascent;
5366 #ifdef USE_X11_MULTIBYTE
5367 int fontset_transsep(char *nfname, char *ofname, int n)
5371 strncpy(nfname, ofname, n);
5372 if (nfname[n-1]!='\0')
5374 if (strchr(nfname, ','))
5377 while ((s = strchr(nfname, FontSetSep)) != NULL){
5389 if ((encoding = pr_GetR(db, ".encoding"))) {
5390 strncpy(default_encoding, encoding, sizeof(default_encoding)-1);
5398 static char previous_font_name[128];
5401 #ifdef USE_X11_MULTIBYTE
5402 char *orgfontname = NULL;
5405 if (!fontname || !(*fontname))
5406 fontname = default_font;
5408 if (!fontname || !(*fontname)) {
5409 if ((fontname = pr_GetR(db, ".font")))
5410 strncpy(default_font, fontname, sizeof(default_font)-1);
5411 FPRINTF((stderr, "gnuplot_x11: setting default font %s from Xresource\n",
5415 #ifdef USE_X11_MULTIBYTE
5416 if (fontname && strncmp(fontname, "mbfont:", 7) == 0) {
5417 if (multibyte_fonts_usable) {
5419 orgfontname = fontname;
5420 fontname = &fontname[7];
5425 } else usemultibyte=0;
5428 fontname = gpFallbackFont();
5430 /* EAM DEBUG - Free previous font before searching for a new one. */
5431 /* This doesn't seem right, since we will probably need it again */
5432 /* very soon. But if we don't free it, we gradually leak memory. */
5433 gpXFreeFont(dpy, font);
5435 font = gpXLoadQueryFont(dpy, fontname);
5437 #ifndef USE_X11_MULTIBYTE
5440 if (!font && !mbfont && !strchr(fontname, FontSetSep)) {
5442 /* EAM 19-Aug-2002 Try to construct a plausible X11 full font spec */
5443 /* We are passed "font<, size><, slant>" */
5444 char shortname[64], *fontencoding, slant, *weight;
5446 #ifdef USE_X11_MULTIBYTE
5450 /* Enhanced font processing wants a method of requesting a new size */
5451 /* for whatever the previously selected font was, so we have to save */
5452 /* and reuse the previous font name to construct the new spec. */
5453 if (!strncmp(fontname, "DEFAULT", 7)) {
5454 sscanf(&fontname[8], "%d", &fontsize);
5455 fontname = default_font;
5456 #ifdef USE_X11_MULTIBYTE
5459 } else if (*fontname == ',') {
5460 sscanf(&fontname[1], "%d", &fontsize);
5461 fontname = previous_font_name;
5462 #ifdef USE_X11_MULTIBYTE
5466 #ifdef USE_X11_MULTIBYTE
5467 if (backfont && fontname && strncmp(fontname, "mbfont:", 7) == 0
5468 && multibyte_fonts_usable) {
5470 orgfontname = fontname;
5471 fontname = &fontname[7];
5475 sep = strcspn(fontname, ",");
5476 if (sep >= sizeof(shortname))
5477 sep = sizeof(shortname) - 1;
5478 strncpy(shortname, fontname, sep);
5479 shortname[sep] = '\0';
5481 sscanf( &(fontname[sep+1]), "%d", &fontsize);
5482 if (fontsize > 99 || fontsize < 1)
5485 slant = strstr(&fontname[sep+1], "italic") ? 'i' :
5486 strstr(&fontname[sep+1], "oblique") ? 'o' :
5489 weight = strstr(&fontname[sep+1], "bold") ? "bold" :
5490 strstr(&fontname[sep+1], "medium") ? "medium" :
5493 if (!strncmp("Symbol", shortname, 6) || !strncmp("symbol", shortname, 6))
5494 fontencoding = "*-*";
5495 #ifdef USE_X11_MULTIBYTE
5496 else if (usemultibyte)
5497 fontencoding = "*-*";
5501 encoding == S_ENC_CP437 ? "dosencoding-cp437" :
5502 encoding == S_ENC_CP850 ? "dosencoding-cp850" :
5503 encoding == S_ENC_ISO8859_1 ? "iso8859-1" :
5504 encoding == S_ENC_ISO8859_2 ? "iso8859-2" :
5505 encoding == S_ENC_ISO8859_15 ? "iso8859-15" :
5506 encoding == S_ENC_KOI8_R ? "koi8-r" :
5507 encoding == S_ENC_KOI8_U ? "koi8-u" :
5508 default_encoding[0] ? default_encoding :
5511 sprintf(fontspec, "-*-%s-%s-%c-*-*-%d-*-*-*-*-*-%s",
5512 shortname, weight, slant, fontsize, fontencoding
5514 font = gpXLoadQueryFont(dpy, fontspec);
5516 #ifndef USE_X11_MULTIBYTE
5519 if (!font && !mbfont) {
5521 /* Try to decode some common PostScript font names */
5522 if (!strcmp("Times-Bold", shortname)
5523 || !strcmp("times-bold", shortname)) {
5524 sprintf(fontspec, "-*-times-bold-r-*-*-%d-*-*-*-*-*-%s",
5525 fontsize, fontencoding);
5526 } else if (!strcmp("Times-Roman", shortname)
5527 || !strcmp("times-roman", shortname)) {
5528 sprintf(fontspec, "-*-times-medium-r-*-*-%d-*-*-*-*-*-%s",
5529 fontsize, fontencoding);
5530 } else if (!strcmp("Times-Italic", shortname)
5531 || !strcmp("times-italic", shortname)) {
5532 sprintf(fontspec, "-*-times-medium-i-*-*-%d-*-*-*-*-*-%s",
5533 fontsize, fontencoding);
5534 } else if (!strcmp("Times-BoldItalic", shortname)
5535 || !strcmp("times-bolditalic", shortname)) {
5536 sprintf(fontspec, "-*-times-bold-i-*-*-%d-*-*-*-*-*-%s",
5537 fontsize, fontencoding);
5538 } else if (!strcmp("Helvetica-Bold", shortname) ||
5539 !strcmp("helvetica-bold", shortname)) {
5540 sprintf(fontspec, "-*-helvetica-bold-r-*-*-%d-*-*-*-*-*-%s",
5541 fontsize, fontencoding);
5542 } else if (!strcmp("Helvetica-Oblique", shortname)
5543 || !strcmp("helvetica-oblique", shortname)) {
5544 sprintf(fontspec, "-*-helvetica-medium-o-*-*-%d-*-*-*-*-*-%s",
5545 fontsize, fontencoding);
5546 } else if (!strcmp("Helvetica-BoldOblique", shortname)
5547 || !strcmp("helvetica-boldoblique", shortname)) {
5548 sprintf(fontspec, "-*-helvetica-bold-o-*-*-%d-*-*-*-*-*-%s",
5549 fontsize, fontencoding);
5550 } else if (!strcmp("Helvetica-Narrow-Bold", shortname)
5551 || !strcmp("helvetica-narrow-bold", shortname)) {
5552 sprintf(fontspec, "-*-arial narrow-bold-r-*-*-%d-*-*-*-*-*-%s",
5553 fontsize, fontencoding);
5555 #ifdef USE_X11_MULTIBYTE
5556 /* Japanese standard PostScript font names (adviced from
5558 else if (multibyte_fonts_usable
5559 && (!strncmp("Ryumin-Light", shortname,
5560 strlen("Ryumin-Light"))
5561 || !strncmp("ryumin-light", shortname,
5562 strlen("ryumin-light")))) {
5563 if (!usemultibyte) {
5565 orgfontname = fontname;
5567 sprintf(fontspec, "-*-mincho-medium-%c-*--%d-*",
5570 else if (multibyte_fonts_usable
5571 && (!strncmp("GothicBBB-Medium", shortname,
5572 strlen("GothicBBB-Medium"))
5573 || !strncmp("gothicbbb-medium", shortname,
5574 strlen("gothicbbb-medium")))) {
5575 if (!usemultibyte) {
5577 orgfontname = fontname;
5579 /* FIXME: Doesn't work on most non-japanese setups, because */
5580 /* many purely Western fonts are gothic-bold. */
5581 sprintf(fontspec, "-*-gothic-bold-%c-*--%d-*", slant, fontsize);
5583 #endif /* USE_X11_MULTIBYTE */
5584 font = gpXLoadQueryFont(dpy, fontspec);
5586 #ifdef USE_X11_MULTIBYTE
5587 if (usemultibyte && !mbfont) {
5588 /* But (mincho|gothic) X fonts are not provided
5589 * on some X servers even in Japan
5591 sprintf(fontspec, "*-%s-%c-*--%d-*", weight, slant, fontsize);
5592 font = gpXLoadQueryFont(dpy, fontspec);
5594 #endif /* USE_X11_MULTIBYTE */
5599 #ifndef USE_X11_MULTIBYTE
5602 if (font || mbfont) {
5603 if (usemultibyte && orgfontname)
5604 fontname = orgfontname;
5606 strncpy(previous_font_name, fontname, sizeof(previous_font_name)-1);
5607 FPRINTF((stderr, "gnuplot_x11:saving current font name \"%s\"\n", previous_font_name));
5610 /* By now we have tried everything we can to honor the specific request. */
5611 /* Try some common scaleable fonts before falling back to a last resort */
5613 #ifndef USE_X11_MULTIBYTE
5616 if (!usemultibyte && !font) {
5618 sprintf(fontspec, "-*-bitstream vera sans-bold-r-*-*-%d-*-*-*-*-*-*-*", fontsize);
5619 font = gpXLoadQueryFont(dpy, fontspec);
5620 fontname = fontspec;
5622 sprintf(fontspec, "-*-arial-medium-r-*-*-%d-*-*-*-*-*-*-*", fontsize);
5623 font = gpXLoadQueryFont(dpy, fontspec);
5626 sprintf(fontspec, "-*-helvetica-medium-r-*-*-%d-*-*-*-*-*-*", fontsize);
5627 font = gpXLoadQueryFont(dpy, fontspec);
5630 font = gpXLoadQueryFont(dpy, gpFallbackFont());
5631 fontname = gpFallbackFont();
5634 fprintf(stderr, "\ngnuplot_x11: can't find usable font - X11 aborted.\n");
5637 FPRINTF((stderr, "\ngnuplot_x11: requested font not found, using '%s' instead.\n", fontname));
5639 #ifdef USE_X11_MULTIBYTE
5640 if (usemultibyte && !mbfont) { /* multibyte font setting */
5641 font = gpXLoadQueryFont(dpy, gpFallbackFont());
5644 font = gpXLoadQueryFont(dpy, gpFallbackFont());
5646 fprintf(stderr, "\ngnuplot_x11: can't find usable font - X11 aborted.\n");
5650 fontname = gpFallbackFont();
5652 #endif /* USE_X11_MULTIBYTE */
5654 vchar = gpXTextHeight(font);
5655 hchar = gpXTextWidth(font, "0123456789", 10) / 10;
5657 FPRINTF((stderr, "gnuplot_x11: pr_font() set font %s, vchar %d hchar %d\n",
5658 fontname, vchar, hchar));
5662 /*-----------------------------------------------------------------------------
5663 * pr_geometry - determine window geometry
5664 *---------------------------------------------------------------------------*/
5667 pr_geometry(char *instr)
5669 char *geometry = (instr != NULL)? instr : pr_GetR(db, ".geometry");
5674 flags = XParseGeometry(geometry, &x, &y, &w, &h);
5675 if (flags & WidthValue)
5677 if (flags & HeightValue)
5679 if (flags & (WidthValue | HeightValue))
5680 gFlags = (gFlags & ~PSize) | USSize;
5683 gX = (flags & XNegative) ? x + DisplayWidth(dpy, scr) - gW - BorderWidth * 2 : x;
5686 gY = (flags & YNegative) ? y + DisplayHeight(dpy, scr) - gH - BorderWidth * 2 : y;
5688 if (flags & (XValue | YValue))
5689 gFlags = (gFlags & ~PPosition) | USPosition;
5693 /*-----------------------------------------------------------------------------
5694 * pr_pointsize - determine size of points for 'points' plotting style
5695 *---------------------------------------------------------------------------*/
5700 if (pr_GetR(db, ".pointsize")) {
5701 if (sscanf((char *) value.addr, "%lf", &pointsize) == 1) {
5702 if (pointsize <= 0 || pointsize > 10) {
5703 fprintf(stderr, "\ngnuplot: invalid pointsize '%s'\n", value.addr);
5707 fprintf(stderr, "\ngnuplot: invalid pointsize '%s'\n", value.addr);
5715 /*-----------------------------------------------------------------------------
5716 * pr_width - determine line width values
5717 *---------------------------------------------------------------------------*/
5719 static const char width_keys[Nwidths][30] = {
5721 "line1", "line2", "line3", "line4", "line5", "line6", "line7", "line8"
5728 char option[20], *v;
5730 for (n = 0; n < Nwidths; n++) {
5731 strcpy(option, ".");
5732 strcat(option, width_keys[n]);
5733 strcat(option, "Width");
5734 if ((v = pr_GetR(db, option)) != NULL) {
5735 if (*v < '0' || *v > '9' || strlen(v) > 1)
5736 fprintf(stderr, "gnuplot: illegal width value %s:%s\n", option, v);
5738 widths[n] = (unsigned int) atoi(v);
5743 /*-----------------------------------------------------------------------------
5744 * pr_window - create window
5745 *---------------------------------------------------------------------------*/
5747 ProcessEvents(Window win)
5749 XSelectInput(dpy, win, KeyPressMask | KeyReleaseMask
5750 | StructureNotifyMask | PointerMotionMask | PointerMotionHintMask
5751 | ButtonPressMask | ButtonReleaseMask | ExposureMask | EnterWindowMask);
5756 pr_window(plot_struct *plot)
5758 char *title = pr_GetR(db, ".title");
5759 static XSizeHints hints;
5762 FPRINTF((stderr, "(pr_window) \n"));
5765 XSetWindowAttributes attr;
5766 unsigned long mask = CWBackPixel | CWBorderPixel | CWColormap;
5767 attr.background_pixel = plot->cmap->colors[0];
5768 attr.border_pixel = plot->cmap->colors[1];
5769 attr.colormap = plot->cmap->colormap;
5770 plot->window = XCreateWindow(dpy, root, plot->x, plot->y, plot->width,
5771 plot->height, BorderWidth, dep, InputOutput, vis, mask, &attr);
5773 plot->window = XCreateSimpleWindow(dpy, root, plot->x, plot->y,
5774 plot->width, plot->height, BorderWidth, plot->cmap->colors[1], plot->cmap->colors[0]);
5776 /* Return if something wrong. */
5780 /* ask ICCCM-compliant window manager to tell us when close window
5781 * has been chosen, rather than just killing us
5784 XChangeProperty(dpy, plot->window, WM_PROTOCOLS, XA_ATOM, 32, PropModeReplace, (unsigned char *) &WM_DELETE_WINDOW, 1);
5786 if (pr_GetR(db, ".clear") && On(value.addr))
5788 if (pr_GetR(db, ".tvtwm") && On(value.addr))
5792 hints.flags = plot->posn_flags;
5794 hints.flags = (plot->posn_flags & ~USPosition) | PPosition; /* ? */
5798 hints.width = plot->width;
5799 hints.height = plot->height;
5801 XSetNormalHints(dpy, plot->window, &hints);
5803 if (pr_GetR(db, ".iconic") && On(value.addr)) {
5806 wmh.flags = StateHint;
5807 wmh.initial_state = IconicState;
5808 XSetWMHints(dpy, plot->window, &wmh);
5810 #if 0 /* 1 clear, 0 do not clear */
5811 if (plot->titlestring) {
5812 free(plot->titlestring);
5813 plot->titlestring = 0;
5817 ProcessEvents(plot->window);
5819 /* If title doesn't exist, create one. */
5821 #define ICON_TEXT "gplt"
5822 #define TEMP_NUM_LEN 16
5824 /* append the X11 terminal number (if greater than zero) */
5825 char numstr[sizeof(ICON_TEXT)+TEMP_NUM_LEN+1]; /* space for text, number and terminating \0 */
5826 if (plot->plot_number)
5827 sprintf(numstr, "%s%d%c", ICON_TEXT, plot->plot_number, '\0');
5829 sprintf(numstr, "%s%c", ICON_TEXT, '\0');
5830 FPRINTF((stderr, "term_number is %d", plot->plot_number));
5831 XSetIconName(dpy, plot->window, numstr);
5833 if (!plot->titlestring) {
5835 if (!title) title = X_Class;
5836 orig_len = strlen(title);
5837 /* memory for text, white space, number and terminating \0 */
5838 if ((plot->titlestring = (char *) malloc(orig_len + ((orig_len && plot->plot_number) ? 1 : 0) + strlen(numstr) - strlen(ICON_TEXT) + 1))) {
5839 strcpy(plot->titlestring, title);
5840 if (orig_len && plot->plot_number)
5841 plot->titlestring[orig_len++] = ' ';
5842 strcpy(plot->titlestring + orig_len, numstr + strlen(ICON_TEXT));
5843 XStoreName(dpy, plot->window, plot->titlestring);
5845 XStoreName(dpy, plot->window, title);
5847 XStoreName(dpy, plot->window, plot->titlestring);
5853 XMapWindow(dpy, plot->window);
5859 /***** pr_raise ***/
5863 if (pr_GetR(db, ".raise"))
5864 do_raise = (On(value.addr));
5871 if (pr_GetR(db, ".persist"))
5872 persist = (On(value.addr));
5878 if (pr_GetR(db, ".feedback"))
5879 feedback = !(!strncasecmp(value.addr, "off", 3) || !strncasecmp(value.addr, "false", 5));
5880 FPRINTF((stderr, "gplt_x11: set feedback to %d (%s)\n", feedback, value.addr));
5886 if (pr_GetR(db, ".ctrlq")) {
5887 ctrlq = (!strncasecmp(value.addr, "on", 2) || !strncasecmp(value.addr, "true", 4));
5888 FPRINTF((stderr, "gplt_x11: require <ctrl>q and <ctrl><space>\n"));
5895 if (pr_GetR(db, ".fastrotate")) {
5896 fast_rotate = (!strncasecmp(value.addr, "on", 2) || !strncasecmp(value.addr, "true", 4));
5897 FPRINTF((stderr, "gplt_x11: Use fast but imperfect text rotation\n"));
5901 #ifdef EXPORT_SELECTION
5903 pr_exportselection()
5905 /* Allow export selection to be turned on or off using X resource *exportselection */
5906 if (pr_GetR(db, ".exportselection")) {
5907 if (!strncmp((char *)value.addr, "off", 3) || !strncmp((char *)value.addr, "false", 5)) {
5908 exportselection = FALSE;
5909 FPRINTF((stderr, "gnuplot_x11: exportselection is disabled\n"));
5915 /************ code to handle selection export *********************/
5917 #ifdef EXPORT_SELECTION
5919 /* bit of a bodge, but ... */
5920 static struct plot_struct *exported_plot;
5921 static Time export_time;
5924 export_graph(struct plot_struct *plot)
5926 FPRINTF((stderr, "export_graph(0x%x)\n", plot));
5928 XSetSelectionOwner(dpy, EXPORT_SELECTION, plot->window, CurrentTime);
5929 /* to check we have selection, we would have to do a
5930 * GetSelectionOwner(), but if it failed, it failed - no big deal
5933 exported_plot = plot;
5934 export_time = (!plot || !(plot->time)) ? 1 : plot->time;
5939 handle_selection_event(XEvent *event)
5941 switch (event->type) {
5942 case SelectionRequest:
5946 static Atom XA_TARGETS = (Atom) 0;
5947 static Atom XA_TIMESTAMP = (Atom) 0;
5949 if (XA_TARGETS == 0)
5950 XA_TARGETS = XInternAtom(dpy, "TARGETS", False);
5951 if (XA_TIMESTAMP == 0)
5952 XA_TIMESTAMP = XInternAtom(dpy, "TIMESTAMP", False);
5954 reply.type = SelectionNotify;
5955 reply.xselection.send_event = True;
5956 reply.xselection.display = event->xselectionrequest.display;
5957 reply.xselection.requestor = event->xselectionrequest.requestor;
5958 reply.xselection.selection = event->xselectionrequest.selection;
5959 reply.xselection.target = event->xselectionrequest.target;
5960 reply.xselection.property = event->xselectionrequest.property;
5961 reply.xselection.time = event->xselectionrequest.time;
5963 if (reply.xselection.target == XA_TARGETS) {
5964 static Atom targets[] = { XA_PIXMAP, XA_COLORMAP };
5965 static Atom mousecoord[] = { XA_STRING };
5967 FPRINTF((stderr, "Targets request from %d\n", reply.xselection.requestor));
5970 XChangeProperty(dpy, reply.xselection.requestor,
5971 reply.xselection.property, reply.xselection.target,
5972 32, PropModeReplace, (unsigned char *) (mousecoord), 1);
5973 else if (exported_plot)
5974 XChangeProperty(dpy, reply.xselection.requestor,
5975 reply.xselection.property, reply.xselection.target,
5976 32, PropModeReplace, (unsigned char *) targets, 2);
5977 } else if (reply.xselection.target == XA_COLORMAP) {
5979 FPRINTF((stderr, "colormap request from %d\n", reply.xselection.requestor));
5981 XChangeProperty(dpy, reply.xselection.requestor,
5982 reply.xselection.property, reply.xselection.target,
5983 32, PropModeReplace, (unsigned char *) &(default_cmap.colormap), 1);
5984 } else if (reply.xselection.target == XA_PIXMAP && exported_plot) {
5986 FPRINTF((stderr, "pixmap request from %d\n", reply.xselection.requestor));
5988 XChangeProperty(dpy, reply.xselection.requestor,
5989 reply.xselection.property, reply.xselection.target,
5990 32, PropModeReplace, (unsigned char *) &(exported_plot->pixmap), 1);
5991 exported_plot = NULL;
5992 } else if (reply.xselection.target == XA_TIMESTAMP) {
5994 FPRINTF((stderr, "timestamp request from %d : %ld\n",
5995 reply.xselection.requestor, export_time));
5997 XChangeProperty(dpy, reply.xselection.requestor,
5998 reply.xselection.property, reply.xselection.target,
5999 32, PropModeReplace, (unsigned char *) &(export_time), 1);
6001 } else if (reply.xselection.target == XA_STRING && *selection) {
6002 FPRINTF((stderr, "XA_STRING request\n"));
6003 XChangeProperty(dpy, reply.xselection.requestor,
6004 reply.xselection.property, reply.xselection.target,
6005 8, PropModeReplace, (unsigned char *) selection, strlen(selection));
6009 FPRINTF((stderr, "selection request target: %d\n", reply.xselection.target));
6010 reply.xselection.property = None;
6011 if (!exported_plot && ! *selection)
6012 /* We have now satisfied the select request. Say goodbye */
6013 XSetSelectionOwner(dpy, EXPORT_SELECTION, None, CurrentTime);
6016 XSendEvent(dpy, reply.xselection.requestor, False, 0L, &reply);
6017 /* we never block on XNextEvent(), so must flush manually
6018 * (took me *ages* to find this out !)
6027 #endif /* EXPORT_SELECTION */
6029 #if defined(USE_MOUSE) && defined(MOUSE_ALL_WINDOWS)
6030 /* Convert X-window mouse coordinates to coordinate system of plot axes */
6032 mouse_to_coords(plot_struct *plot, XEvent *event,
6033 double *x, double *y, double *x2, double *y2)
6035 int xx = 4096. * (event->xbutton.x + 0.5)/ plot->width;
6036 int yy = 4095. - 4096. * (event->xbutton.y + 0.5)/ plot->gheight;
6038 FPRINTF((stderr, "gnuplot_x11 %d: mouse at %d %d\t", __LINE__, xx, yy));
6040 *x = mouse_to_axis(xx, &(plot->axis_scale[FIRST_X_AXIS]));
6041 *y = mouse_to_axis(yy, &(plot->axis_scale[FIRST_Y_AXIS]));
6042 *x2 = mouse_to_axis(xx, &(plot->axis_scale[SECOND_X_AXIS]));
6043 *y2 = mouse_to_axis(yy, &(plot->axis_scale[SECOND_Y_AXIS]));
6045 FPRINTF((stderr, "mouse x y %10g %10g x2 y2 %10g %10g\n", *x, *y, *x2, *y2 ));
6049 mouse_to_axis(int mouse_coord, axis_scale_t *axis)
6053 if (axis->term_scale == 0.0)
6056 axis_coord = ((double)(mouse_coord - axis->term_lower)) / axis->term_scale + axis->min;
6057 if (axis->logbase > 0.0)
6058 axis_coord = exp(axis_coord * axis->logbase);
6065 /*-----------------------------------------------------------------------------
6066 * Add_Plot_To_Linked_List - Create space for plot and put in linked list.
6067 *---------------------------------------------------------------------------*/
6069 static plot_struct *
6070 Add_Plot_To_Linked_List(int plot_number)
6072 /* Make sure plot does not already exist in the list. */
6073 plot_struct *psp = Find_Plot_In_Linked_List_By_Number(plot_number);
6076 psp = (plot_struct *) malloc(sizeof(plot_struct));
6078 /* Initialize structure variables. */
6079 memset((void*)psp, 0, sizeof(plot_struct));
6080 psp->plot_number = plot_number;
6081 /* Add link to beginning of the list. */
6082 psp->prev_plot = NULL;
6083 if (plot_list_start != NULL) {
6084 plot_list_start->prev_plot = psp;
6085 psp->next_plot = plot_list_start;
6087 psp->next_plot = NULL;
6088 plot_list_start = psp;
6092 fprintf(stderr, ERROR_NOTICE("Could not allocate memory for plot.\n\n"));
6100 /*-----------------------------------------------------------------------------
6101 * Remove_Plot_From_Linked_List - Remove from linked list and free memory.
6102 *---------------------------------------------------------------------------*/
6105 Remove_Plot_From_Linked_List(Window plot_window)
6107 /* Make sure plot exists in the list. */
6108 plot_struct *psp = Find_Plot_In_Linked_List_By_Window(plot_window);
6111 /* Remove link from the list. */
6112 if (psp->next_plot != NULL)
6113 psp->next_plot->prev_plot = psp->prev_plot;
6114 if (psp->prev_plot != NULL) {
6115 psp->prev_plot->next_plot = psp->next_plot;
6117 plot_list_start = psp->next_plot;
6119 /* If global pointers point at this plot, reassign them. */
6120 if (current_plot == psp) {
6121 #if 0 /* Make some other plot current. */
6122 if (psp->prev_plot != NULL)
6123 current_plot = psp->prev_plot;
6125 current_plot = psp->next_plot;
6126 #else /* No current plot. */
6127 current_plot = NULL;
6131 plot = current_plot;
6132 /* Deallocate memory. Make sure plot removed from list first. */
6139 /*-----------------------------------------------------------------------------
6140 * Find_Plot_In_Linked_List_By_Number - Search for the plot in the linked list.
6141 *---------------------------------------------------------------------------*/
6143 static plot_struct *
6144 Find_Plot_In_Linked_List_By_Number(int plot_number)
6146 plot_struct *psp = plot_list_start;
6148 while (psp != NULL) {
6149 if (psp->plot_number == plot_number)
6151 psp = psp->next_plot;
6158 /*-----------------------------------------------------------------------------
6159 * Find_Plot_In_Linked_List_By_Window - Search for the plot in the linked list.
6160 *---------------------------------------------------------------------------*/
6162 static plot_struct *
6163 Find_Plot_In_Linked_List_By_Window(Window window)
6165 plot_struct *psp = plot_list_start;
6167 while (psp != NULL) {
6168 if (psp->window == window)
6170 psp = psp->next_plot;
6177 /*-----------------------------------------------------------------------------
6178 * Find_Plot_In_Linked_List_By_CMap - Search for the plot in the linked list.
6179 *---------------------------------------------------------------------------*/
6181 static plot_struct *
6182 Find_Plot_In_Linked_List_By_CMap(cmap_t *cmp)
6184 plot_struct *psp = plot_list_start;
6186 while (psp != NULL) {
6187 if (psp->cmap == cmp)
6189 psp = psp->next_plot;
6196 /* NOTE: The removing of plots via the ErrorHandler routine is rather
6197 tricky. The error events can happen at any time during execution of
6198 the program, very similar to an interrupt. The consequence is that
6199 the error handling routine can't remove plots from the linked list
6200 directly. Instead we use a queuing system in which the main code
6201 eventually removes the plots.
6203 Furthermore, to be safe, only the error handling routine should create
6204 and delete elements in the FIFO. Otherwise, the possibility of bogus
6205 pointers can arise if error events happen at the exact wrong time.
6206 (Requires a lot of thought.)
6208 The scheme here is for the error handler to put elements in the
6209 queue marked as "processed = 0" and then indicate that the main
6210 code should process elements in the queue. The main code then
6211 copies the information about the plot to remove and sets the value
6212 "processed = 1". Afterward the main code removes the plot.
6215 /*-----------------------------------------------------------------------------
6216 * Add_Plot_To_Remove_FIFO_Queue - Method for error handler to destroy plot.
6217 *---------------------------------------------------------------------------*/
6220 Add_Plot_To_Remove_FIFO_Queue(Window plot_window)
6222 /* Clean up any processed links. */
6223 plot_remove_struct *prsp = remove_fifo_queue_start;
6224 FPRINTF((stderr, "Add plot to remove FIFO queue called.\n"));
6225 while (prsp != NULL) {
6226 if (prsp->processed) {
6227 remove_fifo_queue_start = prsp->next_remove;
6229 prsp = remove_fifo_queue_start;
6230 FPRINTF((stderr, " -> Removed a processed element from FIFO queue.\n"));
6236 /* Go to end of list while checking if this window is already in list. */
6237 while (prsp != NULL) {
6238 if (prsp->plot_window_to_remove == plot_window) {
6239 /* Discard this request because the same window is yet to be processed.
6240 X11 could be stuck sending the same error message again and again
6241 while the main program is not responding for some reason. This would
6242 lead to the FIFO queue growing indefinitely. */
6245 if (prsp->next_remove == NULL)
6248 prsp = prsp->next_remove;
6251 /* Create link and add to end of queue. */
6252 {plot_remove_struct *prsp_new = (plot_remove_struct *) malloc(sizeof(plot_remove_struct));
6254 /* Initialize structure variables. */
6255 prsp_new->next_remove = NULL;
6256 prsp_new->plot_window_to_remove = plot_window;
6257 prsp_new->processed = 0;
6258 if (remove_fifo_queue_start)
6259 prsp->next_remove = prsp_new;
6261 remove_fifo_queue_start = prsp_new;
6262 process_remove_fifo_queue = 1; /* Indicate to main loop that there is a plot to remove. */
6263 FPRINTF((stderr, " -> Added an element to FIFO queue.\n"));
6266 fprintf(stderr, ERROR_NOTICE("Could not allocate memory for plot remove queue.\n\n"));
6271 /*-----------------------------------------------------------------------------
6272 * Process_Remove_FIFO_Queue - Remove plots queued by error handler.
6273 *---------------------------------------------------------------------------*/
6276 Process_Remove_FIFO_Queue()
6278 plot_remove_struct *prsp = remove_fifo_queue_start;
6280 /* Clear flag before processing so that if an ErrorHandler event
6281 * comes along while running the remainder of this routine, any new
6282 * error events that were missed because of timing issues will be
6283 * processed next time through the main loop.
6285 process_remove_fifo_queue = 0;
6287 /* Go through the list and process any unprocessed queue request.
6288 * No clean up is done here because having two asynchronous routines
6289 * modifying the queue would be too dodgy. The ErrorHandler creates
6290 * and removes links in the queue based upon the processed flag.
6292 while (prsp != NULL) {
6294 /* Make a copy of the remove information structure before changing flag.
6295 * Otherwise, there would be the possibility of the error handler routine
6296 * removing the associated link upon seeing the "processed" flag set. From
6297 * this side of things, the pointer becomes invalid once that flag is set.
6299 plot_remove_struct prs;
6300 prs.plot_window_to_remove = prsp->plot_window_to_remove;
6301 prs.next_remove = prsp->next_remove;
6302 prs.processed = prsp->processed;
6304 /* Set processed flag before processing the event. This is so
6305 * that the FIFO queue does not have to repeat window entries.
6306 * If the error handler were to break in right before the
6307 * "processed" flag is set to 1 and not put another link in
6308 * the FIFO because it sees the window in question is already
6309 * in the FIFO, we're OK. The reason is that the window in
6310 * question is still to be processed. On the other hand, if
6311 * we were to process then set the flag, an entry in the queue
6312 * could potentially be lost.
6314 prsp->processed = 1;
6315 FPRINTF((stderr, "Processed element in remove FIFO queue.\n"));
6317 /* NOW process the plot to remove. */
6319 Remove_Plot_From_Linked_List(prs.plot_window_to_remove);
6321 prsp = prs.next_remove;
6324 /* Issue an X11 error so that error handler cleans up queue?
6325 * Really, this isn't super important. Without issuing a bogus
6326 * error, the processed queue elements will be deleted the
6327 * next time there is an error. Until another error comes
6328 * along it means there is maybe ten or so words of memory
6329 * reserved on the heap for the FIFO queue. In some sense,
6330 * the extra code is hardly worth the effort, especially
6331 * when X11 documentation is so sparse on the matter of errors.
6338 /* Extract details about the extent of a bit mask by doing a
6339 * single bit shift up and then down (left shift) and down
6340 * and then up (right shift). When the pre- and post-shift
6341 * numbers are not equal, a bit was lost so that is the
6342 * extent of the mask.
6344 static unsigned short
6345 BitMaskDetails(unsigned long mask, unsigned short *left_shift, unsigned short *right_shift)
6348 unsigned long m = mask;
6356 for (i=0; i < 32; i++) {
6357 if ( (((m << 1)&0xffffffff) >> 1) != m )
6365 for (i=0; i < 32 ; i++) {
6366 if ( ((m >> 1) << 1) != m )
6373 return (unsigned short) m;
6378 /*-----------------------------------------------------------------------------
6379 * Add_CMap_To_Linked_List - Create space for colormap and put in linked list.
6380 *---------------------------------------------------------------------------*/
6383 Add_CMap_To_Linked_List(void)
6385 cmap_t *cmp = (cmap_t *) malloc(sizeof(cmap_t));
6387 /* Add link to beginning of the list. */
6388 cmp->prev_cmap = NULL;
6389 if (cmap_list_start != NULL) {
6390 cmap_list_start->prev_cmap = cmp;
6391 cmp->next_cmap = cmap_list_start;
6393 cmp->next_cmap = NULL;
6394 cmap_list_start = cmp;
6397 fprintf(stderr, ERROR_NOTICE("Could not allocate memory for color map.\n\n"));
6399 /* Initialize structure variables. */
6401 cmp->colormap = XCreateColormap(dpy, root, vis, AllocNone);
6402 assert(cmp->colormap);
6403 pr_color(cmp); /* set default colors for lines */
6408 /*-----------------------------------------------------------------------------
6409 * Remove_CMap_From_Linked_List - Remove from linked list and free memory.
6410 *---------------------------------------------------------------------------*/
6413 Remove_CMap_From_Linked_List(cmap_t *cmp)
6415 /* Make sure colormap exists in the list. */
6416 cmp = Find_CMap_In_Linked_List(cmp);
6419 /* Remove link from the list. */
6420 if (cmp->next_cmap != NULL)
6421 cmp->next_cmap->prev_cmap = cmp->prev_cmap;
6422 if (cmp->prev_cmap != NULL) {
6423 cmp->prev_cmap->next_cmap = cmp->next_cmap;
6425 cmap_list_start = cmp->next_cmap;
6427 /* If global pointers point at this plot, reassign them. */
6428 if (current_cmap == cmp) {
6429 #if 0 /* Make some other cmap current. */
6430 if (cmp->prev_cmap != NULL)
6431 current_cmap = cmp->prev_cmap;
6433 current_cmap = psp->next_cmap;
6434 #else /* No current cmap. */
6435 current_cmap = &default_cmap;
6438 /* Remove any memory for pixels and memory for colormap structure. */
6439 ReleaseColormap(cmp);
6444 /*-----------------------------------------------------------------------------
6445 * Find_CMap_In_Linked_List - Search for the color map in the linked list.
6446 *---------------------------------------------------------------------------*/
6449 Find_CMap_In_Linked_List(cmap_t *colormap)
6451 cmap_t *cmp = cmap_list_start;
6453 while (cmp != NULL) {
6454 if (cmp == colormap)
6456 cmp = cmp->next_cmap;
6463 /*-----------------------------------------------------------------------------
6464 * cmaps_differ - Compare two colormaps, return 1 if differ.
6465 *---------------------------------------------------------------------------*/
6468 cmaps_differ(cmap_t *cmap1, cmap_t *cmap2)
6471 /* First compare non-pointer elements. */
6472 if ( memcmp(&(cmap1->colors[0]), &(cmap2->colors[0]), (long)&(cmap1->pixels)-(long)&(cmap1->colors[0])) )
6475 /* Now compare pointer elements. */
6476 if (cmap1->allocated) {
6477 if (cmap1->pixels && cmap2->pixels) {
6478 if ( memcmp(cmap1->pixels, cmap2->pixels, cmap1->allocated*sizeof(cmap1->pixels[0])) )
6484 return 0; /* They are the same. */
6489 * Shared code for setting fill style
6492 x11_setfill(GC *gc, int style, TBOOLEAN poly)
6495 XColor xcolor, bgnd;
6498 /* upper 3 nibbles contain fillparameter (ULIG) */
6499 fillpar = style >> 4;
6501 /* lower nibble contains fillstyle */
6502 switch (style & 0xf) {
6504 /* filldensity is from 0..100 percent */
6507 dim = (double)(fillpar)/100.;
6508 /* retrieve current rgb color and shift it towards the background color */
6509 xcolor.red = (double)(0xffff) * (double)((plot->current_rgb >> 16) & 0xff) /255.;
6510 xcolor.green = (double)(0xffff) * (double)((plot->current_rgb >> 8) & 0xff) /255.;
6511 xcolor.blue = (double)(0xffff) * (double)(plot->current_rgb & 0xff) /255.;
6512 bgnd.red = (double)(0xffff) * (double)((plot->cmap->rgbcolors[0] >> 16) & 0xff) /255.;
6513 bgnd.green = (double)(0xffff) * (double)((plot->cmap->rgbcolors[0] >> 8) & 0xff) /255.;
6514 bgnd.blue = (double)(0xffff) * (double)(plot->cmap->rgbcolors[0] & 0xff) /255.;
6515 xcolor.red = dim*xcolor.red + (1.-dim)*bgnd.red;
6516 xcolor.green = dim*xcolor.green + (1.-dim)*bgnd.green;
6517 xcolor.blue = dim*xcolor.blue + (1.-dim)*bgnd.blue;
6518 if (XAllocColor(dpy, plot->cmap->colormap, &xcolor))
6519 XSetForeground(dpy, *gc, xcolor.pixel);
6522 /* use fill pattern according to fillpattern */
6523 idx = (int) fillpar; /* fillpattern is enumerated */
6526 idx = idx % stipple_pattern_num;
6527 XSetStipple(dpy, *gc, stipple_pattern[idx]);
6528 XSetFillStyle(dpy, *gc, FillOpaqueStippled);
6530 XSetBackground(dpy, *gc, plot->cmap->colors[0]);
6532 XSetForeground(dpy, *gc, plot->cmap->colors[plot->lt + 3]);
6534 case FS_EMPTY: /* fill with background color */
6535 XSetFillStyle(dpy, *gc, FillSolid);
6536 XSetForeground(dpy, *gc, plot->cmap->colors[0]);
6539 XSetFillStyle(dpy, *gc, FillSolid);
6541 XSetForeground(dpy, *gc, plot->cmap->colors[0]);