comparison lwlib/lwlib-Xm.c @ 169:15872534500d r20-3b11

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