source: trunk/third/x3270/save.c @ 9081

Revision 9081, 14.2 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9080, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright 1994, 1995 by Paul Mattes.
3 *  Permission to use, copy, modify, and distribute this software and its
4 *  documentation for any purpose and without fee is hereby granted,
5 *  provided that the above copyright notice appear in all copies and that
6 *  both that copyright notice and this permission notice appear in
7 *  supporting documentation.
8 */
9
10/*
11 *      save.c
12 *              Implements the response to the WM_SAVE_YOURSELF message and
13 *              x3270 profiles.
14 */
15
16#include "globals.h"
17#include <X11/StringDefs.h>
18#include <X11/Xatom.h>
19#include <pwd.h>
20#include <errno.h>
21#include <time.h>
22#include "appres.h"
23#include "resources.h"
24
25#include "mainc.h"
26#include "savec.h"
27#include "popupsc.h"
28#include "utilc.h"
29
30
31/* Support for WM_SAVE_YOURSELF. */
32
33extern Boolean  keypad_changed;
34extern Boolean  keypad_popped;
35extern Boolean  model_changed;
36extern Boolean  scrollbar_changed;
37extern Boolean  efont_changed;
38extern Boolean  oversize_changed;
39extern Boolean  scheme_changed;
40extern Boolean  keymap_changed;
41extern Boolean  charset_changed;
42
43char           *command_string = CN;
44
45static char    *cmd;
46static int      cmd_len;
47
48#define NWORDS  1024
49
50static char   **tmp_cmd;
51static int      tcs;
52
53/* Search for an option in the tmp_cmd array. */
54static int
55cmd_srch(s)
56char *s;
57{
58        int i;
59
60        for (i = 1; i < tcs; i++)
61                if (tmp_cmd[i] && !strcmp(tmp_cmd[i], s))
62                        return i;
63        return 0;
64}
65
66/* Replace an options in the tmp_cmd array. */
67static void
68cmd_replace(ix, s)
69int ix;
70char *s;
71{
72        XtFree(tmp_cmd[ix]);
73        tmp_cmd[ix] = XtNewString(s);
74}
75
76/* Append an option to the tmp_cmd array. */
77static void
78cmd_append(s)
79char *s;
80{
81        tmp_cmd[tcs++] = XtNewString(s);
82        tmp_cmd[tcs] = (char *) NULL;
83}
84
85/* Delete an option from the tmp_cmd array. */
86static void
87cmd_delete(ix)
88int ix;
89{
90        XtFree(tmp_cmd[ix]);
91        tmp_cmd[ix] = (char *) NULL;
92}
93
94/* Save the screen geometry. */
95static void
96save_xy()
97{
98        char tbuf[64];
99        Window window, frame, child;
100        XWindowAttributes wa;
101        int x, y;
102        int ix;
103
104        window = XtWindow(toplevel);
105        if (!x_get_window_attributes(window, &wa))
106                return;
107        (void) XTranslateCoordinates(display, window, wa.root,
108                -wa.border_width, -wa.border_width,
109                &x, &y, &child);
110
111        frame = XtWindow(toplevel);
112        while (True) {
113                Window root, parent;
114                Window *children;
115                unsigned int nchildren;
116
117                int status = XQueryTree(display, frame, &root, &parent,
118                    &children, &nchildren);
119                if (parent == root || !parent || !status)
120                        break;
121                frame = parent;
122                if (status && children)
123                        XFree((char *)children);
124        }
125        if (frame != window) {
126                if (!x_get_window_attributes(frame, &wa))
127                        return;
128                x = wa.x;
129                y = wa.y;
130        }
131
132        (void) sprintf(tbuf, "+%d+%d", x, y);
133        if ((ix = cmd_srch("-geometry")))
134                cmd_replace(ix + 1, tbuf);
135        else {
136                cmd_append("-geometry");
137                cmd_append(tbuf);
138        }
139}
140
141/* Save the icon information: state, label, geometry. */
142static void
143save_icon()
144{
145        unsigned char *data;
146        int iconX, iconY;
147        char tbuf[64];
148        int ix;
149        unsigned long nitems;
150
151        {
152                Atom actual_type;
153                int actual_format;
154                unsigned long leftover;
155
156                if (XGetWindowProperty(display, XtWindow(toplevel), a_state,
157                    0L, 2L, False, a_state, &actual_type, &actual_format,
158                    &nitems, &leftover, &data) != Success)
159                        return;
160                if (actual_type != a_state ||
161                    actual_format != 32 ||
162                    nitems < 1)
163                        return;
164        }
165
166        ix = cmd_srch("-iconic");
167        if (*(unsigned long *)data == IconicState) {
168                if (!ix)
169                        cmd_append("-iconic");
170        } else {
171                if (ix)
172                        cmd_delete(ix);
173        }
174
175        if (nitems < 2)
176                return;
177
178        {
179                Window icon_window;
180                XWindowAttributes wa;
181                Window child;
182
183                icon_window = *(Window *)(data + sizeof(unsigned long));
184                if (icon_window == None)
185                        return;
186                if (!x_get_window_attributes(icon_window, &wa))
187                        return;
188                (void) XTranslateCoordinates(display, icon_window, wa.root,
189                    -wa.border_width, -wa.border_width, &iconX, &iconY,
190                    &child);
191                if (!iconX && !iconY)
192                        return;
193        }
194
195        (void) sprintf(tbuf, "%d", iconX);
196        ix = cmd_srch(OptIconX);
197        if (ix)
198                cmd_replace(ix + 1, tbuf);
199        else {
200                cmd_append(OptIconX);
201                cmd_append(tbuf);
202        }
203
204        (void) sprintf(tbuf, "%d", iconY);
205        ix = cmd_srch(OptIconY);
206        if (ix)
207                cmd_replace(ix + 1, tbuf);
208        else {
209                cmd_append(OptIconY);
210                cmd_append(tbuf);
211        }
212        return;
213}
214
215/* Save the keymap information. */
216/*ARGSUSED*/
217static void
218save_keymap()
219{
220       /* Note: keymap propogation is deliberately disabled, because it
221          may vary from workstation to workstation.  The recommended
222          way of specifying keymaps is through your .Xdefaults or the
223          KEYMAP or KEYBD environment variables, which can be easily set
224          in your .login or .profile to machine-specific values; the
225          -keymap switch is really for debugging or testing keymaps.
226
227          I'm sure I'll regret this.  */
228
229#if defined(notdef) /*[*/
230        if (appres.keymap) {
231                add_string(v, OptKeymap);
232                add_string(v, appres.keymap);
233        }
234#endif /*]*/
235}
236
237/* Save the model name. */
238static void
239save_model()
240{
241        int ix;
242
243        if (!model_changed)
244                return;
245        if ((ix = cmd_srch(OptModel)) && strcmp(tmp_cmd[ix], model_name))
246                cmd_replace(ix + 1, model_name);
247        else {
248                cmd_append(OptModel);
249                cmd_append(model_name);
250        }
251}
252
253/* Save the keypad state. */
254static void
255save_keypad()
256{
257        int ix;
258
259        ix = cmd_srch(OptKeypadOn);
260        if (appres.keypad_on || keypad_popped) {
261                if (!ix)
262                        cmd_append(OptKeypadOn);
263        } else {
264                if (ix)
265                        cmd_delete(ix);
266        }
267}
268
269/* Save the scrollbar state. */
270static void
271save_scrollbar()
272{
273        int i_on, i_off;
274
275        if (!scrollbar_changed)
276                return;
277        i_on = cmd_srch(OptScrollBar);
278        i_off = cmd_srch(OptNoScrollBar);
279        if (toggled(SCROLL_BAR)) {
280                if (!i_on) {
281                        if (i_off)
282                                cmd_replace(i_off, OptScrollBar);
283                        else
284                                cmd_append(OptScrollBar);
285                }
286        } else {
287                if (!i_off) {
288                        if (i_on)
289                                cmd_replace(i_on, OptNoScrollBar);
290                        else
291                                cmd_append(OptNoScrollBar);
292                }
293        }
294}
295
296/* Save the name of the host we are connected to. */
297static void
298save_host()
299{
300        char *space;
301
302        if (!CONNECTED)
303                return;
304        space = strchr(full_current_host, ' ');
305        if (space == (char *) NULL)
306                cmd_append(full_current_host);
307        else {
308                char *tmp = XtNewString(full_current_host);
309                char *port;
310
311                space = strchr(tmp, ' ');
312                *space = '\0';
313                cmd_append(tmp);
314                port = space + 1;
315                while (*port == ' ')
316                        port++;
317                if (*port)
318                        cmd_append(port);
319                XtFree(tmp);
320        }
321}
322
323/* Save the settings of each of the toggles. */
324static void
325save_toggles()
326{
327        int i, j;
328        int ix;
329
330        for (i = 0; i < N_TOGGLES; i++) {
331                if (!appres.toggle[i].changed)
332                        continue;
333
334                /*
335                 * Find the last "-set" or "-clear" for this toggle.
336                 * If there is a preferred alias, delete them instead.
337                 */
338                ix = 0;
339                for (j = 1; j < tcs; j++)
340                        if (tmp_cmd[j] &&
341                            (!strcmp(tmp_cmd[j], OptSet) ||
342                             !strcmp(tmp_cmd[j], OptClear)) &&
343                            tmp_cmd[j+1] &&
344                            !strcmp(tmp_cmd[j+1], toggle_names[i].name)) {
345                                if (i == SCROLL_BAR || i == DS_TRACE) {
346                                        cmd_delete(j);
347                                        cmd_delete(j + 1);
348                                } else
349                                        ix = j;
350                }
351
352                /* Handle aliased switches. */
353                switch (i) {
354                    case SCROLL_BAR:
355                        continue;       /* +sb/-sb done separately */
356                    case DS_TRACE:
357                        ix = cmd_srch(OptDsTrace);
358                        if (appres.toggle[DS_TRACE].value) {
359                                if (!ix)
360                                        cmd_append(OptDsTrace);
361                        } else {
362                                if (ix)
363                                        cmd_delete(ix);
364                        }
365                        continue;
366                }
367
368                /* If need be, switch "-set" with "-clear", or append one. */
369                if (appres.toggle[i].value) {
370                        if (ix && strcmp(tmp_cmd[ix], OptSet))
371                                cmd_replace(ix, OptSet);
372                        else if (!ix) {
373                                cmd_append(OptSet);
374                                cmd_append(toggle_names[i].name);
375                        }
376                } else {
377                        if (ix && strcmp(tmp_cmd[ix], OptClear))
378                                cmd_replace(ix, OptClear);
379                        else if (!ix) {
380                                cmd_append(OptClear);
381                                cmd_append(toggle_names[i].name);
382                        }
383                }
384        }
385}
386
387/* Remove a positional parameter from the command line. */
388static void
389remove_positional(s)
390char *s;
391{
392        char *c;
393
394        c = cmd + cmd_len - 2;  /* last byte of last arg */
395        while (*c && c >= cmd)
396                c--;
397        if (strcmp(s, c + 1))
398                XtError("Command-line switches must precede positional arguments");
399        cmd_len = c - cmd;
400}
401
402/* Save a copy of he XA_WM_COMMAND poperty. */
403void
404save_init(argc, hostname, port)
405int argc;
406char *hostname;
407char *port;
408{
409        Atom actual_type;
410        int actual_format;
411        unsigned long nitems;
412        unsigned long bytes_after;
413
414        /*
415         * Fetch the initial value of the XA_COMMAND property and store
416         * it in 'cmd'.
417         */
418        XGetWindowProperty(display, XtWindow(toplevel), XA_WM_COMMAND,
419            0L, 1000000L, False, XA_STRING, &actual_type, &actual_format,
420            &nitems, &bytes_after, (unsigned char **)&cmd);
421        if (nitems == 0)
422                XtError("Could not get initial XA_COMMAND property");
423        cmd_len = nitems * (actual_format / 8);
424
425        /*
426         * Now locate the hostname and port positional arguments, and
427         * remove them.  If they aren't the last two components of the
428         * command line, abort.
429         */
430        switch (argc) {
431            case 3:
432                remove_positional(port);
433                /* fall through */
434            case 2:
435                remove_positional(hostname);
436                break;
437        }
438}
439
440/* Handle a WM_SAVE_YOURSELF ICCM. */
441void
442save_yourself()
443{
444        int i;
445        char *c, *c2;
446        int len;
447
448        if (command_string != CN) {
449                XtFree(command_string);
450                command_string = CN;
451        }
452
453        /* Copy the original command line into tmp_cmd. */
454        tmp_cmd = (char **) XtMalloc(sizeof(char *) * NWORDS);
455        tcs = 0;
456        i = 0;
457        c = cmd;
458        while (i < cmd_len) {
459                c = cmd + i;
460                tmp_cmd[tcs++] = XtNewString(c);
461                i += strlen(c);
462                i++;
463        }
464        tmp_cmd[tcs] = (char *) NULL;
465
466        /* Replace the first element with the program name. */
467        cmd_replace(0, programname);
468
469        /* Save options. */
470        save_xy();
471        save_icon();
472        save_keymap();
473        save_model();
474        save_keypad();
475        save_scrollbar();
476        save_host();
477        save_toggles();
478
479        /* Copy what's left into contiguous memory. */
480        len = 0;
481        for (i = 0; i < tcs; i++)
482                if (tmp_cmd[i])
483                        len += strlen(tmp_cmd[i]) + 1;
484        c = XtMalloc(len);
485        c[0] = '\0';
486        c2 = c;
487        for (i = 0; i < tcs; i++)
488                if (tmp_cmd[i]) {
489                        (void) strcpy(c2, tmp_cmd[i]);
490                        c2 += strlen(c2) + 1;
491                        XtFree(tmp_cmd[i]);
492                }
493        XtFree((XtPointer)tmp_cmd);
494
495        /* Change the property. */
496        XChangeProperty(display, XtWindow(toplevel), XA_WM_COMMAND,
497            XA_STRING, 8, PropModeReplace, (unsigned char *)c, len);
498
499        /* Save a readable copy of the command string for posterity. */
500        command_string = c;
501        while (((c2 = strchr(c, '\0')) != CN) &&
502               (c2 - command_string < len-1)) {
503                *c2 = ' ';
504                c = c2 + 1;
505        }
506}
507
508
509/* Support for x3270 profiles. */
510
511#define PROFILE_ENV     "X3270PRO"
512#define NO_PROFILE_ENV  "NOX3270PRO"
513#define DEFAULT_PROFILE "~/.x3270pro"
514
515extern XrmOptionDescRec options[];
516extern int num_options;
517
518char *profile_name = CN;
519static char *xcmd;
520static int xargc;
521static char **xargv;
522
523/* Save one option in the file. */
524static void
525save_opt(f, full_name, opt_name, res_name, value)
526FILE *f;
527char *full_name;
528char *opt_name;
529char *res_name;
530char *value;
531{
532        (void) fprintf(f, "! %s (%s)\nx3270.%s: %s\n",
533            full_name, opt_name, res_name, value);
534}
535
536/* Save the current options settings in a profile. */
537int
538save_options(n)
539char *n;
540{
541        FILE *f;
542        Boolean exists = False;
543        char *ct;
544        int i;
545        extern char *build;
546        long clock;
547        char buf[64];
548        Boolean any_toggles = False;
549
550        if (n == CN || *n == '\0')
551                return -1;
552
553        /* Open the file. */
554        n = do_subst(n, True, True);
555        f = fopen(n, "r");
556        if (f != (FILE *)NULL) {
557                (void) fclose(f);
558                exists = True;
559        }
560        f = fopen(n, "a");
561        if (f == (FILE *)NULL) {
562                popup_an_errno(errno, "Cannot open %s", n);
563                XtFree(n);
564                return -1;
565        }
566
567        /* Save the name. */
568        if (profile_name == CN)
569                XtFree(profile_name);
570        profile_name = n;
571
572        /* Print the header. */
573        clock = time((long *)0);
574        ct = ctime(&clock);
575        if (ct[strlen(ct)-1] == '\n')
576                ct[strlen(ct)-1] = '\0';
577        if (exists)
578                (void) fprintf(f, "! File updated %s by %s\n", ct, build);
579        else
580                (void) fprintf(f,
581"! x3270 profile\n\
582! File created %s by %s\n\
583! This file overrides xrdb and .Xdefaults.\n\
584! To skip reading this file, set %s in the environment.\n\
585!\n",
586                    ct, build, NO_PROFILE_ENV);
587
588        /* Save most of the toggles. */
589        for (i = 0; i < N_TOGGLES; i++) {
590                if (!appres.toggle[i].changed)
591                        continue;
592                if (i == DS_TRACE || i == SCREEN_TRACE || i == EVENT_TRACE)
593                        continue;
594                if (!any_toggles) {
595                        (void) fprintf(f, "! toggles (%s, %s)\n",
596                            OptSet, OptClear);
597                        any_toggles = True;
598                }
599                (void) fprintf(f, "x3270.%s: %s\n", toggle_names[i].name,
600                    appres.toggle[i].value ? ResTrue : ResFalse);
601        }
602
603        /* Save the keypad state. */
604        if (keypad_changed)
605                save_opt(f, "keypad state", OptKeypadOn, ResKeypadOn,
606                        (appres.keypad_on || keypad_popped) ?
607                            ResTrue : ResFalse);
608
609        /* Save other menu-changeable options. */
610        if (efont_changed)
611                save_opt(f, "emulator font", OptEmulatorFont, ResEmulatorFont,
612                    efontname);
613        if (model_changed) {
614                (void) sprintf(buf, "%d", model_num);
615                save_opt(f, "model", OptModel, ResModel, buf);
616        }
617        if (oversize_changed) {
618                (void) sprintf(buf, "%dx%d", ov_cols, ov_rows);
619                save_opt(f, "oversize", OptOversize, ResOversize, buf);
620        }
621        if (scheme_changed && appres.color_scheme != CN)
622                save_opt(f, "color scheme", OptColorScheme, ResColorScheme,
623                    appres.color_scheme);
624        if (keymap_changed && appres.key_map != (char *)NULL)
625                save_opt(f, "keymap", OptKeymap, ResKeymap, appres.key_map);
626        if (charset_changed && appres.charset != (char *)NULL)
627                save_opt(f, "charset", OptCharset, ResCharset, appres.charset);
628
629        /* Done. */
630        (void) fclose(f);
631
632        return 0;
633}
634
635/* Save a copy of the command-line options. */
636void
637save_args(argc, argv)
638int argc;
639char *argv[];
640{
641        int i;
642        int len = 0;
643
644        for (i = 0; i < argc; i++)
645                len += strlen(argv[i]) + 1;
646        xcmd = XtMalloc(len + 1);
647        xargv = (char **)XtMalloc((argc + 1) * sizeof(char *));
648        len = 0;
649        for (i = 0; i < argc; i++) {
650                xargv[i] = xcmd + len;
651                (void) strcpy(xcmd + len, argv[i]);
652                len += strlen(argv[i]) + 1;
653        }
654        xargv[i] = CN;
655        *(xcmd + len) = '\0';
656        xargc = argc;
657}
658
659/* Merge in the options settings from a profile. */
660void
661merge_profile(d)
662XrmDatabase *d;
663{
664        char *fname;
665        XrmDatabase dd;
666
667        /* Open the file. */
668        if (getenv(NO_PROFILE_ENV) != CN) {
669                profile_name = do_subst(DEFAULT_PROFILE, True, True);
670                return;
671        }
672        fname = getenv(PROFILE_ENV);
673        if (fname == CN || *fname == '\0')
674                fname = DEFAULT_PROFILE;
675        profile_name = do_subst(fname, True, True);
676
677        /* Create a resource database from the file. */
678        dd = XrmGetFileDatabase(profile_name);
679        if (dd == NULL)
680                goto done;
681
682        /* Merge in the profile options. */
683        XrmMergeDatabases(dd, d);
684
685        /* Merge the saved command-line options back on top of those. */
686        dd = NULL;
687        XrmParseCommand(&dd, options, num_options, programname, &xargc, xargv);
688        XrmMergeDatabases(dd, d);
689
690    done:
691        /* Free the saved command-line options. */
692        XtFree(xcmd);
693        xcmd = CN;
694        XtFree((char *)xargv);
695        xargv = (char **)NULL;
696}
Note: See TracBrowser for help on using the repository browser.