1: #include <X/mit-copyright.h> 2: 3: /* Copyright 1985, Massachusetts Institute of Technology */ 4: #include <X/Xlib.h> 5: 6: #ifndef lint 7: static char *rcsid_dialog_c = "$Header: dialog.c,v 10.4 86/02/01 15:18:29 tony Rel $"; 8: #endif 9: 10: extern int foreground; 11: extern int background; 12: extern Pixmap backmap; 13: extern Pixmap border; 14: extern int borderwidth; 15: extern int invertplane; 16: extern int mousepix; 17: 18: #define NULL 0 19: #define MIN_BETWEEN_COMMANDS 10 20: #define BETWEEN_LINES 10 21: #define TOP_MARGIN 10 22: #define BOTTOM_MARGIN 10 23: #define MSG_RIGHT_MARGIN 7 24: #define MSG_LEFT_MARGIN 7 25: #define COMMAND_WIDTH_FUDGE 8 26: 27: #define max(a,b) ((a > b) ? a : b) 28: 29: #include "../cursors/cross.cursor" 30: #include "../cursors/cross_mask.cursor" 31: static Cursor cross_cursor; 32: 33: static struct dialog_data { 34: Window w; 35: Font font; 36: int font_height; 37: char *msg1, *msg2; 38: int msg1_length, msg2_length; 39: struct command_data *command_info; 40: }; 41: 42: static struct command_data { 43: Window window; 44: char *name; 45: int name_length; 46: int name_width; /* in pixels */ 47: int x_offset; 48: }; 49: 50: int dialog (w, font, font_height, 51: msg1, msg2, command_names, n_commands, input_handler) 52: Window w; 53: Font font; 54: int font_height; 55: char *msg1, *msg2; 56: char **command_names; 57: int n_commands; 58: int (*input_handler) (); 59: { 60: struct dialog_data data; 61: static int initialized = 0; 62: int msg1_width = XQueryWidth (msg1, font); 63: int msg2_width = XQueryWidth (msg2, font); 64: int command_width = 0; 65: int result; 66: register int i; 67: 68: if (!initialized) { 69: Initialize (); 70: initialized = 1; 71: } 72: 73: data.font = font; 74: data.font_height = font_height; 75: data.msg1 = msg1; 76: data.msg2 = msg2; 77: data.msg1_length = strlen (msg1); 78: data.msg2_length = strlen (msg2); 79: data.command_info = (struct command_data *) malloc 80: (n_commands*sizeof (struct command_data)); 81: 82: for (i=0;i<n_commands;i++) { 83: data.command_info[i].name = command_names[i]; 84: data.command_info[i].name_length = strlen (command_names[i]); 85: data.command_info[i].name_width = XQueryWidth (command_names[i], font); 86: if (data.command_info[i].name_width > command_width) 87: command_width = data.command_info[i].name_width; 88: } 89: command_width += COMMAND_WIDTH_FUDGE; 90: 91: { 92: int between_commands; 93: { 94: int height = 95: 3*font_height + 2*BETWEEN_LINES + TOP_MARGIN + BOTTOM_MARGIN; 96: int width = max (msg1_width, msg2_width) 97: + MSG_LEFT_MARGIN + MSG_RIGHT_MARGIN; 98: int min_width = 99: n_commands*command_width + (n_commands+1)*MIN_BETWEEN_COMMANDS; 100: int x, y; 101: DeterminePlace (w, &x, &y); 102: width = max (width, min_width); 103: between_commands = 104: (width - n_commands*command_width)/(n_commands+1); 105: data.w = XCreateWindow (RootWindow, x, y, width, height, 106: borderwidth, border, backmap); 107: } 108: 109: { 110: int xx = between_commands; 111: OpaqueFrame *frames = (OpaqueFrame *)malloc(n_commands*sizeof(OpaqueFrame)); 112: for (i=0;i<n_commands;i++) { 113: register OpaqueFrame *frame = &frames[i]; 114: register struct command_data *command = &data.command_info[i]; 115: command->x_offset = (command_width - command->name_width)/2; 116: frame->x = xx; 117: frame->y = TOP_MARGIN + 2*(font_height+BETWEEN_LINES); 118: frame->width = command_width; 119: frame->height = font_height; 120: frame->bdrwidth = 1; 121: frame->border = border; 122: frame->background = backmap; 123: xx += (between_commands + command_width); 124: } 125: XCreateWindows (data.w, frames, n_commands); 126: for (i=0;i<n_commands;i++) 127: data.command_info[i].window = frames[i].self; 128: free (frames); 129: }} 130: 131: XSelectInput (data.w, 132: ButtonPressed | ButtonReleased | ExposeWindow | LeaveWindow); 133: 134: XDefineCursor (data.w, cross_cursor); 135: XMapWindow (data.w); 136: XMapSubwindows (data.w); 137: 138: while (1) { 139: struct command_data *command = NULL; 140: XEvent event; 141: XNextEvent (&event); 142: if (event.window != data.w) { 143: (*input_handler) (&event); 144: continue; /* back around the loop */ 145: } 146: if (event.subwindow == 0) { 147: ProcessDialogWindowEvent (&data, &event); 148: continue; 149: } 150: for (i=0;i<n_commands;i++) 151: if (event.subwindow == data.command_info[i].window) { 152: command = &data.command_info[i]; 153: break; 154: } 155: if (command == NULL) 156: continue; /* really shouldn't happen, but what can you do? */ 157: result = ProcessCommandEvent (&data, command, &event); 158: if (result >= 0) 159: break; 160: } 161: 162: XDestroyWindow (data.w); 163: 164: free (data.command_info); 165: return (result); 166: } /* end of dialog procedure */ 167: 168: 169: Initialize () 170: { 171: cross_cursor = XCreateCursor (cross_width, cross_height, cross_bits, 172: cross_mask_bits, cross_x_hot, cross_y_hot, 173: mousepix, background, GXcopy); 174: } 175: 176: 177: /* ProcessCommandEvent returns -1 unless a command was actually invoked, 178: in which case it returns the command number. */ 179: 180: static int ProcessCommandEvent (data, command, event) 181: struct dialog_data *data; 182: struct command_data *command; 183: XEvent *event; 184: { 185: static struct command_data *button_down_command = NULL; 186: 187: switch (event->type) { 188: 189: case ExposeWindow: 190: XTextMask (command->window, command->x_offset, 191: 0, command->name, command->name_length, data->font, foreground); 192: break; 193: 194: case ButtonPressed: 195: if (button_down_command != NULL) 196: break; /* must be second button press; ignore it */ 197: button_down_command = command; 198: InvertCommand (data, command); 199: break; 200: 201: case LeaveWindow: 202: if (command == button_down_command) { 203: InvertCommand (data, command); 204: button_down_command = NULL; 205: } 206: break; 207: 208: case ButtonReleased: 209: if (command == button_down_command) { 210: button_down_command = NULL; 211: return (command - data->command_info); 212: } 213: break; 214: 215: } 216: 217: return (-1); 218: } 219: 220: 221: static ProcessDialogWindowEvent (data, event) 222: struct dialog_data *data; 223: XEvent *event; 224: { 225: if (event->type == ExposeWindow) { 226: XTextMask ( 227: data->w, MSG_LEFT_MARGIN, 228: TOP_MARGIN, data->msg1, data->msg1_length, data->font, foreground); 229: XTextMask ( 230: data->w, MSG_LEFT_MARGIN, 231: TOP_MARGIN + data->font_height + BETWEEN_LINES, 232: data->msg2, data->msg2_length, data->font, foreground); 233: } 234: } 235: 236: 237: static InvertCommand (data, command) 238: struct dialog_data *data; 239: struct command_data *command; 240: { 241: XPixFill (command->window, 0, 0, 400, data->font_height, 1, NULL, 242: GXinvert, invertplane); 243: } 244: 245: 246: static DeterminePlace (w, px, py) 247: Window w; 248: int *px, *py; 249: { 250: WindowInfo info; 251: XQueryWindow (w, &info); 252: /* max (0,...) is to make sure dialog window is on screen, even 253: if "parent" window is partially off screen (negative x or y) */ 254: *px = max (0, info.x + 10); 255: *py = max (0, info.y + 10); 256: }