source: tags/arb-6.0/WINDOW/AW_window.cxx

Last change on this file was 12303, checked in by westram, 10 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 115.1 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : AW_window.cxx                                     //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "aw_at.hxx"
12#include "aw_nawar.hxx"
13#include "aw_xfig.hxx"
14#include "aw_Xm.hxx"
15#include "aw_window.hxx"
16#include "aw_window_Xm.hxx"
17#include "aw_xkey.hxx"
18#include "aw_select.hxx"
19#include "aw_awar.hxx"
20#include "aw_msg.hxx"
21#include "aw_root.hxx"
22#include "aw_xargs.hxx"
23#include "aw_device_click.hxx"
24
25#include <arbdbt.h>
26#include <arb_file.h>
27#include <arb_str.h>
28#include <arb_strarray.h>
29
30#include <X11/Shell.h>
31#include <Xm/AtomMgr.h>
32#include <Xm/Frame.h>
33#include <Xm/PushB.h>
34#include <Xm/Protocols.h>
35#include <Xm/RowColumn.h>
36#include <Xm/DrawingA.h>
37#include <Xm/Form.h>
38#include <Xm/Separator.h>
39#include <Xm/MainW.h>
40#include <Xm/CascadeB.h>
41#include <Xm/MenuShell.h>
42#include <Xm/ScrollBar.h>
43#include <Xm/MwmUtil.h>
44
45#include <cctype>
46#include "aw_question.hxx"
47#include <map>
48
49void AW_POPDOWN(AW_window *window){
50    window->hide();
51}
52
53/**
54 * CB wrapper for create_*_window calls to ensure that a window
55 * is only created once.
56 */
57
58#if defined(DEBUG)
59#define NOWINWARN() fputs("window factory did not create a window\n", stderr)
60#else
61#define NOWINWARN()
62#endif
63
64static AW_window *find_or_createAndRegisterWindow(CreateWindowCallback *windowMaker) {
65    typedef std::map<CreateWindowCallback, AW_window*> window_map;
66
67    static window_map     window;  // previously popped up windows
68    CreateWindowCallback& maker = *windowMaker;
69
70    if (window.find(maker) == window.end()) {
71        AW_window *made = maker(AW_root::SINGLETON);
72        if (!made) { NOWINWARN(); return NULL; }
73
74        window[maker] = made;
75    }
76    return window[maker];
77}
78
79void AW_window::popper(AW_window *, CreateWindowCallback *windowMaker) {
80    AW_window *toPopup = find_or_createAndRegisterWindow(windowMaker);
81    if (toPopup) toPopup->activate();
82}
83void AW_window::replacer(AW_window *caller, CreateWindowCallback *windowMaker) {
84    AW_window *toPopup = find_or_createAndRegisterWindow(windowMaker);
85    if (toPopup) {
86        toPopup->activate();
87        caller->hide();
88    }
89}
90
91void AW_POPUP(AW_window */*window*/, AW_CL callback, AW_CL callback_data) { // @@@ obsolete (when #432 is done)
92    typedef AW_window* (*popup_cb_t)(AW_root*, AW_CL);
93    typedef std::map<std::pair<popup_cb_t,AW_CL>, AW_window*> window_map;
94
95    static window_map windows; // previously popped up windows
96
97    std::pair<popup_cb_t, AW_CL> popup((popup_cb_t)callback, callback_data);
98
99    if (windows.find(popup) == windows.end()) {
100        AW_window *made = popup.first(AW_root::SINGLETON, popup.second);
101        if (!made) { NOWINWARN(); return; }
102
103        windows[popup] = made;
104    }
105
106    windows[popup]->activate();
107}
108
109// ----------------------------------------------------------------------
110// force-diff-sync 1927391236 (remove after merging back to trunk)
111// ----------------------------------------------------------------------
112
113void AW_window::get_window_size(int &width, int &height){
114    unsigned short hoffset = 0;
115    if (p_w->menu_bar[0]) XtVaGetValues(p_w->menu_bar[0], XmNheight, &hoffset, NULL);
116    width = _at->max_x_size;
117    height = hoffset + _at->max_y_size;
118}
119
120
121static unsigned timed_window_title_cb(AW_root*, char *title, AW_window *aw) {
122    aw->number_of_timed_title_changes--;
123    if (!aw->number_of_timed_title_changes) {
124        aw->set_window_title_intern(title);
125    }
126
127    delete title;
128    return 0; // do not recall
129}
130
131void AW_window::message(char *title, int ms) {
132    char *old_title = NULL;
133
134    number_of_timed_title_changes++;
135
136    old_title = strdup(window_name);
137
138    XtVaSetValues(p_w->shell, XmNtitle, title, NULL);
139
140    get_root()->add_timed_callback(ms, makeTimedCallback(timed_window_title_cb, old_title, this));
141}
142
143// ----------------------------------------------------------------------
144// force-diff-sync 1284672342939 (remove after merging back to trunk)
145// ----------------------------------------------------------------------
146
147// -------------------------
148//      Hotkey Checking
149
150#if defined(DEBUG)
151#define CHECK_DUPLICATED_MNEMONICS
152#endif
153
154#ifdef CHECK_DUPLICATED_MNEMONICS
155
156inline char oppositeCase(char c) {
157    return isupper(c) ? tolower(c) : toupper(c);
158}
159static void strcpy_overlapping(char *dest, char *src) {
160    int src_len = strlen(src);
161    memmove(dest, src, src_len+1);
162}
163static const char *possible_mnemonics(const char *used_mnemonics, bool top_level, const char *topic_name) {
164    static char *unused;
165    for (int fromTopic = 1; fromTopic>=0; --fromTopic) {
166        freedup(unused, fromTopic ? topic_name : "abcdefghijklmnopqrstuvwxyz");
167
168        for (int t = 0; unused[t]; ++t) {
169            bool remove = false;
170            if ((top_level && !isalpha(unused[t])) || !isalnum(unused[t])) { // remove useless chars
171                remove = true;
172            }
173            else {
174                char *dup = strchr(unused, unused[t]);
175                if (dup && (dup-unused)<t) { // remove duplicated chars
176                    remove = true;
177                }
178                else {
179                    dup = strchr(unused, oppositeCase(unused[t]));
180                    if (dup && (dup-unused)<t) { // char is duplicated with opposite case
181                        dup[0] = toupper(dup[0]); // prefer upper case
182                        remove = true;
183                    }
184                }
185            }
186            if (remove) {
187                strcpy_overlapping(unused+t, unused+t+1);
188                --t;
189            }
190        }
191
192        for (int t = 0; used_mnemonics[t]; ++t) {
193            char c = used_mnemonics[t]; // upper case!
194            char *u = strchr(unused, c);
195            if (u) strcpy_overlapping(u, u+1); // remove char
196            u = strchr(unused, tolower(c));
197            if (u) strcpy_overlapping(u, u+1); // remove char
198        }
199
200        if (unused[0]) {
201            if (!fromTopic) {
202                freeset(unused, GBS_global_string_copy("unused but not in topic: \"%s\"", unused));
203            }
204            break;
205        }
206    }
207    return unused;
208}
209
210class MnemonicScope : virtual Noncopyable {
211    char          *name; // of menu or window
212    char          *used; // mnemonics (all upper case)
213    MnemonicScope *parent;
214    StrArray       requested; // topics lacking sufficient mnemonic
215
216    void print_at_menu(FILE *out) {
217        if (parent) {
218            parent->print_at_menu(out);
219            fputc('|', out);
220        }
221        fputs(name, out);
222    }
223    void print_at_location(FILE *out, const char *topic) {
224        fputs(" (", out);
225        print_at_menu(out);
226        fprintf(out, "|%s)\n", topic);
227    }
228
229    void requestPossibilities(const char *topic_name) {
230        // will be shows delayed (when menu closes)
231        requested.put(strdup(topic_name));
232    }
233
234    void showRequestedPossibilities() {
235        for (int i = 0; requested[i]; ++i) {
236            const char *possible = possible_mnemonics(used, !parent, requested[i]);
237            fprintf(stderr, "Warning: Possible mnemonics for '%s': '%s'\n", requested[i], possible);
238        }
239    }
240
241    void warn_mnemonic(const char *topic_name, const char *mnemonic, const char *warning) {
242        fprintf(stderr, "Warning: mnemonic '%s' %s", mnemonic, warning);
243        print_at_location(stderr, topic_name);
244    }
245
246public:
247
248    MnemonicScope(const char *name_, MnemonicScope *parent_)
249        : name(strdup(name_)),
250          used(strdup("")),
251          parent(parent_)
252    {}
253
254    ~MnemonicScope() {
255        showRequestedPossibilities();
256        free(name);
257        free(used);
258    }
259
260    void add(const char *topic_name, const char *mnemonic);
261
262    MnemonicScope *get_parent() { return parent; }
263};
264
265static MnemonicScope *current_mscope = NULL;
266static MnemonicScope *help_mscope    = NULL;
267
268void MnemonicScope::add(const char *topic_name, const char *mnemonic) {
269    if (mnemonic && mnemonic[0] != 0) {
270        if (mnemonic[1]) { // longer than 1 char -> wrong
271            warn_mnemonic(topic_name, mnemonic, "is too long; only 1 character allowed");
272        }
273
274        if (topic_name[0] == '#') { // graphical menu
275            if (mnemonic[0]) {
276                warn_mnemonic(topic_name, mnemonic, "is useless for graphical menu entry");
277            }
278        }
279        else if (!isalpha(mnemonic[0]) && !get_parent()) { // do not allow top-level numeric mnemonics
280            warn_mnemonic(topic_name, mnemonic, "is invalid (allowed: a-z)");
281            requestPossibilities(topic_name);
282        }
283        else if (!isalnum(mnemonic[0])) {
284            warn_mnemonic(topic_name, mnemonic, "is invalid (allowed: a-z and 0-9)");
285            requestPossibilities(topic_name);
286        }
287        else {
288            char *TOPIC_NAME = ARB_strupper(strdup(topic_name));
289            char  HOTKEY     = toupper(mnemonic[0]); // store hotkeys case-less (case does not matter when pressing the hotkey)
290
291            if (strchr(TOPIC_NAME, HOTKEY)) {  // occurs in menu text
292                if (strchr(used, HOTKEY)) {
293                    warn_mnemonic(topic_name, mnemonic, "is used multiple times");
294                    requestPossibilities(topic_name);
295                }
296                else {
297                    freeset(used, GBS_global_string_copy("%s%c", used, HOTKEY));
298
299                    if (!strchr(topic_name, mnemonic[0])) {
300                        char *warning = GBS_global_string_copy("has wrong case, use '%c'", HOTKEY == mnemonic[0] ? tolower(HOTKEY) : HOTKEY);
301                        warn_mnemonic(topic_name, mnemonic, warning);
302                        free(warning);
303                    }
304                }
305            }
306            else {
307                warn_mnemonic(topic_name, mnemonic, "is useless; does not occur in text");
308                requestPossibilities(topic_name);
309            }
310            free(TOPIC_NAME);
311        }
312    }
313    else {
314        if (topic_name[0] != '#') { // not a graphical menu
315            fputs("Warning: mnemonic is missing", stderr);
316            print_at_location(stderr, topic_name);
317            requestPossibilities(topic_name);
318        }
319    }
320}
321
322static void open_test_duplicate_mnemonics(const char *sub_menu_name, const char *mnemonic) {
323    aw_assert(current_mscope);
324    current_mscope->add(sub_menu_name, mnemonic);
325
326    MnemonicScope *prev = current_mscope;
327    current_mscope             = new MnemonicScope(sub_menu_name, prev);
328}
329
330static void close_test_duplicate_mnemonics() {
331    MnemonicScope *prev = current_mscope->get_parent();
332    delete current_mscope;
333    current_mscope = prev;
334}
335
336static void init_duplicate_mnemonic(const char *window_name) {
337    if (!current_mscope) {
338        current_mscope = new MnemonicScope(window_name, NULL);
339        help_mscope    = new MnemonicScope("<HELP>", current_mscope);
340    }
341    else {
342        while (current_mscope->get_parent()) {
343            close_test_duplicate_mnemonics();
344        }
345    }
346}
347
348static void test_duplicate_mnemonics(const char *topic_name, const char *mnemonic) {
349    aw_assert(current_mscope);
350    current_mscope->add(topic_name, mnemonic);
351}
352
353static void exit_duplicate_mnemonic() {
354    delete help_mscope; help_mscope = NULL;
355    while (current_mscope) close_test_duplicate_mnemonics();
356}
357
358
359#endif
360
361// ----------------------------------------------------------------------
362// force-diff-sync 9273192739 (remove after merging back to trunk)
363// ----------------------------------------------------------------------
364
365void AW_window::create_menu(AW_label name, const char *mnemonic, AW_active mask) {
366    aw_assert(legal_mask(mask));
367    p_w->menu_deep = 0;
368#ifdef CHECK_DUPLICATED_MNEMONICS
369    init_duplicate_mnemonic(window_name);
370#endif
371#if defined(DUMP_MENU_LIST)
372    dumpCloseAllSubMenus();
373#endif // DUMP_MENU_LIST
374    insert_sub_menu(name, mnemonic, mask);
375}
376
377void AW_window::close_sub_menu() {
378#ifdef CHECK_DUPLICATED_MNEMONICS
379    close_test_duplicate_mnemonics();
380#endif
381#if defined(DUMP_MENU_LIST)
382    dumpCloseSubMenu();
383#endif // DUMP_MENU_LIST
384    if (p_w->menu_deep>0)
385        p_w->menu_deep--;
386}
387
388void AW_window::all_menus_created() const { // this is called by AW_window::show() (i.e. after all menus have been created)
389#if defined(DEBUG)
390    if (p_w->menu_deep>0) { // window had menu
391        aw_assert(p_w->menu_deep == 1);
392#ifdef CHECK_DUPLICATED_MNEMONICS
393        exit_duplicate_mnemonic(); // cleanup mnemonic check
394#endif
395    }
396#endif // DEBUG
397}
398
399// ----------------------------------------------------------------------
400// force-diff-sync 2939128467234 (remove after merging back to trunk)
401// ----------------------------------------------------------------------
402
403void AW_window::draw_line(int x1, int y1, int x2, int y2, int width, bool resize){
404    AW_xfig *xfig = (AW_xfig*)xfig_data;
405    aw_assert(xfig);
406    // forgot to call load_xfig ?
407
408    xfig->add_line(x1, y1, x2, y2, width);
409
410    class x {
411public:
412        static inline int max(int i1, int i2) {
413            return i1>i2 ? i1 : i2;
414        }
415    };
416
417    _at->max_x_size = x::max(_at->max_x_size, xfig->maxx - xfig->minx);
418    _at->max_y_size = x::max(_at->max_y_size, xfig->maxy - xfig->miny);
419
420    if (resize) {
421        recalc_size_atShow(AW_RESIZE_ANY);
422        set_window_size(_at->max_x_size+1000, _at->max_y_size+1000);
423    }
424}
425
426AW_device_click *AW_window::get_click_device(AW_area area, int mousex, int mousey, int max_distance) { 
427    AW_area_management *aram         = MAP_ARAM(area);
428    AW_device_click    *click_device = NULL;
429
430    if (aram) {
431        click_device = aram->get_click_device();
432        click_device->init_click(mousex, mousey, max_distance, AW_ALL_DEVICES);
433    }
434    return click_device;
435}
436
437AW_device *AW_window::get_device(AW_area area) { // @@@ rename to get_screen_device
438    AW_area_management *aram   = MAP_ARAM(area);
439    AW_device_Xm       *device = NULL;
440
441    if (aram) device = aram->get_screen_device();
442    return device;
443}
444
445void AW_window::get_event(AW_event *eventi) const {
446    *eventi = event;
447}
448
449AW_device_print *AW_window::get_print_device(AW_area area) {
450    AW_area_management *aram         = MAP_ARAM(area);
451    AW_device_print    *print_device = NULL;
452
453    if (aram) print_device = aram->get_print_device();
454    return print_device;
455}
456
457AW_device_size *AW_window::get_size_device(AW_area area) {
458    AW_area_management *aram        = MAP_ARAM(area);
459    AW_device_size     *size_device = NULL;
460
461    if (aram) {
462        size_device = aram->get_size_device();
463        size_device->restart_tracking();
464        size_device->reset(); // @@@ hm
465    }
466
467    return size_device;
468}
469
470
471void AW_window::insert_help_topic(const char *labeli, 
472                                  const char *mnemonic, const char *helpText,
473                                  AW_active mask, const WindowCallback& cb) {
474    aw_assert(legal_mask(mask));
475    Widget button;
476
477#ifdef CHECK_DUPLICATED_MNEMONICS
478    if (!current_mscope) init_duplicate_mnemonic(window_name);
479    MnemonicScope *tmp = current_mscope;
480    current_mscope     = help_mscope;
481    test_duplicate_mnemonics(labeli, mnemonic);
482    current_mscope     = tmp;
483#endif
484
485    // create one help-sub-menu-point
486    button = XtVaCreateManagedWidget("", xmPushButtonWidgetClass,
487                                     p_w->help_pull_down,
488                                     RES_CONVERT(XmNlabelString, labeli),
489                                     RES_CONVERT(XmNmnemonic, mnemonic), NULL);
490    XtAddCallback(button, XmNactivateCallback,
491                  (XtCallbackProc) AW_server_callback,
492                  (XtPointer) new AW_cb(this, cb, helpText));
493
494    root->make_sensitive(button, mask);
495}
496
497void AW_window::insert_menu_topic(const char *topic_id, const char *labeli,
498                                  const char *mnemonic, const char *helpText,
499                                  AW_active mask, const WindowCallback& cb) {
500    aw_assert(legal_mask(mask));
501    Widget button;
502
503    TuneBackground(p_w->menu_bar[p_w->menu_deep], TUNE_MENUTOPIC); // set background color for normal menu topics
504
505#if defined(DUMP_MENU_LIST)
506    dumpMenuEntry(name);
507#endif // DUMP_MENU_LIST
508#ifdef CHECK_DUPLICATED_MNEMONICS
509    test_duplicate_mnemonics(labeli, mnemonic);
510#endif
511    if (mnemonic && *mnemonic && strchr(labeli, mnemonic[0])) {
512        // create one sub-menu-point
513        button = XtVaCreateManagedWidget("", xmPushButtonWidgetClass,
514                                         p_w->menu_bar[p_w->menu_deep],
515                                         RES_LABEL_CONVERT(labeli),
516                                         RES_CONVERT(XmNmnemonic, mnemonic),
517                                         XmNbackground, _at->background_color, NULL);
518    }
519    else {
520        button = XtVaCreateManagedWidget("",
521                                         xmPushButtonWidgetClass,
522                                         p_w->menu_bar[p_w->menu_deep],
523                                         RES_LABEL_CONVERT(labeli),
524                                         XmNbackground, _at->background_color,
525                                         NULL);
526    }
527
528    AW_label_in_awar_list(this, button, labeli);
529    AW_cb *cbs = new AW_cb(this, cb, helpText);
530    XtAddCallback(button, XmNactivateCallback,
531                  (XtCallbackProc) AW_server_callback,
532                  (XtPointer) cbs);
533
534#if defined(DEVEL_RALF) // wanted version
535    aw_assert(topic_id);
536#else // !defined(DEVEL_RALF)
537    if (!topic_id) topic_id = labeli;
538#endif
539    cbs->id = strdup(topic_id);
540    root->define_remote_command(cbs);
541    root->make_sensitive(button, mask);
542}
543
544// ----------------------------------------------------------------------
545// force-diff-sync 824638723647 (remove after merging back to trunk)
546// ----------------------------------------------------------------------
547
548void AW_window::insert_sub_menu(const char *labeli, const char *mnemonic, AW_active mask){
549    aw_assert(legal_mask(mask));
550    Widget shell, Label;
551
552    TuneBackground(p_w->menu_bar[p_w->menu_deep], TUNE_SUBMENU); // set background color for submenus
553    // (Note: This must even be called if TUNE_SUBMENU is 0!
554    //        Otherwise several submenus get the TUNE_MENUTOPIC color)
555
556#if defined(DUMP_MENU_LIST)
557    dumpOpenSubMenu(name);
558#endif // DUMP_MENU_LIST
559#ifdef CHECK_DUPLICATED_MNEMONICS
560    open_test_duplicate_mnemonics(labeli, mnemonic);
561#endif
562
563    // create shell for Pull-Down
564    shell = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
565                                 p_w->menu_bar[p_w->menu_deep],
566                                 XmNwidth, 1,
567                                 XmNheight, 1,
568                                 XmNallowShellResize, true,
569                                 XmNoverrideRedirect, true,
570                                 NULL);
571
572    // create row column in Pull-Down shell
573
574    p_w->menu_bar[p_w->menu_deep+1] = XtVaCreateWidget("menu_row_column",
575                                                       xmRowColumnWidgetClass, shell,
576                                                       XmNrowColumnType, XmMENU_PULLDOWN,
577                                                       XmNtearOffModel, XmTEAR_OFF_ENABLED,
578                                                       NULL);
579
580    // create label in menu bar
581    if (mnemonic && *mnemonic && strchr(labeli, mnemonic[0])) {
582        // if mnemonic is "" -> Cannot convert string "" to type KeySym
583        Label = XtVaCreateManagedWidget("menu1_top_b1",
584                                        xmCascadeButtonWidgetClass, p_w->menu_bar[p_w->menu_deep],
585                                        RES_CONVERT(XmNlabelString, labeli),
586                                        RES_CONVERT(XmNmnemonic, mnemonic),
587                                        XmNsubMenuId, p_w->menu_bar[p_w->menu_deep+1],
588                                        XmNbackground, _at->background_color, NULL);
589    }
590    else {
591        Label = XtVaCreateManagedWidget("menu1_top_b1",
592                                        xmCascadeButtonWidgetClass,
593                                        p_w->menu_bar[p_w->menu_deep],
594                                        RES_CONVERT(XmNlabelString, labeli),
595                                        XmNsubMenuId, p_w->menu_bar[p_w->menu_deep+1],
596                                        XmNbackground, _at->background_color,
597                                        NULL);
598    }
599
600    if (p_w->menu_deep < AW_MAX_MENU_DEEP-1) p_w->menu_deep++;
601
602    root->make_sensitive(Label, mask);
603}
604
605static void AW_xfigCB_info_area(AW_window *aww, AW_xfig *xfig) {
606    AW_device *device = aww->get_device(AW_INFO_AREA);
607    device->reset();
608
609    if (aww->get_root()->color_mode == 0) { // mono colr
610        device->clear(-1);
611    }
612    device->set_offset(AW::Vector(-xfig->minx, -xfig->miny));
613
614    xfig->print(device);
615}
616
617// ----------------------------------------------------------------------
618// force-diff-sync 264782364273 (remove after merging back to trunk)
619// ----------------------------------------------------------------------
620
621void AW_window::load_xfig(const char *file, bool resize) {
622    if (file)   xfig_data = new AW_xfig(file, get_root()->font_width, get_root()->font_height);
623    else        xfig_data = new AW_xfig(get_root()->font_width, get_root()->font_height); // create an empty xfig
624
625    set_expose_callback(AW_INFO_AREA, makeWindowCallback(AW_xfigCB_info_area, xfig_data));
626    xfig_data->create_gcs(get_device(AW_INFO_AREA), get_root()->color_mode ? 8 : 1);
627
628    int xsize = xfig_data->maxx - xfig_data->minx;
629    int ysize = xfig_data->maxy - xfig_data->miny;
630
631    if (xsize>_at->max_x_size) _at->max_x_size = xsize;
632    if (ysize>_at->max_y_size) _at->max_y_size = ysize;
633
634    if (resize) {
635        recalc_size_atShow(AW_RESIZE_ANY);
636        set_window_size(_at->max_x_size+1000, _at->max_y_size+1000);
637    }
638}
639
640/**
641 * Construct window-local id.
642 * Prefixes @param id with AW_window::window_defaults_name + "/"
643 */
644const char *AW_window::local_id(const char *id) const {
645    static char *last_local_id = 0;
646    freeset(last_local_id, GBS_global_string_copy("%s/%s", get_window_id(), id));
647    return last_local_id;
648}
649
650void AW_window::sep______________() {
651    // create one help-sub-menu-point
652    XtVaCreateManagedWidget("", xmSeparatorWidgetClass,
653                            p_w->menu_bar[p_w->menu_deep],
654                            NULL);
655}
656
657/**
658 * Registers @param wcb as expose callback.
659 * Called whenever the @param area receives an expose event.
660 * This is where any drawing should be handled.
661 */
662void AW_window::set_expose_callback(AW_area area, const WindowCallback& wcb) {
663    AW_area_management *aram = MAP_ARAM(area);
664    if (aram) aram->set_expose_callback(this, wcb);
665}
666
667static void AW_focusCB(Widget /*wgt*/, XtPointer cl_aww, XEvent*, Boolean*) {
668    AW_window *aww = (AW_window*)cl_aww;
669    aww->run_focus_callback();
670}
671
672/**
673 * Registers a focus callback.
674 */
675void AW_window::set_focus_callback(const WindowCallback& wcb) {
676    if (!focus_cb) {
677        XtAddEventHandler(MIDDLE_WIDGET, EnterWindowMask, FALSE, AW_focusCB, (XtPointer) this);
678    }
679    if (!focus_cb || !focus_cb->contains((AW_CB)wcb.callee())) {
680        focus_cb = new AW_cb(this, wcb, 0, focus_cb);
681    }
682}
683
684/**
685 * Registers callback to be executed after the window is shown.
686 * Called multiple times if a show() follows a hide().
687 */
688void AW_window::set_popup_callback(const WindowCallback& wcb) {
689    p_w->popup_cb = new AW_cb(this, wcb, 0, p_w->popup_cb);
690}
691
692void AW_window::set_info_area_height(int height) {
693    XtVaSetValues(INFO_WIDGET, XmNheight, height, NULL);
694    XtVaSetValues(p_w->frame, XmNtopOffset, height, NULL);
695}
696
697void AW_window::set_bottom_area_height(int height) {
698    XtVaSetValues(BOTTOM_WIDGET, XmNheight, height, NULL);
699    XtVaSetValues(p_w->scroll_bar_horizontal, XmNbottomOffset, (int)height, NULL);
700}
701
702void AW_window::set_input_callback(AW_area area, const WindowCallback& wcb) {
703    AW_area_management *aram = MAP_ARAM(area);
704    if (aram) aram->set_input_callback(this, wcb);
705}
706
707void AW_window::set_motion_callback(AW_area area, const WindowCallback& wcb) {
708    AW_area_management *aram = MAP_ARAM(area);
709    if (aram) aram->set_motion_callback(this, wcb);
710}
711
712void AW_window::set_resize_callback(AW_area area, const WindowCallback& wcb) {
713    AW_area_management *aram = MAP_ARAM(area);
714    if (aram) aram->set_resize_callback(this, wcb);
715}
716
717// SCROLL BAR STUFF
718
719void AW_window::tell_scrolled_picture_size(AW_screen_area rectangle) {
720    picture->l = rectangle.l;
721    picture->r = rectangle.r;
722    picture->t = rectangle.t;
723    picture->b = rectangle.b;
724}
725
726void AW_window::tell_scrolled_picture_size(AW_world rectangle) {
727    picture->l = (int)rectangle.l;
728    picture->r = (int)rectangle.r;
729    picture->t = (int)rectangle.t;
730    picture->b = (int)rectangle.b;
731}
732
733AW_pos AW_window::get_scrolled_picture_width() const {
734    return (picture->r - picture->l);
735}
736
737AW_pos AW_window::get_scrolled_picture_height() const {
738    return (picture->b - picture->t);
739}
740
741void AW_window::reset_scrolled_picture_size() {
742    picture->l = 0;
743    picture->r = 0;
744    picture->t = 0;
745    picture->b = 0;
746}
747
748void AW_window::set_vertical_scrollbar_top_indent(int indent) {
749    XtVaSetValues(p_w->scroll_bar_vertical, XmNtopOffset, (int)indent, NULL);
750    top_indent_of_vertical_scrollbar = indent;
751}
752
753void AW_window::set_horizontal_scrollbar_left_indent(int indent) {
754    XtVaSetValues(p_w->scroll_bar_horizontal, XmNleftOffset, (int)indent, NULL);
755    left_indent_of_horizontal_scrollbar = indent;
756}
757
758void AW_window::_get_area_size(AW_area area, AW_screen_area *square) {
759    AW_area_management *aram = MAP_ARAM(area);
760    *square = aram->get_common()->get_screen();
761}
762
763void AW_window::get_scrollarea_size(AW_screen_area *square) {
764    _get_area_size(AW_MIDDLE_AREA, square);
765    square->r -= left_indent_of_horizontal_scrollbar;
766    square->b -= top_indent_of_vertical_scrollbar;
767}
768
769void AW_window::calculate_scrollbars(){
770    AW_screen_area scrollArea;
771    get_scrollarea_size(&scrollArea);
772
773    // HORIZONTAL
774    {
775        int slider_max = (int)get_scrolled_picture_width();
776        if (slider_max <1) {
777            slider_max = 1;
778            XtVaSetValues(p_w->scroll_bar_horizontal, XmNsliderSize, 1, NULL);
779        }
780
781        bool use_horizontal_bar     = true;
782        int  slider_size_horizontal = scrollArea.r;
783
784        if (slider_size_horizontal < 1) slider_size_horizontal = 1; // ist der slider zu klein (<1) ?
785        if (slider_size_horizontal > slider_max) { // Schirm groesser als Bild
786            slider_size_horizontal = slider_max; // slider nimmt ganze laenge ein
787            XtVaSetValues(p_w->scroll_bar_horizontal, XmNvalue, 0, NULL); // slider ganz links setzen
788            use_horizontal_bar = false; // kein horizontaler slider mehr
789        }
790
791        // check wether XmNValue is to big
792        int position_of_slider;
793        XtVaGetValues(p_w->scroll_bar_horizontal, XmNvalue, &position_of_slider, NULL);
794        if (position_of_slider > (slider_max-slider_size_horizontal)) { // steht der slider fuer slidergroesse zu rechts ?
795            position_of_slider = slider_max-slider_size_horizontal; // -1 ? vielleicht !
796            if (position_of_slider < 0) position_of_slider = 0;
797            XtVaSetValues(p_w->scroll_bar_horizontal, XmNvalue, position_of_slider, NULL);
798        }
799        // Anpassung fuer resize, wenn unbeschriebener Bereich vergroessert wird
800        int max_slider_pos = (int)(get_scrolled_picture_width() - scrollArea.r);
801        if (slider_pos_horizontal>max_slider_pos) {
802            slider_pos_horizontal = use_horizontal_bar ? max_slider_pos : 0;
803        }
804
805        XtVaSetValues(p_w->scroll_bar_horizontal, XmNsliderSize, 1, NULL);
806        XtVaSetValues(p_w->scroll_bar_horizontal, XmNmaximum, slider_max, NULL);
807        XtVaSetValues(p_w->scroll_bar_horizontal, XmNsliderSize, slider_size_horizontal, NULL);
808
809        update_scrollbar_settings_from_awars(AW_HORIZONTAL);
810    }
811
812    // VERTICAL
813    {
814        int slider_max = (int)get_scrolled_picture_height();
815        if (slider_max <1) {
816            slider_max = 1;
817            XtVaSetValues(p_w->scroll_bar_vertical, XmNsliderSize, 1, NULL);
818        }
819
820        bool use_vertical_bar     = true;
821        int  slider_size_vertical = scrollArea.b;
822
823        if (slider_size_vertical < 1) slider_size_vertical = 1;
824        if (slider_size_vertical > slider_max) {
825            slider_size_vertical = slider_max;
826            XtVaSetValues(p_w->scroll_bar_vertical, XmNvalue, 0, NULL);
827            use_vertical_bar = false;
828        }
829
830        // check wether XmNValue is to big
831        int position_of_slider;
832        XtVaGetValues(p_w->scroll_bar_vertical, XmNvalue, &position_of_slider, NULL);
833        if (position_of_slider > (slider_max-slider_size_vertical)) {
834            position_of_slider = slider_max-slider_size_vertical; // -1 ? vielleicht !
835            if (position_of_slider < 0) position_of_slider = 0;
836            XtVaSetValues(p_w->scroll_bar_vertical, XmNvalue, position_of_slider, NULL);
837        }
838        // Anpassung fuer resize, wenn unbeschriebener Bereich vergroessert wird
839        int max_slider_pos = (int)(get_scrolled_picture_height() - scrollArea.b);
840        if (slider_pos_vertical>max_slider_pos) {
841            slider_pos_vertical = use_vertical_bar ? max_slider_pos : 0;
842        }
843
844        XtVaSetValues(p_w->scroll_bar_vertical, XmNsliderSize, 1, NULL);
845        XtVaSetValues(p_w->scroll_bar_vertical, XmNmaximum, slider_max, NULL);
846        XtVaSetValues(p_w->scroll_bar_vertical, XmNsliderSize, slider_size_vertical, NULL);
847
848        update_scrollbar_settings_from_awars(AW_VERTICAL);
849    }
850}
851
852// ----------------------------------------------------------------------
853// force-diff-sync 82346723846 (remove after merging back to trunk)
854// ----------------------------------------------------------------------
855
856static void horizontal_scrollbar_redefinition_cb(AW_root*, AW_window *aw) {
857    aw->update_scrollbar_settings_from_awars(AW_HORIZONTAL);
858}
859
860static void vertical_scrollbar_redefinition_cb(AW_root*, AW_window *aw) {
861    aw->update_scrollbar_settings_from_awars(AW_VERTICAL);
862}
863
864const char *AW_window::window_local_awarname(const char *localname, bool tmp) {
865    CONSTEXPR int MAXNAMELEN = 200;
866    static char   buffer[MAXNAMELEN];
867    return GBS_global_string_to_buffer(buffer, MAXNAMELEN,
868                                       tmp ? "tmp/window/%s/%s" : "window/%s/%s",
869                                       window_defaults_name, localname);
870    // (see also aw_size_awar_name)
871}
872
873AW_awar *AW_window::window_local_awar(const char *localname, bool tmp) {
874    return get_root()->awar(window_local_awarname(localname, tmp));
875}
876
877void AW_window::create_window_variables() {
878    RootCallback hor_src = makeRootCallback(horizontal_scrollbar_redefinition_cb, this);
879    RootCallback ver_src = makeRootCallback(vertical_scrollbar_redefinition_cb, this);
880
881    get_root()->awar_int(window_local_awarname("horizontal_page_increment"), 50)->add_callback(hor_src);
882    get_root()->awar_int(window_local_awarname("vertical_page_increment"),   50)->add_callback(ver_src);
883    get_root()->awar_int(window_local_awarname("scroll_delay_horizontal"),   20)->add_callback(hor_src);
884    get_root()->awar_int(window_local_awarname("scroll_delay_vertical"),     20)->add_callback(ver_src);
885    get_root()->awar_int(window_local_awarname("scroll_width_horizontal"),    9)->add_callback(hor_src);
886    get_root()->awar_int(window_local_awarname("scroll_width_vertical"),     20)->add_callback(ver_src);
887}
888
889void AW_window::set_vertical_scrollbar_position(int position){
890#if defined(DEBUG) && 0
891    fprintf(stderr, "set_vertical_scrollbar_position to %i\n", position);
892#endif
893    // @@@ test and constrain against limits
894    slider_pos_vertical = position;
895    XtVaSetValues(p_w->scroll_bar_vertical, XmNvalue, position, NULL);
896}
897
898void AW_window::set_horizontal_scrollbar_position(int position) {
899#if defined(DEBUG) && 0
900    fprintf(stderr, "set_horizontal_scrollbar_position to %i\n", position);
901#endif
902    // @@@ test and constrain against limits
903    slider_pos_horizontal = position;
904    XtVaSetValues(p_w->scroll_bar_horizontal, XmNvalue, position, NULL);
905}
906
907static void value_changed_scroll_bar_vertical(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer call_data) {
908    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
909    AW_cb *cbs = (AW_cb *) aw_cb_struct;
910    cbs->aw->slider_pos_vertical = sbcbs->value; // setzt Scrollwerte im AW_window
911    cbs->run_callbacks();
912}
913static void value_changed_scroll_bar_horizontal(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer call_data) {
914    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
915    AW_cb *cbs = (AW_cb *) aw_cb_struct;
916    (cbs->aw)->slider_pos_horizontal = sbcbs->value; // setzt Scrollwerte im AW_window
917    cbs->run_callbacks();
918}
919
920static void drag_scroll_bar_vertical(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer call_data) {
921    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
922    AW_cb *cbs = (AW_cb *) aw_cb_struct;
923    cbs->aw->slider_pos_vertical = sbcbs->value; // setzt Scrollwerte im AW_window
924    cbs->run_callbacks();
925}
926static void drag_scroll_bar_horizontal(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer call_data) {
927    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
928    AW_cb *cbs = (AW_cb *) aw_cb_struct;
929    (cbs->aw)->slider_pos_horizontal = sbcbs->value; // setzt Scrollwerte im AW_window
930    cbs->run_callbacks();
931}
932
933void AW_window::set_vertical_change_callback(const WindowCallback& wcb) {
934    XtAddCallback(p_w->scroll_bar_vertical, XmNvalueChangedCallback,
935            (XtCallbackProc) value_changed_scroll_bar_vertical,
936            (XtPointer) new AW_cb(this, wcb, ""));
937    XtAddCallback(p_w->scroll_bar_vertical, XmNdragCallback,
938            (XtCallbackProc) drag_scroll_bar_vertical,
939            (XtPointer) new AW_cb(this, wcb, ""));
940
941    XtAddCallback(p_w->scroll_bar_vertical, XmNpageIncrementCallback,
942            (XtCallbackProc) drag_scroll_bar_vertical,
943            (XtPointer) new AW_cb(this, wcb, ""));
944    XtAddCallback(p_w->scroll_bar_vertical, XmNpageDecrementCallback,
945            (XtCallbackProc) drag_scroll_bar_vertical,
946            (XtPointer) new AW_cb(this, wcb, ""));
947}
948
949void AW_window::set_horizontal_change_callback(const WindowCallback& wcb) {
950    XtAddCallback(p_w->scroll_bar_horizontal, XmNvalueChangedCallback,
951                  (XtCallbackProc) value_changed_scroll_bar_horizontal,
952                  (XtPointer) new AW_cb(this, wcb, ""));
953    XtAddCallback(p_w->scroll_bar_horizontal, XmNdragCallback,
954            (XtCallbackProc) drag_scroll_bar_horizontal,
955            (XtPointer) new AW_cb(this, wcb, ""));
956}
957
958// END SCROLLBAR STUFF
959
960
961void AW_window::set_window_size(int width, int height) {
962    XtVaSetValues(p_w->shell, XmNwidth, (int)width, XmNheight, (int)height, NULL);
963}
964
965void AW_window::set_window_title_intern(char *title) {
966    XtVaSetValues(p_w->shell, XmNtitle, title, NULL);
967}
968
969void AW_window::set_window_title(const char *title){
970    XtVaSetValues(p_w->shell, XmNtitle, title, NULL);
971    freedup(window_name, title);
972}
973
974const char *AW_window::get_window_title() const {
975    char *title;
976
977    XtVaGetValues(p_w->shell, XmNtitle, &title, NULL);
978
979    return title;
980}
981
982// ----------------------------------------------------------------------
983// force-diff-sync 874687234237 (remove after merging back to trunk)
984// ----------------------------------------------------------------------
985
986void AW_window::window_fit() {
987    int width, height;
988    get_window_size(width, height);
989    set_window_size(width, height);
990}
991
992AW_window::AW_window()
993{
994    memset((char *)this, 0, sizeof(AW_window)); // @@@ may conflict with vtable - fix
995    p_w = new AW_window_Motif;
996    _at = new AW_at; // Note to valgrinders : the whole AW_window memory management suffers because Windows are NEVER deleted
997    picture = new AW_screen_area;
998    reset_scrolled_picture_size();
999    slider_pos_vertical = 0;
1000    slider_pos_horizontal = 0;
1001}
1002
1003AW_window::~AW_window() {
1004    delete p_w;
1005    delete picture;
1006}
1007
1008#if defined(DEBUG)
1009// #define DUMP_MENU_LIST          // this should NOT be defined normally (if defined, every window writes all menu-entries to stdout)
1010#endif // DEBUG
1011#if defined(DUMP_MENU_LIST)
1012
1013static char *window_name = 0;
1014static char *sub_menu = 0;
1015
1016static void initMenuListing(const char *win_name) {
1017    aw_assert(win_name);
1018
1019    freedup(window_name, win_name);
1020    freenull(sub_menu);
1021
1022    printf("---------------------------------------- list of menus for '%s'\n", window_name);
1023}
1024
1025static void dumpMenuEntry(const char *entry) {
1026    aw_assert(window_name);
1027    if (sub_menu) {
1028        printf("'%s/%s/%s'\n", window_name, sub_menu, entry);
1029    }
1030    else {
1031        printf("'%s/%s'\n", window_name, entry);
1032    }
1033}
1034
1035static void dumpOpenSubMenu(const char *sub_name) {
1036    aw_assert(sub_name);
1037
1038    dumpMenuEntry(sub_name); // dump the menu itself
1039
1040    if (sub_menu) freeset(sub_menu, GBS_global_string_copy("%s/%s", sub_menu, sub_name));
1041    else sub_menu = strdup(sub_name);
1042}
1043
1044static void dumpCloseSubMenu() {
1045    aw_assert(sub_menu);
1046    char *lslash = strrchr(sub_menu, '/');
1047    if (lslash) {
1048        lslash[0] = 0;
1049    }
1050    else freenull(sub_menu);
1051}
1052
1053static void dumpCloseAllSubMenus() {
1054    freenull(sub_menu);
1055}
1056
1057#endif // DUMP_MENU_LIST
1058
1059AW_window_menu_modes::AW_window_menu_modes() : AW_window_menu_modes_private(NULL) {}
1060AW_window_menu_modes::~AW_window_menu_modes() {}
1061
1062AW_window_menu::AW_window_menu() {}
1063AW_window_menu::~AW_window_menu() {}
1064
1065AW_window_simple::AW_window_simple() {}
1066AW_window_simple::~AW_window_simple() {}
1067
1068AW_window_simple_menu::AW_window_simple_menu() {}
1069AW_window_simple_menu::~AW_window_simple_menu() {}
1070
1071AW_window_message::AW_window_message() {}
1072AW_window_message::~AW_window_message() {}
1073
1074#define BUFSIZE 256
1075static char aw_size_awar_name_buffer[BUFSIZE];
1076static const char *aw_size_awar_name(AW_window *aww, const char *sub_entry) {
1077#if defined(DEBUG)
1078    int size =
1079#endif // DEBUG
1080            sprintf(aw_size_awar_name_buffer, "window/windows/%s/%s",
1081                    aww->window_defaults_name, sub_entry);
1082#if defined(DEBUG)
1083    aw_assert(size < BUFSIZE);
1084#endif // DEBUG
1085    return aw_size_awar_name_buffer;
1086    // (see also AW_window::window_local_awarname)
1087}
1088#undef BUFSIZE
1089
1090#define aw_awar_name_posx(aww)   aw_size_awar_name((aww), "posx")
1091#define aw_awar_name_posy(aww)   aw_size_awar_name((aww), "posy")
1092#define aw_awar_name_width(aww)  aw_size_awar_name((aww), "width")
1093#define aw_awar_name_height(aww) aw_size_awar_name((aww), "height")
1094
1095void AW_window::create_user_geometry_awars(int posx, int posy, int width, int height) {
1096    get_root()->awar_int(aw_awar_name_posx(this), posx);
1097    get_root()->awar_int(aw_awar_name_posy(this), posy);
1098    get_root()->awar_int(aw_awar_name_width(this), width);
1099    get_root()->awar_int(aw_awar_name_height(this), height);
1100}
1101
1102
1103void AW_window::store_size_in_awars(int width, int height) {
1104    get_root()->awar(aw_awar_name_width(this))->write_int(width);
1105    get_root()->awar(aw_awar_name_height(this))->write_int(height);
1106}
1107
1108void AW_window::get_size_from_awars(int& width, int& height) {
1109    width  = get_root()->awar(aw_awar_name_width(this))->read_int();
1110    height = get_root()->awar(aw_awar_name_height(this))->read_int();
1111}
1112
1113void AW_window::store_pos_in_awars(int posx, int posy) {
1114    get_root()->awar(aw_awar_name_posx(this))->write_int(posx);
1115    get_root()->awar(aw_awar_name_posy(this))->write_int(posy);
1116}
1117
1118void AW_window::get_pos_from_awars(int& posx, int& posy) {
1119    posx = get_root()->awar(aw_awar_name_posx(this))->read_int();
1120    posy = get_root()->awar(aw_awar_name_posy(this))->read_int();
1121}
1122
1123#undef aw_awar_name_posx
1124#undef aw_awar_name_posy
1125#undef aw_awar_name_width
1126#undef aw_awar_name_height
1127
1128static void aw_onExpose_calc_WM_offsets(AW_window *aww);
1129static unsigned aw_calc_WM_offsets_delayed(AW_root *, AW_window*aww) { aw_onExpose_calc_WM_offsets(aww); return 0; }
1130
1131static void aw_onExpose_calc_WM_offsets(AW_window *aww) {
1132    AW_window_Motif *motif = p_aww(aww);
1133
1134    int posx,  posy;  aww->get_window_content_pos(posx, posy);
1135
1136    bool knows_window_position = posx != 0 || posy != 0;
1137
1138    if (!knows_window_position) { // oops - motif has no idea where the window has been placed
1139        // assume positions stored in awars are correct and use them.
1140        // This works around problems with unclickable GUI-elements when running on 'Unity'
1141
1142        int oposx, oposy; aww->get_pos_from_awars(oposx, oposy);
1143        aww->set_window_frame_pos(oposx, oposy);
1144
1145        if (!motif->knows_WM_offset()) {
1146            aww->get_root()->add_timed_callback(100, makeTimedCallback(aw_calc_WM_offsets_delayed, aww));
1147        }
1148    }
1149    else if (!motif->knows_WM_offset()) {
1150        int oposx, oposy; aww->get_pos_from_awars(oposx, oposy);
1151        // calculate offset
1152        motif->WM_top_offset  = posy-oposy;
1153        motif->WM_left_offset = posx-oposx;
1154    }
1155}
1156
1157AW_root_Motif::AW_root_Motif() {
1158    memset((char*)this, 0, sizeof(*this));
1159}
1160
1161AW_root_Motif::~AW_root_Motif() {
1162    GBS_free_hash(action_hash);
1163    XmFontListFree(fontlist);
1164}
1165
1166void AW_root_Motif::set_cursor(Display *d, Window w, Cursor c) {
1167    XSetWindowAttributes attrs;
1168    old_cursor_display = d;
1169    old_cursor_window = w;
1170
1171    if (c)
1172        attrs.cursor = c;
1173    else
1174        attrs.cursor = None;
1175
1176    if (d && w) {
1177        XChangeWindowAttributes(d, w, CWCursor, &attrs);
1178    }
1179    XChangeWindowAttributes(XtDisplay(main_widget), XtWindow(main_widget),
1180            CWCursor, &attrs);
1181    XFlush(XtDisplay(main_widget));
1182}
1183
1184void AW_root_Motif::normal_cursor() {
1185    set_cursor(old_cursor_display, old_cursor_window, 0);
1186}
1187
1188void AW_server_callback(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer /*call_data*/) {
1189    AW_cb *cbs = (AW_cb *) aw_cb_struct;
1190
1191    AW_root *root = cbs->aw->get_root();
1192    if (p_global->help_active) {
1193        p_global->help_active = 0;
1194        p_global->normal_cursor();
1195
1196        if (cbs->help_text && ((GBS_string_matches(cbs->help_text, "*.ps", GB_IGNORE_CASE)) ||
1197                               (GBS_string_matches(cbs->help_text, "*.hlp", GB_IGNORE_CASE)) ||
1198                               (GBS_string_matches(cbs->help_text, "*.help", GB_IGNORE_CASE))))
1199        {
1200            AW_help_popup(cbs->aw, cbs->help_text);
1201        }
1202        else {
1203            aw_message("Sorry no help available");
1204        }
1205        return;
1206    }
1207
1208    if (root->is_tracking()) root->track_action(cbs->id);
1209
1210    if (cbs->contains(AW_POPUP)) {
1211        cbs->run_callbacks();
1212    }
1213    else {
1214        p_global->set_cursor(XtDisplay(p_global->toplevel_widget),
1215                XtWindow(p_aww(cbs->aw)->shell),
1216                p_global->clock_cursor);
1217        cbs->run_callbacks();
1218
1219        XEvent event; // destroy all old events !!!
1220        while (XCheckMaskEvent(XtDisplay(p_global->toplevel_widget),
1221        ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|
1222        KeyPressMask|KeyReleaseMask|PointerMotionMask, &event)) {
1223        }
1224
1225        if (p_global->help_active) {
1226            p_global->set_cursor(XtDisplay(p_global->toplevel_widget),
1227                    XtWindow(p_aww(cbs->aw)->shell),
1228                    p_global->question_cursor);
1229        }
1230        else {
1231            p_global->set_cursor(XtDisplay(p_global->toplevel_widget),
1232                    XtWindow(p_aww(cbs->aw)->shell),
1233                    0);
1234        }
1235    }
1236
1237}
1238
1239// --------------
1240//      focus
1241
1242
1243static void AW_root_focusCB(Widget /*wgt*/, XtPointer awrp, XEvent*, Boolean*) {
1244    AW_root *aw_root = (AW_root *)awrp;
1245    AW_root_cblist::call(aw_root->focus_callback_list, aw_root);
1246}
1247
1248void AW_window::run_focus_callback() {
1249    if (focus_cb) focus_cb->run_callbacks();
1250}
1251
1252bool AW_window::is_focus_callback(void (*f)(AW_window*, AW_CL, AW_CL)) {
1253    return focus_cb && focus_cb->contains(f);
1254}
1255
1256// ---------------
1257//      expose
1258
1259inline void AW_area_management::run_expose_callback() {
1260    if (expose_cb) expose_cb->run_callbacks();
1261}
1262
1263static void AW_exposeCB(Widget /*wgt*/, XtPointer aw_cb_struct, XmDrawingAreaCallbackStruct *call_data) {
1264    XEvent *ev = call_data->event;
1265    AW_area_management *aram = (AW_area_management *) aw_cb_struct;
1266    if (ev->xexpose.count == 0) { // last expose cb
1267        aram->run_expose_callback();
1268    }
1269}
1270
1271void AW_area_management::set_expose_callback(AW_window *aww, const WindowCallback& cb) {
1272    // insert expose callback for draw_area
1273    if (!expose_cb) {
1274        XtAddCallback(area, XmNexposeCallback, (XtCallbackProc) AW_exposeCB,
1275                (XtPointer) this);
1276    }
1277    expose_cb = new AW_cb(aww, cb, 0, expose_cb);
1278}
1279
1280bool AW_area_management::is_expose_callback(AW_window * /* aww */, void (*f)(AW_window*, AW_CL, AW_CL)) {
1281    return expose_cb && expose_cb->contains(f);
1282}
1283
1284bool AW_window::is_expose_callback(AW_area area, void (*f)(AW_window*, AW_CL, AW_CL)) {
1285    AW_area_management *aram = MAP_ARAM(area);
1286    return aram && aram->is_expose_callback(this, f);
1287}
1288
1289void AW_window::force_expose() {
1290    XmDrawingAreaCallbackStruct da_struct;
1291
1292    da_struct.reason = XmCR_EXPOSE;
1293    da_struct.event = (XEvent *) NULL;
1294    da_struct.window = XtWindow(p_w->shell);
1295
1296    XtCallCallbacks(p_w->shell, XmNexposeCallback, (XtPointer) &da_struct);
1297}
1298
1299// ---------------
1300//      resize
1301
1302
1303bool AW_area_management::is_resize_callback(AW_window * /* aww */, void (*f)(AW_window*, AW_CL, AW_CL)) {
1304    return resize_cb && resize_cb->contains(f);
1305}
1306
1307bool AW_window::is_resize_callback(AW_area area, void (*f)(AW_window*, AW_CL, AW_CL)) {
1308    AW_area_management *aram = MAP_ARAM(area);
1309    return aram && aram->is_resize_callback(this, f);
1310}
1311
1312void AW_window::set_window_frame_pos(int x, int y) {
1313    // this will set the position of the frame around the client-area (see also WM_top_offset ..)
1314    XtVaSetValues(p_w->shell, XmNx, (int)x, XmNy, (int)y, NULL);
1315}
1316void AW_window::get_window_content_pos(int& xpos, int& ypos) {
1317    // this will report the position of the client-area (see also WM_top_offset ..)
1318    unsigned short x, y;
1319    XtVaGetValues(p_w->shell, XmNx, &x, XmNy, &y, NULL);
1320    xpos = x;
1321    ypos = y;
1322}
1323
1324void AW_window::get_screen_size(int &width, int &height) {
1325    Screen *screen = XtScreen(p_w->shell);
1326
1327    width  = WidthOfScreen(screen);
1328    height = HeightOfScreen(screen);
1329}
1330
1331bool AW_window::get_mouse_pos(int& x, int& y) {
1332    Display      *= XtDisplay(p_w->shell);
1333    Window        w1 = XtWindow(p_w->shell);
1334    Window        w2;
1335    Window        w3;
1336    int           rx, ry;
1337    int           wx, wy;
1338    unsigned int  mask;
1339
1340    Bool ok = XQueryPointer(d, w1, &w2, &w3, &rx, &ry, &wx, &wy, &mask);
1341
1342    if (ok) {
1343#if defined(DEBUG) && 0
1344        printf("get_mouse_pos: rx/ry=%i/%i wx/wy=%i/%i\n", rx, ry, wx, wy);
1345#endif // DEBUG
1346        x = rx;
1347        y = ry;
1348    }
1349    return ok;
1350}
1351
1352static int is_resize_event(Display *display, XEvent *event, XPointer) {
1353    // Predicate function: checks, if the given event is a ResizeEvent
1354    if (event && (event->type == ResizeRequest || event->type
1355            == ConfigureNotify) && event->xany.display == display) {
1356        return 1;
1357    }
1358    return 0;
1359}
1360
1361static void cleanupResizeEvents(Display *display) {
1362    // Removes redundant resize events from the x-event queue
1363    if (display) {
1364        XLockDisplay(display);
1365        XEvent event;
1366        if (XCheckIfEvent(display, &event, is_resize_event, 0)) {
1367            // Some magic happens here... ;-) (removing redundant events from queue)
1368            while (XCheckIfEvent(display, &event, is_resize_event, 0))
1369                ;
1370            // Keep last Event in queue
1371            XPutBackEvent(display, &event);
1372        }
1373        XUnlockDisplay(display);
1374    }
1375}
1376
1377
1378inline void AW_area_management::run_resize_callback() {
1379    if (resize_cb) resize_cb->run_callbacks();
1380}
1381
1382static void AW_resizeCB_draw_area(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer /*call_data*/) {
1383    AW_area_management *aram = (AW_area_management *) aw_cb_struct;
1384    cleanupResizeEvents(aram->get_common()->get_display());
1385    aram->run_resize_callback();
1386}
1387
1388void AW_area_management::set_resize_callback(AW_window *aww, const WindowCallback& cb) {
1389    // insert resize callback for draw_area
1390    if (!resize_cb) {
1391        XtAddCallback(area, XmNresizeCallback,
1392                (XtCallbackProc) AW_resizeCB_draw_area, (XtPointer) this);
1393    }
1394    resize_cb = new AW_cb(aww, cb, 0, resize_cb);
1395}
1396
1397// -------------------
1398//      user input
1399
1400
1401static void AW_inputCB_draw_area(Widget wgt, XtPointer aw_cb_struct, XmDrawingAreaCallbackStruct *call_data) {
1402    XEvent             *ev                        = call_data->event;
1403    AW_cb       *cbs                       = (AW_cb *) aw_cb_struct;
1404    AW_window          *aww                       = cbs->aw;
1405    bool                run_callback              = false;
1406    bool                run_double_click_callback = false;
1407    AW_area_management *area                      = 0;
1408    {
1409        int i;
1410        for (i=0; i<AW_MAX_AREA; i++) {
1411            if (p_aww(aww)->areas[i]->get_area() == wgt) {
1412                area = p_aww(aww)->areas[i];
1413                break;
1414            }
1415        }
1416    }
1417
1418    if (ev->xbutton.type == ButtonPress || ev->xbutton.type == ButtonRelease) {
1419        aww->event.button      = AW_MouseButton(ev->xbutton.button);
1420        aww->event.x           = ev->xbutton.x;
1421        aww->event.y           = ev->xbutton.y;
1422        aww->event.keymodifier = (AW_key_mod)(ev->xbutton.state & (AW_KEYMODE_SHIFT|AW_KEYMODE_CONTROL|AW_KEYMODE_ALT));
1423        aww->event.keycode     = AW_KEY_NONE;
1424        aww->event.character   = '\0';
1425
1426        if (ev->xbutton.type == ButtonPress) {
1427            aww->event.type = AW_Mouse_Press;
1428            if (area && area->get_double_click_cb()) {
1429                if ((ev->xbutton.time - area->get_click_time()) < 200) {
1430                    run_double_click_callback = true;
1431                }
1432                else {
1433                    run_callback = true;
1434                }
1435                area->set_click_time(ev->xbutton.time);
1436            }
1437            else {
1438                run_callback = true;
1439            }
1440            aww->event.time = ev->xbutton.time;
1441        }
1442        else if (ev->xbutton.type == ButtonRelease) {
1443            aww->event.type = AW_Mouse_Release;
1444            run_callback = true;
1445            // keep event.time set in ButtonPress-branch
1446        }
1447    }
1448    else if (ev->xkey.type == KeyPress || ev->xkey.type == KeyRelease) {
1449        aww->event.time = ev->xbutton.time;
1450
1451        const awXKeymap *mykey = aw_xkey_2_awkey(&(ev->xkey));
1452
1453        aww->event.keycode = mykey->awkey;
1454        aww->event.keymodifier = mykey->awmod;
1455
1456        if (mykey->awstr) {
1457            aww->event.character = mykey->awstr[0];
1458        }
1459        else {
1460            aww->event.character = 0;
1461        }
1462
1463        if (ev->xkey.type == KeyPress) {
1464            aww->event.type = AW_Keyboard_Press;
1465        }
1466        else {
1467            aww->event.type = AW_Keyboard_Release;
1468        }
1469        aww->event.button = AW_BUTTON_NONE;
1470        aww->event.x = ev->xbutton.x;
1471        aww->event.y = ev->xbutton.y;
1472
1473        if (!mykey->awmod && mykey->awkey >= AW_KEY_F1 && mykey->awkey
1474                <= AW_KEY_F12 && p_aww(aww)->modes_f_callbacks && p_aww(aww)->modes_f_callbacks[mykey->awkey-AW_KEY_F1]
1475                && aww->event.type == AW_Keyboard_Press) {
1476            p_aww(aww)->modes_f_callbacks[mykey->awkey-AW_KEY_F1]->run_callbacks();
1477        }
1478        else {
1479            run_callback = true;
1480        }
1481    }
1482
1483    if (run_double_click_callback) {
1484        if (cbs->help_text == (char*)1) {
1485            cbs->run_callbacks();
1486        }
1487        else {
1488            if (area)
1489                area->get_double_click_cb()->run_callbacks();
1490        }
1491    }
1492
1493    if (run_callback && (cbs->help_text == (char*)0)) {
1494        cbs->run_callbacks();
1495    }
1496}
1497
1498void AW_area_management::set_input_callback(AW_window *aww, const WindowCallback& wcb) {
1499    XtAddCallback(area, XmNinputCallback,
1500            (XtCallbackProc)AW_inputCB_draw_area,
1501            (XtPointer)new AW_cb(aww, wcb));
1502}
1503
1504void AW_area_management::set_double_click_callback(AW_window *aww, const WindowCallback& wcb) {
1505    double_click_cb = new AW_cb(aww, wcb, (char*)0, double_click_cb);
1506}
1507
1508void AW_window::set_double_click_callback(AW_area area, const WindowCallback& wcb) {
1509    AW_area_management *aram = MAP_ARAM(area);
1510    if (!aram)
1511        return;
1512    aram->set_double_click_callback(this, wcb);
1513}
1514
1515// ---------------
1516//      motion
1517
1518static void AW_motionCB(Widget /*w*/, XtPointer aw_cb_struct, XEvent *ev, Boolean*) {
1519    AW_cb *cbs = (AW_cb *) aw_cb_struct;
1520
1521    cbs->aw->event.type    = AW_Mouse_Drag;
1522    cbs->aw->event.x       = ev->xmotion.x;
1523    cbs->aw->event.y       = ev->xmotion.y;
1524    cbs->aw->event.keycode = AW_KEY_NONE;
1525
1526    cbs->run_callbacks();
1527}
1528void AW_area_management::set_motion_callback(AW_window *aww, const WindowCallback& wcb) {
1529    XtAddEventHandler(area, ButtonMotionMask, False,
1530                      AW_motionCB, (XtPointer) new AW_cb(aww, wcb, ""));
1531}
1532static long destroy_awar(const char *, long val, void *) {
1533    AW_awar *awar = (AW_awar*)val;
1534    delete   awar;
1535    return 0; // remove from hash
1536}
1537
1538void AW_root::exit_variables() {
1539    if (hash_table_for_variables) {
1540        GBS_hash_do_loop(hash_table_for_variables, destroy_awar, NULL);
1541        GBS_free_hash(hash_table_for_variables);
1542        hash_table_for_variables = NULL;
1543    }
1544
1545    if (hash_for_windows) {
1546        GBS_free_hash(hash_for_windows);
1547        hash_for_windows = NULL;
1548    }
1549
1550    if (application_database) {
1551        GBDATA *prop_main    = application_database;
1552        application_database = NULL;
1553        GB_close(prop_main);
1554    }
1555}
1556
1557void AW_root::exit_root() {
1558    aw_uninstall_xkeys();
1559}
1560
1561void AW_window::update_scrollbar_settings_from_awars(AW_orientation orientation) {
1562    AW_screen_area scrolled;
1563    get_scrollarea_size(&scrolled);
1564
1565    if (orientation == AW_HORIZONTAL) {
1566        XtVaSetValues(p_w->scroll_bar_horizontal, XmNpageIncrement, (int)(scrolled.r*(window_local_awar("horizontal_page_increment")->read_int()*0.01)), NULL);
1567        XtVaSetValues(p_w->scroll_bar_horizontal, XmNincrement,     (int)(window_local_awar("scroll_width_horizontal")->read_int()), NULL);
1568        XtVaSetValues(p_w->scroll_bar_horizontal, XmNrepeatDelay,   (int)(window_local_awar("scroll_delay_horizontal")->read_int()), NULL);
1569    }
1570    else {
1571        XtVaSetValues(p_w->scroll_bar_vertical, XmNpageIncrement, (int)(scrolled.b*(window_local_awar("vertical_page_increment")->read_int()*0.01)), NULL);
1572        XtVaSetValues(p_w->scroll_bar_vertical, XmNincrement,     (int)(window_local_awar("scroll_width_vertical")->read_int()), NULL);
1573        XtVaSetValues(p_w->scroll_bar_vertical, XmNrepeatDelay,   (int)(window_local_awar("scroll_delay_vertical")->read_int()), NULL);
1574    }
1575}
1576
1577void AW_area_management::create_devices(AW_window *aww, AW_area ar) {
1578    AW_root *root = aww->get_root();
1579    common = new AW_common_Xm(XtDisplay(area), XtWindow(area), p_global->color_table, aww->color_table, aww->color_table_size, aww, ar);
1580}
1581
1582AW_color_idx AW_window::alloc_named_data_color(int colnum, char *colorname) {
1583    if (!color_table_size) {
1584        color_table_size = AW_STD_COLOR_IDX_MAX + colnum;
1585        color_table      = (AW_rgb*)malloc(sizeof(AW_rgb) *color_table_size);
1586        for (int i = 0; i<color_table_size; ++i) color_table[i] = AW_NO_COLOR;
1587    }
1588    else {
1589        if (colnum>=color_table_size) {
1590            long new_size  = colnum+8;
1591            realloc_unleaked(color_table, new_size*sizeof(AW_rgb)); // valgrinders : never freed because AW_window never is freed
1592            if (!color_table) GBK_terminate("out of memory");
1593            for (int i = color_table_size; i<new_size; ++i) color_table[i] = AW_NO_COLOR;
1594            color_table_size                                               = new_size;
1595        }
1596    }
1597    XColor xcolor_returned, xcolor_exakt;
1598
1599    if (p_global->screen_depth == 1) { // Black and White Monitor
1600        static int col = 1;
1601        if (colnum == AW_DATA_BG) {
1602            col = 1;
1603            if (strcmp(colorname, "white"))
1604                col *= -1;
1605        }
1606        if (col==1) {
1607            color_table[colnum] = WhitePixelOfScreen(XtScreen(p_global->toplevel_widget));
1608        }
1609        else {
1610            color_table[colnum] = BlackPixelOfScreen(XtScreen(p_global->toplevel_widget));
1611        }
1612        if (colnum == AW_DATA_BG)
1613            col *= -1;
1614    }
1615    else { // Color monitor
1616        if (color_table[colnum] != AW_NO_COLOR) {
1617            unsigned long color = color_table[colnum];
1618            XFreeColors(p_global->display, p_global->colormap, &color, 1, 0);
1619        }
1620        if (XAllocNamedColor(p_global->display, p_global->colormap, colorname, &xcolor_returned, &xcolor_exakt) == 0) {
1621            aw_message(GBS_global_string("XAllocColor failed: %s\n", colorname));
1622            color_table[colnum] = AW_NO_COLOR;
1623        }
1624        else {
1625            color_table[colnum] = xcolor_returned.pixel;
1626        }
1627    }
1628    if (colnum == AW_DATA_BG) {
1629        XtVaSetValues(p_w->areas[AW_MIDDLE_AREA]->get_area(), XmNbackground, color_table[colnum], NULL);
1630    }
1631    return (AW_color_idx)colnum;
1632}
1633
1634void AW_window::create_devices() {
1635    unsigned long background_color;
1636    if (p_w->areas[AW_INFO_AREA]) {
1637        p_w->areas[AW_INFO_AREA]->create_devices(this, AW_INFO_AREA);
1638        XtVaGetValues(p_w->areas[AW_INFO_AREA]->get_area(), XmNbackground, &background_color, NULL);
1639        p_global->color_table[AW_WINDOW_DRAG] = background_color ^ p_global->color_table[AW_WINDOW_FG];
1640    }
1641    if (p_w->areas[AW_MIDDLE_AREA]) {
1642        p_w->areas[AW_MIDDLE_AREA]->create_devices(this, AW_MIDDLE_AREA);
1643    }
1644    if (p_w->areas[AW_BOTTOM_AREA]) {
1645        p_w->areas[AW_BOTTOM_AREA]->create_devices(this, AW_BOTTOM_AREA);
1646    }
1647}
1648
1649void aw_insert_default_help_entries(AW_window *aww) {
1650    aww->insert_help_topic("Click here and then on the questionable button/menu/...", "q", 0, AWM_ALL, AW_help_entry_pressed);
1651
1652    aww->insert_help_topic("How to use help", "H", "help.hlp", AWM_ALL, makeHelpCallback("help.hlp"));
1653    aww->insert_help_topic("ARB help",        "A", "arb.hlp",  AWM_ALL, makeHelpCallback("arb.hlp"));
1654}
1655
1656const char *aw_str_2_label(const char *str, AW_window *aww) {
1657    aw_assert(str);
1658
1659    static const char *last_label = 0;
1660    static const char *last_str   = 0;
1661    static AW_window  *last_aww   = 0;
1662
1663    const char *label;
1664    if (str == last_str && aww == last_aww) { // reuse result ?
1665        label = last_label;
1666    }
1667    else {
1668        if (str[0] == '#') {
1669            label = AW_get_pixmapPath(str+1);
1670        }
1671        else {
1672            AW_awar *is_awar = aww->get_root()->label_is_awar(str);
1673
1674            if (is_awar) { // for labels displaying awar values, insert dummy text here
1675                int wanted_len = aww->_at->length_of_buttons - 2;
1676                if (wanted_len < 1) wanted_len = 1;
1677
1678                char *labelbuf       = GB_give_buffer(wanted_len+1);
1679                memset(labelbuf, 'y', wanted_len);
1680                labelbuf[wanted_len] = 0;
1681
1682                label = labelbuf;
1683            }
1684            else {
1685                label = str;
1686            }
1687        }
1688
1689        // store results locally, cause aw_str_2_label is nearly always called twice with same arguments
1690        // (see RES_LABEL_CONVERT)
1691        last_label = label;
1692        last_str   = str;
1693        last_aww   = aww;
1694    }
1695    return label;
1696}
1697
1698void AW_label_in_awar_list(AW_window *aww, Widget widget, const char *str) {
1699    AW_awar *is_awar = aww->get_root()->label_is_awar(str);
1700    if (is_awar) {
1701        char *display = is_awar->read_as_string();
1702
1703        if (!display) {
1704            aw_assert(0); // awar not found
1705            freeset(display, GBS_global_string_copy("<undef AWAR: %s>", str));
1706        }
1707        if (!display[0]) freeset(display, strdup(" ")); // empty string causes wrong-sized buttons
1708
1709        aww->update_label(widget, display);
1710        free(display);
1711
1712        is_awar->tie_widget(0, widget, AW_WIDGET_LABEL_FIELD, aww);
1713    }
1714}
1715
1716static void aw_window_avoid_destroy_cb(Widget, AW_window *, XmAnyCallbackStruct *) {
1717    aw_message("If YOU do not know what to answer, how should ARB know?\nPlease think again and answer the prompt!");
1718}
1719
1720static void aw_window_noexit_destroy_cb(Widget,  AW_window *aww, XmAnyCallbackStruct *) {
1721    aww->hide();
1722    // don't exit, when using destroy callback
1723}
1724
1725static void aw_window_destroy_cb(Widget,  AW_window *aww, XmAnyCallbackStruct *) {
1726    AW_root *root = aww->get_root();
1727    if ((p_global->main_aww == aww) || !p_global->main_aww->is_shown()) {
1728#ifdef NDEBUG
1729        if (!aw_ask_sure("quit_by_X", "Are you sure to quit?")) return;
1730#endif
1731        exit(EXIT_SUCCESS);
1732    }
1733    aww->hide();
1734}
1735
1736static void aw_update_window_geometry_awars(AW_window *aww) {
1737    AW_window_Motif *motif = p_aww(aww);
1738
1739    short          posx, posy;
1740    unsigned short width, height, borderwidth;
1741    XtVaGetValues(motif->shell, // bad hack
1742                  XmNborderWidth, &borderwidth,
1743                  XmNwidth, &width,
1744                  XmNheight, &height,
1745                  XmNx, &posx,
1746                  XmNy, &posy,
1747                  NULL);
1748
1749    if (motif->knows_WM_offset()) {
1750        posy -= motif->WM_top_offset;
1751        posx -= motif->WM_left_offset;
1752
1753        if (posx<0) posx = 0;
1754        if (posy<0) posy = 0;
1755
1756        aww->store_pos_in_awars(posx, posy);
1757    }
1758#if defined(DEBUG)
1759    else {
1760        fprintf(stderr, " WM_offsets unknown. Did not update awars!\n");
1761    }
1762#endif
1763    aww->store_size_in_awars(width, height);
1764}
1765
1766static long aw_loop_get_window_geometry(const char *, long val, void *) {
1767    aw_update_window_geometry_awars((AW_window *)val);
1768    return val;
1769}
1770
1771void aw_update_all_window_geometry_awars(AW_root *awr) {
1772    GBS_hash_do_loop(awr->hash_for_windows, aw_loop_get_window_geometry, NULL);
1773}
1774
1775static const char *existingPixmap(const char *icon_relpath, const char *name) {
1776    const char *icon_relname  = GBS_global_string("%s/%s.xpm", icon_relpath, name);
1777    const char *icon_fullname = AW_get_pixmapPath(icon_relname);
1778
1779    if (!GB_is_regularfile(icon_fullname)) icon_fullname = NULL;
1780
1781    return icon_fullname;
1782}
1783
1784static Pixmap getIcon(Screen *screen, const char *iconName, Pixel foreground, Pixel background) {
1785    static GB_HASH *icon_hash = 0;
1786    if (!icon_hash) icon_hash = GBS_create_hash(100, GB_MIND_CASE);
1787
1788    Pixmap pixmap = GBS_read_hash(icon_hash, iconName);
1789
1790    if (!pixmap && iconName) {
1791        const char *iconFile = existingPixmap("icons", iconName);
1792
1793        if (iconFile) {
1794            char *ico = strdup(iconFile);
1795            pixmap    = XmGetPixmap(screen, ico, foreground, background);
1796            GBS_write_hash(icon_hash, iconName, pixmap);
1797            free(ico);
1798        }
1799    }
1800
1801    return pixmap;
1802}
1803
1804static void aw_set_delete_window_cb(AW_window *aww, Widget shell, bool allow_close) {
1805    Atom WM_DELETE_WINDOW = XmInternAtom(XtDisplay(shell), (char*)"WM_DELETE_WINDOW", False);
1806
1807    // remove any previous callbacks
1808    XmRemoveWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_avoid_destroy_cb,  (caddr_t)aww);
1809    XmRemoveWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_noexit_destroy_cb, (caddr_t)aww);
1810    XmRemoveWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_destroy_cb,        (caddr_t)aww);
1811
1812    if (!allow_close) {
1813        XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_avoid_destroy_cb, (caddr_t)aww);
1814    }
1815    else {
1816        AW_root *root = aww->get_root();
1817        if (p_global->no_exit) {
1818            XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_noexit_destroy_cb, (caddr_t)aww);
1819        }
1820        else {
1821            XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_destroy_cb, (caddr_t)aww);
1822        }
1823    }
1824}
1825
1826void AW_window::allow_delete_window(bool allow_close) {
1827    aw_set_delete_window_cb(this, p_w->shell, allow_close);
1828}
1829
1830Widget aw_create_shell(AW_window *aww, bool allow_resize, bool allow_close, int width, int height, int posx, int posy) {
1831    AW_root *root = aww->get_root();
1832    Widget shell;
1833
1834    // set minimum window size to size provided by init
1835    if (width >aww->_at->max_x_size) aww->_at->max_x_size = width;
1836    if (height>aww->_at->max_y_size) aww->_at->max_y_size = height;
1837
1838    bool has_user_geometry = false;
1839    if (!GBS_read_hash(root->hash_for_windows, aww->get_window_id())) {
1840        GBS_write_hash(root->hash_for_windows, aww->get_window_id(), (long)aww);
1841
1842        aww->create_user_geometry_awars(posx, posy, width, height);
1843    }
1844    {
1845        int user_width, user_height; aww->get_size_from_awars(user_width, user_height);
1846        int user_posx,  user_posy;   aww->get_pos_from_awars(user_posx,  user_posy);
1847
1848        if (allow_resize) {
1849            if (width != user_width) { width = user_width; has_user_geometry = true; }
1850            if (height != user_height) { height = user_height; has_user_geometry = true; }
1851        }
1852
1853        // @@@ FIXME:  maximum should be set to current screen size minus some offset
1854        // to ensure that windows do not appear outside screen
1855        if (posx != user_posx) { posx = user_posx; has_user_geometry = true; }
1856        if (posy != user_posy) { posy = user_posy; has_user_geometry = true; }
1857
1858        if (has_user_geometry) {
1859            aww->recalc_size_atShow(AW_RESIZE_USER); // keep user geometry (only if user size is smaller than default size, the latter is used)
1860        }
1861        else { // no geometry yet
1862            aww->recalc_pos_atShow(AW_REPOS_TO_MOUSE_ONCE); // popup the window at current mouse position
1863        }
1864    }
1865   
1866    if (allow_resize) {
1867        // create the window big enough to ensure that all widgets
1868        // are created in visible area (otherwise widget are crippled).
1869        // window will be resized later (on show)
1870
1871        width = 4000;
1872        height = 3000;
1873
1874        aww->recalc_size_atShow(AW_RESIZE_ANY);
1875    }
1876
1877    Widget  father      = p_global->toplevel_widget;
1878    Screen *screen      = XtScreen(father);
1879    Pixmap  icon_pixmap = getIcon(screen, aww->window_defaults_name, p_global->foreground, p_global->background);
1880
1881    if (!icon_pixmap) {
1882        icon_pixmap = getIcon(screen, root->program_name, p_global->foreground, p_global->background);
1883    }
1884
1885    if (!icon_pixmap) {
1886        GBK_terminatef("Missing icon pixmap for window '%s'\n", aww->window_defaults_name);
1887    }
1888    else if (icon_pixmap == XmUNSPECIFIED_PIXMAP) {
1889        GBK_terminatef("Failed to load icon pixmap for window '%s'\n", aww->window_defaults_name);
1890    }
1891
1892    int focusPolicy = root->focus_follows_mouse ? XmPOINTER : XmEXPLICIT;
1893
1894    {
1895        aw_xargs args(9);
1896
1897        args.add(XmNwidth, width);
1898        args.add(XmNheight, height);
1899        args.add(XmNx, posx);
1900        args.add(XmNy, posy);
1901        args.add(XmNtitle, (XtArgVal)aww->window_name);
1902        args.add(XmNiconName, (XtArgVal)aww->window_name);
1903        args.add(XmNkeyboardFocusPolicy, focusPolicy);
1904        args.add(XmNdeleteResponse, XmDO_NOTHING);
1905        args.add(XtNiconPixmap, icon_pixmap);
1906
1907        if (!p_global->main_widget || !p_global->main_aww->is_shown()) {
1908            shell = XtCreatePopupShell("editor", applicationShellWidgetClass, father, args.list(), args.size());
1909        }
1910        else {
1911            shell = XtCreatePopupShell("transient", transientShellWidgetClass, father, args.list(), args.size());
1912        }
1913    }
1914    XtAddEventHandler(shell, EnterWindowMask, FALSE, AW_root_focusCB, (XtPointer) aww->get_root());
1915
1916    if (!p_global->main_widget) {
1917        p_global->main_widget = shell;
1918        p_global->main_aww    = aww;
1919    }
1920    else {
1921        if (!p_global->main_aww->is_shown()) {  // now i am the root window
1922            p_global->main_widget = shell;
1923            p_global->main_aww    = aww;
1924        }
1925    }
1926
1927    aw_set_delete_window_cb(aww, shell, allow_close);
1928
1929    // set icon window (for window managers where iconified applications are dropped onto desktop or similar)
1930    {
1931        Window icon_window;
1932        XtVaGetValues(shell, XmNiconWindow, &icon_window, NULL);
1933
1934        Display *dpy = XtDisplay(shell);
1935        if (!icon_window) {
1936            XSetWindowAttributes attr;
1937            attr.background_pixmap = icon_pixmap;
1938
1939            int          xpos, ypos;
1940            unsigned int xsize, ysize, borderwidth, depth;
1941            Window       wroot;
1942
1943            if (XGetGeometry(dpy, icon_pixmap, &wroot, &xpos, &ypos, &xsize, &ysize, &borderwidth, &depth)) {
1944                icon_window = XCreateWindow(dpy, wroot, 0, 0, xsize, ysize, 0, depth, CopyFromParent, CopyFromParent, CWBackPixmap, &attr);
1945            }
1946        }
1947        if (!icon_window) {
1948            XtVaSetValues(shell, XmNiconPixmap, icon_pixmap, NULL);
1949        }
1950        else {
1951            XtVaSetValues(shell, XmNiconWindow, icon_window, NULL);
1952            XSetWindowBackgroundPixmap(dpy, icon_window, icon_pixmap);
1953            XClearWindow(dpy, icon_window);
1954        }
1955    }
1956
1957    return shell;
1958}
1959
1960
1961void aw_realize_widget(AW_window *aww) {
1962    if (p_aww(aww)->areas[AW_INFO_AREA] && p_aww(aww)->areas[AW_INFO_AREA]->get_form()) {
1963        XtManageChild(p_aww(aww)->areas[AW_INFO_AREA]->get_form());
1964    }
1965    if (p_aww(aww)->areas[AW_MIDDLE_AREA] && p_aww(aww)->areas[AW_MIDDLE_AREA]->get_form()) {
1966        XtManageChild(p_aww(aww)->areas[AW_MIDDLE_AREA]->get_form());
1967    }
1968    if (p_aww(aww)->areas[AW_BOTTOM_AREA] && p_aww(aww)->areas[AW_BOTTOM_AREA]->get_form()) {
1969        XtManageChild(p_aww(aww)->areas[AW_BOTTOM_AREA]->get_form());
1970    }
1971    XtRealizeWidget(p_aww(aww)->shell);
1972    p_aww(aww)->WM_top_offset = AW_CALC_OFFSET_ON_EXPOSE;
1973}
1974
1975void AW_window_menu_modes::init(AW_root *root_in, const char *wid, const char *windowname, int  width, int height) { 
1976    Widget      main_window;
1977    Widget      help_popup;
1978    Widget      help_label;
1979    Widget      separator;
1980    Widget      form1;
1981    Widget      form2;
1982    const char *help_button   = "HELP";
1983    const char *help_mnemonic = "H";
1984
1985#if defined(DUMP_MENU_LIST)
1986    initMenuListing(windowname);
1987#endif // DUMP_MENU_LIST
1988    root = root_in; // for macro
1989    window_name = strdup(windowname);
1990    window_defaults_name = GBS_string_2_key(wid);
1991
1992    int posx = 50;
1993    int posy = 50;
1994
1995    p_w->shell = aw_create_shell(this, true, true, width, height, posx, posy);
1996
1997    main_window = XtVaCreateManagedWidget("mainWindow1",
1998                                          xmMainWindowWidgetClass, p_w->shell,
1999                                          NULL);
2000
2001    p_w->menu_bar[0] = XtVaCreateManagedWidget("menu1", xmRowColumnWidgetClass,
2002                                               main_window,
2003                                               XmNrowColumnType, XmMENU_BAR,
2004                                               NULL);
2005
2006    // create shell for help-cascade
2007    help_popup = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
2008                                      p_w->menu_bar[0],
2009                                      XmNwidth, 1,
2010                                      XmNheight, 1,
2011                                      XmNallowShellResize, true,
2012                                      XmNoverrideRedirect, true,
2013                                      NULL);
2014
2015    // create row column in Pull-Down shell
2016    p_w->help_pull_down = XtVaCreateWidget("menu_row_column",
2017                                           xmRowColumnWidgetClass, help_popup,
2018                                           XmNrowColumnType, XmMENU_PULLDOWN,
2019                                           NULL);
2020
2021    // create HELP-label in menu bar
2022    help_label = XtVaCreateManagedWidget("menu1_top_b1",
2023                                         xmCascadeButtonWidgetClass, p_w->menu_bar[0],
2024                                         RES_CONVERT(XmNlabelString, help_button),
2025                                         RES_CONVERT(XmNmnemonic, help_mnemonic),
2026                                         XmNsubMenuId, p_w->help_pull_down, NULL);
2027    XtVaSetValues(p_w->menu_bar[0], XmNmenuHelpWidget, help_label, NULL);
2028    root->make_sensitive(help_label, AWM_ALL);
2029
2030    form1 = XtVaCreateManagedWidget("form1",
2031                                    xmFormWidgetClass,
2032                                    main_window,
2033                                    // XmNwidth, width,
2034                                    // XmNheight, height,
2035                                    XmNresizePolicy, XmRESIZE_NONE,
2036                                    // XmNx, 0,
2037                                    // XmNy, 0,
2038                                    NULL);
2039
2040    p_w->mode_area = XtVaCreateManagedWidget("mode area",
2041                                             xmDrawingAreaWidgetClass,
2042                                             form1,
2043                                             XmNresizePolicy, XmRESIZE_NONE,
2044                                             XmNwidth, 38,
2045                                             XmNheight, height,
2046                                             XmNx, 0,
2047                                             XmNy, 0,
2048                                             XmNleftOffset, 0,
2049                                             XmNtopOffset, 0,
2050                                             XmNbottomAttachment, XmATTACH_FORM,
2051                                             XmNleftAttachment, XmATTACH_POSITION,
2052                                             XmNtopAttachment, XmATTACH_POSITION,
2053                                             XmNmarginHeight, 2,
2054                                             XmNmarginWidth, 1,
2055                                             NULL);
2056
2057    separator = XtVaCreateManagedWidget("separator",
2058                                        xmSeparatorWidgetClass,
2059                                        form1,
2060                                        XmNx, 37,
2061                                        XmNshadowThickness, 4,
2062                                        XmNorientation, XmVERTICAL,
2063                                        XmNbottomAttachment, XmATTACH_FORM,
2064                                        XmNtopAttachment, XmATTACH_FORM,
2065                                        XmNleftAttachment, XmATTACH_NONE,
2066                                        XmNleftWidget, NULL,
2067                                        XmNrightAttachment, XmATTACH_NONE,
2068                                        XmNleftOffset, 70,
2069                                        XmNleftPosition, 0,
2070                                        NULL);
2071
2072    form2 = XtVaCreateManagedWidget("form2",
2073                                    xmFormWidgetClass,
2074                                    form1,
2075                                    XmNwidth, width,
2076                                    XmNheight, height,
2077                                    XmNtopOffset, 0,
2078                                    XmNbottomOffset, 0,
2079                                    XmNleftOffset, 0,
2080                                    XmNrightOffset, 0,
2081                                    XmNrightAttachment, XmATTACH_FORM,
2082                                    XmNbottomAttachment, XmATTACH_FORM,
2083                                    XmNleftAttachment, XmATTACH_WIDGET,
2084                                    XmNleftWidget, separator,
2085                                    XmNtopAttachment, XmATTACH_POSITION,
2086                                    XmNresizePolicy, XmRESIZE_NONE,
2087                                    XmNx, 0,
2088                                    XmNy, 0,
2089                                    NULL);
2090    p_w->areas[AW_INFO_AREA] =
2091        new AW_area_management(root, form2, XtVaCreateManagedWidget("info_area",
2092                                                                    xmDrawingAreaWidgetClass,
2093                                                                    form2,
2094                                                                    XmNheight, 0,
2095                                                                    XmNbottomAttachment, XmATTACH_NONE,
2096                                                                    XmNtopAttachment, XmATTACH_FORM,
2097                                                                    XmNleftAttachment, XmATTACH_FORM,
2098                                                                    XmNrightAttachment, XmATTACH_FORM,
2099                                                                    XmNmarginHeight, 2,
2100                                                                    XmNmarginWidth, 2,
2101                                                                    NULL));
2102
2103    p_w->areas[AW_BOTTOM_AREA] =
2104        new AW_area_management(root, form2, XtVaCreateManagedWidget("bottom_area",
2105                                                                    xmDrawingAreaWidgetClass,
2106                                                                    form2,
2107                                                                    XmNheight, 0,
2108                                                                    XmNbottomAttachment, XmATTACH_FORM,
2109                                                                    XmNtopAttachment, XmATTACH_NONE,
2110                                                                    XmNleftAttachment, XmATTACH_FORM,
2111                                                                    XmNrightAttachment, XmATTACH_FORM,
2112                                                                    NULL));
2113
2114    p_w->scroll_bar_horizontal = XtVaCreateManagedWidget("scroll_bar_horizontal",
2115                                                         xmScrollBarWidgetClass,
2116                                                         form2,
2117                                                         XmNheight, 15,
2118                                                         XmNminimum, 0,
2119                                                         XmNmaximum, AW_SCROLL_MAX,
2120                                                         XmNincrement, 10,
2121                                                         XmNsliderSize, AW_SCROLL_MAX,
2122                                                         XmNrightAttachment, XmATTACH_FORM,
2123                                                         XmNbottomAttachment, XmATTACH_FORM,
2124                                                         XmNbottomOffset, 0,
2125                                                         XmNleftAttachment, XmATTACH_FORM,
2126                                                         XmNtopAttachment, XmATTACH_NONE,
2127                                                         XmNorientation, XmHORIZONTAL,
2128                                                         XmNrightOffset, 18,
2129                                                         NULL);
2130
2131    p_w->scroll_bar_vertical = XtVaCreateManagedWidget("scroll_bar_vertical",
2132                                                       xmScrollBarWidgetClass,
2133                                                       form2,
2134                                                       XmNwidth, 15,
2135                                                       XmNminimum, 0,
2136                                                       XmNmaximum, AW_SCROLL_MAX,
2137                                                       XmNincrement, 10,
2138                                                       XmNsliderSize, AW_SCROLL_MAX,
2139                                                       XmNrightAttachment, XmATTACH_FORM,
2140                                                       XmNbottomAttachment, XmATTACH_WIDGET,
2141                                                       XmNbottomWidget, p_w->scroll_bar_horizontal,
2142                                                       XmNbottomOffset, 3,
2143                                                       XmNleftOffset, 3,
2144                                                       XmNrightOffset, 3,
2145                                                       XmNleftAttachment, XmATTACH_NONE,
2146                                                       XmNtopAttachment, XmATTACH_WIDGET,
2147                                                       XmNtopWidget, INFO_WIDGET,
2148                                                       NULL);
2149
2150    p_w->frame = XtVaCreateManagedWidget("draw_area",
2151                                         xmFrameWidgetClass,
2152                                         form2,
2153                                         XmNshadowType, XmSHADOW_IN,
2154                                         XmNshadowThickness, 2,
2155                                         XmNleftOffset, 3,
2156                                         XmNtopOffset, 3,
2157                                         XmNbottomOffset, 3,
2158                                         XmNrightOffset, 3,
2159                                         XmNbottomAttachment, XmATTACH_WIDGET,
2160                                         XmNbottomWidget, p_w->scroll_bar_horizontal,
2161                                         XmNtopAttachment, XmATTACH_FORM,
2162                                         XmNtopOffset, 0,
2163                                         XmNleftAttachment, XmATTACH_FORM,
2164                                         XmNrightAttachment, XmATTACH_WIDGET,
2165                                         XmNrightWidget, p_w->scroll_bar_vertical,
2166                                         NULL);
2167
2168    p_w->areas[AW_MIDDLE_AREA] =
2169        new AW_area_management(root, p_w->frame, XtVaCreateManagedWidget("draw area",
2170                                                                         xmDrawingAreaWidgetClass,
2171                                                                         p_w->frame,
2172                                                                         XmNmarginHeight, 0,
2173                                                                         XmNmarginWidth, 0,
2174                                                                         NULL));
2175
2176    XmMainWindowSetAreas(main_window, p_w->menu_bar[0], (Widget) NULL, (Widget) NULL, (Widget) NULL, form1);
2177
2178    aw_realize_widget(this);
2179
2180    create_devices();
2181    aw_insert_default_help_entries(this);
2182    create_window_variables();
2183}
2184
2185void AW_window_menu::init(AW_root *root_in, const char *wid, const char *windowname, int width, int height) { 
2186    Widget      main_window;
2187    Widget      help_popup;
2188    Widget      help_label;
2189    Widget      separator;
2190    Widget      form1;
2191    Widget      form2;
2192    const char *help_button   = "HELP";
2193    const char *help_mnemonic = "H";
2194
2195#if defined(DUMP_MENU_LIST)
2196    initMenuListing(windowname);
2197#endif // DUMP_MENU_LIST
2198    root = root_in; // for macro
2199    window_name = strdup(windowname);
2200    window_defaults_name = GBS_string_2_key(wid);
2201
2202    int posx = 50;
2203    int posy = 50;
2204
2205    p_w->shell = aw_create_shell(this, true, true, width, height, posx, posy);
2206
2207    main_window = XtVaCreateManagedWidget("mainWindow1",
2208                                          xmMainWindowWidgetClass, p_w->shell,
2209                                          NULL);
2210
2211    p_w->menu_bar[0] = XtVaCreateManagedWidget("menu1", xmRowColumnWidgetClass,
2212                                               main_window,
2213                                               XmNrowColumnType, XmMENU_BAR,
2214                                               NULL);
2215
2216    // create shell for help-cascade
2217    help_popup = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
2218                                      p_w->menu_bar[0],
2219                                      XmNwidth, 1,
2220                                      XmNheight, 1,
2221                                      XmNallowShellResize, true,
2222                                      XmNoverrideRedirect, true,
2223                                      NULL);
2224
2225    // create row column in Pull-Down shell
2226    p_w->help_pull_down = XtVaCreateWidget("menu_row_column",
2227                                           xmRowColumnWidgetClass, help_popup,
2228                                           XmNrowColumnType, XmMENU_PULLDOWN,
2229                                           NULL);
2230
2231    // create HELP-label in menu bar
2232    help_label = XtVaCreateManagedWidget("menu1_top_b1",
2233                                         xmCascadeButtonWidgetClass, p_w->menu_bar[0],
2234                                         RES_CONVERT(XmNlabelString, help_button),
2235                                         RES_CONVERT(XmNmnemonic, help_mnemonic),
2236                                         XmNsubMenuId, p_w->help_pull_down, NULL);
2237    XtVaSetValues(p_w->menu_bar[0], XmNmenuHelpWidget, help_label, NULL);
2238    root->make_sensitive(help_label, AWM_ALL);
2239
2240    form1 = XtVaCreateManagedWidget("form1",
2241                                    xmFormWidgetClass,
2242                                    main_window,
2243                                    // XmNwidth, width,
2244                                    // XmNheight, height,
2245                                    XmNresizePolicy, XmRESIZE_NONE,
2246                                    // XmNx, 0,
2247                                    // XmNy, 0,
2248                                    NULL);
2249
2250    p_w->mode_area = XtVaCreateManagedWidget("mode area",
2251                                             xmDrawingAreaWidgetClass,
2252                                             form1,
2253                                             XmNresizePolicy, XmRESIZE_NONE,
2254                                             XmNwidth, 17,
2255                                             XmNheight, height,
2256                                             XmNx, 0,
2257                                             XmNy, 0,
2258                                             XmNleftOffset, 0,
2259                                             XmNtopOffset, 0,
2260                                             XmNbottomAttachment, XmATTACH_FORM,
2261                                             XmNleftAttachment, XmATTACH_POSITION,
2262                                             XmNtopAttachment, XmATTACH_POSITION,
2263                                             XmNmarginHeight, 2,
2264                                             XmNmarginWidth, 1,
2265                                             NULL);
2266
2267    separator = p_w->mode_area;
2268
2269    form2 = XtVaCreateManagedWidget("form2",
2270                                    xmFormWidgetClass,
2271                                    form1,
2272                                    XmNwidth, width,
2273                                    XmNheight, height,
2274                                    XmNtopOffset, 0,
2275                                    XmNbottomOffset, 0,
2276                                    XmNleftOffset, 0,
2277                                    XmNrightOffset, 0,
2278                                    XmNrightAttachment, XmATTACH_FORM,
2279                                    XmNbottomAttachment, XmATTACH_FORM,
2280                                    XmNleftAttachment, XmATTACH_WIDGET,
2281                                    XmNleftWidget, separator,
2282                                    XmNtopAttachment, XmATTACH_POSITION,
2283                                    XmNresizePolicy, XmRESIZE_NONE,
2284                                    XmNx, 0,
2285                                    XmNy, 0,
2286                                    NULL);
2287    p_w->areas[AW_INFO_AREA] =
2288        new AW_area_management(root, form2, XtVaCreateManagedWidget("info_area",
2289                                                                    xmDrawingAreaWidgetClass,
2290                                                                    form2,
2291                                                                    XmNheight, 0,
2292                                                                    XmNbottomAttachment, XmATTACH_NONE,
2293                                                                    XmNtopAttachment, XmATTACH_FORM,
2294                                                                    XmNleftAttachment, XmATTACH_FORM,
2295                                                                    XmNrightAttachment, XmATTACH_FORM,
2296                                                                    XmNmarginHeight, 2,
2297                                                                    XmNmarginWidth, 2,
2298                                                                    NULL));
2299
2300    p_w->areas[AW_BOTTOM_AREA] =
2301        new AW_area_management(root, form2, XtVaCreateManagedWidget("bottom_area",
2302                                                                    xmDrawingAreaWidgetClass,
2303                                                                    form2,
2304                                                                    XmNheight, 0,
2305                                                                    XmNbottomAttachment, XmATTACH_FORM,
2306                                                                    XmNtopAttachment, XmATTACH_NONE,
2307                                                                    XmNleftAttachment, XmATTACH_FORM,
2308                                                                    XmNrightAttachment, XmATTACH_FORM,
2309                                                                    NULL));
2310
2311    p_w->scroll_bar_horizontal = XtVaCreateManagedWidget("scroll_bar_horizontal",
2312                                                         xmScrollBarWidgetClass,
2313                                                         form2,
2314                                                         XmNheight, 15,
2315                                                         XmNminimum, 0,
2316                                                         XmNmaximum, AW_SCROLL_MAX,
2317                                                         XmNincrement, 10,
2318                                                         XmNsliderSize, AW_SCROLL_MAX,
2319                                                         XmNrightAttachment, XmATTACH_FORM,
2320                                                         XmNbottomAttachment, XmATTACH_FORM,
2321                                                         XmNbottomOffset, 0,
2322                                                         XmNleftAttachment, XmATTACH_FORM,
2323                                                         XmNtopAttachment, XmATTACH_NONE,
2324                                                         XmNorientation, XmHORIZONTAL,
2325                                                         XmNrightOffset, 18,
2326                                                         NULL);
2327
2328    p_w->scroll_bar_vertical = XtVaCreateManagedWidget("scroll_bar_vertical",
2329                                                       xmScrollBarWidgetClass,
2330                                                       form2,
2331                                                       XmNwidth, 15,
2332                                                       XmNminimum, 0,
2333                                                       XmNmaximum, AW_SCROLL_MAX,
2334                                                       XmNincrement, 10,
2335                                                       XmNsliderSize, AW_SCROLL_MAX,
2336                                                       XmNrightAttachment, XmATTACH_FORM,
2337                                                       XmNbottomAttachment, XmATTACH_WIDGET,
2338                                                       XmNbottomWidget, p_w->scroll_bar_horizontal,
2339                                                       XmNbottomOffset, 3,
2340                                                       XmNleftOffset, 3,
2341                                                       XmNrightOffset, 3,
2342                                                       XmNleftAttachment, XmATTACH_NONE,
2343                                                       XmNtopAttachment, XmATTACH_WIDGET,
2344                                                       XmNtopWidget, INFO_WIDGET,
2345                                                       NULL);
2346
2347    p_w->frame = XtVaCreateManagedWidget("draw_area",
2348                                         xmFrameWidgetClass,
2349                                         form2,
2350                                         XmNshadowType, XmSHADOW_IN,
2351                                         XmNshadowThickness, 2,
2352                                         XmNleftOffset, 3,
2353                                         XmNtopOffset, 3,
2354                                         XmNbottomOffset, 3,
2355                                         XmNrightOffset, 3,
2356                                         XmNbottomAttachment, XmATTACH_WIDGET,
2357                                         XmNbottomWidget, p_w->scroll_bar_horizontal,
2358                                         XmNtopAttachment, XmATTACH_FORM,
2359                                         XmNtopOffset, 0,
2360                                         XmNleftAttachment, XmATTACH_FORM,
2361                                         XmNrightAttachment, XmATTACH_WIDGET,
2362                                         XmNrightWidget, p_w->scroll_bar_vertical,
2363                                         NULL);
2364
2365    p_w->areas[AW_MIDDLE_AREA] =
2366        new AW_area_management(root, p_w->frame, XtVaCreateManagedWidget("draw area",
2367                                                                         xmDrawingAreaWidgetClass,
2368                                                                         p_w->frame,
2369                                                                         XmNmarginHeight, 0,
2370                                                                         XmNmarginWidth, 0,
2371                                                                         NULL));
2372
2373    XmMainWindowSetAreas(main_window, p_w->menu_bar[0], (Widget) NULL,
2374                         (Widget) NULL, (Widget) NULL, form1);
2375
2376    aw_realize_widget(this);
2377
2378    create_devices();
2379    aw_insert_default_help_entries(this);
2380    create_window_variables();
2381}
2382
2383void AW_window_simple::init(AW_root *root_in, const char *wid, const char *windowname) {
2384    root = root_in; // for macro
2385
2386    int width  = 100;                               // this is only the minimum size!
2387    int height = 100;
2388    int posx   = 50;
2389    int posy   = 50;
2390
2391    window_name = strdup(windowname);
2392    window_defaults_name = GBS_string_2_key(wid);
2393
2394    p_w->shell = aw_create_shell(this, true, true, width, height, posx, posy);
2395
2396    // add this to disable resize or maximize in simple dialogs (avoids broken layouts)
2397    // XtVaSetValues(p_w->shell, XmNmwmFunctions, MWM_FUNC_MOVE | MWM_FUNC_CLOSE, NULL);
2398
2399    Widget form1 = XtVaCreateManagedWidget("forms", xmFormWidgetClass,
2400            p_w->shell,
2401            NULL);
2402
2403    p_w->areas[AW_INFO_AREA] = new AW_area_management(root, form1, XtVaCreateManagedWidget("info_area",
2404                    xmDrawingAreaWidgetClass,
2405                    form1,
2406                    XmNbottomAttachment, XmATTACH_FORM,
2407                    XmNtopAttachment, XmATTACH_FORM,
2408                    XmNleftAttachment, XmATTACH_FORM,
2409                    XmNrightAttachment, XmATTACH_FORM,
2410                    XmNmarginHeight, 2,
2411                    XmNmarginWidth, 2,
2412                    NULL));
2413
2414    aw_realize_widget(this);
2415    create_devices();
2416}
2417
2418void AW_window_simple_menu::init(AW_root *root_in, const char *wid, const char *windowname) { 
2419    root = root_in; // for macro
2420
2421    const char *help_button = "HELP";
2422    const char *help_mnemonic = "H";
2423    window_name = strdup(windowname);
2424    window_defaults_name = GBS_string_2_key(wid);
2425
2426    int width = 100;
2427    int height = 100;
2428    int posx = 50;
2429    int posy = 50;
2430
2431    p_w->shell = aw_create_shell(this, true, true, width, height, posx, posy);
2432
2433    Widget main_window;
2434    Widget help_popup;
2435    Widget help_label;
2436    Widget form1;
2437
2438    main_window = XtVaCreateManagedWidget("mainWindow1",
2439                                          xmMainWindowWidgetClass, p_w->shell,
2440                                          NULL);
2441
2442    p_w->menu_bar[0] = XtVaCreateManagedWidget("menu1", xmRowColumnWidgetClass,
2443                                               main_window,
2444                                               XmNrowColumnType, XmMENU_BAR,
2445                                               NULL);
2446
2447    // create shell for help-cascade
2448    help_popup = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
2449                                      p_w->menu_bar[0],
2450                                      XmNwidth, 1,
2451                                      XmNheight, 1,
2452                                      XmNallowShellResize, true,
2453                                      XmNoverrideRedirect, true,
2454                                      NULL);
2455
2456    // create row column in Pull-Down shell
2457    p_w->help_pull_down = XtVaCreateWidget("menu_row_column",
2458                                           xmRowColumnWidgetClass, help_popup,
2459                                           XmNrowColumnType, XmMENU_PULLDOWN,
2460                                           NULL);
2461
2462    // create HELP-label in menu bar
2463    help_label = XtVaCreateManagedWidget("menu1_top_b1",
2464                                         xmCascadeButtonWidgetClass, p_w->menu_bar[0],
2465                                         RES_CONVERT(XmNlabelString, help_button),
2466                                         RES_CONVERT(XmNmnemonic, help_mnemonic),
2467                                         XmNsubMenuId, p_w->help_pull_down, NULL);
2468    XtVaSetValues(p_w->menu_bar[0], XmNmenuHelpWidget, help_label, NULL);
2469    root->make_sensitive(help_label, AWM_ALL);
2470
2471    form1 = XtVaCreateManagedWidget("form1",
2472                                    xmFormWidgetClass,
2473                                    main_window,
2474                                    XmNtopOffset, 10,
2475                                    XmNresizePolicy, XmRESIZE_NONE,
2476                                    NULL);
2477
2478    p_w->areas[AW_INFO_AREA] =
2479        new AW_area_management(root, form1, XtVaCreateManagedWidget("info_area",
2480                                                                    xmDrawingAreaWidgetClass,
2481                                                                    form1,
2482                                                                    XmNbottomAttachment, XmATTACH_FORM,
2483                                                                    XmNtopAttachment, XmATTACH_FORM,
2484                                                                    XmNleftAttachment, XmATTACH_FORM,
2485                                                                    XmNrightAttachment, XmATTACH_FORM,
2486                                                                    XmNmarginHeight, 2,
2487                                                                    XmNmarginWidth, 2,
2488                                                                    NULL));
2489
2490    aw_realize_widget(this);
2491
2492    aw_insert_default_help_entries(this);
2493    create_devices();
2494}
2495
2496void AW_window_message::init(AW_root *root_in, const char *windowname, bool allow_close) {
2497    root = root_in; // for macro
2498
2499    int width  = 100;
2500    int height = 100;
2501    int posx   = 50;
2502    int posy   = 50;
2503
2504    window_name = strdup(windowname);
2505    window_defaults_name = GBS_string_2_key(window_name);
2506
2507    // create shell for message box
2508    p_w->shell = aw_create_shell(this, true, allow_close, width, height, posx, posy);
2509
2510    // disable resize or maximize in simple dialogs (avoids broken layouts)
2511    XtVaSetValues(p_w->shell, XmNmwmFunctions, MWM_FUNC_MOVE | MWM_FUNC_CLOSE,
2512            NULL);
2513
2514    p_w->areas[AW_INFO_AREA] = new AW_area_management(root, p_w->shell, XtVaCreateManagedWidget("info_area",
2515                    xmDrawingAreaWidgetClass,
2516                    p_w->shell,
2517                    XmNheight, 0,
2518                    XmNbottomAttachment, XmATTACH_NONE,
2519                    XmNtopAttachment, XmATTACH_FORM,
2520                    XmNleftAttachment, XmATTACH_FORM,
2521                    XmNrightAttachment, XmATTACH_FORM,
2522                    NULL));
2523
2524    aw_realize_widget(this);
2525}
2526
2527void AW_window::set_focus_policy(bool follow_mouse) {
2528    int focusPolicy = follow_mouse ? XmPOINTER : XmEXPLICIT;
2529    XtVaSetValues(p_w->shell, XmNkeyboardFocusPolicy, focusPolicy, NULL);
2530}
2531
2532void AW_window::select_mode(int mode) {
2533    if (mode >= p_w->number_of_modes)
2534        return;
2535
2536    Widget oldwidget = p_w->modes_widgets[p_w->selected_mode];
2537    p_w->selected_mode = mode;
2538    Widget widget = p_w->modes_widgets[p_w->selected_mode];
2539    XtVaSetValues(oldwidget, XmNbackground, p_global->background, NULL);
2540    XtVaSetValues(widget, XmNbackground, p_global->foreground, NULL);
2541}
2542
2543static void aw_mode_callback(AW_window *aww, long mode, AW_cb *cbs) {
2544    aww->select_mode((int)mode);
2545    cbs->run_callbacks();
2546}
2547
2548#define MODE_BUTTON_OFFSET 34
2549inline int yoffset_for_mode_button(int button_number) {
2550    return button_number*MODE_BUTTON_OFFSET + (button_number/4)*8 + 2;
2551}
2552
2553int AW_window::create_mode(const char *pixmap, const char *helpText, AW_active mask, const WindowCallback& cb) {
2554    aw_assert(legal_mask(mask));
2555    Widget button;
2556
2557    TuneBackground(p_w->mode_area, TUNE_BUTTON); // set background color for mode-buttons
2558
2559    const char *path = AW_get_pixmapPath(pixmap);
2560
2561    int y = yoffset_for_mode_button(p_w->number_of_modes);
2562    button = XtVaCreateManagedWidget("", xmPushButtonWidgetClass, p_w->mode_area,
2563                                     XmNx,               0,
2564                                     XmNy,               y,
2565                                     XmNlabelType,       XmPIXMAP,
2566                                     XmNshadowThickness, 1,
2567                                     XmNbackground,      _at->background_color,
2568                                     NULL);
2569    XtVaSetValues(button, RES_CONVERT(XmNlabelPixmap, path), NULL);
2570    XtVaGetValues(button, XmNforeground, &p_global->foreground, NULL);
2571
2572    AW_cb *cbs = new AW_cb(this, cb, 0);
2573    AW_cb *cb2 = new AW_cb(this, (AW_CB)aw_mode_callback, (AW_CL)p_w->number_of_modes, (AW_CL)cbs, helpText, cbs);
2574    XtAddCallback(button, XmNactivateCallback,
2575    (XtCallbackProc) AW_server_callback,
2576    (XtPointer) cb2);
2577
2578    if (!p_w->modes_f_callbacks) {
2579        p_w->modes_f_callbacks = (AW_cb **)GB_calloc(sizeof(AW_cb*), AW_NUMBER_OF_F_KEYS); // valgrinders : never freed because AW_window never is freed
2580    }
2581    if (!p_w->modes_widgets) {
2582        p_w->modes_widgets = (Widget *)GB_calloc(sizeof(Widget), AW_NUMBER_OF_F_KEYS);
2583    }
2584    if (p_w->number_of_modes<AW_NUMBER_OF_F_KEYS) {
2585        p_w->modes_f_callbacks[p_w->number_of_modes] = cb2;
2586        p_w->modes_widgets[p_w->number_of_modes] = button;
2587    }
2588
2589    root->make_sensitive(button, mask);
2590    p_w->number_of_modes++;
2591
2592    int ynext = yoffset_for_mode_button(p_w->number_of_modes);
2593    if (ynext> _at->max_y_size) _at->max_y_size = ynext;
2594
2595    return p_w->number_of_modes;
2596}
2597
2598AW_area_management::AW_area_management(AW_root *awr, Widget formi, Widget widget) {
2599    memset((char *)this, 0, sizeof(AW_area_management));
2600    form = formi;
2601    area = widget;
2602    XtAddEventHandler(area, EnterWindowMask, FALSE, AW_root_focusCB, (XtPointer)awr);
2603}
2604
2605AW_device_Xm *AW_area_management::get_screen_device() {
2606    if (!device) device = new AW_device_Xm(common);
2607    return device;
2608}
2609
2610AW_device_size *AW_area_management::get_size_device() {
2611    if (!size_device) size_device = new AW_device_size(common);
2612    return size_device;
2613}
2614
2615AW_device_print *AW_area_management::get_print_device() {
2616    if (!print_device) print_device = new AW_device_print(common);
2617    return print_device;
2618}
2619
2620AW_device_click *AW_area_management::get_click_device() {
2621    if (!click_device) click_device = new AW_device_click(common);
2622    return click_device;
2623}
2624
2625void AW_window::wm_activate() {
2626    {
2627        Boolean iconic = False;
2628        XtVaGetValues(p_w->shell, XmNiconic, &iconic, NULL);
2629
2630        if (iconic == True) {
2631            XtVaSetValues(p_w->shell, XmNiconic, False, NULL);
2632
2633            XtMapWidget(p_w->shell);
2634            XRaiseWindow(XtDisplay(p_w->shell), XtWindow(p_w->shell));
2635        }
2636    }
2637
2638    {
2639        Display *xdpy            = XtDisplay(p_w->shell);
2640        Window   window          = XtWindow(p_w->shell);
2641        Atom     netactivewindow = XInternAtom(xdpy, "_NET_ACTIVE_WINDOW", False);
2642
2643        if (netactivewindow) {
2644
2645            XClientMessageEvent ce;
2646            ce.type         = ClientMessage;
2647            ce.display      = xdpy;
2648            ce.window       = window;
2649            ce.message_type = netactivewindow;
2650            ce.format       = 32;
2651            ce.data.l[0]    = 2;
2652            ce.data.l[1]    = None;
2653            ce.data.l[2]    = Above;
2654            ce.data.l[3]    = 0;
2655            ce.data.l[4]    = 0;
2656
2657#if defined(DEBUG)
2658            Status ret =
2659#endif // DEBUG
2660                XSendEvent(xdpy, XDefaultRootWindow(xdpy),
2661                           False,
2662                           SubstructureRedirectMask | SubstructureNotifyMask,
2663                           (XEvent *) &ce);
2664
2665#if defined(DEBUG)
2666            if (!ret) { fprintf(stderr, "Failed to send _NET_ACTIVE_WINDOW to WM (XSendEvent returns %i)\n", ret); }
2667#endif // DEBUG
2668            XSync(xdpy, False);
2669        }
2670#if defined(DEBUG)
2671        else {
2672            fputs("No such atom '_NET_ACTIVE_WINDOW'\n", stderr);
2673        }
2674#endif // DEBUG
2675    }
2676}
2677
2678// ----------------------------------------------------------------------
2679// force-diff-sync 9268347253894 (remove after merging back to trunk)
2680// ----------------------------------------------------------------------
2681
2682bool AW_window::is_shown() const {
2683    // return true if window is shown ( = not invisible and already created)
2684    // Note: does return TRUE!, if window is only minimized by WM
2685    return window_is_shown;
2686}
2687
2688void AW_window::show() {
2689    bool was_shown = true;
2690    if (!window_is_shown) {
2691        all_menus_created();
2692        get_root()->window_show();
2693        window_is_shown = true;
2694        was_shown       = false;
2695    }
2696
2697    if (recalc_size_at_show != AW_KEEP_SIZE) {
2698        if (recalc_size_at_show == AW_RESIZE_DEFAULT) {
2699            window_fit();
2700        }
2701        else {
2702            aw_assert(recalc_size_at_show == AW_RESIZE_USER);
2703            // check whether user size is too small and increase to minimum window size
2704
2705            int min_width, min_height;   get_window_size(min_width, min_height);
2706            int user_width, user_height; get_size_from_awars(user_width, user_height);
2707
2708            if (user_width <min_width)  user_width  = min_width;
2709            if (user_height<min_height) user_height = min_height;
2710
2711            set_window_size(user_width, user_height);
2712        }
2713        recalc_size_at_show = AW_KEEP_SIZE;
2714    }
2715
2716    {
2717        int  posx, posy;
2718        bool setPos = false;
2719
2720        switch (recalc_pos_at_show) {
2721            case AW_REPOS_TO_MOUSE_ONCE:
2722                recalc_pos_at_show = AW_KEEP_POS;
2723                // fallthrough
2724            case AW_REPOS_TO_MOUSE: {
2725                int mx, my; if (!get_mouse_pos(mx, my)) goto FALLBACK_CENTER;
2726                int width, height; get_window_size(width, height);
2727                {
2728                    int wx, wy; get_window_content_pos(wx, wy);
2729                    if (wx || wy) {
2730                        if (p_w->knows_WM_offset()) {
2731                            wx -= p_w->WM_left_offset;
2732                            wy -= p_w->WM_top_offset; // @@@ values of wx/wy never used
2733
2734                            // add size of window decoration
2735                            width  += p_w->WM_left_offset;
2736                            height += p_w->WM_top_offset;
2737                        }
2738                    }
2739                }
2740
2741                setPos = true;
2742                posx   = mx-width/2;
2743                posy   = my-height/2;
2744               
2745                // avoid windows outside of screen
2746                {
2747                    int swidth, sheight; get_screen_size(swidth, sheight);
2748                    int maxx = swidth-width;
2749                    int maxy = sheight-height;
2750
2751                    if (posx>maxx) posx = maxx;
2752                    if (posy>maxy) posy = maxy;
2753
2754                    if (posx<0) posx = 0;
2755                    if (posy<0) posy = 0;
2756                }
2757
2758                break;
2759            }
2760            case AW_REPOS_TO_CENTER: {
2761                  FALLBACK_CENTER :
2762                int width, height; get_window_size(width, height);
2763                int swidth, sheight; get_screen_size(swidth, sheight);
2764
2765                setPos = true;
2766                posx   = (swidth-width)/2;
2767                posy   = (sheight-height)/4;
2768                break;
2769            }
2770
2771            case AW_KEEP_POS:
2772                if (was_shown) {
2773                    // user might have moved the window -> store (new) positions
2774                    aw_update_window_geometry_awars(this);
2775                }
2776                break;
2777        }
2778
2779        if (setPos) store_pos_in_awars(posx, posy);
2780        else get_pos_from_awars(posx, posy);
2781
2782        set_window_frame_pos(posx, posy); // always set pos
2783    }
2784
2785    XtPopup(p_w->shell, XtGrabNone);
2786    if (!expose_callback_added) {
2787        set_expose_callback(AW_INFO_AREA, aw_onExpose_calc_WM_offsets); // @@@ should be removed after it was called once
2788        expose_callback_added = true;
2789    }
2790}
2791
2792void AW_window::show_modal() {
2793    recalc_pos_atShow(AW_REPOS_TO_MOUSE);
2794    get_root()->current_modal_window = this;
2795    activate();
2796}
2797
2798void AW_window::hide() {
2799    if (window_is_shown) {
2800        aw_update_window_geometry_awars(this);
2801        if (hide_cb) hide_cb(this);
2802        get_root()->window_hide(this);
2803        window_is_shown = false;
2804    }
2805    XtPopdown(p_w->shell);
2806}
2807
2808void AW_window::hide_or_notify(const char *error){
2809    if (error) aw_message(error);
2810    else hide();
2811}
2812
2813void AW_window::_set_activate_callback(void *widget) {
2814    if (_callback && (long)_callback != 1) {
2815        if (!_callback->help_text && _at->helptext_for_next_button) {
2816            _callback->help_text = _at->helptext_for_next_button;
2817            _at->helptext_for_next_button = 0;
2818        }
2819
2820        XtAddCallback((Widget) widget, XmNactivateCallback,
2821                (XtCallbackProc) AW_server_callback, (XtPointer) _callback);
2822    }
2823    _callback = NULL;
2824}
2825
2826
2827void AW_window::set_background(const char *colorname, Widget parentWidget) {
2828    bool colorSet = false;
2829
2830    if (colorname) {
2831        XColor unused, color;
2832
2833        if (XAllocNamedColor(p_global->display, p_global->colormap, colorname, &color, &unused)
2834                == 0) {
2835            fprintf(stderr, "XAllocColor failed: %s\n", colorname);
2836        }
2837        else {
2838            _at->background_color = color.pixel;
2839            colorSet = true;
2840        }
2841    }
2842
2843    if (!colorSet) {
2844        XtVaGetValues(parentWidget, XmNbackground, &(_at->background_color),
2845                NULL); // fallback to background color
2846    }
2847}
2848
2849void AW_window::TuneOrSetBackground(Widget w, const char *color, int modStrength) {
2850    // Sets the background for the next created widget.
2851    //
2852    // If 'color' is specified, it may contain one of the following values:
2853    //      "+"    means: slightly increase color of parent widget 'w'
2854    //      "-"    means: slightly decrease color of parent widget 'w'
2855    //      otherwise it contains a specific color ('name' or '#RGB')
2856    //
2857    // If color is not specified, the color of the parent widget 'w' is modified
2858    // by 'modStrength' (increased if positive,  decreased if negative)
2859    //
2860    // If it's not possible to modify the color (e.g. we cannot increase 'white'),
2861    // the color will be modified in the opposite direction. For details see TuneBackground()
2862
2863    if (color) {
2864        switch (color[0]) {
2865        case '+':
2866            TuneBackground(w, TUNE_BRIGHT);
2867            break;
2868        case '-':
2869            TuneBackground(w, TUNE_DARK);
2870            break;
2871        default:
2872            set_background(color, w); // use explicit color
2873        }
2874    }
2875    else {
2876        TuneBackground(w, modStrength);
2877    }
2878}
2879
2880void AW_window::TuneBackground(Widget w, int modStrength) {
2881    // Gets the Background Color, modifies the rgb values slightly and sets new background color
2882    // Intended to give buttons a nicer 3D-look.
2883    //
2884    // possible values for modStrength:
2885    //
2886    //    0        = do not modify (i.e. set to background color of parent widget)
2887    //    1 .. 127 = increase if background is bright, decrease if background is dark
2888    //   -1 ..-127 = opposite behavior than above
2889    //  256 .. 383 = always increase
2890    // -256 ..-383 = always decrease
2891    //
2892    // if it's impossible to decrease or increase -> opposite direction is used.
2893
2894    int col[3];
2895    {
2896        Pixel bg;
2897        XtVaGetValues(w, XmNbackground, &bg, NULL);
2898
2899        XColor xc;
2900        xc.pixel = bg;
2901        XQueryColor(XtDisplay(w), p_global->colormap, &xc);
2902
2903        col[0] = xc.red >> 8; // take MSB
2904        col[1] = xc.green >> 8;
2905        col[2] = xc.blue >> 8;
2906    }
2907
2908    int mod = modStrength;
2909    int preferredDir = 0;
2910    bool invertedMod = false;
2911
2912    if (modStrength>0) {
2913        if (modStrength>255) {
2914            mod -= 256;
2915            preferredDir = 1; // increase preferred
2916        }
2917    }
2918    else {
2919        if (modStrength<-255) {
2920            mod = -modStrength-256;
2921            preferredDir = -1; // decrease preferred
2922        }
2923        else {
2924            invertedMod = true;
2925            mod = -mod;
2926        }
2927    }
2928
2929    aw_assert(mod >= 0 && mod < 128);
2930    // illegal modification
2931
2932    bool incPossible[3]; // increment possible for color
2933    bool decPossible[3]; // decrement possible for color
2934    int incs = 0; // count possible increments
2935    int decs = 0; // count possible decrements
2936
2937    for (int i = 0; i<3; ++i) {
2938        if ((incPossible[i] = ((col[i]+mod) <= 255)))
2939            incs++;
2940        if ((decPossible[i] = ((col[i]-mod) >= 0)))
2941            decs++;
2942    }
2943
2944    aw_assert(incs||decs);
2945
2946    switch (preferredDir) {
2947    case 0: // no direction preferred yet, need to decide
2948        if (invertedMod)
2949            preferredDir = decs ? -1 : 1;
2950        else
2951            preferredDir = incs ? 1 : -1;
2952        break;
2953    case 1:
2954        if (!incs)
2955            preferredDir = -1;
2956        break;
2957    case -1:
2958        if (!decs)
2959            preferredDir = 1;
2960        break;
2961    }
2962
2963    aw_assert(preferredDir == 1 || preferredDir == -1); // no direction chosen above
2964
2965    if (preferredDir == 1) {
2966        for (int i=0; i<3; ++i) col[i] += (incPossible[i] ? mod : 0);
2967    }
2968    else if (preferredDir == -1) {
2969        for (int i=0; i<3; ++i) col[i] -= (decPossible[i] ? mod : 0);
2970    }
2971
2972
2973    char hex_color[50];
2974    sprintf(hex_color, "#%2.2X%2.2X%2.2X", col[0], col[1], col[2]);
2975    aw_assert(strlen(hex_color) == 7);
2976    // otherwise some value overflowed
2977    set_background(hex_color, w);
2978}
2979
2980void AW_root::make_sensitive(Widget w, AW_active mask) {
2981    // Don't call make_sensitive directly!
2982    //
2983    // Simply set sens_mask(AWM_EXP) and after creating the expert-mode-only widgets,
2984    // set it back using sens_mask(AWM_ALL)
2985
2986    aw_assert(w);
2987    aw_assert(legal_mask(mask));
2988
2989    prvt->set_last_widget(w);
2990
2991    if (mask != AWM_ALL) { // no need to make widget sensitive, if its shown unconditionally
2992        button_sens_list = new AW_buttons_struct(mask, w, button_sens_list);
2993        if (!(mask & global_mask)) XtSetSensitive(w, False); // disable widget if mask doesn't match
2994    }
2995}
2996
2997AW_buttons_struct::AW_buttons_struct(AW_active maski, Widget w, AW_buttons_struct *prev_button) {
2998    aw_assert(w);
2999    aw_assert(legal_mask(maski));
3000
3001    mask     = maski;
3002    button   = w;
3003    next     = prev_button;
3004}
3005
3006AW_buttons_struct::~AW_buttons_struct() {
3007    delete next;
3008}
3009
3010bool AW_root::remove_button_from_sens_list(Widget button) {
3011    bool removed = false;
3012    if (button_sens_list) {
3013        AW_buttons_struct *prev = 0;
3014        AW_buttons_struct *bl   = button_sens_list;
3015
3016        while (bl) {
3017            if (bl->button == button) break; // found wanted widget
3018            prev = bl;
3019            bl = bl->next;
3020        }
3021
3022        if (bl) {
3023            // remove from list
3024            if (prev) prev->next  = bl->next;
3025            else button_sens_list = bl->next;
3026
3027            bl->next = 0;
3028            removed  = true;
3029
3030            delete bl;
3031        }
3032    }
3033    return removed;
3034}
3035
3036AW_option_menu_struct::AW_option_menu_struct(int numberi, const char *variable_namei,
3037                                             AW_VARIABLE_TYPE variable_typei, Widget label_widgeti,
3038                                             Widget menu_widgeti, AW_pos xi, AW_pos yi, int correct) {
3039    option_menu_number = numberi;
3040    variable_name      = strdup(variable_namei);
3041    variable_type      = variable_typei;
3042    label_widget       = label_widgeti;
3043    menu_widget        = menu_widgeti;
3044    first_choice       = NULL;
3045    last_choice        = NULL;
3046    default_choice     = NULL;
3047    next               = NULL;
3048    x                  = xi;
3049    y                  = yi;
3050
3051    correct_for_at_center_intern = correct;
3052}
3053
3054AW_toggle_field_struct::AW_toggle_field_struct(int toggle_field_numberi,
3055        const char *variable_namei, AW_VARIABLE_TYPE variable_typei,
3056        Widget label_widgeti, int correct) {
3057
3058    toggle_field_number = toggle_field_numberi;
3059    variable_name = strdup(variable_namei);
3060    variable_type = variable_typei;
3061    label_widget = label_widgeti;
3062    first_toggle = NULL;
3063    last_toggle = NULL;
3064    default_toggle = NULL;
3065    next = NULL;
3066    correct_for_at_center_intern = correct;
3067}
3068
3069AW_window_Motif::AW_window_Motif() {
3070    memset((char*)this, 0, sizeof(AW_window_Motif));
3071}
Note: See TracBrowser for help on using the repository browser.