comparison lwlib/lwlib-Xm.c @ 171:929b76928fce r20-3b12

Import from CVS: tag r20-3b12
author cvs
date Mon, 13 Aug 2007 09:47:52 +0200
parents 15872534500d
children 41ff10fd062f
comparison
equal deleted inserted replaced
170:98a42ee61975 171:929b76928fce
795 if (class == xmPushButtonWidgetClass || 795 if (class == xmPushButtonWidgetClass ||
796 class == xmArrowButtonWidgetClass) 796 class == xmArrowButtonWidgetClass)
797 { 797 {
798 xm_update_pushbutton (instance, widget, val); 798 xm_update_pushbutton (instance, widget, val);
799 } 799 }
800 #ifdef MENUBARS_MOTIF
801 else if (class == xmCascadeButtonWidgetClass)
802 {
803 xm_update_cascadebutton (instance, widget, val);
804 }
805 #endif
806 else if (class == xmToggleButtonWidgetClass
807 || class == xmToggleButtonGadgetClass)
808 {
809 xm_update_toggle (instance, widget, val);
810 }
811 else if (class == xmRowColumnWidgetClass)
812 {
813 Boolean radiobox = 0;
814
815 XtSetArg (al [0], XmNradioBehavior, &radiobox);
816 XtGetValues (widget, al, 1);
817
818 if (radiobox)
819 xm_update_radiobox (instance, widget, val);
820 #ifdef MENUBARS_MOTIF
821 else
822 xm_update_menu (instance, widget, val, deep_p);
823 #endif
824 }
825 #ifdef DIALOGS_MOTIF
826 else if (class == xmTextWidgetClass)
827 {
828 xm_update_text (instance, widget, val);
829 }
830 else if (class == xmTextFieldWidgetClass)
831 {
832 xm_update_text_field (instance, widget, val);
833 }
834 #endif
835 else if (class == xmListWidgetClass)
836 {
837 xm_update_list (instance, widget, val);
838 }
839 #ifdef SCROLLBARS_MOTIF
840 else if (class == xmScrollBarWidgetClass)
841 {
842 xm_update_scrollbar (instance, widget, val);
843 }
844 #endif
845 }
846
847 /* getting the value back */
848 void
849 xm_update_one_value (widget_instance* instance, Widget widget,
850 widget_value* val)
851 {
852 WidgetClass class = XtClass (widget);
853 widget_value *old_wv;
854
855 /* copy the call_data slot into the "return" widget_value */
856 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
857 if (!strcmp (val->name, old_wv->name))
858 {
859 val->call_data = old_wv->call_data;
860 break;
861 }
862
863 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
864 {
865 Arg al [1];
866 XtSetArg (al [0], XmNset, &val->selected);
867 XtGetValues (widget, al, 1);
868 val->edited = True;
869 }
870 #ifdef DIALOGS_MOTIF
871 else if (class == xmTextWidgetClass)
872 {
873 if (val->value)
874 free (val->value);
875 val->value = XmTextGetString (widget);
876 val->edited = True;
877 }
878 else if (class == xmTextFieldWidgetClass)
879 {
880 if (val->value)
881 free (val->value);
882 val->value = XmTextFieldGetString (widget);
883 val->edited = True;
884 }
885 #endif
886 else if (class == xmRowColumnWidgetClass)
887 {
888 Boolean radiobox = 0;
889 {
890 Arg al [1];
891 XtSetArg (al [0], XmNradioBehavior, &radiobox);
892 XtGetValues (widget, al, 1);
893 }
894
895 if (radiobox)
896 {
897 CompositeWidget radio = (CompositeWidget)widget;
898 int i;
899 for (i = 0; i < radio->composite.num_children; i++)
900 {
901 int set = False;
902 Widget toggle = radio->composite.children [i];
903 Arg al [1];
904
905 XtSetArg (al [0], XmNset, &set);
906 XtGetValues (toggle, al, 1);
907 if (set)
908 {
909 if (val->value)
910 free (val->value);
911 val->value = safe_strdup (XtName (toggle));
912 }
913 }
914 val->edited = True;
915 }
916 }
917 else if (class == xmListWidgetClass)
918 {
919 int pos_cnt;
920 int* pos_list;
921 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
922 {
923 int i;
924 widget_value* cur;
925 for (cur = val->contents, i = 0; cur; cur = cur->next)
926 if (cur->value)
927 {
928 int j;
929 cur->selected = False;
930 i += 1;
931 for (j = 0; j < pos_cnt; j++)
932 if (pos_list [j] == i)
933 {
934 cur->selected = True;
935 val->value = safe_strdup (cur->name);
936 }
937 }
938 val->edited = 1;
939 XtFree ((char *) pos_list);
940 }
941 }
942 #ifdef SCROLLBARS_MOTIF
943 else if (class == xmScrollBarWidgetClass)
944 {
945 /* This function is not used by the scrollbar. */
946 return;
947 }
948 #endif
949 }
950
951
952 /* This function is for activating a button from a program. It's wrong because
953 we pass a NULL argument in the call_data which is not Motif compatible.
954 This is used from the XmNdefaultAction callback of the List widgets to
955 have a dble-click put down a dialog box like the button woudl do.
956 I could not find a way to do that with accelerators.
957 */
958 static void
959 activate_button (Widget widget, XtPointer closure, XtPointer call_data)
960 {
961 Widget button = (Widget)closure;
962 XtCallCallbacks (button, XmNactivateCallback, NULL);
963 }
964
965 /* creation functions */
966
967 #ifdef DIALOGS_MOTIF
968
969 /* dialogs */
970
971 #if (XmVersion >= 1002)
972 # define ARMANDACTIVATE_KLUDGE
973 # define DND_KLUDGE
974 #endif
975
976 #ifdef ARMANDACTIVATE_KLUDGE
977 /* We want typing Return at a dialog box to select the default button; but
978 we're satisfied with having it select the leftmost button instead.
979
980 In Motif 1.1.5 we could do this by putting this resource in the
981 app-defaults file:
982
983 *dialog*button1.accelerators:#override\
984 <KeyPress>Return: ArmAndActivate()\n\
985 <KeyPress>KP_Enter: ArmAndActivate()\n\
986 Ctrl<KeyPress>m: ArmAndActivate()\n
987
988 but that doesn't work with 1.2.1 and I don't understand why. However,
989 doing the equivalent C code does work, with the notable disadvantage that
990 the user can't override it. So that's what we do until we figure out
991 something better....
992 */
993 static char button_trans[] = "\
994 <KeyPress>Return: ArmAndActivate()\n\
995 <KeyPress>KP_Enter: ArmAndActivate()\n\
996 Ctrl<KeyPress>m: ArmAndActivate()\n";
997
998 #endif /* ARMANDACTIVATE_KLUDGE */
999
1000
1001 #ifdef DND_KLUDGE
1002 /* This is a kludge to disable drag-and-drop in dialog boxes. The symptom
1003 was a segv down in libXm somewhere if you used the middle button on a
1004 dialog box to begin a drag; when you released the button to make a drop
1005 things would lose if you were not over the button where you started the
1006 drag (canceling the operation). This was probably due to the fact that
1007 the dialog boxes were not set up to handle a drag but were trying to do
1008 so anyway for some reason.
1009
1010 So we disable drag-and-drop in dialog boxes by turning off the binding for
1011 Btn2Down which, by default, initiates a drag. Clearly this is a shitty
1012 solution as it only works in default configurations, but...
1013 */
1014 static char disable_dnd_trans[] = "<Btn2Down>: ";
1015 #endif /* DND_KLUDGE */
1016
1017
1018 static Widget
1019 make_dialog (char* name, Widget parent, Boolean pop_up_p,
1020 CONST char* shell_title, CONST char* icon_name,
1021 Boolean text_input_slot, Boolean radio_box, Boolean list,
1022 int left_buttons, int right_buttons)
1023 {
1024 Widget result;
1025 Widget form;
1026 Widget row;
1027 Widget icon;
1028 Widget icon_separator;
1029 Widget message;
1030 Widget value = 0;
1031 Widget separator;
1032 Widget button = 0;
1033 Widget children [16]; /* for the final XtManageChildren */
1034 int n_children;
1035 Arg al[64]; /* Arg List */
1036 int ac; /* Arg Count */
1037 int i;
1038
1039 #ifdef DND_KLUDGE
1040 XtTranslations dnd_override = XtParseTranslationTable (disable_dnd_trans);
1041 # define DO_DND_KLUDGE(widget) XtOverrideTranslations ((widget), dnd_override)
1042 #else /* ! DND_KLUDGE */
1043 # define DO_DND_KLUDGE(widget)
1044 #endif /* ! DND_KLUDGE */
1045
1046 if (pop_up_p)
1047 {
1048 ac = 0;
1049 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
1050 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
1051 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
1052 result = XmCreateDialogShell (parent, "dialog", al, ac);
1053
1054 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1055 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
1056 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1057 form = XmCreateForm (result, (char *) shell_title, al, ac);
1058 }
1059 else
1060 {
1061 ac = 0;
1062 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
1063 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1064 form = XmCreateForm (parent, (char *) shell_title, al, ac);
1065 result = form;
1066 }
1067
1068 ac = 0;
1069 XtSetArg(al[ac], XmNpacking, XmPACK_COLUMN); ac++;
1070 XtSetArg(al[ac], XmNorientation, XmVERTICAL); ac++;
1071 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
1072 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1073 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1074 XtSetArg(al[ac], XmNspacing, 13); ac++;
1075 XtSetArg(al[ac], XmNadjustLast, False); ac++;
1076 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1077 XtSetArg(al[ac], XmNisAligned, True); ac++;
1078 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1079 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
1080 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1081 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1082 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1083 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1084 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1085 row = XmCreateRowColumn (form, "row", al, ac);
1086
1087 n_children = 0;
1088 for (i = 0; i < left_buttons; i++)
1089 {
1090 char button_name [16];
1091 sprintf (button_name, "button%d", i + 1);
1092 ac = 0;
1093 if (i == 0)
1094 {
1095 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
1096 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
1097 }
1098 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1099 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1100 DO_DND_KLUDGE (children [n_children]);
1101
1102 if (i == 0)
1103 {
1104 button = children [n_children];
1105 ac = 0;
1106 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
1107 XtSetValues (row, al, ac);
1108
1109 #ifdef ARMANDACTIVATE_KLUDGE /* See comment above */
1110 {
1111 XtTranslations losers = XtParseTranslationTable (button_trans);
1112 XtOverrideTranslations (button, losers);
1113 XtFree ((char *) losers);
1114 }
1115 #endif /* ARMANDACTIVATE_KLUDGE */
1116 }
1117
1118 n_children++;
1119 }
1120
1121 /* invisible seperator button */
1122 ac = 0;
1123 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
1124 children [n_children] = XmCreateLabel (row, "separator_button",
1125 al, ac);
1126 DO_DND_KLUDGE (children [n_children]);
1127 n_children++;
1128
1129 for (i = 0; i < right_buttons; i++)
1130 {
1131 char button_name [16];
1132 sprintf (button_name, "button%d", left_buttons + i + 1);
1133 ac = 0;
1134 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
1135 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
1136 DO_DND_KLUDGE (children [n_children]);
1137 if (! button) button = children [n_children];
1138 n_children++;
1139 }
1140
1141 XtManageChildren (children, n_children);
1142
1143 ac = 0;
1144 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1145 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1146 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1147 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
1148 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1149 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
1150 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1151 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
1152 separator = XmCreateSeparator (form, "", al, ac);
1153
1154 ac = 0;
1155 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
1156 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1157 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1158 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
1159 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
1160 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1161 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1162 icon = XmCreateLabel (form, (char *) icon_name, al, ac);
1163 DO_DND_KLUDGE (icon);
1164
1165 ac = 0;
1166 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
1167 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
1168 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
1169 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
1170 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1171 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
1172 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1173 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
1174 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
1175 icon_separator = XmCreateLabel (form, "", al, ac);
1176 DO_DND_KLUDGE (icon_separator);
1177
1178 if (text_input_slot)
1179 {
1180 ac = 0;
1181 XtSetArg(al[ac], XmNcolumns, 50); ac++;
1182 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1183 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1184 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1185 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1186 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1187 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1188 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1189 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1190 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1191 value = XmCreateTextField (form, "value", al, ac);
1192 DO_DND_KLUDGE (value);
1193 }
1194 else if (radio_box)
1195 {
1196 Widget radio_butt;
1197 ac = 0;
1198 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
1199 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1200 XtSetArg(al[ac], XmNspacing, 13); ac++;
1201 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
1202 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
1203 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1204 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1205 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1206 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1207 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1208 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1209 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1210 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1211 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
1212 ac = 0;
1213 i = 0;
1214 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
1215 children [i++] = radio_butt;
1216 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
1217 children [i++] = radio_butt;
1218 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
1219 children [i++] = radio_butt;
1220 XtManageChildren (children, i);
1221 }
1222 else if (list)
1223 {
1224 ac = 0;
1225 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
1226 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
1227 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1228 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1229 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
1230 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1231 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1232 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1233 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1234 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1235 value = XmCreateScrolledList (form, "list", al, ac);
1236
1237 /* this is the easiest way I found to have the dble click in the
1238 list activate the default button */
1239 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
1240 }
1241
1242 ac = 0;
1243 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
1244 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
1245 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
1246 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
1247 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
1248 XtSetArg(al[ac], XmNbottomWidget,
1249 text_input_slot || radio_box || list ? value : separator); ac++;
1250 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
1251 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
1252 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
1253 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
1254 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
1255 message = XmCreateLabel (form, "message", al, ac);
1256 DO_DND_KLUDGE (message);
1257
1258 if (list)
1259 XtManageChild (value);
1260
1261 i = 0;
1262 children [i] = row; i++;
1263 children [i] = separator; i++;
1264 if (text_input_slot || radio_box)
1265 {
1266 children [i] = value; i++;
1267 }
1268 children [i] = message; i++;
1269 children [i] = icon; i++;
1270 children [i] = icon_separator; i++;
1271 XtManageChildren (children, i);
1272
1273 if (text_input_slot || list)
1274 {
1275 XtInstallAccelerators (value, button);
1276 XmProcessTraversal(value, XmTRAVERSE_CURRENT);
1277 }
1278 else
1279 {
1280 XtInstallAccelerators (form, button);
1281 XmProcessTraversal(value, XmTRAVERSE_CURRENT);
1282 }
1283
1284 #ifdef DND_KLUDGE
1285 XtFree ((char *) dnd_override);
1286 #endif
1287 #undef DO_DND_KLUDGE
1288
1289 return result;
1290 }
1291
1292 static destroyed_instance*
1293 find_matching_instance (widget_instance* instance)
1294 {
1295 destroyed_instance* cur;
1296 destroyed_instance* prev;
1297 char* type = instance->info->type;
1298 char* name = instance->info->name;
1299
1300 for (prev = NULL, cur = all_destroyed_instances;
1301 cur;
1302 prev = cur, cur = cur->next)
1303 {
1304 if (!strcmp (cur->name, name)
1305 && !strcmp (cur->type, type)
1306 && cur->parent == instance->parent
1307 && cur->pop_up_p == instance->pop_up_p)
1308 {
1309 if (prev)
1310 prev->next = cur->next;
1311 else
1312 all_destroyed_instances = cur->next;
1313 return cur;
1314 }
1315 /* do some cleanup */
1316 else if (!cur->widget)
1317 {
1318 if (prev)
1319 prev->next = cur->next;
1320 else
1321 all_destroyed_instances = cur->next;
1322 free_destroyed_instance (cur);
1323 cur = prev ? prev : all_destroyed_instances;
1324 }
1325 }
1326 return NULL;
1327 }
1328
1329 static void
1330 mark_dead_instance_destroyed (Widget widget, XtPointer closure,
1331 XtPointer call_data)
1332 {
1333 destroyed_instance* instance = (destroyed_instance*)closure;
1334 instance->widget = NULL;
1335 }
1336
1337 static void
1338 recenter_widget (Widget widget)
1339 {
1340 Widget parent = XtParent (widget);
1341 Screen* screen = XtScreen (widget);
1342 Dimension screen_width = WidthOfScreen (screen);
1343 Dimension screen_height = HeightOfScreen (screen);
1344 Dimension parent_width = 0;
1345 Dimension parent_height = 0;
1346 Dimension child_width = 0;
1347 Dimension child_height = 0;
1348 Position x;
1349 Position y;
1350 Arg al [2];
1351
1352 XtSetArg (al [0], XtNwidth, &child_width);
1353 XtSetArg (al [1], XtNheight, &child_height);
1354 XtGetValues (widget, al, 2);
1355
1356 XtSetArg (al [0], XtNwidth, &parent_width);
1357 XtSetArg (al [1], XtNheight, &parent_height);
1358 XtGetValues (parent, al, 2);
1359
1360 x = (Position) ((parent_width - child_width) / 2);
1361 y = (Position) ((parent_height - child_height) / 2);
1362
1363 XtTranslateCoords (parent, x, y, &x, &y);
1364
1365 if ((Dimension) (x + child_width) > screen_width)
1366 x = screen_width - child_width;
1367 if (x < 0)
1368 x = 0;
1369
1370 if ((Dimension) (y + child_height) > screen_height)
1371 y = screen_height - child_height;
1372 if (y < 0)
1373 y = 0;
1374
1375 XtSetArg (al [0], XtNx, x);
1376 XtSetArg (al [1], XtNy, y);
1377 XtSetValues (widget, al, 2);
1378 }
1379
1380 static Widget
1381 recycle_instance (destroyed_instance* instance)
1382 {
1383 Widget widget = instance->widget;
1384
1385 /* widget is NULL if the parent was destroyed. */
1386 if (widget)
1387 {
1388 Widget focus;
1389 Widget separator;
1390
1391 /* Remove the destroy callback as the instance is not in the list
1392 anymore */
1393 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1394 mark_dead_instance_destroyed,
1395 (XtPointer)instance);
1396
1397 /* Give the focus to the initial item */
1398 focus = XtNameToWidget (widget, "*value");
1399 if (!focus)
1400 focus = XtNameToWidget (widget, "*button1");
1401 if (focus)
1402 XmProcessTraversal(focus, XmTRAVERSE_CURRENT);
1403
1404 /* shrink the separator label back to their original size */
1405 separator = XtNameToWidget (widget, "*separator_button");
1406 if (separator)
1407 {
1408 Arg al [2];
1409 XtSetArg (al [0], XtNwidth, 5);
1410 XtSetArg (al [1], XtNheight, 5);
1411 XtSetValues (separator, al, 2);
1412 }
1413
1414 /* Center the dialog in its parent */
1415 recenter_widget (widget);
1416 }
1417 free_destroyed_instance (instance);
1418 return widget;
1419 }
1420
1421 Widget
1422 xm_create_dialog (widget_instance* instance)
1423 {
1424 char* name = instance->info->type;
1425 Widget parent = instance->parent;
1426 Widget widget;
1427 Boolean pop_up_p = instance->pop_up_p;
1428 CONST char* shell_name = 0;
1429 CONST char* icon_name = 0;
1430 Boolean text_input_slot = False;
1431 Boolean radio_box = False;
1432 Boolean list = False;
1433 int total_buttons;
1434 int left_buttons = 0;
1435 int right_buttons = 1;
1436 destroyed_instance* dead_one;
1437
1438 /* try to find a widget to recycle */
1439 dead_one = find_matching_instance (instance);
1440 if (dead_one)
1441 {
1442 Widget recycled_widget = recycle_instance (dead_one);
1443 if (recycled_widget)
1444 return recycled_widget;
1445 }
1446
1447 switch (name [0]){
1448 case 'E': case 'e':
1449 icon_name = "dbox-error";
1450 shell_name = "Error";
1451 break;
1452
1453 case 'I': case 'i':
1454 icon_name = "dbox-info";
1455 shell_name = "Information";
1456 break;
1457
1458 case 'L': case 'l':
1459 list = True;
1460 icon_name = "dbox-question";
1461 shell_name = "Prompt";
1462 break;
1463
1464 case 'P': case 'p':
1465 text_input_slot = True;
1466 icon_name = "dbox-question";
1467 shell_name = "Prompt";
1468 break;
1469
1470 case 'Q': case 'q':
1471 icon_name = "dbox-question";
1472 shell_name = "Question";
1473 break;
1474 }
1475
1476 total_buttons = name [1] - '0';
1477
1478 if (name [3] == 'T' || name [3] == 't')
1479 {
1480 text_input_slot = False;
1481 radio_box = True;
1482 }
1483 else if (name [3])
1484 right_buttons = name [4] - '0';
1485
1486 left_buttons = total_buttons - right_buttons;
1487
1488 widget = make_dialog (name, parent, pop_up_p,
1489 shell_name, icon_name, text_input_slot, radio_box,
1490 list, left_buttons, right_buttons);
1491
1492 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1493 (XtPointer) instance);
1494 return widget;
1495 }
1496
1497 #endif /* DIALOGS_MOTIF */
1498
1499 #ifdef MENUBARS_MOTIF
1500 static Widget
1501 make_menubar (widget_instance* instance)
1502 {
1503 Arg al[10];
1504 int ac = 0;
1505
1506 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
1507 XtSetArg(al[ac], XmNshadowThickness, 3); ac++;
1508
1509 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac);
1510 }
1511
1512 static void
1513 remove_grabs (Widget shell, XtPointer closure, XtPointer call_data)
1514 {
1515 Widget menu = (Widget) closure;
1516 XmRemoveFromPostFromList (menu, XtParent (XtParent ((Widget) menu)));
1517 }
1518
1519 static Widget
1520 make_popup_menu (widget_instance* instance)
1521 {
1522 Widget parent = instance->parent;
1523 Window parent_window = parent->core.window;
1524 Widget result;
1525
1526 /* sets the parent window to 0 to fool Motif into not generating a grab */
1527 parent->core.window = 0;
1528 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1529 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1530 (XtPointer)result);
1531 parent->core.window = parent_window;
1532 return result;
1533 }
1534 #endif /* MENUBARS_MOTIF */
1535
1536 #ifdef SCROLLBARS_MOTIF
1537 static Widget
1538 make_scrollbar (widget_instance *instance, int vertical)
1539 {
1540 Arg al[20];
1541 int ac = 0;
1542 static XtCallbackRec callbacks[2] =
1543 { {xm_scrollbar_callback, NULL}, {NULL, NULL} };
1544
1545 callbacks[0].closure = (XtPointer) instance;
1546
1547 XtSetArg (al[ac], XmNminimum, 1); ac++;
1548 XtSetArg (al[ac], XmNmaximum, INT_MAX); ac++;
1549 XtSetArg (al[ac], XmNincrement, 1); ac++;
1550 XtSetArg (al[ac], XmNpageIncrement, 1); ac++;
1551 XtSetArg (al[ac], XmNborderWidth, 0); ac++;
1552 XtSetArg (al[ac], XmNorientation, vertical ? XmVERTICAL : XmHORIZONTAL); ac++;
1553
1554 XtSetArg (al[ac], XmNdecrementCallback, callbacks); ac++;
1555 XtSetArg (al[ac], XmNdragCallback, callbacks); ac++;
1556 XtSetArg (al[ac], XmNincrementCallback, callbacks); ac++;
1557 XtSetArg (al[ac], XmNpageDecrementCallback, callbacks); ac++;
1558 XtSetArg (al[ac], XmNpageIncrementCallback, callbacks); ac++;
1559 XtSetArg (al[ac], XmNtoBottomCallback, callbacks); ac++;
1560 XtSetArg (al[ac], XmNtoTopCallback, callbacks); ac++;
1561 XtSetArg (al[ac], XmNvalueChangedCallback, callbacks); ac++;
1562
1563 return XmCreateScrollBar (instance->parent, instance->info->name, al, ac);
1564 }
1565
1566 static Widget
1567 make_vertical_scrollbar (widget_instance *instance)
1568 {
1569 return make_scrollbar (instance, 1);
1570 }
1571
1572 static Widget
1573 make_horizontal_scrollbar (widget_instance *instance)
1574 {
1575 return make_scrollbar (instance, 0);
1576 }
1577
1578 #endif /* SCROLLBARS_MOTIF */
1579
1580 /* Table of functions to create widgets */
1581
1582 #ifdef ENERGIZE
1583
1584 /* interface with the XDesigner generated functions */
1585 typedef Widget (*widget_maker) (Widget);
1586 extern Widget create_project_p_sheet (Widget parent);
1587 extern Widget create_debugger_p_sheet (Widget parent);
1588 extern Widget create_breaklist_p_sheet (Widget parent);
1589 extern Widget create_le_browser_p_sheet (Widget parent);
1590 extern Widget create_class_browser_p_sheet (Widget parent);
1591 extern Widget create_call_browser_p_sheet (Widget parent);
1592 extern Widget create_build_dialog (Widget parent);
1593 extern Widget create_editmode_dialog (Widget parent);
1594 extern Widget create_search_dialog (Widget parent);
1595 extern Widget create_project_display_dialog (Widget parent);
1596
1597 static Widget
1598 make_one (widget_instance* instance, widget_maker fn)
1599 {
1600 Widget result;
1601 Arg al [64];
1602 int ac = 0;
1603
1604 if (instance->pop_up_p)
1605 {
1606 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1607 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1608 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1609 (XtPointer) instance);
1610 (*fn) (result);
1611 }
1612 else
1613 {
1614 result = (*fn) (instance->parent);
1615 XtRealizeWidget (result);
1616 }
1617 return result;
1618 }
1619
1620 static Widget
1621 make_project_p_sheet (widget_instance* instance)
1622 {
1623 return make_one (instance, create_project_p_sheet);
1624 }
1625
1626 static Widget
1627 make_debugger_p_sheet (widget_instance* instance)
1628 {
1629 return make_one (instance, create_debugger_p_sheet);
1630 }
1631
1632 static Widget
1633 make_breaklist_p_sheet (widget_instance* instance)
1634 {
1635 return make_one (instance, create_breaklist_p_sheet);
1636 }
1637
1638 static Widget
1639 make_le_browser_p_sheet (widget_instance* instance)
1640 {
1641 return make_one (instance, create_le_browser_p_sheet);
1642 }
1643
1644 static Widget
1645 make_class_browser_p_sheet (widget_instance* instance)
1646 {
1647 return make_one (instance, create_class_browser_p_sheet);
1648 }
1649
1650 static Widget
1651 make_call_browser_p_sheet (widget_instance* instance)
1652 {
1653 return make_one (instance, create_call_browser_p_sheet);
1654 }
1655
1656 static Widget
1657 make_build_dialog (widget_instance* instance)
1658 {
1659 return make_one (instance, create_build_dialog);
1660 }
1661
1662 static Widget
1663 make_editmode_dialog (widget_instance* instance)
1664 {
1665 return make_one (instance, create_editmode_dialog);
1666 }
1667
1668 static Widget
1669 make_search_dialog (widget_instance* instance)
1670 {
1671 return make_one (instance, create_search_dialog);
1672 }
1673
1674 static Widget
1675 make_project_display_dialog (widget_instance* instance)
1676 {
1677 return make_one (instance, create_project_display_dialog);
1678 }
1679
1680 #endif /* ENERGIZE */
1681
1682 widget_creation_entry
1683 xm_creation_table [] =
1684 {
1685 #ifdef MENUBARS_MOTIF
1686 {"menubar", make_menubar},
1687 {"popup", make_popup_menu},
1688 #endif
1689 #ifdef SCROLLBARS_MOTIF
1690 {"vertical-scrollbar", make_vertical_scrollbar},
1691 {"horizontal-scrollbar", make_horizontal_scrollbar},
1692 #endif
1693 #ifdef ENERGIZE
1694 {"project_p_sheet", make_project_p_sheet},
1695 {"debugger_p_sheet", make_debugger_p_sheet},
1696 {"breaklist_psheet", make_breaklist_p_sheet},
1697 {"leb_psheet", make_le_browser_p_sheet},
1698 {"class_browser_psheet", make_class_browser_p_sheet},
1699 {"ctree_browser_psheet", make_call_browser_p_sheet},
1700 {"build", make_build_dialog},
1701 {"editmode", make_editmode_dialog},
1702 {"search", make_search_dialog},
1703 {"project_display", make_project_display_dialog},
1704 #endif /* ENERGIZE */
1705 {NULL, NULL}
1706 };
1707
1708 /* Destruction of instances */
1709 void
1710 xm_destroy_instance (widget_instance* instance)
1711 {
1712 #ifdef DIALOGS_MOTIF
1713 /* It appears that this is used only for dialog boxes. */
1714 Widget widget = instance->widget;
1715 /* recycle the dialog boxes */
1716 /* Disable the recycling until we can find a way to have the dialog box
1717 get reasonable layout after we modify its contents. */
1718 if (0
1719 && XtClass (widget) == xmDialogShellWidgetClass)
1720 {
1721 destroyed_instance* dead_instance =
1722 make_destroyed_instance (instance->info->name,
1723 instance->info->type,
1724 instance->widget,
1725 instance->parent,
1726 instance->pop_up_p);
1727 dead_instance->next = all_destroyed_instances;
1728 all_destroyed_instances = dead_instance;
1729 XtUnmanageChild (first_child (instance->widget));
1730 XFlush (XtDisplay (instance->widget));
1731 XtAddCallback (instance->parent, XtNdestroyCallback,
1732 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1733 }
1734 else
1735 {
1736 /* This might not be necessary now that the nosel is attached to
1737 popdown instead of destroy, but it can't hurt. */
1738 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1739 xm_nosel_callback, (XtPointer)instance);
1740
1741 XtDestroyWidget (instance->widget);
1742 }
1743 #endif /* DIALOGS_MOTIF */
1744 }
1745
1746 /* popup utility */
1747 #ifdef MENUBARS_MOTIF
1748
1749 void
1750 xm_popup_menu (Widget widget, XEvent *event)
1751 {
1752 if (event->type == ButtonPress || event->type == ButtonRelease)
1753 {
1754 /* This is so totally ridiculous: there's NO WAY to tell Motif
1755 that *any* button can select a menu item. Only one button
1756 can have that honor.
1757 */
1758 char *trans = 0;
1759 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1760 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1761 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1762 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1763 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1764 if (trans)
1765 {
1766 Arg al [1];
1767 XtSetArg (al [0], XmNmenuPost, trans);
1768 XtSetValues (widget, al, 1);
1769 }
1770 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1771 }
1772 XtManageChild (widget);
1773 }
1774
1775 #endif
1776
1777 #ifdef DIALOGS_MOTIF
1778
1779 static void
1780 set_min_dialog_size (Widget w)
1781 {
1782 short width;
1783 short height;
1784 Arg al [2];
1785
1786 XtSetArg (al [0], XmNwidth, &width);
1787 XtSetArg (al [1], XmNheight, &height);
1788 XtGetValues (w, al, 2);
1789
1790 XtSetArg (al [0], XmNminWidth, width);
1791 XtSetArg (al [1], XmNminHeight, height);
1792 XtSetValues (w, al, 2);
1793 }
1794
1795 #endif
1796
1797 void
1798 xm_pop_instance (widget_instance* instance, Boolean up)
1799 {
1800 Widget widget = instance->widget;
1801
1802 #ifdef DIALOGS_MOTIF
1803 if (XtClass (widget) == xmDialogShellWidgetClass)
1804 {
1805 Widget widget_to_manage = first_child (widget);
1806 if (up)
1807 {
1808 XtManageChild (widget_to_manage);
1809 set_min_dialog_size (widget);
1810 XmProcessTraversal(widget, XmTRAVERSE_CURRENT);
1811 }
1812 else
1813 XtUnmanageChild (widget_to_manage);
1814 }
1815 else
1816 #endif
1817 {
1818 if (up)
1819 XtManageChild (widget);
1820 else
1821 XtUnmanageChild (widget);
1822 }
1823 }
1824
1825
1826 /* motif callback */
1827
1828 enum do_call_type { pre_activate, selection, no_selection, post_activate };
1829
1830 static void
1831 do_call (Widget widget, XtPointer closure, enum do_call_type type)
1832 {
1833 XtPointer user_data;
1834 widget_instance* instance = (widget_instance*)closure;
1835 Widget instance_widget;
1836 LWLIB_ID id;
1837 Arg al [1];
1838
1839 if (!instance)
1840 return;
1841 if (widget->core.being_destroyed)
1842 return;
1843
1844 instance_widget = instance->widget;
1845 if (!instance_widget)
1846 return;
1847
1848 id = instance->info->id;
1849 user_data = NULL;
1850 XtSetArg(al [0], XmNuserData, &user_data);
1851 XtGetValues (widget, al, 1);
1852 switch (type)
1853 {
1854 case pre_activate:
1855 if (instance->info->pre_activate_cb)
1856 instance->info->pre_activate_cb (widget, id, user_data);
1857 break;
1858 case selection:
1859 if (instance->info->selection_cb)
1860 instance->info->selection_cb (widget, id, user_data);
1861 break;
1862 case no_selection:
1863 if (instance->info->selection_cb)
1864 instance->info->selection_cb (widget, id, (XtPointer) -1);
1865 break;
1866 case post_activate:
1867 if (instance->info->post_activate_cb)
1868 instance->info->post_activate_cb (widget, id, user_data);
1869 break;
1870 default:
1871 abort ();
1872 }
1873 }
1874
1875 /* Like lw_internal_update_other_instances except that it does not do
1876 anything if its shell parent is not managed. This is to protect
1877 lw_internal_update_other_instances to dereference freed memory
1878 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1879 list */
1880 static void
1881 xm_internal_update_other_instances (Widget widget, XtPointer closure,
1882 XtPointer call_data)
1883 {
1884 Widget parent;
1885 for (parent = widget; parent; parent = XtParent (parent))
1886 if (XtIsShell (parent))
1887 break;
1888 else if (!XtIsManaged (parent))
1889 return;
1890 lw_internal_update_other_instances (widget, closure, call_data);
1891 }
1892
1893 static void
1894 xm_generic_callback (Widget widget, XtPointer closure, XtPointer call_data)
1895 {
1896 #if !defined (ENERGIZE) && (defined (MENUBARS_MOTIF) || defined (DIALOGS_MOTIF))
1897 /* We want the selected status to change only when we decide it
1898 should change. Yuck but correct. */
1899 if (XtClass (widget) == xmToggleButtonWidgetClass
1900 || XtClass (widget) == xmToggleButtonGadgetClass)
1901 {
1902 Boolean check;
1903 Arg al [1];
1904
1905 XtSetArg (al [0], XmNset, &check);
1906 XtGetValues (widget, al, 1);
1907
1908 XtSetArg (al [0], XmNset, !check);
1909 XtSetValues (widget, al, 1);
1910 }
1911 #endif
1912 lw_internal_update_other_instances (widget, closure, call_data);
1913 do_call (widget, closure, selection);
1914 }
1915
1916 #ifdef DIALOGS_MOTIF
1917
1918 static void
1919 xm_nosel_callback (Widget widget, XtPointer closure, XtPointer call_data)
1920 {
1921 /* This callback is only called when a dialog box is dismissed with the wm's
1922 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1923 in that case, not just unmapped, so that it releases its keyboard grabs.
1924 But there are problems with running our callbacks while the widget is in
1925 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1926 instead of XmDESTROY and then destroy it ourself after having run the
1927 callback.
1928 */
1929 do_call (widget, closure, no_selection);
1930 XtDestroyWidget (widget);
1931 }
1932
1933 #endif
1934
1935 #ifdef MENUBARS_MOTIF
1936
1937 static void
1938 xm_pull_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
1939 {
1940 #if 0
1941 if (call_data)
1942 {
1943 /* new behavior for incremental menu construction */
1944
1945 }
1946 else
1947 #endif
1948 do_call (widget, closure, pre_activate);
1949 }
1950
1951 #if 0
1952 static void
1953 xm_pop_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
1954 {
1955 do_call (widget, closure, post_activate);
1956 }
1957 #endif /* 0 */
1958
1959 #endif /* MENUBARS_MOTIF */
1960
1961 #ifdef SCROLLBARS_MOTIF
1962 static void
1963 xm_scrollbar_callback (Widget widget, XtPointer closure, XtPointer call_data)
1964 {
1965 widget_instance *instance = (widget_instance *) closure;
1966 LWLIB_ID id;
1967 XmScrollBarCallbackStruct *data =
1968 (XmScrollBarCallbackStruct *) call_data;
1969 scroll_event event_data;
1970 scrollbar_values *val =
1971 (scrollbar_values *) instance->info->val->scrollbar_data;
1972 double percent;
1973
1974 if (!instance || widget->core.being_destroyed)
1975 return;
1976
1977 id = instance->info->id;
1978
1979 percent = (double) (data->value - 1) / (double) (INT_MAX - 1);
1980 event_data.slider_value =
1981 (int) (percent * (double) (val->maximum - val->minimum)) + val->minimum;
1982
1983 if (event_data.slider_value > (val->maximum - val->slider_size))
1984 event_data.slider_value = val->maximum - val->slider_size;
1985 else if (event_data.slider_value < 1)
1986 event_data.slider_value = 1;
1987
1988 if (data->event)
1989 {
1990 switch (data->event->xany.type)
1991 {
1992 case KeyPress:
1993 case KeyRelease:
1994 event_data.time = data->event->xkey.time;
1995 break;
1996 case ButtonPress:
1997 case ButtonRelease:
1998 event_data.time = data->event->xbutton.time;
1999 break;
2000 case MotionNotify:
2001 event_data.time = data->event->xmotion.time;
2002 break;
2003 case EnterNotify:
2004 case LeaveNotify:
2005 event_data.time = data->event->xcrossing.time;
2006 break;
2007 default:
2008 event_data.time = 0;
2009 break;
2010 }
2011 }
2012 else
2013 event_data.time = 0;
2014
2015 switch (data->reason)
2016 {
2017 case XmCR_DECREMENT:
2018 event_data.action = SCROLLBAR_LINE_UP;
2019 break;
2020 case XmCR_INCREMENT:
2021 event_data.action = SCROLLBAR_LINE_DOWN;
2022 break;
2023 case XmCR_PAGE_DECREMENT:
2024 event_data.action = SCROLLBAR_PAGE_UP;
2025 break;
2026 case XmCR_PAGE_INCREMENT:
2027 event_data.action = SCROLLBAR_PAGE_DOWN;
2028 break;
2029 case XmCR_TO_TOP:
2030 event_data.action = SCROLLBAR_TOP;
2031 break;
2032 case XmCR_TO_BOTTOM:
2033 event_data.action = SCROLLBAR_BOTTOM;
2034 break;
2035 case XmCR_DRAG:
2036 event_data.action = SCROLLBAR_DRAG;
2037 break;
2038 case XmCR_VALUE_CHANGED:
2039 event_data.action = SCROLLBAR_CHANGE;
2040 break;
2041 default:
2042 event_data.action = SCROLLBAR_CHANGE;
2043 break;
2044 }
2045
2046 if (instance->info->pre_activate_cb)
2047 instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data);
2048 }
2049 #endif /* SCROLLBARS_MOTIF */
2050
2051
2052 /* set the keyboard focus */
2053 void
2054 xm_set_keyboard_focus (Widget parent, Widget w)
2055 {
2056 XmProcessTraversal (w, XmTRAVERSE_CURRENT);
2057 /* At some point we believed that it was necessary to use XtSetKeyboardFocus
2058 instead of XmProcessTraversal when using Motif >= 1.2.1, but that's bogus.
2059 Presumably the problem was elsewhere, and is now gone...
2060 */
2061 }