source: tags/arb_5.3/WINDOW/AW_window.cxx

Last change on this file was 6149, checked in by westram, 15 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 124.4 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <memory.h>
4#include <stdarg.h>
5#include <ctype.h>
6
7#include <sys/types.h>
8#include <sys/uio.h>
9#include <unistd.h>
10
11#include <Xm/Xm.h>
12#include <X11/keysym.h>
13#include <X11/Xlib.h>
14#include <X11/Xutil.h>
15#include <X11/Shell.h>
16#include <X11/cursorfont.h>
17#include <Xm/AtomMgr.h>
18#include <Xm/Frame.h>
19#include <Xm/PushB.h>
20#include <Xm/Protocols.h>
21#include <Xm/RowColumn.h>
22#include <Xm/DrawingA.h>
23#include <Xm/Form.h>
24#include <Xm/Separator.h>
25#include <Xm/MainW.h>
26#include <Xm/CascadeB.h>
27#include <Xm/MenuShell.h>
28#include <Xm/ScrollBar.h>
29#include <Xm/MwmUtil.h>
30
31#include <arbdb.h>
32#include <arbdbt.h>
33
34/* Eigene Klassendefinition */
35#include "aw_root.hxx"
36#include "aw_device.hxx"
37#include "aw_commn.hxx"
38#include "aw_keysym.hxx"
39#include "aw_at.hxx"
40#include "aw_window.hxx"
41#include "aw_awar.hxx"
42#include "aw_xfig.hxx"
43#include "aw_xfigfont.hxx"
44/* hier die Motif abhaengigen Teile */
45#include "aw_Xm.hxx"
46#include "aw_click.hxx"
47#include "aw_size.hxx"
48#include "aw_print.hxx"
49#include "aw_window_Xm.hxx"
50#include "aw_xkey.hxx"
51
52#include "aw_global.hxx"
53
54AW_root *AW_root::THIS= NULL;
55
56AW_cb_struct::AW_cb_struct(AW_window *awi, void (*g)(AW_window*,AW_CL,AW_CL), AW_CL cd1i, AW_CL cd2i,
57        const char *help_texti, class AW_cb_struct *nexti) {
58    aw = awi;
59    f = g;
60    cd1 = cd1i;
61    cd2 = cd2i;
62    help_text = help_texti;
63    pop_up_window = NULL;
64    this->next = nexti;
65}
66
67AW_timer_cb_struct::AW_timer_cb_struct(AW_root *ari, void (*g)(AW_root*,AW_CL,AW_CL), AW_CL cd1i, AW_CL cd2i) {
68    ar = ari;
69    f = g;
70    cd1 = cd1i;
71    cd2 = cd2i;
72}
73AW_timer_cb_struct::~AW_timer_cb_struct(void) {
74}
75
76void AW_root::make_sensitive(Widget w, AW_active mask) {
77    // Dont call make_sensitive directly!
78    //
79    // Simply set sens_mask(AWM_EXP) and after creating the expert-mode-only widgets,
80    // set it back using sens_mask(AWM_ALL)
81
82    aw_assert(w);
83    aw_assert(legal_mask(mask));
84   
85    prvt->set_last_widget(w);
86
87    if (mask != AWM_ALL) { // no need to make widget sensitive, if its shown unconditionally
88        prvt->button_list = new AW_buttons_struct(mask, w, prvt->button_list);
89        if (!(mask & global_mask)) XtSetSensitive(w, False); // disable widget if mask doesnt match
90    }
91}
92
93AW_buttons_struct::AW_buttons_struct(AW_active maski, Widget w, AW_buttons_struct *prev_button) {
94    aw_assert(w);
95    aw_assert(legal_mask(maski));
96
97    mask     = maski;
98    button   = w;
99    next     = prev_button;
100}
101
102AW_buttons_struct::~AW_buttons_struct() {
103    aw_assert(next == 0); // has to be removed from global list before calling dtor
104}
105
106bool AW_remove_button_from_sens_list(AW_root *root, Widget w) {
107    bool removed = false;
108    if (p_global->button_list) {
109        AW_buttons_struct *prev = 0;
110        AW_buttons_struct *bl   = p_global->button_list;
111
112        while (bl) {
113            if (bl->button == w) break; // found wanted widget
114            prev = bl;
115            bl = bl->next;
116        }
117
118        if (bl) {
119            // remove from list
120            if (prev) prev->next       = bl->next;
121            else p_global->button_list = bl->next;
122
123            bl->next = 0;
124            removed  = true;
125           
126            delete bl;
127        }
128    }
129    return removed;
130}
131
132AW_config_struct::AW_config_struct(const char *idi, AW_active maski, Widget w,
133                                   const char *variable_namei, const char *variable_valuei,
134                                   AW_config_struct *nexti)
135{
136    aw_assert(legal_mask(maski));
137   
138    id             = strdup(idi);
139    mask           = maski;
140    widget         = w;
141    variable_name  = strdup(variable_namei);
142    variable_value = strdup(variable_valuei);
143    next           = nexti;
144}
145
146/*************************************************************************************************************/
147
148AW_option_struct::AW_option_struct(const char *variable_valuei,
149        Widget choice_widgeti) :
150    variable_value(strdup(variable_valuei)), choice_widget(choice_widgeti),
151            next(0) {
152}
153
154AW_option_struct::AW_option_struct(int variable_valuei, Widget choice_widgeti) :
155    variable_value(0), variable_int_value(variable_valuei),
156            choice_widget(choice_widgeti), next(0) {
157}
158
159AW_option_struct::AW_option_struct(float variable_valuei, Widget choice_widgeti) :
160    variable_value(0), variable_float_value(variable_valuei),
161            choice_widget(choice_widgeti), next(0) {
162}
163
164AW_option_struct::~AW_option_struct() {
165    aw_assert(next == 0);
166    // has to be unlinked from list BEFORE calling dtor
167    free(variable_value);
168}
169
170AW_option_menu_struct::AW_option_menu_struct(int numberi, const char *variable_namei,
171                                             AW_VARIABLE_TYPE variable_typei, Widget label_widgeti,
172                                             Widget menu_widgeti, AW_pos xi, AW_pos yi, int correct) {
173    option_menu_number = numberi;
174    variable_name      = strdup(variable_namei);
175    variable_type      = variable_typei;
176    label_widget       = label_widgeti;
177    menu_widget        = menu_widgeti;
178    first_choice       = NULL;
179    last_choice        = NULL;
180    default_choice     = NULL;
181    next               = NULL;
182    x                  = xi;
183    y                  = yi;
184
185    correct_for_at_center_intern = correct;
186}
187
188AW_toggle_field_struct::AW_toggle_field_struct(int toggle_field_numberi,
189        const char *variable_namei, AW_VARIABLE_TYPE variable_typei,
190        Widget label_widgeti, int correct) {
191
192    toggle_field_number = toggle_field_numberi;
193    variable_name = strdup(variable_namei);
194    variable_type = variable_typei;
195    label_widget = label_widgeti;
196    first_toggle = NULL;
197    last_toggle = NULL;
198    default_toggle = NULL;
199    next = NULL;
200    correct_for_at_center_intern = correct;
201}
202AW_toggle_struct::AW_toggle_struct(const char *variable_valuei,
203        Widget toggle_widgeti) {
204
205    variable_value = strdup(variable_valuei);
206    toggle_widget = toggle_widgeti;
207    next = NULL;
208
209}
210AW_toggle_struct::AW_toggle_struct(int variable_valuei, Widget toggle_widgeti) {
211
212    variable_int_value = variable_valuei;
213    toggle_widget = toggle_widgeti;
214    next = NULL;
215
216}
217AW_toggle_struct::AW_toggle_struct(float variable_valuei, Widget toggle_widgeti) {
218
219    variable_float_value = variable_valuei;
220    toggle_widget = toggle_widgeti;
221    next = NULL;
222
223}
224char *AW_select_table_struct::copy_string(const char *str) {
225    char *out = strdup(str);
226    char *p   = out;
227    int   ch;
228   
229    while ((ch=*(p++)) != 0) {
230        if (ch==',')
231            p[-1] = ';';
232        if (ch=='\n')
233            p[-1] = '#';
234    }
235    return out;
236}
237
238AW_select_table_struct::AW_select_table_struct(const char *displayedi, const char *valuei) {
239    memset((char *)this, 0, sizeof(AW_select_table_struct));
240    displayed = copy_string(displayedi);
241    char_value = strdup(valuei);
242}
243AW_select_table_struct::AW_select_table_struct(const char *displayedi, long valuei) {
244    memset((char *)this, 0, sizeof(AW_select_table_struct));
245    displayed = copy_string(displayedi);
246    int_value = valuei;;
247}
248AW_select_table_struct::AW_select_table_struct(const char *displayedi, float valuei) {
249    memset((char *)this, 0, sizeof(AW_select_table_struct));
250    displayed = copy_string(displayedi);
251    float_value = valuei;
252}
253AW_select_table_struct::AW_select_table_struct(const char *displayedi, void *pointer) {
254    memset((char *)this, 0, sizeof(AW_select_table_struct));
255    displayed = copy_string(displayedi);
256    pointer_value = pointer;
257}
258AW_select_table_struct::~AW_select_table_struct(void) {
259    free(displayed);
260    free(char_value);
261}
262
263AW_selection_list::AW_selection_list(const char *variable_namei, int variable_typei, Widget select_list_widgeti) {
264    memset((char *)this, 0, sizeof(AW_selection_list));
265    variable_name = nulldup(variable_namei);
266    variable_type = (AW_VARIABLE_TYPE)variable_typei;
267    select_list_widget = select_list_widgeti;
268    list_table = NULL;
269    last_of_list_table = NULL;
270    default_select = NULL;
271    value_equal_display = false;
272}
273
274AW_root::AW_root(void) {
275    memset((char *)this, 0, sizeof(AW_root));
276    this->THIS = this;
277    this->prvt = (AW_root_Motif *)GB_calloc(sizeof(AW_root_Motif), 1);
278}
279
280AW_root::~AW_root(void) {
281    delete prvt;
282}
283
284AW_window_Motif::AW_window_Motif() {
285    memset((char*)this, 0, sizeof(AW_window_Motif));
286}
287
288AW_window::AW_window(void) {
289    memset((char *)this, 0, sizeof(AW_window));
290    p_w = new AW_window_Motif;
291    _at = new AW_at; // Note to valgrinders : the whole AW_window memory management suffers because Windows are NEVER deleted
292    picture = new AW_rectangle;
293    reset_scrolled_picture_size();
294    slider_pos_vertical = 0;
295    slider_pos_horizontal = 0;
296
297}
298
299AW_window::~AW_window(void) {
300    delete p_w;
301    delete picture;
302}
303
304#if defined(DEBUG)
305// #define DUMP_MENU_LIST          // this should NOT be defined normally (if defined, every window writes all menu-entries to stdout)
306#endif // DEBUG
307#if defined(DUMP_MENU_LIST)
308
309static char *window_name = 0;
310static char *sub_menu = 0;
311
312static void initMenuListing(const char *win_name) {
313    aw_assert(win_name);
314
315    freedup(window_name, win_name);
316    freeset(sub_menu, 0);
317
318    printf("---------------------------------------- list of menus for '%s'\n", window_name);
319}
320
321static void dumpMenuEntry(const char *entry) {
322    aw_assert(window_name);
323    if (sub_menu) {
324        printf("'%s/%s/%s'\n", window_name, sub_menu, entry);
325    }
326    else {
327        printf("'%s/%s'\n", window_name, entry);
328    }
329}
330
331static void dumpOpenSubMenu(const char *sub_name) {
332    aw_assert(sub_name);
333
334    dumpMenuEntry(sub_name); // dump the menu itself
335
336    if (sub_menu) freeset(sub_menu, GBS_global_string_copy("%s/%s", sub_menu, sub_name));
337    else sub_menu = strdup(sub_name);
338}
339
340static void dumpCloseSubMenu() {
341    aw_assert(sub_menu);
342    char *lslash = strrchr(sub_menu, '/');
343    if (lslash) {
344        lslash[0] = 0;
345    }
346    else freeset(sub_menu, 0);
347}
348
349static void dumpCloseAllSubMenus() {
350    freeset(sub_menu, 0);
351}
352
353#endif // DUMP_MENU_LIST
354AW_window_menu_modes::AW_window_menu_modes(void) {
355}
356AW_window_menu_modes::~AW_window_menu_modes(void) {
357}
358
359AW_window_menu::AW_window_menu(void) {
360}
361AW_window_menu::~AW_window_menu(void) {
362}
363
364AW_window_simple::AW_window_simple(void) {
365}
366AW_window_simple::~AW_window_simple(void) {
367}
368
369AW_window_simple_menu::AW_window_simple_menu(void) {
370}
371AW_window_simple_menu::~AW_window_simple_menu(void) {
372}
373
374AW_window_message::AW_window_message(void) {
375}
376AW_window_message::~AW_window_message(void) {
377}
378
379/***********************************************************************/
380void AW_window::set_horizontal_scrollbar_left_indent(int indent) {
381    XtVaSetValues(p_w->scroll_bar_horizontal, XmNleftOffset, (int)indent, NULL);
382    left_indent_of_horizontal_scrollbar = indent;
383}
384
385/***********************************************************************/
386static void value_changed_scroll_bar_horizontal(Widget wgt,
387        XtPointer aw_cb_struct, XtPointer call_data) {
388    AWUSE(wgt);
389    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
390    AW_cb_struct *cbs = (AW_cb_struct *) aw_cb_struct;
391    (cbs->aw)->slider_pos_horizontal = sbcbs->value; //setzt Scrollwerte im AW_window
392    cbs->run_callback();
393}
394static void drag_scroll_bar_horizontal(Widget wgt, XtPointer aw_cb_struct,
395        XtPointer call_data) {
396    AWUSE(wgt);
397    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
398    AW_cb_struct *cbs = (AW_cb_struct *) aw_cb_struct;
399    (cbs->aw)->slider_pos_horizontal = sbcbs->value; //setzt Scrollwerte im AW_window
400    cbs->run_callback();
401}
402void AW_window::set_horizontal_change_callback(void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
403    XtAddCallback(p_w->scroll_bar_horizontal, XmNvalueChangedCallback,
404            (XtCallbackProc) value_changed_scroll_bar_horizontal,
405            (XtPointer) new AW_cb_struct(this, f, cd1, cd2, "") );
406    XtAddCallback(p_w->scroll_bar_horizontal, XmNdragCallback,
407            (XtCallbackProc) drag_scroll_bar_horizontal,
408            (XtPointer) new AW_cb_struct(this, f, cd1, cd2, "") );
409}
410
411static void value_changed_scroll_bar_vertical(Widget wgt,
412        XtPointer aw_cb_struct, XtPointer call_data) {
413    AWUSE(wgt);
414    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
415    AW_cb_struct *cbs = (AW_cb_struct *) aw_cb_struct;
416    cbs->aw->slider_pos_vertical = sbcbs->value; //setzt Scrollwerte im AW_window
417    cbs->run_callback();
418}
419static void drag_scroll_bar_vertical(Widget wgt, XtPointer aw_cb_struct,
420        XtPointer call_data) {
421    AWUSE(wgt);
422    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
423    AW_cb_struct *cbs = (AW_cb_struct *) aw_cb_struct;
424    cbs->aw->slider_pos_vertical = sbcbs->value; //setzt Scrollwerte im AW_window
425    cbs->run_callback();
426}
427
428void AW_window::set_vertical_change_callback(void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
429    XtAddCallback(p_w->scroll_bar_vertical, XmNvalueChangedCallback,
430            (XtCallbackProc) value_changed_scroll_bar_vertical,
431            (XtPointer) new AW_cb_struct(this, f, cd1, cd2, "") );
432    XtAddCallback(p_w->scroll_bar_vertical, XmNdragCallback,
433            (XtCallbackProc) drag_scroll_bar_vertical,
434            (XtPointer) new AW_cb_struct(this, f, cd1, cd2, "") );
435
436    XtAddCallback(p_w->scroll_bar_vertical, XmNpageIncrementCallback,
437            (XtCallbackProc) drag_scroll_bar_vertical,
438            (XtPointer) new AW_cb_struct(this, f, cd1, cd2, "") );
439    XtAddCallback(p_w->scroll_bar_vertical, XmNpageDecrementCallback,
440            (XtCallbackProc) drag_scroll_bar_vertical,
441            (XtPointer) new AW_cb_struct(this, f, cd1, cd2, "") );
442}
443
444void AW_window::tell_scrolled_picture_size(AW_rectangle rectangle) {
445    picture->l = rectangle.l;
446    picture->r = rectangle.r;
447    picture->t = rectangle.t;
448    picture->b = rectangle.b;
449}
450void AW_window::tell_scrolled_picture_size(AW_world rectangle) {
451    picture->l = (int)rectangle.l;
452    picture->r = (int)rectangle.r;
453    picture->t = (int)rectangle.t;
454    picture->b = (int)rectangle.b;
455}
456
457void AW_window::reset_scrolled_picture_size() {
458    picture->l = 0;
459    picture->r = 0;
460    picture->t = 0;
461    picture->b = 0;
462}
463AW_pos AW_window::get_scrolled_picture_width() {
464    return (picture->r - picture->l);
465}
466
467AW_pos AW_window::get_scrolled_picture_height() {
468    return (picture->b - picture->t);
469}
470
471void AW_window::calculate_scrollbars(void) {
472    AW_rectangle screen;
473   
474    int  slider_size_horizontal;
475    int  slider_size_vertical;
476    bool vertical, horizontal;
477    int  position_of_slider;
478    int  slider_max;
479
480    vertical = horizontal = true; // es gibt verticalen & horizontalen scrollbar
481
482    this->_get_area_size(AW_MIDDLE_AREA, &screen);
483
484    // HORIZONTAL
485    slider_max = (int)get_scrolled_picture_width();
486    if (slider_max <1) {
487        slider_max = 1;
488        XtVaSetValues(p_w->scroll_bar_horizontal, XmNsliderSize, 1, NULL);
489    }
490
491    slider_size_horizontal = (int)( (screen.r
492            -left_indent_of_horizontal_scrollbar));
493    if (slider_size_horizontal < 1)
494        slider_size_horizontal = 1; // ist der slider zu klein (<1) ?
495    if (slider_size_horizontal > slider_max) { // Schirm groesser als Bild
496        slider_size_horizontal = slider_max; // slider nimmt ganze laenge ein
497        XtVaSetValues(p_w->scroll_bar_horizontal, XmNvalue, 0, NULL); // slider ganz links setzen
498        horizontal = false; // kein horizontaler slider mehr
499    }
500
501    // check wether XmNValue is to big
502    XtVaGetValues(p_w->scroll_bar_horizontal, XmNvalue, &position_of_slider,
503            NULL);
504    if (position_of_slider > (slider_max-slider_size_horizontal)) {//steht der slider fuer slidergroesse zu rechts ?
505        position_of_slider = slider_max-slider_size_horizontal; //-1 ? vielleicht !
506        if (position_of_slider < 0)
507            position_of_slider = 0;
508        XtVaSetValues(p_w->scroll_bar_horizontal, XmNvalue, position_of_slider,
509                NULL);
510    }
511    // Anpassung fuer resize, wenn unbeschriebener Bereich vergroessert wird
512    if ( -slider_pos_horizontal + get_scrolled_picture_width() < screen.r
513            -left_indent_of_horizontal_scrollbar) {
514        if (horizontal == true)
515            slider_pos_horizontal = (int)(get_scrolled_picture_width()
516                    - (screen.r-left_indent_of_horizontal_scrollbar) );
517        else
518            slider_pos_horizontal = 0; //slider nach ganz oben, da alles sichtbar
519    }
520    XtVaSetValues(p_w->scroll_bar_horizontal, XmNsliderSize, 1, NULL);
521    XtVaSetValues(p_w->scroll_bar_horizontal, XmNmaximum, slider_max, NULL);
522    XtVaSetValues(p_w->scroll_bar_horizontal, XmNsliderSize,
523            slider_size_horizontal, NULL);
524    char buffer[200];
525    sprintf(buffer, "window/%s/horizontal_page_increment", window_defaults_name);
526    XtVaSetValues(p_w->scroll_bar_horizontal, XmNpageIncrement, (int)((screen.r
527            -left_indent_of_horizontal_scrollbar)*(get_root()->awar( buffer )->read_int()*0.01)), 
528    NULL);
529
530    sprintf(buffer, "window/%s/scroll_width_horizontal", window_defaults_name);
531    XtVaSetValues(p_w->scroll_bar_horizontal, XmNincrement, (int)(get_root()->awar( buffer )->read_int()), NULL);
532
533    sprintf(buffer, "window/%s/scroll_delay_horizontal", window_defaults_name);
534    XtVaSetValues(p_w->scroll_bar_horizontal, XmNrepeatDelay, (int)(get_root()->awar( buffer )->read_int()), NULL);
535
536    // VERTICAL
537    slider_max = (int)get_scrolled_picture_height();
538    if (slider_max <1) {
539        slider_max = 1;
540        XtVaSetValues(p_w->scroll_bar_vertical, XmNsliderSize, 1, NULL);
541    }
542
543    slider_size_vertical = (int)( (screen.b-top_indent_of_vertical_scrollbar
544            -bottom_indent_of_vertical_scrollbar));
545    if (slider_size_vertical < 1)
546        slider_size_vertical = 1;
547    if (slider_size_vertical > slider_max) {
548        slider_size_vertical = slider_max;
549        XtVaSetValues(p_w->scroll_bar_vertical, XmNvalue, 0, NULL);
550        vertical = false;
551    }
552
553    // check wether XmNValue is to big
554    XtVaGetValues(p_w->scroll_bar_vertical, XmNvalue, &position_of_slider, NULL);
555    if (position_of_slider > (slider_max-slider_size_vertical)) {
556        position_of_slider = slider_max-slider_size_vertical; //-1 ? vielleicht !
557        if (position_of_slider < 0)
558            position_of_slider = 0;
559        XtVaSetValues(p_w->scroll_bar_vertical, XmNvalue, position_of_slider,
560                NULL);
561    }
562    // Anpassung fuer resize, wenn unbeschriebener Bereich vergroessert wird
563    if ( -slider_pos_vertical + get_scrolled_picture_height() < screen.b
564            -top_indent_of_vertical_scrollbar
565            -bottom_indent_of_vertical_scrollbar) {
566        if (vertical == true)
567            slider_pos_vertical = (int)(get_scrolled_picture_height()
568                    - (screen.b-top_indent_of_vertical_scrollbar
569                            -bottom_indent_of_vertical_scrollbar));
570        else
571            slider_pos_vertical = 0; //slider nach ganz oben, da alles sichtbar
572    }
573    XtVaSetValues(p_w->scroll_bar_vertical, XmNsliderSize, 1, NULL);
574    XtVaSetValues(p_w->scroll_bar_vertical, XmNmaximum, slider_max, NULL);
575    XtVaSetValues(p_w->scroll_bar_vertical, XmNsliderSize,
576            slider_size_vertical, NULL);
577    sprintf(buffer, "window/%s/vertical_page_increment", window_defaults_name);
578    XtVaSetValues(p_w->scroll_bar_vertical, XmNpageIncrement, (int)((screen.b
579            -top_indent_of_vertical_scrollbar
580            -bottom_indent_of_vertical_scrollbar)*(get_root()->awar( buffer )->read_int()*0.01)), 
581    NULL);
582
583    sprintf(buffer, "window/%s/scroll_width_vertical", window_defaults_name);
584    XtVaSetValues(p_w->scroll_bar_vertical, XmNincrement, (int)(get_root()->awar( buffer )->read_int()), NULL);
585
586    sprintf(buffer, "window/%s/scroll_delay_vertical", window_defaults_name);
587    XtVaSetValues(p_w->scroll_bar_vertical, XmNrepeatDelay, (int)(get_root()->awar( buffer )->read_int()), NULL);
588}
589
590void AW_window::set_vertical_scrollbar_position(int position) {
591    slider_pos_vertical = position;
592    XtVaSetValues(p_w->scroll_bar_vertical, XmNvalue, position, NULL);
593}
594
595void AW_window::set_horizontal_scrollbar_position(int position) {
596    slider_pos_horizontal = position;
597    XtVaSetValues(p_w->scroll_bar_horizontal, XmNvalue, position, NULL);
598}
599
600/***********************************************************************/
601static void AW_timer_callback(XtPointer aw_timer_cb_struct, XtIntervalId *id) {
602    AWUSE(id);
603    AW_timer_cb_struct *tcbs = (AW_timer_cb_struct *) aw_timer_cb_struct;
604    if (!tcbs)
605        return;
606
607    AW_root *root = tcbs->ar;
608    if (root->disable_callbacks) {
609        // delay the timer callback for 25ms
610        XtAppAddTimeOut(p_global->context,
611        (unsigned long)25, // wait 25 msec = 1/40 sec
612        (XtTimerCallbackProc)AW_timer_callback,
613        aw_timer_cb_struct);
614    } else {
615        tcbs->f(root, tcbs->cd1, tcbs->cd2);
616        delete tcbs; // timer only once
617    }
618}
619
620static void AW_timer_callback_never_disabled(XtPointer aw_timer_cb_struct,
621        XtIntervalId *id) {
622    AWUSE(id);
623    AW_timer_cb_struct *tcbs = (AW_timer_cb_struct *) aw_timer_cb_struct;
624    if (!tcbs)
625        return;
626
627    tcbs->f(tcbs->ar, tcbs->cd1, tcbs->cd2);
628    delete tcbs; // timer only once
629}
630
631void AW_root::add_timed_callback(int ms, void (*f)(AW_root*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
632    XtAppAddTimeOut(p_r->context,
633    (unsigned long)ms,
634    (XtTimerCallbackProc)AW_timer_callback,
635    (XtPointer) new AW_timer_cb_struct( this, f, cd1, cd2));
636}
637
638void AW_root::add_timed_callback_never_disabled(int ms, void (*f)(AW_root*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
639    XtAppAddTimeOut(p_r->context,
640    (unsigned long)ms,
641    (XtTimerCallbackProc)AW_timer_callback_never_disabled,
642    (XtPointer) new AW_timer_cb_struct( this, f, cd1, cd2));
643}
644
645/***********************************************************************/
646void AW_POPDOWN(AW_window *aww) {
647    aww->hide();
648}
649
650#define BUFSIZE 256
651static char aw_size_awar_name_buffer[BUFSIZE];
652static const char *aw_size_awar_name(AW_window *aww, const char *sub_entry) {
653#if defined(DEBUG)
654    int size =
655#endif // DEBUG
656            sprintf(aw_size_awar_name_buffer, "window/windows/%s/%s",
657                    aww->window_defaults_name, sub_entry);
658#if defined(DEBUG)
659    aw_assert(size < BUFSIZE);
660#endif // DEBUG
661    return aw_size_awar_name_buffer;
662}
663#undef BUFSIZE
664
665#define aw_awar_name_posx(aww)   aw_size_awar_name((aww), "posx")
666#define aw_awar_name_posy(aww)   aw_size_awar_name((aww), "posy")
667#define aw_awar_name_width(aww)  aw_size_awar_name((aww), "width")
668#define aw_awar_name_height(aww) aw_size_awar_name((aww), "height")
669
670static void aw_calculate_WM_offsets(AW_window *aww) {
671    if (p_aww(aww)->WM_top_offset != -1000)
672        return; // very bad hack continued
673
674    AW_root *root = aww->get_root();
675    short posy, posx;
676    int oposy, oposx;
677
678    oposx = root->awar(aw_awar_name_posx(aww))->read_int();
679    oposy = root->awar(aw_awar_name_posy(aww))->read_int();
680
681    XtVaGetValues( p_aww(aww)->shell ,
682                   XmNx, &posx,
683                   XmNy, &posy,
684                   NULL);
685
686    p_aww(aww)->WM_top_offset  = posy-oposy;
687    p_aww(aww)->WM_left_offset = posx-oposx;
688}
689
690/************** standard callback server *********************/
691
692static void macro_message_cb(AW_window *aw, AW_CL);
693
694bool AW_cb_struct::is_equal(const AW_cb_struct& other) const {
695    bool equal = false;
696    if (f == other.f) {                             // same callback function
697        equal = (cd1 == other.cd1) && (cd2 == other.cd2);
698        if (equal) {
699            if (f == AW_POPUP) {
700                equal = aw->get_root() == other.aw->get_root();
701            }
702            else {
703                equal = aw == other.aw;
704                if (!equal) {
705                    equal = aw->get_root() == other.aw->get_root();
706#if defined(DEBUG) && 0
707                    if (equal) {
708                        fprintf(stderr,
709                                "callback '%s' instanciated twice with different windows (w1='%s' w2='%s') -- assuming the callbacks are equal\n",
710                                id, aw->get_window_id(), other.aw->get_window_id());
711                    }
712#endif // DEBUG
713                }
714            }
715        }
716    }
717    return equal;
718}
719
720void AW_cb_struct::run_callback(void) {
721    AW_PPP g;
722    if (next)
723        next->run_callback(); // callback the whole list
724
725    AW_root *root = aw->get_root();
726    if (!f)
727        return;
728
729    if (root->disable_callbacks) {
730        // some functions (namely aw_message, aw_input, aw_string_selection and aw_file_selection)
731        // have to disable most callbacks, because they are often called from inside these callbacks
732        // (e.g. because some exceptional condition occurred which needs user interaction) and if
733        // callbacks weren't disabled, a recursive deadlock occurs.
734
735        // the following callbacks are allowed even if disable_callbacks is true
736        if ((f != (AW_CB)message_cb)       &&
737            (f != (AW_CB)macro_message_cb) &&
738            (f != (AW_CB)input_history_cb) &&
739            (f != (AW_CB)input_cb)         &&
740            (f != (AW_CB)AW_POPUP_HELP)    &&
741            (f != (AW_CB)AW_POPDOWN)       &&
742            !aw->is_expose_callback(AW_INFO_AREA, f)      &&
743            !aw->is_resize_callback(AW_INFO_AREA, f) )
744        {
745            // don't warn about the following callback, just silently ignore them :
746            if (!aw->is_expose_callback(AW_MIDDLE_AREA, f) &&
747                !aw->is_resize_callback(AW_MIDDLE_AREA, f) )
748            {
749                // otherwise remind the user to answer the prompt:
750                aw_message("That has been ignored. Answer the prompt first!");
751            }
752            return;
753        }
754    }
755
756    if (f == AW_POPUP) {
757        if (pop_up_window) { // already exists
758            pop_up_window->activate();
759        }
760        else {
761            g = (AW_PPP)cd1;
762            if (g) {
763                pop_up_window = g(aw->get_root(), cd2, 0);
764                pop_up_window->show();
765            } else {
766                aw_message("Sorry Function not implemented");
767            }
768        }
769        if (pop_up_window && p_aww(pop_up_window)->popup_cb)
770            p_aww(pop_up_window)->popup_cb->run_callback();
771    } else {
772        f(aw, cd1, cd2);
773    }
774}
775
776bool AW_cb_struct::contains(void (*g)(AW_window*,AW_CL ,AW_CL)) {
777    return (f == g) || (next && next->contains(g));
778}
779
780void AW_root_Motif::set_cursor(Display *d, Window w, Cursor c) {
781    XSetWindowAttributes attrs;
782    old_cursor_display = d;
783    old_cursor_window = w;
784
785    if (c)
786        attrs.cursor = c;
787    else
788        attrs.cursor = None;
789
790    if (d && w) {
791        XChangeWindowAttributes(d, w, CWCursor, &attrs);
792    }
793    XChangeWindowAttributes(XtDisplay(main_widget), XtWindow(main_widget),
794            CWCursor, &attrs);
795    XFlush(XtDisplay(main_widget));
796}
797
798void AW_root_Motif::normal_cursor(void) {
799    set_cursor(old_cursor_display, old_cursor_window, 0);
800}
801
802void AW_server_callback(Widget wgt, XtPointer aw_cb_struct, XtPointer call_data) {
803    AWUSE(wgt);
804    AWUSE(call_data);
805    AW_cb_struct *cbs = (AW_cb_struct *) aw_cb_struct;
806
807    AW_root *root = cbs->aw->get_root();
808    if (p_global->help_active) {
809        p_global->help_active = 0;
810        p_global->normal_cursor();
811
812        if (cbs->help_text && ((GBS_string_matches(cbs->help_text, "*.ps", GB_IGNORE_CASE)) ||
813                               (GBS_string_matches(cbs->help_text, "*.hlp", GB_IGNORE_CASE)) ||
814                               (GBS_string_matches(cbs->help_text, "*.help", GB_IGNORE_CASE))))
815        {
816            AW_POPUP_HELP(cbs->aw, (AW_CL)cbs->help_text);
817        }
818        else {
819            aw_message("Sorry no help available");
820        }
821        return;
822    }
823
824    if (root->prvt->recording_macro_file) {
825        if (cbs->id && strcmp(cbs->id, root->prvt->stop_action_name)) {
826            fprintf(root->prvt->recording_macro_file,
827                    "BIO::remote_action($gb_main,\"%s\",",
828                    root->prvt->application_name_for_macros);
829            GBS_fwrite_string(cbs->id, root->prvt->recording_macro_file);
830            fprintf(root->prvt->recording_macro_file, ");\n");
831        }
832    }
833
834    if (cbs->f == AW_POPUP) {
835        cbs->run_callback();
836    } else {
837        p_global->set_cursor(XtDisplay(p_global->toplevel_widget),
838                XtWindow(p_aww(cbs->aw)->shell),
839                p_global->clock_cursor);
840        cbs->run_callback();
841
842        XEvent event; // destroy all old events !!!
843        while (XCheckMaskEvent(XtDisplay(p_global->toplevel_widget), 
844        ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|
845        KeyPressMask|KeyReleaseMask|PointerMotionMask, &event)) {
846        }
847
848        if (p_global->help_active) {
849            p_global->set_cursor(XtDisplay(p_global->toplevel_widget),
850                    XtWindow(p_aww(cbs->aw)->shell),
851                    p_global->question_cursor);
852        } else {
853            p_global->set_cursor(XtDisplay(p_global->toplevel_widget),
854                    XtWindow(p_aww(cbs->aw)->shell),
855                    0);
856        }
857    }
858
859}
860
861void AW_clock_cursor(AW_root *root) {
862    p_global->set_cursor(0, 0, p_global->clock_cursor);
863}
864
865void AW_normal_cursor(AW_root *root) {
866    p_global->set_cursor(0, 0, 0);
867}
868
869/***********************************************************************/
870static void AW_root_focusCB(Widget wgt, XtPointer awrp, XEvent*, Boolean*) {
871    AWUSE(wgt);
872    AW_root *aw_root = (AW_root *)awrp;
873    if (aw_root->focus_callback_list) {
874        aw_root->focus_callback_list->run_callback(aw_root);
875    }
876}
877
878void AW_root::set_focus_callback(void (*f)(class AW_root*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
879    focus_callback_list = new AW_var_callback(f,cd1,cd2,focus_callback_list);
880}
881
882static void AW_focusCB(Widget wgt, XtPointer aw_cb_struct, XEvent*, Boolean*) {
883    AWUSE(wgt);
884    AW_cb_struct *cbs = (AW_cb_struct *) aw_cb_struct;
885    cbs->run_callback();
886}
887
888void AW_window::set_popup_callback(void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
889    p_w->popup_cb = new AW_cb_struct(this, f, cd1, cd2, 0, p_w->popup_cb);
890}
891
892void AW_window::set_focus_callback(void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
893    XtAddEventHandler(MIDDLE_WIDGET, EnterWindowMask, FALSE,
894    AW_focusCB, (XtPointer) new AW_cb_struct(this, f, cd1, cd2, 0));
895}
896
897/*******************************    expose  ****************************************/
898
899static void AW_exposeCB(Widget wgt, XtPointer aw_cb_struct,
900        XmDrawingAreaCallbackStruct *call_data) {
901    XEvent *ev = call_data->event;
902    AWUSE(wgt);
903    AW_area_management *aram = (AW_area_management *) aw_cb_struct;
904    if (ev->xexpose.count == 0) { // last expose cb
905        if (aram->expose_cb)
906            aram->expose_cb->run_callback();
907    }
908}
909
910void AW_area_management::set_expose_callback(AW_window *aww, void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
911    // insert expose callback for draw_area
912    if (!expose_cb) {
913        XtAddCallback(area, XmNexposeCallback, (XtCallbackProc) AW_exposeCB,
914                (XtPointer) this );
915    }
916    expose_cb = new AW_cb_struct(aww, f, cd1, cd2, 0, expose_cb);
917}
918
919void AW_window::set_expose_callback(AW_area area, void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
920    AW_area_management *aram= MAP_ARAM(area);
921    if (!aram)
922        return;
923    aram->set_expose_callback(this, f, cd1, cd2);
924}
925
926bool AW_area_management::is_expose_callback(AW_window */*aww*/, void (*f)(AW_window*,AW_CL,AW_CL)) {
927    return expose_cb && expose_cb->contains(f);
928}
929
930bool AW_window::is_expose_callback(AW_area area, void (*f)(AW_window*,AW_CL,AW_CL)) {
931    AW_area_management *aram = MAP_ARAM(area);
932    return aram && aram->is_expose_callback(this, f);
933}
934
935void AW_window::force_expose() {
936    XmDrawingAreaCallbackStruct da_struct;
937
938    da_struct.reason = XmCR_EXPOSE;
939    da_struct.event = (XEvent *) NULL;
940    da_struct.window = XtWindow(p_w->shell);
941
942    XtCallCallbacks(p_w->shell, XmNexposeCallback, (XtPointer) &da_struct);
943}
944
945bool AW_area_management::is_resize_callback(AW_window */*aww*/, void (*f)(AW_window*,AW_CL,AW_CL)) {
946    return resize_cb && resize_cb->contains(f);
947}
948
949bool AW_window::is_resize_callback(AW_area area, void (*f)(AW_window*,AW_CL,AW_CL)) {
950    AW_area_management *aram = MAP_ARAM(area);
951    return aram && aram->is_resize_callback(this, f);
952}
953
954void AW_window::set_window_size(int width, int height) {
955    XtVaSetValues(p_w->shell, XmNwidth, (int)width, XmNheight, (int)height,
956            NULL);
957}
958
959void AW_window::get_window_size(int &width, int &height) {
960    unsigned short hoffset = 0;
961    if (p_w->menu_bar[0])
962        XtVaGetValues(p_w->menu_bar[0], XmNheight, &hoffset, NULL);
963    width = _at->max_x_size;
964    height = hoffset + _at->max_y_size;
965}
966
967void AW_window::window_fit(void) {
968    int width, height;
969    get_window_size(width, height);
970    set_window_size(width, height);
971}
972
973void AW_window::align(void) {
974    int width, height;
975    get_window_size(width, height);
976    int x = (WidthOfScreen(XtScreen(p_w->shell)) / 2) - (width / 2);
977    int y = (HeightOfScreen(XtScreen(p_w->shell)) / 4) - (height / 4);
978    if (x < 0) x= 0;
979    if (y < 0) y= 0;
980    XtVaSetValues(p_w->shell, XmNx, x, XmNy, y, NULL);
981}
982
983/*******************************    resize  ****************************************/
984
985// Predicate function: checks, if the given event is a ResizeEvent
986int is_resize_event(Display *display, XEvent *event, XPointer) {
987    if (event && (event->type == ResizeRequest || event->type
988            == ConfigureNotify) && event->xany.display == display) {
989        return 1;
990    }
991    return 0;
992}
993
994// Removes redundant resize events from the x-event queue
995void cleanupResizeEvents(Display *display) {
996    if (display) {
997        XLockDisplay(display);
998        XEvent event;
999        if (XCheckIfEvent(display, &event, is_resize_event, 0)) {
1000            // Some magic happens here... ;-) (removing redundant events from queue)
1001            while (XCheckIfEvent(display, &event, is_resize_event, 0))
1002                ;
1003            // Keep last Event in queue
1004            XPutBackEvent(display, &event);
1005        }
1006        XUnlockDisplay(display);
1007    }
1008}
1009
1010static void AW_resizeCB_draw_area(Widget wgt, XtPointer aw_cb_struct,
1011        XtPointer call_data) {
1012    AWUSE(wgt);
1013    AWUSE(call_data);
1014    AW_area_management *aram = (AW_area_management *) aw_cb_struct;
1015    cleanupResizeEvents(aram->common->display);
1016    if (aram->resize_cb)
1017        aram->resize_cb->run_callback();
1018}
1019
1020void AW_area_management::set_resize_callback(AW_window *aww, void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
1021    // insert resize callback for draw_area
1022    if (!resize_cb) {
1023        XtAddCallback(area, XmNresizeCallback,
1024                (XtCallbackProc) AW_resizeCB_draw_area, (XtPointer) this );
1025    }
1026    resize_cb = new AW_cb_struct(aww, f, cd1, cd2, 0, resize_cb);
1027}
1028
1029void AW_window::set_resize_callback(AW_area area, void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
1030    AW_area_management *aram= MAP_ARAM(area);
1031    if (!aram)
1032        return;
1033    aram->set_resize_callback(this, f, cd1, cd2);
1034}
1035
1036/***********************************************************************/
1037static void AW_inputCB_draw_area(Widget wgt, XtPointer aw_cb_struct, XmDrawingAreaCallbackStruct *call_data) {
1038    AWUSE(wgt);
1039    XEvent             *ev                        = call_data->event;
1040    AW_cb_struct       *cbs                       = (AW_cb_struct *) aw_cb_struct;
1041    AW_window          *aww                       = cbs->aw;
1042    bool                run_callback              = false;
1043    bool                run_double_click_callback = false;
1044    AW_area_management *area                      = 0;
1045    {
1046        int i;
1047        for (i=0; i<AW_MAX_AREA; i++) {
1048            if (p_aww(aww)->areas[i]->area == wgt) {
1049                area = p_aww(aww)->areas[i];
1050                break;
1051            }
1052        }
1053    }
1054
1055    if (ev->xbutton.type == ButtonPress) {
1056        aww->event.type = AW_Mouse_Press;
1057        aww->event.button = ev->xbutton.button;
1058        aww->event.x = ev->xbutton.x;
1059        aww->event.y = ev->xbutton.y;
1060        aww->event.keycode = AW_KEY_NONE;
1061        aww->event.keymodifier = AW_KEYMODE_NONE;
1062        aww->event.character = '\0';
1063
1064        if (area && area->double_click_cb) {
1065            if ( (ev->xbutton.time - area->click_time ) < 200) {
1066                run_double_click_callback = true;
1067            } else {
1068                run_callback = true;
1069            }
1070            area->click_time = ev->xbutton.time;
1071        } else {
1072            run_callback = true;
1073        }
1074
1075        aww->event.time = ev->xbutton.time;
1076    } else if (ev->xbutton.type == ButtonRelease) {
1077        aww->event.type = AW_Mouse_Release;
1078        aww->event.button = ev->xbutton.button;
1079        aww->event.x = ev->xbutton.x;
1080        aww->event.y = ev->xbutton.y;
1081        aww->event.keycode = AW_KEY_NONE;
1082        aww->event.keymodifier = AW_KEYMODE_NONE;
1083        aww->event.character = '\0';
1084        //  aww->event.time     use old time
1085
1086        run_callback = true;
1087    } else if (ev->xkey.type == KeyPress || ev->xkey.type == KeyRelease) {
1088        aww->event.time = ev->xbutton.time;
1089
1090        const awXKeymap *mykey = aw_xkey_2_awkey(&(ev->xkey));
1091
1092        aww->event.keycode = mykey->awkey;
1093        aww->event.keymodifier = mykey->awmod;
1094
1095        if (mykey->awstr) {
1096            aww->event.character = mykey->awstr[0];
1097        } else {
1098            aww->event.character = 0;
1099        }
1100
1101        if (ev->xkey.type == KeyPress) {
1102            aww->event.type = AW_Keyboard_Press;
1103        } else {
1104            aww->event.type = AW_Keyboard_Release;
1105        }
1106        aww->event.button = 0;
1107        aww->event.x = ev->xbutton.x;
1108        aww->event.y = ev->xbutton.y;
1109
1110        if (!mykey->awmod && mykey->awkey >= AW_KEY_F1 && mykey->awkey
1111                <= AW_KEY_F12 && p_aww(aww)->modes_f_callbacks && p_aww(aww)->modes_f_callbacks[mykey->awkey-AW_KEY_F1]
1112                && aww->event.type == AW_Keyboard_Press) {
1113            p_aww(aww)->modes_f_callbacks[mykey->awkey-AW_KEY_F1]->run_callback();
1114        } else {
1115            run_callback = true;
1116        }
1117    }
1118
1119    //  this is done above :
1120    //     else if (ev->xkey.type == KeyRelease) { // added Jan 98 to fetch multiple keystrokes in EDIT4 (may cause side effects)
1121    //         aww->event.time = ev->xbutton.time;
1122    //         aww->event.type = AW_Keyboard_Release;
1123    //         run_callback = true;
1124    //     }
1125
1126    if (run_double_click_callback) {
1127        if (cbs->help_text == (char*)1) {
1128            cbs->run_callback();
1129        } else {
1130            if (area)
1131                area->double_click_cb->run_callback();
1132        }
1133    }
1134
1135    if (run_callback && (cbs->help_text == (char*)0)) {
1136        cbs->run_callback();
1137    }
1138}
1139
1140void AW_area_management::set_input_callback(AW_window *aww, void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
1141    XtAddCallback(area, XmNinputCallback,
1142            (XtCallbackProc) AW_inputCB_draw_area,
1143            (XtPointer) new AW_cb_struct(aww, f, cd1, cd2, (char*)0) );
1144}
1145
1146void AW_window::set_input_callback(AW_area area, void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
1147    AW_area_management *aram= MAP_ARAM(area);
1148    if (!aram)
1149        return;
1150    aram->set_input_callback(this, f, cd1, cd2);
1151}
1152
1153/***********************************************************************/
1154void AW_area_management::set_double_click_callback(AW_window *aww, void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
1155    double_click_cb = new AW_cb_struct(aww, f, cd1, cd2, (char*)0, double_click_cb);
1156}
1157
1158void AW_window::set_double_click_callback(AW_area area, void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
1159    AW_area_management *aram= MAP_ARAM(area);
1160    if (!aram)
1161        return;
1162    aram->set_double_click_callback(this, f, cd1, cd2);
1163}
1164
1165void AW_window::get_event(AW_event *eventi) {
1166    *eventi = event;
1167}
1168
1169/***********************************************************************/
1170
1171static void AW_motionCB(Widget w, XtPointer aw_cb_struct, XEvent *ev, Boolean*) {
1172    AWUSE(w);
1173    AW_cb_struct *cbs = (AW_cb_struct *) aw_cb_struct;
1174
1175    cbs->aw->event.type = AW_Mouse_Drag;
1176    //  cbs->aw->event.button   = cbs->aw->event.button;
1177    cbs->aw->event.x = ev->xmotion.x;
1178    cbs->aw->event.y = ev->xmotion.y;
1179    cbs->aw->event.keycode = AW_KEY_NONE;
1180
1181    cbs->run_callback();
1182}
1183void AW_area_management::set_motion_callback(AW_window *aww, void (*f)(AW_window *,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
1184    XtAddEventHandler(area, ButtonMotionMask, False,
1185                      AW_motionCB, (XtPointer) new AW_cb_struct(aww, f, cd1, cd2, "") );
1186}
1187void AW_window::set_motion_callback(AW_area area, void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2) {
1188    AW_area_management *aram= MAP_ARAM(area);
1189    if (!aram)
1190        return;
1191    aram->set_motion_callback(this, f, cd1, cd2);
1192}
1193
1194struct fallbacks {
1195    const char *fb;
1196    const char *awar;
1197    const char *init;
1198};
1199
1200static struct fallbacks aw_fb[] = {
1201// fallback awarname    init
1202
1203        { "FontList", "window/font", "8x13bold" }, { "background",
1204                "window/background", "grey" }, { "foreground",
1205                "window/foreground", "Black", }
1206, {0, "window/color_1", "red",}
1207, {0, "window/color_2", "green",}
1208, {0, "window/color_3", "blue",}
1209, {0, 0, 0}
1210};
1211
1212static const char *aw_awar_2_color[] = { "window/background",
1213        "window/foreground", "window/color_1", "window/color_2",
1214        "window/color_3", 0 };
1215
1216void AW_root::init_variables(AW_default database) {
1217
1218    application_database = database;
1219
1220    hash_table_for_variables = GBS_create_hash(1000, GB_MIND_CASE);
1221    hash_for_windows = GBS_create_hash(100, GB_MIND_CASE);
1222    prvt->action_hash = GBS_create_hash(1000, GB_MIND_CASE);
1223    int i;
1224    for (i=0; i<1000; i++) {
1225        if (aw_fb[i].awar == 0)
1226            break;
1227        awar_string(aw_fb[i].awar, aw_fb[i].init, application_database);
1228    }
1229    // PJ temporary site for vectorfont stuff
1230    vectorfont_lines =NULL; // font data not yet loaded
1231
1232    awar_float("vectorfont/userscale", 1.0, application_database); // ratio font point size to pixels
1233    awar_string("vectorfont/name", "lib/pictures/fontgfx.vfont", application_database); // name for default font in lib/pictures
1234    // from the filerequester
1235    awar_int("vectorfont/active", 1, application_database); // zoomtext-calls: call text or use vectorfont (1)
1236
1237    // this MIGHT lead to inconsistencies, as the validated data is in /name ---> worst case: reset
1238    aw_create_selection_box_awars(this, "vectorfont",
1239                                  GB_path_in_ARBLIB("pictures", NULL), 
1240                                  ".vfont", vectorfont_name, application_database, true);
1241    awar("vectorfont/file_name")->add_callback( (AW_RCB0) aw_xfig_font_changefont_cb);
1242}
1243
1244void *AW_root::get_aw_var_struct(char *awar_name) {
1245    long vs;
1246    vs = (long)GBS_read_hash(hash_table_for_variables, awar_name);
1247    if (!vs) {
1248        AW_ERROR("AW_root::get_aw_var_struct: Variable %s not defined", awar_name);
1249    }
1250    return (void *)vs;
1251}
1252void *AW_root::get_aw_var_struct_no_error(char *awar_name) {
1253    long vs;
1254    vs = (long)GBS_read_hash(hash_table_for_variables, awar_name);
1255    return (void*)vs;
1256}
1257
1258static void aw_root_create_color_map(AW_root *root) {
1259    int i;
1260    XColor xcolor_returned, xcolor_exakt;
1261    GBDATA *gbd = (GBDATA*)root->application_database;
1262    p_global->color_table = (unsigned long *)GB_calloc(sizeof(unsigned long),AW_COLOR_MAX);
1263
1264    if (p_global->screen_depth == 1) { //Black and White Monitor
1265        unsigned long white= WhitePixelOfScreen( XtScreen(p_global->toplevel_widget) );
1266        unsigned long black= BlackPixelOfScreen( XtScreen(p_global->toplevel_widget) );
1267        p_global->foreground = black;
1268        p_global->background = white;
1269        for (i=0; i< AW_COLOR_MAX; i++) {
1270            p_global->color_table[i] = black;
1271        }
1272        p_global->color_table[AW_WINDOW_FG] = white;
1273        p_global->color_table[AW_WINDOW_C1] = white;
1274        p_global->color_table[AW_WINDOW_C2] = white;
1275        p_global->color_table[AW_WINDOW_C3] = white;
1276    } else { // Color monitor
1277        const char **awar_2_color;
1278        int color;
1279        for (color = 0, awar_2_color = aw_awar_2_color;
1280             *awar_2_color;
1281             awar_2_color++, color++)
1282        {
1283            const char *name_of_color = GB_read_char_pntr(GB_search(gbd, *awar_2_color, GB_FIND));
1284            if (XAllocNamedColor(p_global->display,p_global->colormap,name_of_color, &xcolor_returned,&xcolor_exakt) == 0) {
1285                fprintf(stderr,"XAllocColor failed: %s\n",name_of_color);
1286            }
1287            else {
1288                p_global->color_table[color] = xcolor_returned.pixel;
1289            }
1290        }
1291        p_global->foreground= BlackPixelOfScreen( XtScreen(p_global->toplevel_widget) );
1292        XtVaGetValues(p_global->toplevel_widget,XmNbackground,
1293        &p_global->background, NULL);
1294    }
1295    // AW_WINDOW_DRAG see init_devices
1296
1297}
1298
1299static void aw_message_forwarder(const char *msg) {
1300    aw_message(msg);
1301}
1302static void aw_message_forwarder_verbose(const char *msg) {
1303    fprintf(stderr, "ARB: %s\n", msg); // print to console as well
1304    aw_message(msg);
1305}
1306
1307static int aw_status_dummy(double val) {
1308    return aw_status(val);
1309}
1310
1311static int aw_status_dummy2(const char *val) {
1312    return aw_status((char *)val);
1313}
1314
1315void AW_root::init_root(const char *programmname, bool no_exit) {
1316    // Initialisiert eine gesamte X-Anwendung
1317    int a = 0;
1318    int i;
1319    XFontStruct *fontstruct;
1320    char buffer[256];
1321    char *fallback_resources[100];
1322
1323    p_r-> no_exit = no_exit;
1324    program_name  = strdup(programmname);
1325
1326    for (i=0; i<1000; i++) {
1327        if (aw_fb[i].fb == 0)
1328            break;
1329        sprintf(buffer, "*%s: %s", aw_fb[i].fb, GB_read_char_pntr(GB_search(
1330                (GBDATA*)application_database, aw_fb[i].awar, GB_FIND)));
1331        fallback_resources[i] = strdup(buffer);
1332    }
1333    fallback_resources[i] = 0;
1334    GB_install_error_handler((gb_warning_func_type)aw_message_forwarder_verbose);
1335    GB_install_warning((gb_warning_func_type)aw_message_forwarder);
1336    GB_install_information((gb_information_func_type)0); // 0 means -> write to stdout only
1337
1338    GB_install_status((gb_status_func_type)aw_status_dummy);
1339    GB_install_status2((gb_status_func2_type)aw_status_dummy2);
1340
1341    // @@@ FIXME: the next line hangs if program runs inside debugger
1342    p_r->toplevel_widget = XtOpenApplication(&(p_r->context), programmname, 
1343            NULL, 0, // XrmOptionDescRec+numOpts
1344            &a, /*&argc*/
1345            NULL, /*argv*/
1346            fallback_resources, 
1347            applicationShellWidgetClass, // widget class
1348            NULL, 0);
1349
1350    for (i=0; i<1000 && fallback_resources[i]; i++) {
1351        free(fallback_resources[i]);
1352    }
1353
1354    p_r->display = XtDisplay(p_r->toplevel_widget);
1355
1356    if (p_r->display == NULL) {
1357        printf("cannot open display\n");
1358        exit(-1);
1359    }
1360    {
1361        GBDATA *gbd = (GBDATA*)application_database;
1362        const char *font = GB_read_char_pntr(GB_search(gbd, "window/font", GB_FIND));
1363        if ( !(fontstruct = XLoadQueryFont( p_r->display, font))) {
1364            if ( !(fontstruct = XLoadQueryFont( p_r->display, "fixed"))) {
1365                printf("can not load font\n");
1366                exit( -1);
1367            }
1368        }
1369    }
1370
1371    if (fontstruct->max_bounds.width == fontstruct->min_bounds.width) {
1372        font_width = fontstruct->max_bounds.width;
1373    } else {
1374        font_width = (fontstruct->min_bounds.width
1375                + fontstruct->max_bounds.width) / 2;
1376    }
1377
1378    font_height = fontstruct->max_bounds.ascent
1379            + fontstruct->max_bounds.descent;
1380    font_ascent = fontstruct->max_bounds.ascent;
1381
1382    p_r->fontlist = XmFontListCreate(fontstruct,XmSTRING_DEFAULT_CHARSET);
1383
1384    p_r->button_list = 0;
1385
1386    p_r->config_list = new AW_config_struct( "", AWM_ALL, NULL, "Programmer Name", "SH", NULL );
1387    p_r->last_config = p_r->config_list;
1388
1389    p_r->last_option_menu = p_r->current_option_menu = p_r->option_menu_list = NULL;
1390    p_r->last_toggle_field = p_r->toggle_field_list = NULL;
1391    p_r->last_selection_list = p_r->selection_list = NULL;
1392
1393    value_changed = false;
1394    y_correction_for_input_labels = 5;
1395    global_mask = AWM_ALL;
1396
1397    p_r->screen_depth = PlanesOfScreen( XtScreen(p_r->toplevel_widget) );
1398    if (p_r->screen_depth == 1) {
1399        color_mode = AW_MONO_COLOR;
1400    } else {
1401        color_mode = AW_RGB_COLOR;
1402    }
1403    p_r->colormap = DefaultColormapOfScreen( XtScreen(p_r->toplevel_widget) );
1404    p_r->clock_cursor = XCreateFontCursor(XtDisplay(p_r->toplevel_widget),XC_watch);
1405    p_r->question_cursor = XCreateFontCursor(XtDisplay(p_r->toplevel_widget),XC_question_arrow);
1406
1407    aw_root_create_color_map(this);
1408    aw_root_init_font(XtDisplay(p_r->toplevel_widget));
1409    aw_install_xkeys(XtDisplay(p_r->toplevel_widget));
1410
1411}
1412
1413/***********************************************************************/
1414void AW_window::_get_area_size(AW_area area, AW_rectangle *square) {
1415    AW_area_management *aram= MAP_ARAM(area);
1416    *square = aram->common->screen;
1417}
1418
1419/***********************************************************************/
1420
1421static void horizontal_scrollbar_redefinition_cb(class AW_root *aw_root,
1422        AW_CL cd1, AW_CL cd2) {
1423    AW_rectangle screen;
1424    AWUSE(aw_root);
1425
1426    char buffer[200];
1427    AW_window *aw = (AW_window *)cd1;
1428    Widget w = (Widget)cd2;
1429
1430    aw->_get_area_size(AW_MIDDLE_AREA, &screen);
1431
1432    sprintf(buffer, "window/%s/horizontal_page_increment",
1433            aw->window_defaults_name);
1434    XtVaSetValues(w, XmNpageIncrement, (int)((screen.r
1435            -aw->left_indent_of_horizontal_scrollbar)*(aw->get_root()->awar( buffer )->read_int()*0.01)), NULL);
1436
1437    sprintf(buffer, "window/%s/scroll_width_horizontal",
1438            aw->window_defaults_name);
1439    XtVaSetValues(w, XmNincrement, (int)(aw->get_root()->awar( buffer )->read_int()), NULL);
1440
1441    sprintf(buffer, "window/%s/scroll_delay_horizontal",
1442            aw->window_defaults_name);
1443    XtVaSetValues(w, XmNrepeatDelay, (int)(aw->get_root()->awar( buffer )->read_int()), NULL);
1444
1445}
1446
1447static void vertical_scrollbar_redefinition_cb(class AW_root *aw_root,
1448        AW_CL cd1, AW_CL cd2) {
1449    AW_rectangle screen;
1450    AWUSE(aw_root);
1451
1452    char buffer[200];
1453    AW_window *aw = (AW_window *)cd1;
1454    Widget w = (Widget)cd2;
1455
1456    aw->_get_area_size(AW_MIDDLE_AREA, &screen);
1457
1458    sprintf(buffer, "window/%s/vertical_page_increment",
1459            aw->window_defaults_name);
1460    XtVaSetValues(w, XmNpageIncrement, (int)((screen.b
1461            -aw->top_indent_of_vertical_scrollbar
1462            -aw->bottom_indent_of_vertical_scrollbar)*(aw->get_root()->awar( buffer )->read_int()*0.01)), NULL);
1463
1464    sprintf(buffer, "window/%s/scroll_width_vertical", aw->window_defaults_name);
1465    XtVaSetValues(w, XmNincrement, (int)(aw->get_root()->awar( buffer )->read_int()), NULL);
1466
1467    sprintf(buffer, "window/%s/scroll_delay_vertical", aw->window_defaults_name);
1468    XtVaSetValues(w, XmNrepeatDelay, (int)(aw->get_root()->awar( buffer )->read_int()), NULL);
1469}
1470
1471void AW_window::create_window_variables(void) {
1472
1473    char buffer[200];
1474    memset(buffer, 0, 200);
1475    sprintf(buffer, "window/%s/horizontal_page_increment", window_defaults_name);
1476    get_root()->awar_int(buffer, 50, get_root()->application_database);
1477    get_root()->awar( buffer)->add_callback(
1478            (AW_RCB)horizontal_scrollbar_redefinition_cb, (AW_CL)this,
1479            (AW_CL)p_w->scroll_bar_horizontal );
1480
1481    sprintf(buffer, "window/%s/vertical_page_increment", window_defaults_name);
1482    get_root()->awar_int(buffer, 50, get_root()->application_database);
1483    get_root()->awar( buffer)->add_callback( (AW_RCB)vertical_scrollbar_redefinition_cb,
1484            (AW_CL)this, (AW_CL)p_w->scroll_bar_vertical );
1485
1486    sprintf(buffer, "window/%s/scroll_delay_vertical", window_defaults_name);
1487    get_root()->awar_int(buffer, 20, get_root()->application_database);
1488    get_root()->awar( buffer)->add_callback( (AW_RCB)vertical_scrollbar_redefinition_cb,
1489            (AW_CL)this, (AW_CL)p_w->scroll_bar_vertical );
1490
1491    sprintf(buffer, "window/%s/scroll_delay_horizontal", window_defaults_name);
1492    get_root()->awar_int(buffer, 20, get_root()->application_database);
1493    get_root()->awar( buffer)->add_callback(
1494            (AW_RCB)horizontal_scrollbar_redefinition_cb, (AW_CL)this,
1495            (AW_CL)p_w->scroll_bar_horizontal );
1496
1497    sprintf(buffer, "window/%s/scroll_width_horizontal", window_defaults_name);
1498    get_root()->awar_int(buffer, 9, get_root()->application_database);
1499    get_root()->awar( buffer)->add_callback(
1500            (AW_RCB)horizontal_scrollbar_redefinition_cb, (AW_CL)this,
1501            (AW_CL)p_w->scroll_bar_horizontal );
1502
1503    sprintf(buffer, "window/%s/scroll_width_vertical", window_defaults_name);
1504    get_root()->awar_int(buffer, 20, get_root()->application_database);
1505    get_root()->awar( buffer)->add_callback( (AW_RCB)vertical_scrollbar_redefinition_cb,
1506            (AW_CL)this, (AW_CL)p_w->scroll_bar_vertical );
1507
1508}
1509
1510/***********************************************************************/
1511void AW_area_management::create_devices(AW_window *aww, AW_area ar) {
1512    AW_root *root =aww->get_root();
1513    common = new AW_common(aww,ar,XtDisplay(area),XtWindow(area),p_global->color_table,
1514            (unsigned int **)&aww->color_table, &aww->color_table_size );
1515}
1516
1517const char *AW_window::GC_to_RGB(AW_device *device, int gc, int& red,
1518        int& green, int& blue) {
1519    AW_common *common = device->common;
1520    AW_GC_Xm *gcm= AW_MAP_GC(gc);
1521    aw_assert(gcm);
1522    unsigned pixel = (unsigned short)(gcm->color);
1523    GB_ERROR error = 0;
1524    XColor query_color;
1525
1526    query_color.pixel = pixel;
1527    XQueryColor(p_global->display, p_global->colormap, &query_color);
1528    // @@@ FIXME: error handling!
1529
1530    red = query_color.red;
1531    green = query_color.green;
1532    blue = query_color.blue;
1533
1534    if (error) {
1535        red = green = blue = -1;
1536    }
1537    return error;
1538}
1539
1540// Converts GC to RGB float values to the range (0 - 1.0)
1541const char *AW_window::GC_to_RGB_float(AW_device *device, int gc, float& red,
1542        float& green, float& blue) {
1543    AW_common *common = device->common;
1544    AW_GC_Xm *gcm= AW_MAP_GC(gc);
1545    aw_assert(gcm);
1546    unsigned pixel = (unsigned short)(gcm->color);
1547    GB_ERROR error = 0;
1548    XColor query_color;
1549
1550    query_color.pixel = pixel;
1551
1552    XQueryColor(p_global->display, p_global->colormap, &query_color);
1553    // @@@ FIXME: error handling!
1554
1555    red = query_color.red/65535.0;
1556    green = query_color.green/65535.0;
1557    blue = query_color.blue/65535.0;
1558
1559    if (error) {
1560        red = green = blue = 1.0f;
1561    }
1562    return error;
1563}
1564
1565AW_color AW_window::alloc_named_data_color(int colnum, char *colorname) {
1566    if (!color_table_size) {
1567        color_table_size = AW_COLOR_MAX + colnum;
1568        color_table = (unsigned long *)malloc(sizeof(unsigned long)
1569                *color_table_size);
1570        memset((char *)color_table, -1, (size_t)(color_table_size
1571                *sizeof(unsigned long)));
1572    } else {
1573        if (colnum>=color_table_size) {
1574            color_table = (unsigned long *)realloc((char *)color_table, (8
1575                    + colnum)*sizeof(long)); // valgrinders : never free'd because AW_window never is free'd
1576            memset( (char *)(color_table+color_table_size), -1, (int)(8
1577                    + colnum - color_table_size) * sizeof(long));
1578            color_table_size = 8+colnum;
1579        }
1580    }
1581    XColor xcolor_returned, xcolor_exakt;
1582
1583    if (p_global->screen_depth == 1) { //Black and White Monitor
1584        static int col = 1;
1585        if (colnum == AW_DATA_BG) {
1586            col =1;
1587            if (strcmp(colorname, "white"))
1588                col *=-1;
1589        }
1590        if (col==1) {
1591            color_table[colnum] = WhitePixelOfScreen( XtScreen(p_global->toplevel_widget) );
1592        } else {
1593            color_table[colnum] = BlackPixelOfScreen( XtScreen(p_global->toplevel_widget) );
1594        }
1595        if (colnum == AW_DATA_BG)
1596            col *=-1;
1597    } else { // Color monitor
1598        if (color_table[colnum] !=(unsigned long)-1 ) {
1599            XFreeColors(p_global->display, p_global->colormap, &color_table[colnum],1,0);
1600        }
1601        if (XAllocNamedColor(p_global->display,p_global->colormap,colorname,
1602        &xcolor_returned,&xcolor_exakt) == 0) {
1603            sprintf(AW_ERROR_BUFFER, "XAllocColor failed: %s\n", colorname);
1604            aw_message();
1605            color_table[colnum] = (unsigned long)-1;
1606        } else {
1607            color_table[colnum] = xcolor_returned.pixel;
1608        }
1609    }
1610    if (colnum == AW_DATA_BG) {
1611        XtVaSetValues(p_w->areas[AW_MIDDLE_AREA]->area, 
1612        XmNbackground, color_table[colnum], NULL);
1613    }
1614    return (AW_color)colnum;
1615}
1616
1617void AW_window::create_devices(void) {
1618    unsigned long background_color;
1619    if (p_w->areas[AW_INFO_AREA]) {
1620        p_w->areas[AW_INFO_AREA]->create_devices(this, AW_INFO_AREA);
1621        XtVaGetValues(p_w->areas[AW_INFO_AREA]->area, 
1622        XmNbackground, &background_color, NULL);
1623        p_global->color_table[AW_WINDOW_DRAG] =
1624        background_color ^ p_global->color_table[AW_WINDOW_FG];
1625    }
1626    if (p_w->areas[AW_MIDDLE_AREA]) {
1627        p_w->areas[AW_MIDDLE_AREA]->create_devices(this, AW_MIDDLE_AREA);
1628    }
1629    if (p_w->areas[AW_BOTTOM_AREA]) {
1630        p_w->areas[AW_BOTTOM_AREA]->create_devices(this, AW_BOTTOM_AREA);
1631    }
1632}
1633
1634void AW_help_entry_pressed(AW_window *aww) {
1635    AW_root *root = aww->get_root();
1636    p_global->help_active = 1;
1637}
1638
1639void aw_create_help_entry(AW_window *aww) {
1640    aww->insert_help_topic("Click here and then on the questionable button/menu/...", "P", 0,
1641                           AWM_ALL, (AW_CB)AW_help_entry_pressed, 0, 0);
1642}
1643
1644/****************************************************************************************************************************/
1645/****************************************************************************************************************************/
1646/****************************************************************************************************************************/
1647
1648const char *aw_str_2_label(const char *str, AW_window *aww) {
1649    aw_assert(str);
1650   
1651    static const char *last_label = 0;
1652    static const char *last_str   = 0;
1653    static AW_window  *last_aww   = 0;
1654
1655    const char *label;
1656    if (str == last_str && aww == last_aww) { // reuse result ?
1657        label = last_label;
1658    }
1659    else {
1660        if (str[0] == '#') {
1661            label = GB_path_in_ARBLIB("pixmaps", str+1);
1662        }
1663        else {
1664            AW_awar *is_awar = aww->get_root()->label_is_awar(str);
1665
1666            if (is_awar) { // for labels displaying awar values, insert dummy text here
1667                int wanted_len = aww->_at->length_of_buttons - 2;
1668                if (wanted_len < 1) wanted_len = 1;
1669
1670                char *labelbuf       = GB_give_buffer(wanted_len+1);
1671                memset(labelbuf, 'y', wanted_len);
1672                labelbuf[wanted_len] = 0;
1673
1674                label = labelbuf;
1675            }
1676            else {
1677                label = str;
1678            }
1679        }
1680
1681        // store results locally, cause aw_str_2_label is nearly always called twice with same arguments
1682        // (see RES_LABEL_CONVERT)
1683        last_label = label;
1684        last_str   = str;
1685        last_aww   = aww;
1686    }
1687    return label;
1688}
1689
1690void AW_label_in_awar_list(AW_window *aww, Widget widget, const char *str) {
1691    AW_awar *is_awar = aww->get_root()->label_is_awar(str);
1692    if (is_awar) {
1693        char *var_value = is_awar->read_as_string();
1694        if (var_value) {
1695            aww->update_label((int*)widget, var_value);
1696        }
1697        else {
1698            AW_ERROR("AW_label_in_awar_list:: AWAR %s not found\n", str);
1699            aww->update_label((int*)widget, str);
1700        }
1701        free(var_value);
1702        AW_INSERT_BUTTON_IN_AWAR_LIST(is_awar, 0, widget, AW_WIDGET_LABEL_FIELD, aww);
1703    }
1704}
1705/*********************************************************************************************/
1706/*********************************************************************************************/
1707/*********************************************************************************************/
1708
1709static void aw_window_avoid_destroy_cb(Widget, AW_window *, XmAnyCallbackStruct *) {
1710    aw_message("If YOU do not know what to answer, how should ARB know?\nPlease think again and answer the prompt!");
1711}
1712
1713static void aw_window_noexit_destroy_cb(Widget , AW_window *aww, XmAnyCallbackStruct *) {
1714    aww->hide();
1715    // don't exit, when using destroy callback
1716}
1717
1718static void aw_window_destroy_cb(Widget , AW_window *aww, XmAnyCallbackStruct *) {
1719    AW_root *root = aww->get_root();
1720    if ( (p_global->main_aww == aww) || !p_global->main_aww->is_shown()) {
1721#ifdef NDEBUG
1722        if (aw_question("Are you sure to quit?","YES,NO") ) return;
1723#endif
1724        exit(0);
1725    }
1726    aww->hide();
1727}
1728
1729static long aw_loop_get_window_geometry(const char *, long val, void *) {
1730    AW_window *aww = (AW_window *)val;
1731    short posx, posy;
1732
1733    AW_root *root = aww->get_root();
1734    unsigned short width, height, borderwidth;
1735
1736    XtVaGetValues( p_aww(aww)->shell , // bad hack
1737    XmNborderWidth, &borderwidth,
1738    XmNwidth, &width,
1739    XmNheight, &height,
1740    XmNx, &posx,
1741    XmNy, &posy,
1742    NULL);
1743    if ( p_aww(aww)->WM_top_offset != -1000) {
1744        posy -= p_aww(aww)->WM_top_offset;
1745    }
1746    posx -= p_aww(aww)->WM_left_offset;
1747
1748    if (posx<0)
1749        posx = 0;
1750    if (posy<0)
1751        posy = 0;
1752
1753    root->awar(aw_awar_name_width (aww))->write_int(width);
1754    root->awar(aw_awar_name_height(aww))->write_int(height);
1755    root->awar(aw_awar_name_posx (aww))->write_int(posx);
1756    root->awar(aw_awar_name_posy (aww))->write_int(posy);
1757
1758    return val;
1759}
1760
1761void aw_update_awar_window_geometry(AW_root *awr) {
1762    GBS_hash_do_loop(awr->hash_for_windows, aw_loop_get_window_geometry, NULL);
1763}
1764
1765static const char *existingPixmap(const char *iconpath, const char *name) {
1766    const char *icon = GBS_global_string("%s/%s.xpm", iconpath, name);
1767
1768    if (!GB_is_regularfile(icon)) {
1769        icon = GBS_global_string("%s/%s.bitmap", iconpath, name);
1770        if (!GB_is_regularfile(icon)) icon = NULL;
1771    }
1772
1773    return icon;
1774}
1775
1776static Pixmap getIcon(Screen *screen, const char *iconName, Pixel foreground, Pixel background) {
1777    static GB_HASH *icon_hash = 0;
1778    if (!icon_hash) icon_hash = GBS_create_hash(100, GB_MIND_CASE);
1779
1780    Pixmap pixmap = GBS_read_hash(icon_hash, iconName);
1781
1782    if (!pixmap && iconName) {
1783        const char *iconpath = GB_path_in_ARBLIB("pixmaps/icons", NULL);
1784        const char *iconFile = existingPixmap(iconpath, iconName);
1785
1786        if (iconFile) {
1787            char *ico = strdup(iconFile);
1788            pixmap    = XmGetPixmap(screen, ico, foreground, background);
1789            GBS_write_hash(icon_hash, iconName, pixmap);
1790            free(ico);
1791        }
1792    }
1793
1794    return pixmap;
1795}
1796
1797Widget aw_create_shell(AW_window *aww, bool allow_resize, bool allow_close, int width, int height, int posx, int posy) {
1798    AW_root *root = aww->get_root();
1799    Widget shell;
1800
1801    // set minimum window size to size provided by init
1802    if (width >aww->_at->max_x_size) aww->_at->max_x_size = width;
1803    if (height>aww->_at->max_y_size) aww->_at->max_y_size = height;
1804
1805    if ( !GBS_read_hash(root->hash_for_windows, aww->get_window_id())) {
1806        GBS_write_hash(root->hash_for_windows, aww->get_window_id(), (long)aww);
1807        bool has_user_geometry = false;
1808
1809        const char *temp= aw_awar_name_width(aww);
1810        root->awar_int(temp, width);
1811        if (allow_resize) {
1812            int found_width = (int)root->awar(temp)->read_int();
1813            if (width != found_width) {
1814                has_user_geometry = true;
1815                width = found_width;
1816            }
1817        }
1818
1819        temp = aw_awar_name_height(aww);
1820        root->awar_int(temp, height);
1821        if (allow_resize) {
1822            int found_height = (int)root->awar(temp)->read_int();
1823            if (height != found_height) {
1824                has_user_geometry = true;
1825                height = found_height;
1826            }
1827        }
1828
1829        temp = aw_awar_name_posx(aww);
1830        root->awar_int(temp,posx)->set_minmax(0, 4000);
1831        // @@@ FIXME:  maximum should be set to current screen size minus some offset
1832        // to ensure that windows do not appear outside screen
1833        // same for posy below!
1834
1835        int found_posx = (int)root->awar(temp)->read_int();
1836        if (posx != found_posx) {
1837            has_user_geometry = true;
1838            posx = found_posx;
1839        }
1840
1841        temp = aw_awar_name_posy(aww);
1842        root->awar_int(temp,posy)->set_minmax(0, 3000);
1843        int found_posy = (int)root->awar(temp)->read_int();
1844        if (posy != found_posy) {
1845            has_user_geometry = true;
1846            posy = found_posy;
1847        }
1848
1849        if (has_user_geometry) {
1850#if defined(DEBUG)
1851            // printf("User geometry detected for window '%s'\n", aww->window_defaults_name);
1852#endif // DEBUG
1853            aww->recalc_size_at_show = 2; // keep user geometry (only if user size is smaller than default size, the latter is used)
1854        }
1855    }
1856
1857    if (allow_resize) {
1858        // create the window big enough to ensure that all widgets
1859        // are created in visible area (otherwise widget are crippled).
1860        // window will be resized later (on show)
1861
1862        width = 4000;
1863        height = 3000;
1864
1865        if (!aww->recalc_size_at_show) aww->recalc_size_at_show = 1;
1866    }
1867
1868    Widget  father      = p_global->toplevel_widget;
1869    Screen *screen      = XtScreen(father);
1870    Pixmap  icon_pixmap = getIcon(screen, aww->window_defaults_name, p_global->foreground, p_global->background);
1871
1872    if (!icon_pixmap) {
1873        icon_pixmap = getIcon(screen, root->program_name, p_global->foreground, p_global->background);
1874    }
1875
1876    if (!icon_pixmap) {
1877        AW_ERROR("Error: Missing icon pixmap for window '%s'\n", aww->window_defaults_name);
1878    }
1879    else if (icon_pixmap == XmUNSPECIFIED_PIXMAP) {
1880        AW_ERROR("Error: Failed to load icon pixmap for window '%s'\n", aww->window_defaults_name);
1881    }
1882
1883    if (!p_global->main_widget || !p_global->main_aww->is_shown()) {
1884        shell = XtVaCreatePopupShell("editor", applicationShellWidgetClass,
1885                                     father,
1886                                     XmNwidth, width, 
1887                                     XmNheight, height, 
1888                                     XmNx, posx, 
1889                                     XmNy, posy, 
1890                                     XmNtitle, aww->window_name, 
1891                                     XmNiconName, aww->window_name, 
1892                                     XmNkeyboardFocusPolicy, XmEXPLICIT,
1893                                     XmNdeleteResponse, XmDO_NOTHING,
1894                                     XtNiconPixmap, icon_pixmap, 
1895                                     NULL);
1896    } else {
1897        shell = XtVaCreatePopupShell("transient", transientShellWidgetClass,
1898                                     father, 
1899                                     XmNwidth, width, 
1900                                     XmNheight, height, 
1901                                     XmNx, posx, 
1902                                     XmNy, posy, 
1903                                     XmNtitle, aww->window_name, 
1904                                     XmNiconName, aww->window_name, 
1905                                     XmNkeyboardFocusPolicy, XmEXPLICIT, 
1906                                     XmNdeleteResponse, XmDO_NOTHING, 
1907                                     XtNiconPixmap, icon_pixmap, 
1908                                     NULL);
1909    }
1910    XtAddEventHandler(shell, EnterWindowMask, FALSE, AW_root_focusCB, (XtPointer) aww->get_root());
1911
1912    if (!p_global->main_widget) {
1913        p_global->main_widget = shell;
1914        p_global->main_aww    = aww;
1915    }
1916    else {
1917        if ( !p_global->main_aww->is_shown()) { // now i am the root window
1918            p_global->main_widget = shell;
1919            p_global->main_aww    = aww;
1920        }
1921    }
1922
1923    Atom WM_DELETE_WINDOW = XmInternAtom(XtDisplay(shell), (char*)"WM_DELETE_WINDOW", False);
1924
1925    if (allow_close == false) {
1926        XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_avoid_destroy_cb,(caddr_t)aww);
1927    }
1928    else if (p_global->no_exit) {
1929        XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_noexit_destroy_cb,(caddr_t)aww);
1930    }
1931    else {
1932        XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_destroy_cb,(caddr_t)aww);
1933    }
1934
1935    // set icon window (for window managers where iconified applications are dropped onto desktop or similar)
1936    {
1937        Window icon_window;
1938        XtVaGetValues(shell, XmNiconWindow, &icon_window, NULL);
1939
1940        Display *dpy = XtDisplay(shell);
1941        if (!icon_window) {
1942            XSetWindowAttributes attr;
1943            attr.background_pixmap = icon_pixmap;
1944
1945            int          xpos, ypos;
1946            unsigned int xsize, ysize, borderwidth, depth;
1947            Window       wroot;
1948
1949            if (XGetGeometry(dpy, icon_pixmap, &wroot, &xpos, &ypos, &xsize, &ysize, &borderwidth, &depth)) {
1950                icon_window = XCreateWindow(dpy, wroot, 0, 0, xsize, ysize, 0, depth, CopyFromParent, CopyFromParent, CWBackPixmap, &attr);
1951            }
1952        }
1953        if (!icon_window) {
1954            XtVaSetValues(shell, XmNiconPixmap, icon_pixmap, NULL);
1955        }
1956        else {
1957            XtVaSetValues(shell, XmNiconWindow, icon_window, NULL);
1958            XSetWindowBackgroundPixmap(dpy, icon_window, icon_pixmap);
1959            XClearWindow(dpy, icon_window);
1960        }
1961    }
1962
1963    return shell;
1964}
1965
1966
1967void aw_realize_widget(AW_window *aww) {
1968    if ( p_aww(aww)->areas[AW_INFO_AREA] && p_aww(aww)->areas[AW_INFO_AREA]->form) {
1969        XtManageChild(p_aww(aww)->areas[AW_INFO_AREA]->form);
1970    }
1971    if ( p_aww(aww)->areas[AW_MIDDLE_AREA] && p_aww(aww)->areas[AW_MIDDLE_AREA]->form) {
1972        XtManageChild(p_aww(aww)->areas[AW_MIDDLE_AREA]->form);
1973    }
1974    if ( p_aww(aww)->areas[AW_BOTTOM_AREA] && p_aww(aww)->areas[AW_BOTTOM_AREA]->form) {
1975        XtManageChild(p_aww(aww)->areas[AW_BOTTOM_AREA]->form);
1976    }
1977    XtRealizeWidget( p_aww(aww)->shell);
1978    p_aww(aww)->WM_top_offset = -1000;
1979}
1980
1981void AW_window_menu_modes::init(AW_root *root_in, const char *wid,
1982        const char *windowname, int width, int height) {
1983    Widget main_window;
1984    Widget help_popup;
1985    Widget help_label;
1986    Widget separator;
1987    Widget form1;
1988    Widget form2;
1989    //Widget frame;
1990    const char *help_button = "HELP";
1991    const char *help_mnemonic = "H";
1992
1993#if defined(DUMP_MENU_LIST)
1994    initMenuListing(windowname);
1995#endif // DUMP_MENU_LIST
1996    root = root_in; // for makro
1997    window_name = strdup(windowname);
1998    window_defaults_name = GBS_string_2_key(wid);
1999
2000    int posx = 50;
2001    int posy = 50;
2002
2003    p_w->shell= aw_create_shell(this, true, true, width, height, posx, posy);
2004
2005    main_window = XtVaCreateManagedWidget("mainWindow1",
2006            xmMainWindowWidgetClass, p_w->shell, 
2007            NULL);
2008
2009    p_w->menu_bar[0] = XtVaCreateManagedWidget("menu1", xmRowColumnWidgetClass,
2010            main_window, 
2011            XmNrowColumnType, XmMENU_BAR, 
2012            NULL);
2013
2014    // create shell for help-cascade
2015    help_popup = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
2016            p_w->menu_bar[0], 
2017            XmNwidth, 1, 
2018            XmNheight, 1, 
2019            XmNallowShellResize, true, 
2020            XmNoverrideRedirect, true, 
2021            NULL);
2022
2023    //create row column in Pull-Down shell
2024    p_w->help_pull_down = XtVaCreateWidget("menu_row_column",
2025            xmRowColumnWidgetClass, help_popup, 
2026            XmNrowColumnType, XmMENU_PULLDOWN, 
2027            NULL);
2028
2029    // create HELP-label in menu bar
2030    help_label = XtVaCreateManagedWidget("menu1_top_b1",
2031            xmCascadeButtonWidgetClass, p_w->menu_bar[0], 
2032            RES_CONVERT( XmNlabelString, help_button ),
2033                                          RES_CONVERT( XmNmnemonic, help_mnemonic ), 
2034                                          XmNsubMenuId, p_w->help_pull_down, NULL );
2035    XtVaSetValues(p_w->menu_bar[0], XmNmenuHelpWidget, help_label, NULL);
2036    root->make_sensitive(help_label, AWM_ALL);
2037   
2038    form1 = XtVaCreateManagedWidget( "form1",
2039    xmFormWidgetClass,
2040    main_window,
2041    // XmNwidth, width,
2042    // XmNheight, height,
2043    XmNresizePolicy, XmRESIZE_NONE,
2044    // XmNx, 0,
2045    // XmNy, 0,
2046    NULL);
2047
2048    p_w->mode_area = XtVaCreateManagedWidget( "mode area",
2049    xmDrawingAreaWidgetClass,
2050    form1,
2051    XmNresizePolicy, XmRESIZE_NONE,
2052    XmNwidth, 38,
2053    XmNheight, height,
2054    XmNx, 0,
2055    XmNy, 0,
2056    XmNleftOffset, 0,
2057    XmNtopOffset, 0,
2058    XmNbottomAttachment, XmATTACH_FORM,
2059    XmNleftAttachment, XmATTACH_POSITION,
2060    XmNtopAttachment, XmATTACH_POSITION,
2061    XmNmarginHeight, 2,
2062    XmNmarginWidth, 1,
2063    NULL);
2064
2065    separator = XtVaCreateManagedWidget( "separator",
2066    xmSeparatorWidgetClass,
2067    form1,
2068    XmNx, 37,
2069    XmNshadowThickness, 4,
2070    XmNorientation, XmVERTICAL,
2071    XmNbottomAttachment, XmATTACH_FORM,
2072    XmNtopAttachment, XmATTACH_FORM,
2073    XmNleftAttachment, XmATTACH_NONE,
2074    XmNleftWidget, NULL,
2075    XmNrightAttachment, XmATTACH_NONE,
2076    XmNleftOffset, 70,
2077    XmNleftPosition, 0,
2078    NULL);
2079
2080    form2 = XtVaCreateManagedWidget( "form2",
2081    xmFormWidgetClass,
2082    form1,
2083    XmNwidth, width,
2084    XmNheight, height,
2085    XmNtopOffset, 0,
2086    XmNbottomOffset, 0,
2087    XmNleftOffset, 0,
2088    XmNrightOffset, 0,
2089    XmNrightAttachment, XmATTACH_FORM,
2090    XmNbottomAttachment, XmATTACH_FORM,
2091    XmNleftAttachment, XmATTACH_WIDGET,
2092    XmNleftWidget, separator,
2093    XmNtopAttachment, XmATTACH_POSITION,
2094    XmNresizePolicy, XmRESIZE_NONE,
2095    XmNx, 0,
2096    XmNy, 0,
2097    NULL);
2098    p_w->areas[AW_INFO_AREA] =
2099    new AW_area_management(root, form2, XtVaCreateManagedWidget( "info_area",
2100            xmDrawingAreaWidgetClass,
2101            form2,
2102            XmNheight, 0,
2103            XmNbottomAttachment, XmATTACH_NONE,
2104            XmNtopAttachment, XmATTACH_FORM,
2105            XmNleftAttachment, XmATTACH_FORM,
2106            XmNrightAttachment, XmATTACH_FORM,
2107            XmNmarginHeight, 2,
2108            XmNmarginWidth, 2,
2109            NULL));
2110
2111    p_w->areas[AW_BOTTOM_AREA] =
2112    new AW_area_management(root, form2, XtVaCreateManagedWidget( "bottom_area",
2113            xmDrawingAreaWidgetClass,
2114            form2,
2115            XmNheight, 0,
2116            XmNbottomAttachment, XmATTACH_FORM,
2117            XmNtopAttachment, XmATTACH_NONE,
2118            XmNleftAttachment, XmATTACH_FORM,
2119            XmNrightAttachment, XmATTACH_FORM,
2120            NULL));
2121
2122    p_w->scroll_bar_horizontal = XtVaCreateManagedWidget( "scroll_bar_horizontal",
2123    xmScrollBarWidgetClass,
2124    form2,
2125    XmNheight, 15,
2126    XmNminimum, 0,
2127    XmNmaximum, AW_SCROLL_MAX,
2128    XmNincrement, 10,
2129    XmNsliderSize, AW_SCROLL_MAX,
2130    XmNrightAttachment, XmATTACH_FORM,
2131    XmNbottomAttachment, XmATTACH_FORM,
2132    XmNbottomOffset, 0,
2133    XmNleftAttachment, XmATTACH_FORM,
2134    XmNtopAttachment, XmATTACH_NONE,
2135    XmNorientation, XmHORIZONTAL,
2136    XmNrightOffset, 18,
2137    NULL );
2138
2139    p_w->scroll_bar_vertical = XtVaCreateManagedWidget( "scroll_bar_vertical",
2140    xmScrollBarWidgetClass,
2141    form2,
2142    XmNwidth, 15,
2143    XmNminimum, 0,
2144    XmNmaximum, AW_SCROLL_MAX,
2145    XmNincrement, 10,
2146    XmNsliderSize, AW_SCROLL_MAX,
2147    XmNrightAttachment, XmATTACH_FORM,
2148    XmNbottomAttachment, XmATTACH_WIDGET,
2149    XmNbottomWidget, p_w->scroll_bar_horizontal,
2150    XmNbottomOffset, 3,
2151    XmNleftOffset, 3,
2152    XmNrightOffset, 3,
2153    XmNleftAttachment, XmATTACH_NONE,
2154    XmNtopAttachment, XmATTACH_WIDGET,
2155    XmNtopWidget, INFO_WIDGET,
2156    NULL );
2157
2158    p_w->frame = XtVaCreateManagedWidget( "draw_area",
2159    xmFrameWidgetClass,
2160    form2,
2161    XmNshadowType, XmSHADOW_IN,
2162    XmNshadowThickness, 2,
2163    XmNleftOffset, 3,
2164    XmNtopOffset, 3,
2165    XmNbottomOffset, 3,
2166    XmNrightOffset, 3,
2167    XmNbottomAttachment, XmATTACH_WIDGET,
2168    XmNbottomWidget, p_w->scroll_bar_horizontal,
2169    XmNtopAttachment, XmATTACH_FORM,
2170    XmNtopOffset, 0,
2171    XmNleftAttachment, XmATTACH_FORM,
2172    XmNrightAttachment, XmATTACH_WIDGET,
2173    XmNrightWidget, p_w->scroll_bar_vertical,
2174    NULL);
2175
2176    p_w->areas[AW_MIDDLE_AREA] =
2177    new AW_area_management(root,p_w->frame, XtVaCreateManagedWidget( "draw area",
2178            xmDrawingAreaWidgetClass,
2179            p_w->frame,
2180            XmNmarginHeight, 0,
2181            XmNmarginWidth, 0,
2182            NULL));
2183
2184    XmMainWindowSetAreas( main_window, p_w->menu_bar[0], (Widget) NULL, (Widget) NULL, (Widget) NULL, form1 );
2185
2186    aw_realize_widget(this);
2187
2188    create_devices();
2189    aw_create_help_entry(this);
2190    create_window_variables();
2191}
2192
2193void AW_window_menu::init(AW_root *root_in, const char *wid,
2194        const char *windowname, int width, int height) {
2195    Widget main_window;
2196    Widget help_popup;
2197    Widget help_label;
2198    Widget separator;
2199    Widget form1;
2200    Widget form2;
2201    //Widget frame;
2202    const char *help_button = "HELP";
2203    const char *help_mnemonic = "H";
2204
2205#if defined(DUMP_MENU_LIST)
2206    initMenuListing(windowname);
2207#endif // DUMP_MENU_LIST
2208    root = root_in; // for makro
2209    window_name = strdup(windowname);
2210    window_defaults_name = GBS_string_2_key(wid);
2211
2212    int posx = 50;
2213    int posy = 50;
2214
2215    p_w->shell= aw_create_shell(this, true, true, width, height, posx, posy);
2216
2217    main_window = XtVaCreateManagedWidget("mainWindow1",
2218            xmMainWindowWidgetClass, p_w->shell, 
2219            NULL);
2220
2221    p_w->menu_bar[0] = XtVaCreateManagedWidget("menu1", xmRowColumnWidgetClass,
2222            main_window, 
2223            XmNrowColumnType, XmMENU_BAR, 
2224            NULL);
2225
2226    // create shell for help-cascade
2227    help_popup = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
2228            p_w->menu_bar[0], 
2229            XmNwidth, 1, 
2230            XmNheight, 1, 
2231            XmNallowShellResize, true, 
2232            XmNoverrideRedirect, true, 
2233            NULL);
2234
2235    //create row column in Pull-Down shell
2236    p_w->help_pull_down = XtVaCreateWidget("menu_row_column",
2237            xmRowColumnWidgetClass, help_popup, 
2238            XmNrowColumnType, XmMENU_PULLDOWN, 
2239            NULL);
2240
2241    // create HELP-label in menu bar
2242    help_label = XtVaCreateManagedWidget("menu1_top_b1",
2243            xmCascadeButtonWidgetClass, p_w->menu_bar[0], 
2244            RES_CONVERT( XmNlabelString, help_button ),
2245                                          RES_CONVERT( XmNmnemonic, help_mnemonic ), 
2246                                          XmNsubMenuId, p_w->help_pull_down, NULL );
2247    XtVaSetValues(p_w->menu_bar[0], XmNmenuHelpWidget, help_label, NULL);
2248    root->make_sensitive(help_label, AWM_ALL);
2249   
2250    form1 = XtVaCreateManagedWidget( "form1",
2251    xmFormWidgetClass,
2252    main_window,
2253    // XmNwidth, width,
2254    // XmNheight, height,
2255    XmNresizePolicy, XmRESIZE_NONE,
2256    // XmNx, 0,
2257    // XmNy, 0,
2258    NULL);
2259
2260    p_w->mode_area = XtVaCreateManagedWidget( "mode area",
2261    xmDrawingAreaWidgetClass,
2262    form1,
2263    XmNresizePolicy, XmRESIZE_NONE,
2264    XmNwidth, 17,
2265    XmNheight, height,
2266    XmNx, 0,
2267    XmNy, 0,
2268    XmNleftOffset, 0,
2269    XmNtopOffset, 0,
2270    XmNbottomAttachment, XmATTACH_FORM,
2271    XmNleftAttachment, XmATTACH_POSITION,
2272    XmNtopAttachment, XmATTACH_POSITION,
2273    XmNmarginHeight, 2,
2274    XmNmarginWidth, 1,
2275    NULL);
2276
2277    separator = p_w->mode_area;
2278
2279    form2 = XtVaCreateManagedWidget( "form2",
2280    xmFormWidgetClass,
2281    form1,
2282    XmNwidth, width,
2283    XmNheight, height,
2284    XmNtopOffset, 0,
2285    XmNbottomOffset, 0,
2286    XmNleftOffset, 0,
2287    XmNrightOffset, 0,
2288    XmNrightAttachment, XmATTACH_FORM,
2289    XmNbottomAttachment, XmATTACH_FORM,
2290    XmNleftAttachment, XmATTACH_WIDGET,
2291    XmNleftWidget, separator,
2292    XmNtopAttachment, XmATTACH_POSITION,
2293    XmNresizePolicy, XmRESIZE_NONE,
2294    XmNx, 0,
2295    XmNy, 0,
2296    NULL);
2297    p_w->areas[AW_INFO_AREA] =
2298    new AW_area_management(root,form2, XtVaCreateManagedWidget( "info_area",
2299            xmDrawingAreaWidgetClass,
2300            form2,
2301            XmNheight, 0,
2302            XmNbottomAttachment, XmATTACH_NONE,
2303            XmNtopAttachment, XmATTACH_FORM,
2304            XmNleftAttachment, XmATTACH_FORM,
2305            XmNrightAttachment, XmATTACH_FORM,
2306            XmNmarginHeight, 2,
2307            XmNmarginWidth, 2,
2308            NULL));
2309
2310    p_w->areas[AW_BOTTOM_AREA] =
2311    new AW_area_management(root,form2, XtVaCreateManagedWidget( "bottom_area",
2312            xmDrawingAreaWidgetClass,
2313            form2,
2314            XmNheight, 0,
2315            XmNbottomAttachment, XmATTACH_FORM,
2316            XmNtopAttachment, XmATTACH_NONE,
2317            XmNleftAttachment, XmATTACH_FORM,
2318            XmNrightAttachment, XmATTACH_FORM,
2319            NULL));
2320
2321    p_w->scroll_bar_horizontal = XtVaCreateManagedWidget( "scroll_bar_horizontal",
2322    xmScrollBarWidgetClass,
2323    form2,
2324    XmNheight, 15,
2325    XmNminimum, 0,
2326    XmNmaximum, AW_SCROLL_MAX,
2327    XmNincrement, 10,
2328    XmNsliderSize, AW_SCROLL_MAX,
2329    XmNrightAttachment, XmATTACH_FORM,
2330    XmNbottomAttachment, XmATTACH_FORM,
2331    XmNbottomOffset, 0,
2332    XmNleftAttachment, XmATTACH_FORM,
2333    XmNtopAttachment, XmATTACH_NONE,
2334    XmNorientation, XmHORIZONTAL,
2335    XmNrightOffset, 18,
2336    NULL );
2337
2338    p_w->scroll_bar_vertical = XtVaCreateManagedWidget( "scroll_bar_vertical",
2339    xmScrollBarWidgetClass,
2340    form2,
2341    XmNwidth, 15,
2342    XmNminimum, 0,
2343    XmNmaximum, AW_SCROLL_MAX,
2344    XmNincrement, 10,
2345    XmNsliderSize, AW_SCROLL_MAX,
2346    XmNrightAttachment, XmATTACH_FORM,
2347    XmNbottomAttachment, XmATTACH_WIDGET,
2348    XmNbottomWidget, p_w->scroll_bar_horizontal,
2349    XmNbottomOffset, 3,
2350    XmNleftOffset, 3,
2351    XmNrightOffset, 3,
2352    XmNleftAttachment, XmATTACH_NONE,
2353    XmNtopAttachment, XmATTACH_WIDGET,
2354    XmNtopWidget, INFO_WIDGET,
2355    NULL );
2356
2357    p_w->frame = XtVaCreateManagedWidget( "draw_area",
2358    xmFrameWidgetClass,
2359    form2,
2360    XmNshadowType, XmSHADOW_IN,
2361    XmNshadowThickness, 2,
2362    XmNleftOffset, 3,
2363    XmNtopOffset, 3,
2364    XmNbottomOffset, 3,
2365    XmNrightOffset, 3,
2366    XmNbottomAttachment, XmATTACH_WIDGET,
2367    XmNbottomWidget, p_w->scroll_bar_horizontal,
2368    XmNtopAttachment, XmATTACH_FORM,
2369    XmNtopOffset, 0,
2370    XmNleftAttachment, XmATTACH_FORM,
2371    XmNrightAttachment, XmATTACH_WIDGET,
2372    XmNrightWidget, p_w->scroll_bar_vertical,
2373    NULL);
2374
2375    p_w->areas[AW_MIDDLE_AREA] =
2376    new AW_area_management(root,p_w->frame, XtVaCreateManagedWidget( "draw area",
2377            xmDrawingAreaWidgetClass,
2378            p_w->frame,
2379            XmNmarginHeight, 0,
2380            XmNmarginWidth, 0,
2381            NULL));
2382
2383    XmMainWindowSetAreas( main_window, p_w->menu_bar[0], (Widget) NULL,
2384    (Widget) NULL, (Widget) NULL, form1 );
2385
2386    aw_realize_widget(this);
2387
2388    create_devices();
2389    aw_create_help_entry(this);
2390    create_window_variables();
2391}
2392
2393void AW_window_simple::init(AW_root *root_in, const char *wid,
2394        const char *windowname) {
2395    //Arg args[10];
2396    root = root_in; // for makro
2397
2398    int width = 100; // this is only the minimum size!
2399    int height = 100;
2400    int posx = 50;
2401    int posy = 50;
2402
2403    window_name = strdup(windowname);
2404    window_defaults_name = GBS_string_2_key(wid);
2405
2406    p_w->shell= aw_create_shell(this, true, true, width, height, posx, posy);
2407
2408    // add this to disable resize or maximize in simple dialogs (avoids broken layouts)
2409    // XtVaSetValues(p_w->shell, XmNmwmFunctions, MWM_FUNC_MOVE | MWM_FUNC_CLOSE,
2410    //         NULL);
2411
2412    Widget form1 = XtVaCreateManagedWidget("forms", xmFormWidgetClass,
2413            p_w->shell, 
2414            NULL);
2415
2416    p_w->areas[AW_INFO_AREA] = new AW_area_management(root,form1, XtVaCreateManagedWidget( "info_area",
2417                    xmDrawingAreaWidgetClass,
2418                    form1,
2419                    XmNbottomAttachment, XmATTACH_FORM,
2420                    XmNtopAttachment, XmATTACH_FORM,
2421                    XmNleftAttachment, XmATTACH_FORM,
2422                    XmNrightAttachment, XmATTACH_FORM,
2423                    XmNmarginHeight, 2,
2424                    XmNmarginWidth, 2,
2425                    NULL));
2426
2427    aw_realize_widget(this);
2428    create_devices();
2429}
2430
2431void AW_window_simple_menu::init(AW_root *root_in, const char *wid,
2432        const char *windowname) {
2433    //  Arg args[10];
2434
2435    root = root_in; // for makro
2436
2437    const char *help_button = "HELP";
2438    const char *help_mnemonic = "H";
2439    window_name = strdup(windowname);
2440    window_defaults_name = GBS_string_2_key(wid);
2441
2442    int width = 100;
2443    int height = 100;
2444    int posx = 50;
2445    int posy = 50;
2446
2447    p_w->shell= aw_create_shell(this, true, true, width, height, posx, posy);
2448
2449    Widget main_window;
2450    Widget help_popup;
2451    Widget help_label;
2452    Widget form1;
2453
2454    main_window = XtVaCreateManagedWidget("mainWindow1",
2455            xmMainWindowWidgetClass, p_w->shell, 
2456            NULL);
2457
2458    p_w->menu_bar[0] = XtVaCreateManagedWidget("menu1", xmRowColumnWidgetClass,
2459            main_window, 
2460            XmNrowColumnType, XmMENU_BAR, 
2461            NULL);
2462
2463    // create shell for help-cascade
2464    help_popup = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
2465            p_w->menu_bar[0], 
2466            XmNwidth, 1, 
2467            XmNheight, 1, 
2468            XmNallowShellResize, true, 
2469            XmNoverrideRedirect, true, 
2470            NULL);
2471
2472    //create row column in Pull-Down shell
2473    p_w->help_pull_down = XtVaCreateWidget("menu_row_column",
2474            xmRowColumnWidgetClass, help_popup, 
2475            XmNrowColumnType, XmMENU_PULLDOWN, 
2476            NULL);
2477
2478    // create HELP-label in menu bar
2479    help_label = XtVaCreateManagedWidget("menu1_top_b1",
2480            xmCascadeButtonWidgetClass, p_w->menu_bar[0], 
2481            RES_CONVERT( XmNlabelString, help_button ),
2482                                          RES_CONVERT( XmNmnemonic, help_mnemonic ), 
2483                                          XmNsubMenuId, p_w->help_pull_down, NULL );
2484    XtVaSetValues(p_w->menu_bar[0], XmNmenuHelpWidget, help_label, NULL);
2485    root->make_sensitive(help_label, AWM_ALL);
2486   
2487    form1 = XtVaCreateManagedWidget( "form1",
2488    xmFormWidgetClass,
2489    main_window,
2490    XmNtopOffset, 10,
2491    XmNresizePolicy, XmRESIZE_NONE,
2492    NULL);
2493
2494    p_w->areas[AW_INFO_AREA] =
2495    new AW_area_management(root, form1, XtVaCreateManagedWidget( "info_area",
2496            xmDrawingAreaWidgetClass,
2497            form1,
2498            XmNbottomAttachment, XmATTACH_FORM,
2499            XmNtopAttachment, XmATTACH_FORM,
2500            XmNleftAttachment, XmATTACH_FORM,
2501            XmNrightAttachment, XmATTACH_FORM,
2502            XmNmarginHeight, 2,
2503            XmNmarginWidth, 2,
2504            NULL));
2505
2506    aw_realize_widget(this );
2507
2508    aw_create_help_entry(this);
2509    create_devices();
2510}
2511
2512void AW_window_message::init(AW_root *root_in, const char *windowname,
2513        bool allow_close) {
2514    //  Arg args[10];
2515
2516    root = root_in; // for makro
2517
2518    int width = 100;
2519    int height = 100;
2520    int posx = 50;
2521    int posy = 50;
2522
2523    window_name = strdup(windowname);
2524    window_defaults_name = GBS_string_2_key(window_name);
2525
2526    // create shell for message box
2527    p_w->shell= aw_create_shell(this, true, allow_close, width, height, posx, posy);
2528
2529    // disable resize or maximize in simple dialogs (avoids broken layouts)
2530    XtVaSetValues(p_w->shell, XmNmwmFunctions, MWM_FUNC_MOVE | MWM_FUNC_CLOSE,
2531            NULL);
2532
2533    p_w->areas[AW_INFO_AREA] = new AW_area_management(root,p_w->shell, XtVaCreateManagedWidget( "info_area",
2534                    xmDrawingAreaWidgetClass,
2535                    p_w->shell,
2536                    XmNheight, 0,
2537                    XmNbottomAttachment, XmATTACH_NONE,
2538                    XmNtopAttachment, XmATTACH_FORM,
2539                    XmNleftAttachment, XmATTACH_FORM,
2540                    XmNrightAttachment, XmATTACH_FORM,
2541                    NULL));
2542
2543    aw_realize_widget(this);
2544    //  create_devices();
2545}
2546
2547void AW_window::set_info_area_height(int height) {
2548    XtVaSetValues(INFO_WIDGET, XmNheight, height, NULL);
2549    XtVaSetValues(p_w->frame, XmNtopOffset, height, NULL);
2550}
2551
2552void AW_window::set_bottom_area_height(int height) {
2553    XtVaSetValues(BOTTOM_WIDGET, XmNheight, height, NULL);
2554    XtVaSetValues(p_w->scroll_bar_horizontal, XmNbottomOffset, (int)height,
2555            NULL);
2556}
2557
2558void AW_window::set_vertical_scrollbar_top_indent(int indent) {
2559    XtVaSetValues(p_w->scroll_bar_vertical, XmNtopOffset, (int)indent, NULL);
2560    top_indent_of_vertical_scrollbar = indent;
2561}
2562
2563void AW_window::set_vertical_scrollbar_bottom_indent(int indent) {
2564    XtVaSetValues(p_w->scroll_bar_vertical, XmNbottomOffset, (int)(3+indent),
2565            NULL);
2566    bottom_indent_of_vertical_scrollbar = indent;
2567}
2568
2569void AW_root::apply_sensitivity(AW_active mask) {
2570    aw_assert(legal_mask(mask));
2571    AW_buttons_struct *list;
2572
2573    global_mask = mask;
2574    for (list = p_r->button_list; list; list = list->next) {
2575        XtSetSensitive(list->button, (list->mask & mask) ? True : False);
2576    }
2577}
2578
2579void AW_window::select_mode(int mode) {
2580    if (mode >= p_w->number_of_modes)
2581        return;
2582
2583    Widget oldwidget = p_w->modes_widgets[p_w->selected_mode];
2584    p_w->selected_mode = mode;
2585    Widget widget = p_w->modes_widgets[p_w->selected_mode];
2586    XtVaSetValues(oldwidget, XmNbackground, p_global->background, NULL);
2587    XtVaSetValues(widget, XmNbackground, p_global->foreground, NULL);
2588}
2589
2590static void aw_mode_callback(AW_window *aww, long mode, AW_cb_struct *cbs) {
2591    aww->select_mode((int)mode);
2592    cbs->run_callback();
2593}
2594
2595#define MODE_BUTTON_OFFSET 34
2596inline int yoffset_for_mode_button(int button_number) {
2597    return button_number*MODE_BUTTON_OFFSET + (button_number/4)*8 + 2;
2598}
2599
2600int AW_window::create_mode(const char *pixmap, const char *helpText, AW_active Mask, void (*f)(AW_window*, AW_CL, AW_CL), AW_CL cd1, AW_CL cd2) {
2601    aw_assert(legal_mask(Mask));
2602    Widget button;
2603
2604    TuneBackground(p_w->mode_area, TUNE_BUTTON); // set background color for mode-buttons
2605
2606    const char *path = GB_path_in_ARBLIB("pixmaps", pixmap);
2607
2608    int y = yoffset_for_mode_button(p_w->number_of_modes);
2609    button = XtVaCreateManagedWidget("", xmPushButtonWidgetClass, p_w->mode_area,
2610                                     XmNx,               0,
2611                                     XmNy,               y,
2612                                     XmNlabelType,       XmPIXMAP,
2613                                     XmNshadowThickness, 1,
2614                                     XmNbackground,      _at->background_color,
2615                                     NULL);
2616    XtVaSetValues(button, RES_CONVERT( XmNlabelPixmap, path ),NULL );
2617    XtVaGetValues(button,XmNforeground, &p_global->foreground, NULL);
2618
2619    AW_cb_struct *cbs = new AW_cb_struct(this, f, cd1, cd2, 0);
2620    AW_cb_struct *cb2 = new AW_cb_struct(this, (AW_CB)aw_mode_callback, (AW_CL)p_w->number_of_modes, (AW_CL)cbs, helpText, cbs);
2621    XtAddCallback(button, XmNactivateCallback,
2622    (XtCallbackProc) AW_server_callback,
2623    (XtPointer) cb2);
2624
2625    if (!p_w->modes_f_callbacks) {
2626        p_w->modes_f_callbacks = (AW_cb_struct **)GB_calloc(sizeof(AW_cb_struct*),AW_NUMBER_OF_F_KEYS); // valgrinders : never free'd because AW_window never is free'd
2627    }
2628    if (!p_w->modes_widgets) {
2629        p_w->modes_widgets = (Widget *)GB_calloc(sizeof(Widget),AW_NUMBER_OF_F_KEYS);
2630    }
2631    if (p_w->number_of_modes<AW_NUMBER_OF_F_KEYS) {
2632        p_w->modes_f_callbacks[p_w->number_of_modes] = cb2;
2633        p_w->modes_widgets[p_w->number_of_modes] = button;
2634    }
2635
2636    root->make_sensitive(button, Mask);
2637    p_w->number_of_modes++;
2638
2639    int ynext = yoffset_for_mode_button(p_w->number_of_modes);
2640    if (ynext> _at->max_y_size) _at->max_y_size = ynext;
2641
2642    return p_w->number_of_modes;
2643}
2644
2645// ------------------------
2646//      Hotkey Checking
2647// ------------------------
2648
2649#ifdef DEBUG
2650
2651#define MAX_DEEP_TO_TEST       10
2652#define MAX_MENU_ITEMS_TO_TEST 50
2653
2654static char *TD_menu_name = 0;
2655static char  TD_mnemonics[MAX_DEEP_TO_TEST][MAX_MENU_ITEMS_TO_TEST];
2656static int   TD_topics[MAX_DEEP_TO_TEST];
2657
2658struct SearchPossibilities {
2659    char *menu_topic;
2660    SearchPossibilities *next;
2661
2662    SearchPossibilities(const char* menu_topic_, SearchPossibilities *next_) {
2663        menu_topic = strdup(menu_topic_);
2664        next = next_;
2665    }
2666
2667    ~SearchPossibilities() {
2668        free(menu_topic);
2669        delete next;
2670    }
2671};
2672
2673typedef SearchPossibilities *SearchPossibilitiesPtr;
2674static SearchPossibilitiesPtr TD_poss[MAX_DEEP_TO_TEST] = { 0 };
2675
2676inline void addToPoss(int menu_deep, const char *topic_name) {
2677    TD_poss[menu_deep] = new SearchPossibilities(topic_name, TD_poss[menu_deep]);
2678}
2679
2680inline char oppositeCase(char c) {
2681    return isupper(c) ? tolower(c) : toupper(c);
2682}
2683
2684static void strcpy_overlapping(char *dest, char *src) {
2685    int src_len = strlen(src);
2686    memmove(dest, src, src_len+1);
2687}
2688
2689static const char *possible_mnemonics(int menu_deep, const char *topic_name) {
2690    int t;
2691    static char *unused;
2692
2693    freedup(unused, topic_name);
2694
2695    for (t = 0; unused[t]; ++t) {
2696        bool remove = false;
2697        if (!isalnum(unused[t])) { // remove useless chars
2698            remove = true;
2699        } else {
2700            char *dup = strchr(unused, unused[t]);
2701            if (dup && (dup-unused)<t) { // remove duplicated chars
2702                remove = true;
2703            } else {
2704                dup = strchr(unused, oppositeCase(unused[t]));
2705                if (dup && (dup-unused)<t) { // char is duplicated with opposite case
2706                    dup[0] = toupper(dup[0]); // prefer upper case
2707                    remove = true;
2708                }
2709            }
2710        }
2711        if (remove) {
2712            strcpy_overlapping(unused+t, unused+t+1);
2713            --t;
2714        }
2715    }
2716
2717    int topics = TD_topics[menu_deep];
2718    for (t = 0; t<topics; ++t) {
2719        char c = TD_mnemonics[menu_deep][t]; // upper case!
2720        char *u = strchr(unused, c);
2721        if (u)
2722            strcpy_overlapping(u, u+1); // remove char
2723        u = strchr(unused, tolower(c));
2724        if (u)
2725            strcpy_overlapping(u, u+1); // remove char
2726    }
2727
2728    return unused;
2729}
2730
2731static void printPossibilities(int menu_deep) {
2732    SearchPossibilities *sp = TD_poss[menu_deep];
2733    while (sp) {
2734        const char *poss = possible_mnemonics(menu_deep, sp->menu_topic);
2735        fprintf(stderr, "          - Possibilities for '%s': '%s'\n", sp->menu_topic, poss);
2736
2737        sp = sp->next;
2738    }
2739
2740    delete TD_poss[menu_deep];
2741    TD_poss[menu_deep] = 0;
2742}
2743
2744static int menu_deep_check = 0;
2745
2746static void test_duplicate_mnemonics(int menu_deep, const char *topic_name, const char *mnemonic) {
2747    if (mnemonic && mnemonic[0] != 0) {
2748        if (mnemonic[1]) { // longer than 1 char -> wrong
2749            fprintf(stderr, "Warning: Hotkey '%s' is too long; only 1 character allowed (%s|%s)\n", mnemonic, TD_menu_name, topic_name);
2750        }
2751        if (topic_name[0] == '#') { // graphical menu
2752            if (mnemonic[0]) {
2753                fprintf(stderr, "Warning: Hotkey '%s' is useless for graphical menu entry (%s|%s)\n", mnemonic, TD_menu_name, topic_name);
2754            }
2755        }
2756        else {
2757            // fprintf(stderr, "- menu_deep=%i, TD_menu_name='%s', topic_name='%s' mnemonic='%s'\n", menu_deep, TD_menu_name, topic_name, mnemonic);
2758            if (strchr(topic_name, mnemonic[0])) {  // occurs in menu text
2759                int topics = TD_topics[menu_deep];
2760                int t;
2761                char hotkey = toupper(mnemonic[0]); // store hotkeys case-less (case does not matter when pressing the hotkey)
2762
2763                TD_mnemonics[menu_deep][topics] = hotkey;
2764
2765                for (t=0; t<topics; t++) {
2766                    if (TD_mnemonics[menu_deep][t]==hotkey) {
2767                        fprintf(stderr, "Warning: Hotkey '%c' used twice (%s|%s)\n", hotkey, TD_menu_name, topic_name);
2768                        addToPoss(menu_deep, topic_name);
2769                        break;
2770                    }
2771                }
2772
2773                TD_topics[menu_deep] = topics+1;
2774            }
2775            else {
2776                fprintf(stderr, "Warning: Hotkey '%c' is useless; does not occur in text (%s|%s)\n", mnemonic[0], TD_menu_name, topic_name);
2777                addToPoss(menu_deep, topic_name);
2778            }
2779        }
2780    }
2781#if defined(DEVEL_RALF)
2782    else {
2783        if (topic_name[0] != '#') { // not a graphical menu
2784            fprintf(stderr, "Warning: Missing hotkey for (%s|%s)\n", TD_menu_name, topic_name);
2785            addToPoss(menu_deep, topic_name);
2786        }
2787    }
2788#endif // DEVEL_RALF
2789}
2790
2791static void open_test_duplicate_mnemonics(int menu_deep, const char *sub_menu_name, const char *mnemonic) {
2792    aw_assert(menu_deep == menu_deep_check+1);
2793    menu_deep_check = menu_deep;
2794
2795    int len = strlen(TD_menu_name)+1+strlen(sub_menu_name)+1;
2796    char *buf = (char*)malloc(len);
2797
2798    memset(buf, 0, len);
2799    sprintf(buf, "%s|%s", TD_menu_name, sub_menu_name);
2800
2801    test_duplicate_mnemonics(menu_deep-1, sub_menu_name, mnemonic);
2802
2803    freeset(TD_menu_name, buf);
2804    TD_poss[menu_deep] = 0;
2805}
2806
2807static void close_test_duplicate_mnemonics(int menu_deep) {
2808    aw_assert(menu_deep == menu_deep_check);
2809    menu_deep_check = menu_deep-1;
2810
2811    printPossibilities(menu_deep);
2812    TD_topics[menu_deep] = 0;
2813
2814    aw_assert(TD_menu_name);
2815    // otherwise no menu was opened
2816
2817    char *slash = strrchr(TD_menu_name, '|');
2818    if (slash) {
2819        slash[0] = 0;
2820    } else {
2821        TD_menu_name[0] = 0;
2822    }
2823}
2824
2825static void init_duplicate_mnemonic() {
2826    int i;
2827
2828    if (TD_menu_name) close_test_duplicate_mnemonics(1); // close last menu
2829    freedup(TD_menu_name, "");
2830
2831    for (i=0; i<MAX_DEEP_TO_TEST; i++) {
2832        TD_topics[i] = 0;
2833    }
2834    aw_assert(menu_deep_check == 0);
2835}
2836static void exit_duplicate_mnemonic() {
2837    close_test_duplicate_mnemonics(1); // close last menu
2838    aw_assert(TD_menu_name);
2839    freeset(TD_menu_name, 0);
2840    aw_assert(menu_deep_check == 0);
2841}
2842#endif
2843
2844// --------------------------------------------------------------------------------
2845
2846void AW_window::create_menu(AW_label name, const char *mnemonic, const char *helpText, AW_active Mask) {
2847    aw_assert(legal_mask(Mask));
2848    p_w->menu_deep = 0;
2849#ifdef DEBUG
2850    init_duplicate_mnemonic();
2851#endif
2852#if defined(DUMP_MENU_LIST)
2853    dumpCloseAllSubMenus();
2854#endif // DUMP_MENU_LIST
2855    insert_sub_menu(name, mnemonic, helpText, Mask);
2856}
2857
2858void AW_window::all_menus_created() { // this is called by AW_window::show() (i.e. after all menus have been created)
2859#if defined(DEBUG)
2860    if (p_w->menu_deep>0) { // window had menu
2861        aw_assert(p_w->menu_deep == 1);
2862        // some unclosed sub-menus ?
2863        if (menu_deep_check == 1) { // otherwise the window is just re-shown (already has been checked!)
2864            exit_duplicate_mnemonic();
2865        }
2866    }
2867#endif // DEBUG
2868}
2869
2870void AW_window::insert_sub_menu(AW_label name, const char *mnemonic, const char *helpText, AW_active Mask) {
2871    aw_assert(legal_mask(Mask));
2872    AWUSE(helpText);
2873    Widget shell, Label;
2874
2875    TuneBackground(p_w->menu_bar[p_w->menu_deep], TUNE_SUBMENU); // set background color for submenus
2876    // (Note: This must even be called if TUNE_SUBMENU is 0!
2877    //        Otherwise several submenus get the TUNE_MENUTOPIC color)
2878
2879#if defined(DUMP_MENU_LIST)
2880    dumpOpenSubMenu(name);
2881#endif // DUMP_MENU_LIST
2882#ifdef DEBUG
2883    open_test_duplicate_mnemonics(p_w->menu_deep+1, name, mnemonic);
2884#endif
2885
2886    // create shell for Pull-Down
2887    shell = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
2888            p_w->menu_bar[p_w->menu_deep], 
2889            XmNwidth, 1, 
2890            XmNheight, 1, 
2891            XmNallowShellResize, true, 
2892            XmNoverrideRedirect, true, 
2893            NULL);
2894
2895    //create row column in Pull-Down shell
2896
2897    p_w->menu_bar[p_w->menu_deep+1] = XtVaCreateWidget("menu_row_column",
2898            xmRowColumnWidgetClass, shell, 
2899            XmNrowColumnType, XmMENU_PULLDOWN, 
2900            XmNtearOffModel, XmTEAR_OFF_ENABLED, 
2901            NULL);
2902
2903    // create label in menu bar
2904    if (mnemonic && *mnemonic && strchr(name, mnemonic[0])) {
2905        // if mnemonic is "" -> Cannot convert string "" to type KeySym
2906        Label = XtVaCreateManagedWidget("menu1_top_b1",
2907                xmCascadeButtonWidgetClass, p_w->menu_bar[p_w->menu_deep], 
2908                RES_CONVERT( XmNlabelString, name ),
2909                                         RES_CONVERT( XmNmnemonic, mnemonic ), 
2910                                         XmNsubMenuId, p_w->menu_bar[p_w->menu_deep+1], 
2911                                         XmNbackground, _at->background_color, NULL );
2912    }
2913    else {
2914        Label = XtVaCreateManagedWidget( "menu1_top_b1",
2915        xmCascadeButtonWidgetClass,
2916        p_w->menu_bar[p_w->menu_deep],
2917        RES_CONVERT( XmNlabelString, name ),
2918        XmNsubMenuId, p_w->menu_bar[p_w->menu_deep+1],
2919        XmNbackground, _at->background_color,
2920        NULL);
2921    }
2922
2923    if (p_w->menu_deep < AW_MAX_MENU_DEEP-1) p_w->menu_deep++;
2924
2925    root->make_sensitive(Label, Mask);
2926}
2927
2928void AW_window::close_sub_menu(void) {
2929#ifdef DEBUG
2930    close_test_duplicate_mnemonics(p_w->menu_deep);
2931#endif
2932#if defined(DUMP_MENU_LIST)
2933    dumpCloseSubMenu();
2934#endif // DUMP_MENU_LIST
2935    if (p_w->menu_deep>0)
2936        p_w->menu_deep--;
2937}
2938
2939void AW_window::insert_menu_topic(const char *topic_id, AW_label name,
2940                                  const char *mnemonic, const char *helpText, AW_active Mask,
2941                                  void (*f)(AW_window*,AW_CL,AW_CL), AW_CL cd1, AW_CL cd2)
2942{
2943    aw_assert(legal_mask(Mask));
2944    Widget button;
2945   
2946    if (!topic_id) topic_id = name; // hmm, due to this we cannot insert_menu_topic w/o id. Change? @@@
2947
2948    TuneBackground(p_w->menu_bar[p_w->menu_deep], TUNE_MENUTOPIC); // set background color for normal menu topics
2949
2950#if defined(DUMP_MENU_LIST)
2951    dumpMenuEntry(name);
2952#endif // DUMP_MENU_LIST
2953#ifdef DEBUG
2954    test_duplicate_mnemonics(p_w->menu_deep, name, mnemonic);
2955#endif
2956    if (mnemonic && *mnemonic && strchr(name, mnemonic[0])) {
2957        // create one sub-menu-point
2958        button = XtVaCreateManagedWidget("", xmPushButtonWidgetClass,
2959                p_w->menu_bar[p_w->menu_deep], 
2960                RES_LABEL_CONVERT( name ),
2961                                          RES_CONVERT( XmNmnemonic, mnemonic ), 
2962                                          XmNbackground, _at->background_color, NULL );
2963    } else {
2964        button = XtVaCreateManagedWidget( "",
2965        xmPushButtonWidgetClass,
2966        p_w->menu_bar[p_w->menu_deep],
2967        RES_LABEL_CONVERT( name ),
2968        XmNbackground, _at->background_color,
2969        NULL);
2970    }
2971
2972    AW_label_in_awar_list(this,button,name);
2973    AW_cb_struct *cbs = new AW_cb_struct(this, f, cd1, cd2, helpText);
2974    XtAddCallback(button, XmNactivateCallback,
2975                  (XtCallbackProc) AW_server_callback,
2976                  (XtPointer) cbs);
2977
2978    cbs->id = strdup(topic_id);
2979    root->define_remote_command(cbs);
2980    root->make_sensitive(button, Mask);
2981}
2982
2983void AW_window::insert_help_topic(AW_label name, const char *mnemonic, const char *helpText, AW_active Mask,
2984                                  void (*f)(AW_window*, AW_CL , AW_CL ), AW_CL cd1, AW_CL cd2)
2985{
2986    aw_assert(legal_mask(Mask));
2987    Widget button;
2988
2989    // create one help-sub-menu-point
2990    button = XtVaCreateManagedWidget("", xmPushButtonWidgetClass,
2991            p_w->help_pull_down, 
2992            RES_CONVERT( XmNlabelString, name ),
2993                                      RES_CONVERT( XmNmnemonic, mnemonic ), NULL );
2994    XtAddCallback(button, XmNactivateCallback,
2995    (XtCallbackProc) AW_server_callback,
2996    (XtPointer) new AW_cb_struct(this, f, cd1, cd2, helpText));
2997
2998    root->make_sensitive(button, Mask);
2999}
3000
3001void AW_window::insert_separator(void) {
3002    Widget separator;
3003
3004    // create one help-sub-menu-point
3005    separator = XtVaCreateManagedWidget("", xmSeparatorWidgetClass,
3006            p_w->menu_bar[p_w->menu_deep], 
3007            NULL);
3008}
3009
3010void AW_window::insert_separator_help(void) {
3011    Widget separator;
3012
3013    // create one help-sub-menu-point
3014    separator = XtVaCreateManagedWidget("", xmSeparatorWidgetClass,
3015            p_w->help_pull_down, 
3016            NULL);
3017}
3018
3019AW_area_management::AW_area_management(AW_root *awr, Widget formi, Widget widget) {
3020    memset((char *)this, 0, sizeof(AW_area_management));
3021    form = formi;
3022    area = widget;
3023    XtAddEventHandler(area, EnterWindowMask, FALSE, AW_root_focusCB, (XtPointer)awr);
3024}
3025
3026AW_device *AW_window::get_device(AW_area area) {
3027    AW_area_management *aram= MAP_ARAM(area);
3028    if (!aram)
3029        return 0;
3030    if (!aram->device)
3031        aram->device = new AW_device_Xm(aram->common);
3032    aram->device->init();
3033    return (AW_device *)(aram->device);
3034}
3035
3036AW_device *AW_window::get_size_device(AW_area area) {
3037    AW_area_management *aram= MAP_ARAM(area);
3038    if (!aram)
3039        return 0;
3040    if (!aram->size_device)
3041        aram->size_device = new AW_device_size(aram->common);
3042    aram->size_device->init();
3043    aram->size_device->reset();
3044    return (AW_device *)(aram->size_device);
3045}
3046
3047AW_device *AW_window::get_print_device(AW_area area) {
3048    AW_area_management *aram= MAP_ARAM(area);
3049    if (!aram)
3050        return 0;
3051    if (!aram->print_device)
3052        aram->print_device = new AW_device_print(aram->common);
3053    aram->print_device->init();
3054    return (AW_device *)(aram->print_device);
3055}
3056
3057AW_device *AW_window::get_click_device(AW_area area, int mousex, int mousey,
3058        AW_pos max_distance_linei, AW_pos max_distance_texti, AW_pos radi) {
3059    AW_area_management *aram= MAP_ARAM(area);
3060    if (!aram)
3061        return 0;
3062    if (!aram->click_device)
3063        aram->click_device = new AW_device_click(aram->common);
3064    aram->click_device->init(mousex, mousey, max_distance_linei,
3065                             max_distance_texti, radi, (AW_bitset)-1);
3066    return (AW_device *)(aram->click_device);
3067}
3068
3069void AW_window::wm_activate() {
3070    {
3071        Boolean iconic = False;
3072        XtVaGetValues(p_w->shell, XmNiconic, &iconic, NULL) ;
3073
3074        if (iconic == True) {
3075            XtVaSetValues(p_w->shell, XmNiconic, False, NULL) ;
3076
3077            XtMapWidget(p_w->shell) ;
3078            XRaiseWindow(XtDisplay(p_w->shell), XtWindow(p_w->shell)) ;
3079        }
3080    }
3081
3082    {
3083        Display *xdpy            = XtDisplay(p_w->shell);
3084        Window   window          = XtWindow(p_w->shell);
3085        Atom     netactivewindow = XInternAtom(xdpy, "_NET_ACTIVE_WINDOW", False);
3086
3087        if (netactivewindow) {
3088
3089            XClientMessageEvent ce;
3090            ce.type         = ClientMessage;
3091            ce.display      = xdpy;
3092            ce.window       = window;
3093            ce.message_type = netactivewindow;
3094            ce.format       = 32;
3095            ce.data.l[0]    = 2;
3096            ce.data.l[1]    = None;
3097            ce.data.l[2]    = Above;
3098            ce.data.l[3]    = 0;
3099            ce.data.l[4]    = 0;
3100
3101#if defined(DEBUG)
3102            Status ret = 
3103#endif // DEBUG
3104                XSendEvent(xdpy, XDefaultRootWindow(xdpy),
3105                           False,
3106                           SubstructureRedirectMask | SubstructureNotifyMask,
3107                           (XEvent *) &ce);
3108
3109#if defined(DEBUG)
3110            if (!ret) { fprintf(stderr, "Failed to send _NET_ACTIVE_WINDOW to WM (XSendEvent returns %i)\n", ret); }
3111#endif // DEBUG
3112            XSync(xdpy, False);
3113        }
3114#if defined(DEBUG)
3115        else {
3116            fputs("No such atom '_NET_ACTIVE_WINDOW'\n", stderr);
3117        }
3118#endif // DEBUG
3119    }
3120}
3121
3122void AW_window::show(void) {
3123    if (!window_is_shown) {
3124        all_menus_created();
3125        get_root()->window_show();
3126        window_is_shown = true;
3127    }
3128
3129    if (recalc_size_at_show) {
3130        if (recalc_size_at_show == 1) {
3131            window_fit();
3132        } else {
3133            aw_assert(recalc_size_at_show == 2);
3134            // check whether user size is too small and increase to minimum (aka default)
3135            int default_width, default_height;
3136            get_window_size(default_width, default_height);
3137            AW_root *tmp_root = get_root();
3138            int user_width = tmp_root->awar(aw_awar_name_width(this))->read_int();
3139            int user_height = tmp_root->awar(aw_awar_name_height(this))->read_int();
3140
3141#if defined(DEBUG)
3142            // printf("default size = %i/%i  user size = %i/%i\n", default_width, default_height, user_width, user_height);
3143#endif // DEBUG
3144            if (user_width<default_width)
3145                user_width = default_width;
3146            if (user_height<default_height)
3147                user_height = default_height;
3148
3149#if defined(DEBUG)
3150            // printf("using size = %i/%i\n", user_width, user_height);
3151#endif // DEBUG
3152            set_window_size(user_width, user_height);
3153        }
3154        recalc_size_at_show = 0;
3155    }
3156
3157    XtPopup(p_w->shell, XtGrabNone);
3158    if (p_w->WM_top_offset == -1000) {              // very bad hack
3159        set_expose_callback(AW_INFO_AREA, (AW_CB)aw_calculate_WM_offsets, 0, 0);
3160    }
3161}
3162
3163void AW_window::show_grabbed(void) {
3164    if (!window_is_shown) {
3165        get_root()->window_show();
3166        window_is_shown = true;
3167    }
3168    XtPopup(p_w->shell, XtGrabExclusive);
3169    if (p_w->WM_top_offset == -1000) { // very bad hack
3170        set_expose_callback(AW_INFO_AREA, (AW_CB)aw_calculate_WM_offsets, 0, 0);
3171    }
3172}
3173
3174void AW_window::hide(void) {
3175    if (window_is_shown) {
3176        get_root()->window_hide();
3177        window_is_shown = false;
3178    }
3179    XtPopdown(p_w->shell);
3180}
3181
3182bool AW_window::is_shown(void) {
3183    // return true if window is shown ( = not invisible and already created)
3184    // Note: does return TRUE!, if window is only minimized by WM
3185    return window_is_shown;
3186}
3187
3188void AW_root::window_show() {
3189    active_windows++;
3190}
3191
3192void AW_root::window_hide() {
3193    active_windows--;
3194    if (active_windows<0) {
3195        exit(0);
3196    }
3197}
3198
3199void AW_root::main_loop(void) {
3200    XtAppMainLoop(p_r->context);
3201}
3202
3203void AW_root::process_events(void) {
3204    XtAppProcessEvent(p_r->context,XtIMAll);
3205}
3206void AW_root::process_pending_events(void) {
3207    XtInputMask pending = XtAppPending(p_r->context);
3208    while (pending) {
3209        XtAppProcessEvent(p_r->context, pending);
3210        pending = XtAppPending(p_r->context);
3211    }
3212}
3213
3214/** Returns type if key event follows, else 0 */
3215
3216AW_ProcessEventType AW_root::peek_key_event(AW_window */*aww*/) {
3217    XEvent xevent;
3218    Boolean result = XtAppPeekEvent(p_r->context,&xevent);
3219
3220#if defined(DEBUG) && 0
3221    printf("peek_key_event\n");
3222#endif // DEBUG
3223    if (!result)
3224        return NO_EVENT;
3225    if ( (xevent.type != KeyPress) && (xevent.type != KeyRelease))
3226        return NO_EVENT;
3227    //XKeyEvent *kev = &xevent.xkey;
3228    return (AW_ProcessEventType)xevent.type;
3229}
3230
3231static void timed_window_title_cb(class AW_root* aw_root, AW_CL cd1, AW_CL cd2) {
3232    AWUSE(aw_root);
3233    char *title = (char *)cd1;
3234    AW_window *aw = (AW_window *)cd2;
3235
3236    aw->number_of_timed_title_changes--;
3237    if ( !aw->number_of_timed_title_changes) {
3238        aw->set_window_title_intern(title);
3239    }
3240
3241    delete title;
3242}
3243void AW_window::message(char *title, int ms) {
3244    char *old_title= NULL;
3245
3246    number_of_timed_title_changes++;
3247
3248    old_title = strdup(window_name);
3249
3250    XtVaSetValues(p_w->shell, XmNtitle, title, NULL);
3251
3252    get_root()->add_timed_callback(ms, timed_window_title_cb, (AW_CL)old_title,
3253            (AW_CL)this );
3254
3255}
3256
3257void AW_window::set_window_title_intern(char *title) {
3258    XtVaSetValues(p_w->shell, XmNtitle, title, NULL);
3259}
3260
3261void AW_window::set_window_title(const char *title) {
3262    XtVaSetValues(p_w->shell, XmNtitle, title, NULL);
3263    freedup(window_name, title);
3264}
3265
3266const char *AW_window::get_window_title(void) {
3267    char *title;
3268
3269    XtVaGetValues(p_w->shell, XmNtitle, &title, NULL);
3270
3271    return title;
3272}
3273
3274const char *AW_window::local_id(const char *id) const {
3275    static char *last_local_id = 0;
3276    freeset(last_local_id, GBS_global_string_copy("%s/%s", get_window_id(), id));
3277    return last_local_id;
3278}
3279
3280/***************************************************************************************************************************/
3281/***************************************************************************************************************************/
3282/***************************************************************************************************************************/
3283static void AW_xfigCB_info_area(AW_window *aww, AW_xfig *xfig) {
3284
3285    AW_device *device = aww->get_device(AW_INFO_AREA);
3286    device->reset();
3287    if (aww->get_root()->color_mode == 0) { // mono colr
3288        device->clear(-1);
3289    }
3290    device->set_offset(AW::Vector(-xfig->minx, -xfig->miny));
3291    xfig->print(device);
3292}
3293
3294void AW_window::load_xfig(const char *file, bool resize) {
3295    AW_xfig *xfig;
3296
3297    if (file)
3298        xfig = new AW_xfig(file, get_root()->font_width, get_root()->font_height);
3299    else
3300        xfig = new AW_xfig( get_root()->font_width, get_root()->font_height); // create an empty xfig
3301
3302    xfig_data = (void*)xfig;
3303
3304    set_expose_callback(AW_INFO_AREA, (AW_CB)AW_xfigCB_info_area,
3305            (AW_CL)xfig_data, 0);
3306    xfig->create_gcs(get_device(AW_INFO_AREA), get_root()->color_mode ? 8 : 1);
3307
3308    int xsize = xfig->maxx - xfig->minx;
3309    int ysize = xfig->maxy - xfig->miny;
3310
3311    if (xsize>_at->max_x_size)
3312        _at->max_x_size = xsize;
3313    if (ysize>_at->max_y_size)
3314        _at->max_y_size = ysize;
3315
3316    if (resize) {
3317        if (recalc_size_at_show == 0)
3318            recalc_size_at_show = 1;
3319        set_window_size(_at->max_x_size+1000, _at->max_y_size+1000);
3320        align();
3321    }
3322}
3323
3324void AW_window::draw_line(int x1, int y1, int x2, int y2, int width, bool resize) {
3325    AW_xfig *xfig = (AW_xfig*)xfig_data;
3326    aw_assert(xfig);
3327    // forgot to call load_xfig ?
3328
3329    xfig->add_line(x1, y1, x2, y2, width);
3330
3331    class x {
3332public:
3333        static inline int max(int i1, int i2) {
3334            return i1>i2 ? i1 : i2;
3335        }
3336    };
3337
3338    _at->max_x_size = x::max(_at->max_x_size, xfig->maxx - xfig->minx);
3339    _at->max_y_size = x::max(_at->max_y_size, xfig->maxy - xfig->miny);
3340
3341    if (resize) {
3342        if (recalc_size_at_show == 0)
3343            recalc_size_at_show = 1;
3344        set_window_size(_at->max_x_size+1000, _at->max_y_size+1000);
3345    }
3346}
3347
3348void AW_window::_set_activate_callback(void *widget) {
3349    if (_callback && (long)_callback != 1) {
3350        if (!_callback->help_text && _at->helptext_for_next_button) {
3351            _callback->help_text = _at->helptext_for_next_button;
3352            _at->helptext_for_next_button = 0;
3353        }
3354
3355        XtAddCallback((Widget) widget, XmNactivateCallback,
3356                (XtCallbackProc) AW_server_callback, (XtPointer) _callback );
3357    }
3358    _callback = NULL;
3359}
3360
3361/***********************************************************************/
3362/*****************      AW_MACRO_MESSAGE     *******************/
3363/***********************************************************************/
3364
3365#define AW_MESSAGE_AWAR "tmp/message/macro"
3366
3367static void macro_message_cb(AW_window *aw, AW_CL) {
3368    AW_root *root = aw->get_root();
3369    aw->hide();
3370
3371    if (root->prvt->recording_macro_file) {
3372        char *s = root->awar(AW_MESSAGE_AWAR)->read_string();
3373        fprintf(root->prvt->recording_macro_file, "MESSAGE\t");
3374        GBS_fwrite_string(s, root->prvt->recording_macro_file);
3375        fprintf(root->prvt->recording_macro_file, "\n");
3376        delete s;
3377    }
3378
3379    if (root->prvt->executing_macro_file) {
3380        //root->enable_execute_macro(); @@@@
3381    }
3382
3383    return;
3384}
3385
3386static void aw_clear_macro_message_cb(AW_window *aww) {
3387    aww->get_root()->awar(AW_MESSAGE_AWAR)->write_string("");
3388}
3389
3390void aw_macro_message(const char *templat, ...)
3391// @@@ this function is unused.
3392{
3393
3394    AW_root *root = AW_root::THIS;
3395    char buffer[10000];
3396    {
3397        va_list parg;
3398        va_start(parg,templat);
3399        vsprintf(buffer, templat, parg);
3400    }
3401    static AW_window_message *aw_msg = 0;
3402
3403    root->awar_string(AW_MESSAGE_AWAR)->write_string(buffer);
3404
3405    if (!aw_msg) {
3406        aw_msg = new AW_window_message;
3407
3408        aw_msg->init(root, "MESSAGE", false);
3409        aw_msg->load_xfig("macro_message.fig");
3410
3411        aw_msg->at("clear");
3412        aw_msg->callback(aw_clear_macro_message_cb);
3413        aw_msg->create_button("OK", "OK", "O");
3414
3415        aw_msg->at("Message");
3416        aw_msg->create_text_field(AW_MESSAGE_AWAR);
3417
3418        aw_msg->at("hide");
3419        aw_msg->callback(macro_message_cb, 0);
3420        aw_msg->create_button("OK", "OK", "O");
3421    }
3422
3423    aw_msg->show();
3424    if (root->prvt->executing_macro_file) {
3425        root->stop_execute_macro();
3426    }
3427}
3428
3429GB_ERROR AW_root::start_macro_recording(const char *file,
3430        const char *application_id, const char *stop_action_name) {
3431    if (prvt->recording_macro_file) {
3432        return GB_export_error("Already Recording Macro");
3433    }
3434    char *path = 0;
3435    if (file[0] == '/') {
3436        path = strdup(file);
3437    } else {
3438        path = GBS_global_string_copy("%s/%s", GB_getenvARBMACROHOME(), file);
3439    }
3440    char *macro_header = GB_read_file("$(ARBHOME)/lib/macro.head");
3441    if (!macro_header) {
3442        return GB_export_errorf("Cannot open file '%s'", "$(ARBHOME)/lib/macro.head");
3443    }
3444
3445    prvt->recording_macro_file = fopen(path, "w");
3446    prvt->recording_macro_path = path;
3447    if (!prvt->recording_macro_file) {
3448        delete macro_header;
3449        return GB_export_errorf("Cannot open file '%s' for writing", file);
3450    }
3451    prvt->stop_action_name = strdup(stop_action_name);
3452    prvt->application_name_for_macros = strdup(application_id);
3453
3454    fprintf(prvt->recording_macro_file, "%s", macro_header);
3455    free(macro_header);
3456    return 0;
3457}
3458
3459GB_ERROR AW_root::stop_macro_recording() {
3460    if (!prvt->recording_macro_file) {
3461        return GB_export_error("Not recording macro");
3462    }
3463    fprintf(prvt->recording_macro_file, "ARB::close($gb_main);");
3464    fclose(prvt->recording_macro_file);
3465
3466    long mode = GB_mode_of_file(prvt->recording_macro_path);
3467
3468    GB_set_mode_of_file(prvt->recording_macro_path, mode | ((mode >> 2)& 0111));
3469    prvt->recording_macro_file = 0;
3470
3471    freeset(prvt->recording_macro_path, 0);
3472    freeset(prvt->stop_action_name, 0);
3473    freeset(prvt->application_name_for_macros, 0);
3474
3475    return 0;
3476}
3477
3478GB_ERROR AW_root::execute_macro(const char *file) {
3479    char *path = 0;
3480    if (file[0] == '/') {
3481        path = strdup(file);
3482    } else {
3483        path = GBS_global_string_copy("%s/%s", GB_getenvARBMACROHOME(), file);
3484    }
3485    const char *com = GBS_global_string("perl %s &", path);
3486    printf("[Action '%s']\n", com);
3487    if (system(com)) {
3488        aw_message(GBS_global_string("Calling '%s' failed", com));
3489    }
3490    free(path);
3491    return 0;
3492}
3493
3494void AW_root::stop_execute_macro() {
3495
3496}
3497
3498void AW_root::define_remote_command(AW_cb_struct *cbs) {
3499    if (cbs->f == (AW_CB)AW_POPDOWN) {
3500        aw_assert(!cbs->get_cd1() && !cbs->get_cd2()); // popdown takes no parameters (please pass ", 0, 0"!)
3501    }
3502
3503    AW_cb_struct *old_cbs = (AW_cb_struct*)GBS_write_hash(prvt->action_hash, cbs->id, (long)cbs);
3504    if (old_cbs) {
3505        if (!old_cbs->is_equal(*cbs)) {                  // existing remote command replaced by different callback
3506#if defined(DEBUG)
3507            fputs(GBS_global_string("Warning: reused callback id '%s' for different callback\n", old_cbs->id), stderr);
3508#if defined(DEVEL_RALF)
3509            gb_assert(0);
3510#endif // DEVEL_RALF
3511#endif // DEBUG
3512        }
3513        // do not free old_cbs, cause it's still reachable from first widget that defined this remote command
3514    }
3515}
3516
3517#if defined(DEBUG)
3518#if defined(DEVEL_RALF)
3519#define DUMP_REMOTE_ACTIONS
3520#endif // DEVEL_RALF
3521#endif // DEBUG
3522GB_ERROR AW_root::check_for_remote_command(AW_default gb_maind, const char *rm_base) {
3523    GBDATA *gb_main = (GBDATA *)gb_maind;
3524
3525    char *awar_action = GBS_global_string_copy("%s/action", rm_base);
3526    char *awar_value  = GBS_global_string_copy("%s/value", rm_base);
3527    char *awar_awar   = GBS_global_string_copy("%s/awar", rm_base);
3528    char *awar_result = GBS_global_string_copy("%s/result", rm_base);
3529
3530    GB_push_transaction(gb_main);
3531
3532    char *action   = GBT_readOrCreate_string(gb_main, awar_action, "");
3533    char *value    = GBT_readOrCreate_string(gb_main, awar_value, "");
3534    char *tmp_awar = GBT_readOrCreate_string(gb_main, awar_awar, "");
3535   
3536    if (tmp_awar[0]) {
3537        GB_ERROR error = 0;
3538        if (strcmp(action, "AWAR_REMOTE_READ") == 0) {
3539            char *read_value = this->awar(tmp_awar)->read_as_string();
3540            GBT_write_string(gb_main, awar_value, read_value);
3541#if defined(DUMP_REMOTE_ACTIONS)
3542            printf("remote command 'AWAR_REMOTE_READ' awar='%s' value='%s'\n", tmp_awar, read_value);
3543#endif // DUMP_REMOTE_ACTIONS
3544            free(read_value);
3545            // clear action (AWAR_REMOTE_READ is just a pseudo-action) :
3546            action[0] = 0;
3547            GBT_write_string(gb_main, awar_action, "");
3548        }
3549        else if (strcmp(action, "AWAR_REMOTE_TOUCH") == 0) {
3550            this->awar(tmp_awar)->touch();
3551#if defined(DUMP_REMOTE_ACTIONS)
3552            printf("remote command 'AWAR_REMOTE_TOUCH' awar='%s'\n", tmp_awar);
3553#endif // DUMP_REMOTE_ACTIONS
3554            // clear action (AWAR_REMOTE_TOUCH is just a pseudo-action) :
3555            action[0] = 0;
3556            GBT_write_string(gb_main, awar_action, "");
3557        }
3558        else {
3559#if defined(DUMP_REMOTE_ACTIONS)
3560            printf("remote command (write awar) awar='%s' value='%s'\n", tmp_awar, value);
3561#endif // DUMP_REMOTE_ACTIONS
3562            error = this->awar(tmp_awar)->write_as_string(value);
3563        }
3564        GBT_write_string(gb_main, awar_result, error ? error : "");
3565        GBT_write_string(gb_main, awar_awar, ""); // this works as READY-signal for perl-client (BIO::remote_awar and BIO:remote_read_awar)
3566    }
3567    GB_pop_transaction(gb_main);
3568
3569    if (action[0]) {
3570        AW_cb_struct *cbs = (AW_cb_struct *)GBS_read_hash(prvt->action_hash, action);
3571
3572#if defined(DUMP_REMOTE_ACTIONS)
3573        printf("remote command (%s) exists=%i\n", action, int(cbs != 0));
3574#endif                          // DUMP_REMOTE_ACTIONS
3575        if (cbs) {
3576            cbs->run_callback();
3577            GBT_write_string(gb_main, awar_result, "");
3578        } else {
3579            aw_message(GB_export_errorf("Unknown action '%s' in macro", action));
3580            GBT_write_string(gb_main, awar_result, GB_await_error());
3581        }
3582        GBT_write_string(gb_main, awar_action, ""); // this works as READY-signal for perl-client (remote_action)
3583    }
3584   
3585    free(tmp_awar);
3586    free(value);
3587    free(action);
3588
3589    free(awar_result);
3590    free(awar_awar);
3591    free(awar_value);
3592    free(awar_action);
3593   
3594    return 0;
3595}
3596
3597void AW_window::set_background(const char *colorname, Widget parentWidget) {
3598    bool colorSet = false;
3599
3600    if (colorname) {
3601        XColor unused, color;
3602
3603        if (XAllocNamedColor(p_global->display, p_global->colormap, colorname, &color, &unused)
3604                == 0) {
3605            fprintf(stderr,"XAllocColor failed: %s\n", colorname);
3606        } else {
3607            _at->background_color = color.pixel;
3608            colorSet = true;
3609        }
3610    }
3611
3612    if (!colorSet) {
3613        XtVaGetValues(parentWidget, XmNbackground, &(_at->background_color),
3614                NULL); // fallback to background color
3615    }
3616}
3617
3618void AW_window::TuneOrSetBackground(Widget w, const char *color, int modStrength) {
3619    // Sets the background for the next created widget.
3620    //
3621    // If 'color' is specified, it may contain one of the following values:
3622    //      "+"    means: slightly increase color of parent widget 'w'
3623    //      "-"    means: slightly decrease color of parent widget 'w'
3624    //      otherwise it contains a specific color ('name' or '#RGB')
3625    //
3626    // If color is not specified, the color of the parent widget 'w' is modified
3627    // by 'modStrength' (increased if positive,  decreased if negative)
3628    //
3629    // If it's not possible to modify the color (e.g. we cannot increase 'white'),
3630    // the color will be modified in the opposite direction. For details see TuneBackground()
3631
3632    if (color) {
3633        switch (color[0]) {
3634        case '+':
3635            TuneBackground(w, TUNE_BRIGHT);
3636            break;
3637        case '-':
3638            TuneBackground(w, TUNE_DARK);
3639            break;
3640        default:
3641            set_background(color, w); // use explicit color
3642        }
3643    } else {
3644        TuneBackground(w, modStrength);
3645    }
3646}
3647
3648void AW_window::TuneBackground(Widget w, int modStrength) {
3649    // Gets the Background Color, modifies the rgb values slightly and sets new background color
3650    // Intended to give buttons a nicer 3D-look.
3651    //
3652    // possible values for modStrength:
3653    //
3654    //    0        = do not modify (i.e. set to background color of parent widget)
3655    //    1 .. 127 = increase if background is bright, decrease if background is dark
3656    //   -1 ..-127 = opposite behavior than above
3657    //  256 .. 383 = always increase
3658    // -256 ..-383 = always decrease
3659    //
3660    // if it's impossible to decrease or increase -> opposite direction is used.
3661
3662    int col[3];
3663    {
3664        Pixel bg;
3665        XtVaGetValues(w, XmNbackground, &bg, NULL);
3666
3667        XColor xc;
3668        xc.pixel = bg;
3669        XQueryColor(XtDisplay(w), p_global->colormap, &xc);
3670
3671        col[0] = xc.red >> 8; // take MSB
3672        col[1] = xc.green >> 8;
3673        col[2] = xc.blue >> 8;
3674    }
3675
3676    int mod = modStrength;
3677    int preferredDir = 0;
3678    bool invertedMod = false;
3679
3680    if (modStrength>0) {
3681        if (modStrength>255) {
3682            mod -= 256;
3683            preferredDir = 1; // increase preferred
3684        }
3685    } else {
3686        if (modStrength<-255) {
3687            mod = -modStrength-256;
3688            preferredDir = -1; // decrease preferred
3689        } else {
3690            invertedMod = true;
3691            mod = -mod;
3692        }
3693    }
3694
3695    aw_assert(mod >= 0 && mod < 128);
3696    // illegal modification
3697
3698    bool incPossible[3]; // increment possible for color
3699    bool decPossible[3]; // decrement possible for color
3700    int incs = 0; // count possible increments
3701    int decs = 0; // count possible decrements
3702
3703    for (int i = 0; i<3; ++i) {
3704        if ((incPossible[i] = ((col[i]+mod) <= 255)))
3705            incs++;
3706        if ((decPossible[i] = ((col[i]-mod) >= 0)))
3707            decs++;
3708    }
3709
3710    aw_assert(incs||decs);
3711
3712    switch (preferredDir) {
3713    case 0: // no direction preferred yet, need to decide
3714        if (invertedMod)
3715            preferredDir = decs ? -1 : 1;
3716        else
3717            preferredDir = incs ? 1 : -1;
3718        break;
3719    case 1:
3720        if (!incs)
3721            preferredDir = -1;
3722        break;
3723    case -1:
3724        if (!decs)
3725            preferredDir = 1;
3726        break;
3727    }
3728
3729    aw_assert(preferredDir == 1 || preferredDir == -1); // no direction chosen above
3730   
3731    if (preferredDir == 1) {
3732        for (int i=0; i<3; ++i) col[i] += (incPossible[i] ? mod : 0);
3733    }
3734    else if (preferredDir == -1) {
3735        for (int i=0; i<3; ++i) col[i] -= (decPossible[i] ? mod : 0);
3736    }
3737   
3738
3739    char hex_color[50];
3740    sprintf(hex_color, "#%2.2X%2.2X%2.2X", col[0], col[1], col[2]);
3741    aw_assert(strlen(hex_color) == 7);
3742    // otherwise some value overflowed
3743    set_background(hex_color, w);
3744}
3745
Note: See TracBrowser for help on using the repository browser.