1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/choose.c,v 1.11 2011/05/16 16:21:56 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_CHOOSE_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "auxtext.e"
26 #include "button.e"
27 #include "choose.e"
28 #include "cutpaste.e"
29 #include "cursor.e"
30 #include "dialog.e"
31 #include "drawing.e"
32 #include "file.e"
33 #include "font.e"
34 #include "mainloop.e"
35 #include "mainmenu.e"
36 #include "menu.e"
37 #include "msg.e"
38 #include "names.e"
39 #include "raster.e"
40 #include "rect.e"
41 #include "remote.e"
42 #include "ruler.e"
43 #include "scroll.e"
44 #include "setup.e"
45 #include "strtbl.e"
46 #include "util.e"
47 
48 GC nameGC=(GC)0, revNameGC=(GC)0;
49 
50 typedef struct NamesRec {
51    Window base_win, dsp_base_win, dsp_win, scroll_win;
52    int base_win_w, base_win_h;
53    int dsp_base_win_w, dsp_base_win_h;
54    int dsp_area_w, dsp_area_h, scroll_area_h;
55 
56    char **entries;
57    int num_entries;
58    int first_index;
59    int marked_index;
60    int num_btns;
61    struct BBRec btn_bbox[MAXBUTTONS], path_bbox;
62    char btn_str[MAXBUTTONS][40];
63    int btn_id[MAXBUTTONS];
64 
65    char inbuf[512];
66    int buf_index, just_clicked, scroll_dir;
67 
68    DspList *dsp_ptr;
69    char *title_str, *formatted_title_str;
70 
71    struct CheckArrayRec *p_check_array;
72 
73    int title_w, title_h, title_num_lines;
74    int a_btn_w, graph_w, btn_start, title_start, graph_start;
75    int btn_w, btn_gap, btn_selected, exposed, screen_w, screen_h;
76    int edit_style, loop_once, dont_free_entries, leading;
77 
78    int change_to_root, pop_from_root, faking_dot_dot;
79    int tabbed_from_root, just_tabbed_from_root;
80    int def_btn_id, double_click_btn_id;
81 
82    GetEntriesFunc *pf_before_loop;
83    AfterLoopFunc *pf_after_loop;
84    CheckUpdateFunc *pf_check_update; /* called when a checkbox changes state */
85 
86    /* used only when edit_style== NAMES_SELECT_FILE */
87    char dir_name[MAXPATHLENGTH+1], saved_dir_name[MAXPATHLENGTH+1];
88    char name[MAXPATHLENGTH+1], saved_name[MAXPATHLENGTH+1];
89    int name_index, remote_file;
90 
91    void *userdata;
92 } *NamesRecPtr;
93 
94 static struct NamesRec namesInfo;
95 
96 static XComposeStatus c_stat;
97 
GetWorkingDirectory(buf,buf_sz)98 int GetWorkingDirectory(buf, buf_sz)
99    char *buf;
100    int buf_sz;
101 {
102    char *psz_result=NULL;
103 
104 #ifdef VMS
105    psz_result = getcwd(buf, buf_sz, 0);
106 #else /* ~VMS */
107 #ifdef ibm
108    psz_result = getwd(buf, buf_sz);
109 #else /* ~ibm */
110 #ifdef NeXT
111    psz_result = getwd(buf, buf_sz);
112 #else /* ~NeXT */
113 #ifdef luna88k
114    psz_result = getwd(buf);
115 #else /* ~luna88k */
116 #ifdef sequent
117    psz_result = getwd(buf);
118 #else /* ~sequent */
119    psz_result = getcwd(buf, buf_sz);
120 #endif /* sequent */
121 #endif /* luna88k */
122 #endif /* NeXT */
123 #endif /* ibm */
124 #endif /* VMS */
125    if (psz_result == NULL) {
126       UtilStrCpyN(buf, buf_sz, ".");
127       return FALSE;
128    }
129    return TRUE;
130 }
131 
SetWorkingDirectory(dir)132 int SetWorkingDirectory(dir)
133    char *dir;
134 {
135    return (chdir(dir) == 0);
136 }
137 
138 static
CalcBaseWinWidth(pni)139 void CalcBaseWinWidth(pni)
140    struct NamesRec *pni;
141 {
142    int max_w=max(pni->graph_w,pni->btn_w);
143 
144    pni->base_win_w = max_w + (defaultFontWidth<<2);
145    pni->graph_start = ((pni->base_win_w-pni->graph_w)>>1);
146    if (pni->title_num_lines <= 1) {
147       pni->title_start = ((pni->base_win_w-pni->title_w)>>1);
148    } else {
149       pni->title_start = pni->graph_start;
150    }
151    pni->btn_start = ((pni->base_win_w-pni->btn_w)>>1);
152 
153    pni->path_bbox.ltx = pni->graph_start;
154    pni->path_bbox.lty = (ROW_HEIGHT<<1)+pni->title_h;
155    /* the path_bbox needs 2 pixels around it */
156    pni->path_bbox.lty -= 2;
157    pni->path_bbox.rbx = pni->path_bbox.ltx + ITEM_LEN*defaultFontWidth+6;
158    pni->path_bbox.rby = pni->path_bbox.lty +
159          ((msgFontSet==NULL && msgFontPtr==NULL) ? defaultFontHeight :
160          msgFontHeight)+1+4;
161    if (boldMsgFontSet == NULL && boldMsgFontPtr == NULL) {
162       pni->base_win_h = (7+ITEM_DSPED)*ROW_HEIGHT + pni->title_h;
163    } else {
164       pni->base_win_h = (6+ITEM_DSPED)*ROW_HEIGHT + boldMsgFontHeight + 1 +
165             pni->title_h;
166    }
167 }
168 
CleanUpCheckArray(pCheckArray)169 void CleanUpCheckArray(pCheckArray)
170    /* Does not free pCheckArray */
171    struct CheckArrayRec *pCheckArray;
172 {
173    int i, num_cols=pCheckArray->num_cols;
174 
175    if (pCheckArray->col_name != NULL) {
176       /* there's an extra one column here! */
177       for (i=0; i <= num_cols; i++) {
178          if (pCheckArray->col_name[i] != NULL) {
179             UtilFree(pCheckArray->col_name[i]);
180          }
181       }
182       free(pCheckArray->col_name);
183    }
184    if (pCheckArray->value != NULL) {
185       for (i=0; i < num_cols; i++) {
186          if (pCheckArray->value[i] != NULL) {
187             free(pCheckArray->value[i]);
188          }
189       }
190       free(pCheckArray->value);
191    }
192    memset(pCheckArray, 0, sizeof(struct CheckArrayRec));
193 }
194 
CopyCheckArray(pCheckArrayTo,pCheckArrayFrom)195 int CopyCheckArray(pCheckArrayTo, pCheckArrayFrom)
196    struct CheckArrayRec *pCheckArrayTo, *pCheckArrayFrom;
197 {
198    int i;
199    int num_cols=pCheckArrayFrom->num_cols, num_rows=pCheckArrayFrom->num_rows;
200 
201    memset(pCheckArrayTo, 0, sizeof(struct CheckArrayRec));
202    pCheckArrayTo->num_cols = num_cols;
203    pCheckArrayTo->num_rows = num_rows;
204    if (pCheckArrayFrom->col_name != NULL) {
205       /* there's an extra one column here! */
206       pCheckArrayTo->col_name = (char**)malloc((num_cols+1)*sizeof(char*));
207       if (pCheckArrayTo->col_name == NULL) FailAllocMessage();
208       memset(pCheckArrayTo->col_name, 0, (num_cols+1)*sizeof(char*));
209 
210       for (i=0; i <= num_cols; i++) {
211          if (pCheckArrayFrom->col_name[i] != NULL) {
212             pCheckArrayTo->col_name[i] =
213                   UtilStrDup(pCheckArrayFrom->col_name[i]);
214             if (pCheckArrayTo->col_name[i] == NULL) FailAllocMessage();
215          }
216       }
217    }
218    if (pCheckArrayFrom->value != NULL) {
219       pCheckArrayTo->value = (int**)malloc(num_cols*sizeof(int*));
220       if (pCheckArrayTo->value == NULL) FailAllocMessage();
221       memset(pCheckArrayTo->value, 0, num_cols*sizeof(int*));
222 
223       for (i=0; i < num_cols; i++) {
224          if (pCheckArrayFrom->value[i] != NULL) {
225             pCheckArrayTo->value[i] = (int*)malloc(num_rows*sizeof(int));
226             if (pCheckArrayTo->value[i] == NULL) FailAllocMessage();
227             memcpy(pCheckArrayTo->value[i], pCheckArrayFrom->value[i],
228                   num_rows*sizeof(int));
229          }
230       }
231    }
232    return TRUE;
233 }
234 
NamesSetTitle(title_str)235 void NamesSetTitle(title_str)
236    char *title_str;
237 {
238    struct NamesRec *pni=(&namesInfo);
239 
240    if (pni->title_str != NULL) free(pni->title_str);
241    if (pni->formatted_title_str != NULL) free(pni->formatted_title_str);
242    pni->formatted_title_str = NULL;
243    pni->title_str = UtilStrDup(title_str);
244    if (pni->title_str == NULL) FailAllocMessage();
245 
246    if (boldMsgFontSet == NULL && boldMsgFontPtr == NULL) {
247       CalcFormatStringInBox(pni->title_str, defaultFontPtr, defaultFontHeight,
248             pni->graph_w, &pni->title_num_lines, &pni->title_w, &pni->title_h,
249             &pni->formatted_title_str);
250    } else {
251       CalcFormatStringInBox(pni->title_str, boldMsgFontPtr, boldMsgFontHeight,
252             pni->graph_w, &pni->title_num_lines, &pni->title_w, &pni->title_h,
253             &pni->formatted_title_str);
254    }
255    CalcBaseWinWidth(pni);
256 }
257 
ResetNamesInfo()258 void ResetNamesInfo()
259 {
260    struct NamesRec *pni=(&namesInfo);
261 
262    if (pni->title_str != NULL) {
263       free(pni->title_str);
264       pni->title_str = NULL;
265    }
266    if (pni->formatted_title_str != NULL) {
267       free(pni->formatted_title_str);
268       pni->formatted_title_str = NULL;
269    }
270    if (!pni->dont_free_entries) {
271       if (pni->dsp_ptr != NULL) {
272          free(pni->dsp_ptr);
273          pni->dsp_ptr = NULL;
274       }
275       if (pni->entries != NULL) {
276          free(*(pni->entries));
277          free(pni->entries);
278          pni->entries = NULL;
279       }
280    }
281 
282    memset(&namesInfo, 0, sizeof(struct NamesRec));
283 
284    pni->num_entries = INVALID;
285    pni->first_index = INVALID;
286    pni->marked_index = INVALID;
287    /* do not translate -- the string is used to measure things */
288    pni->a_btn_w = ButtonWidth("OK", 8, NULL);
289    pni->btn_gap = defaultFontWidth;
290    pni->screen_w = DisplayWidth(mainDisplay, mainScreen);
291    pni->screen_h = DisplayHeight(mainDisplay, mainScreen);
292    pni->dsp_area_w = ITEM_LEN * defaultFontWidth;
293    pni->dsp_area_h = ITEM_DSPED * ROW_HEIGHT;
294    pni->scroll_area_h = pni->dsp_area_h;
295    pni->dsp_base_win_w = pni->dsp_area_w + scrollBarW + (windowPadding<<1) +
296          (brdrW<<2);
297    pni->dsp_base_win_h = pni->dsp_area_h + (windowPadding<<1) + (brdrW<<1);
298    pni->graph_w = pni->dsp_area_w + scrollBarW + (brdrW<<2);
299    NamesSetTitle("");
300    if (boldMsgFontSet == NULL && boldMsgFontPtr == NULL) {
301       pni->base_win_h = (8+ITEM_DSPED)*ROW_HEIGHT;
302    } else {
303       pni->base_win_h = (6+ITEM_DSPED)*ROW_HEIGHT + 2*(boldMsgFontHeight+1);
304    }
305    pni->def_btn_id = BUTTON_OK;
306    pni->double_click_btn_id = BUTTON_OK;
307    pni->tabbed_from_root = TRUE;
308 }
309 
InitNamesInfo()310 void InitNamesInfo()
311 {
312    XGCValues values;
313 
314    memset(&namesInfo, 0, sizeof(struct NamesRec));
315 
316    values.foreground = myFgPixel;
317    values.background = (threeDLook ? myLtGryPixel : myBgPixel);
318    values.fill_style = FillSolid;
319    if (msgFontPtr == NULL) {
320       values.font = defaultFontPtr->fid;
321    } else {
322       values.font = msgFontPtr->fid;
323    }
324    nameGC = XCreateGC(mainDisplay, rootWindow,
325          GCForeground | GCBackground | GCFillStyle | GCFont, &values);
326 
327    values.foreground = myBgPixel;
328    values.background = myFgPixel;
329    revNameGC = XCreateGC(mainDisplay, rootWindow,
330          GCForeground | GCBackground | GCFillStyle | GCFont, &values);
331 }
332 
CleanUpNamesInfo()333 void CleanUpNamesInfo()
334 {
335    struct NamesRec *pni=(&namesInfo);
336 
337    ResetNamesInfo();
338    if (pni->title_str != NULL) free(pni->title_str);
339    pni->title_str = NULL;
340    if (pni->formatted_title_str != NULL) free(pni->formatted_title_str);
341    pni->formatted_title_str = NULL;
342    XFreeGC(mainDisplay, nameGC);
343    XFreeGC(mainDisplay, revNameGC);
344    nameGC = revNameGC = (GC)0;
345 }
346 
NamesAddButton(btn_str,btn_id)347 void NamesAddButton(btn_str, btn_id)
348    char *btn_str;
349    int btn_id;
350 {
351    struct NamesRec *pni=(&namesInfo);
352 
353    pni->btn_id[pni->num_btns] = btn_id;
354    strcpy(pni->btn_str[pni->num_btns], btn_str);
355    pni->btn_w += ButtonWidth(btn_str, 8, NULL);
356    if (pni->num_btns != 0) {
357       pni->btn_w += pni->btn_gap;
358    }
359    pni->num_btns++;
360    if (pni->num_btns > MAXBUTTONS) {
361 #ifdef _TGIF_DBG /* debug, do not translate */
362       TgAssert(FALSE,
363             "Too many buttons detected in NamesAddButton().", NULL);
364 #endif /* _TGIF_DBG */
365    }
366    CalcBaseWinWidth(pni);
367 }
368 
369 static
RedrawNameScrollWin()370 void RedrawNameScrollWin()
371 {
372    struct NamesRec *pni=(&namesInfo);
373    double frac, start_frac;
374    int block_h, block_start;
375 
376    start_frac = (pni->num_entries > 0) ?
377          (double)((double)(pni->first_index) /
378          (double)(pni->num_entries)) : ((double)0.0);
379    /* starting pixel */
380    block_start = (int)(pni->scroll_area_h * start_frac);
381 
382    if (pni->num_entries > ITEM_DSPED) {
383       frac = (double)((double)ITEM_DSPED / (double)(pni->num_entries));
384    } else {
385       frac = 1.0;
386    }
387    if (pni->first_index+ITEM_DSPED >= pni->num_entries) {
388       block_h = pni->scroll_area_h - block_start;
389    } else {
390       block_h = (int)(pni->scroll_area_h * frac);
391    }
392    TgDrawScrollBar(mainDisplay, pni->scroll_win, VERT_SCROLLBAR,
393          0, 0, scrollBarW, pni->scroll_area_h, start_frac, ITEM_DSPED,
394          pni->num_entries);
395 }
396 
397 #include "xbm/check.xbm"
398 
DrawCheckbox(dpy,win,gc,x,y,w,h,checked)399 void DrawCheckbox(dpy, win, gc, x, y, w, h, checked)
400    Display *dpy;
401    Window win;
402    GC gc;
403    int x, y, w, h, checked;
404 {
405    if (threeDLook) {
406       struct BBRec bbox;
407 
408       SetBBRec(&bbox, x, y, x+w+1, y+h+1);
409       TgDrawThreeDButton(dpy, win, textMenuGC, &bbox, TGBS_LOWRED, 2, FALSE);
410    } else {
411       XDrawRectangle(dpy, win, gc, x, y, w, h);
412    }
413    if (checked) {
414       if (threeDLook) {
415          XGCValues values;
416 
417          values.fill_style = FillStippled;
418          values.stipple = checkBitmap;
419          values.ts_x_origin = x+2;
420          values.ts_y_origin = y+2;
421          XChangeGC(dpy, gc,
422                GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin,
423                &values);
424          XFillRectangle(dpy, win, gc, values.ts_x_origin,
425                values.ts_y_origin, check_width, check_height);
426          values.fill_style = FillSolid;
427          values.ts_x_origin = 0;
428          values.ts_y_origin = 0;
429          XChangeGC(dpy, gc,
430                GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin, &values);
431       } else {
432          XDrawLine(dpy, win, gc, x, y, x+w, y+h);
433          XDrawLine(dpy, win, gc, x, y+h, x+w, y);
434       }
435    }
436    if (check_bits == NULL) { }
437 }
438 
439 static
RedrawItem(pni,index)440 void RedrawItem(pni, index)
441    struct NamesRec *pni;
442    int index;
443 {
444    int len=0, top=0, end=0, checkbox_cols=0, text_left=0, box_offset=0, box_w=0;
445    int selected=(index==pni->marked_index);
446 
447    if ((msgFontSet==NULL && msgFontPtr==NULL)) {
448       top = defaultFontAsc+1;
449    } else {
450       top = msgFontAsc+1;
451    }
452    if (pni->first_index+ITEM_DSPED > pni->num_entries) {
453       end = pni->num_entries;
454    } else {
455       end = pni->first_index + ITEM_DSPED;
456    }
457    if (pni->p_check_array != NULL && pni->p_check_array->num_cols > 0) {
458       checkbox_cols = pni->p_check_array->num_cols;
459       text_left = checkbox_cols*ROW_HEIGHT;
460       box_offset = 1;
461       box_w = (ROW_HEIGHT-((box_offset+1)<<1));
462    }
463    len = strlen(pni->entries[index]);
464    XFillRectangle(mainDisplay, pni->dsp_win,
465          (selected ? nameGC : revNameGC), 0,
466          (index-pni->first_index)*ROW_HEIGHT, ITEM_LEN*defaultFontWidth,
467          ROW_HEIGHT);
468    DrawMsgString(mainDisplay, pni->dsp_win,
469          (selected ? revNameGC : nameGC), text_left,
470          (index-pni->first_index)*ROW_HEIGHT+top, pni->entries[index], len);
471    if (checkbox_cols > 0) {
472       int col=0, cur_x=0;
473 
474       for (col=0; col < pni->p_check_array->num_cols; col++) {
475          DrawCheckbox(mainDisplay, pni->dsp_win,
476                (selected ? revNameGC : nameGC), cur_x+box_offset,
477                (index-pni->first_index)*ROW_HEIGHT+top-box_w,
478                box_w, box_w, pni->p_check_array->value[col][index]);
479          cur_x += ROW_HEIGHT;
480       }
481    }
482 }
483 
484 static
RedrawDspWindow()485 void RedrawDspWindow()
486 {
487    struct NamesRec *pni=(&namesInfo);
488    int i, end=0;
489 
490    if (pni->first_index+ITEM_DSPED > pni->num_entries) {
491       end = pni->num_entries;
492    } else {
493       end = pni->first_index + ITEM_DSPED;
494    }
495    XFillRectangle(mainDisplay, pni->dsp_win, revNameGC, 0, 0,
496          ITEM_LEN*defaultFontWidth, ITEM_DSPED*ROW_HEIGHT);
497 
498    for (i=pni->first_index; i < end; i++) {
499       RedrawItem(pni, i);
500    }
501 }
502 
503 static
RedrawDspBaseWindow()504 void RedrawDspBaseWindow()
505 {
506    if (threeDLook) {
507       struct NamesRec *pni=(&namesInfo);
508       struct BBRec bbox;
509 
510       SetBBRec(&bbox, 0, 0, pni->dsp_base_win_w, pni->dsp_base_win_h);
511       TgDrawThreeDButton(mainDisplay, pni->dsp_base_win, textMenuGC, &bbox,
512             TGBS_LOWRED, 2, FALSE);
513    }
514 }
515 
516 static
RedrawNamePath()517 void RedrawNamePath()
518 {
519    struct NamesRec *pni=(&namesInfo);
520    int len=strlen(pni->inbuf), cursor_x=0, cursor_y, box_w, box_h, x, y;
521    char *c_ptr;
522    struct BBRec bbox;
523 
524    if (msgFontPtr == NULL) {
525       XSetFont(mainDisplay, nameGC, defaultFontPtr->fid);
526    } else {
527       XSetFont(mainDisplay, nameGC, msgFontPtr->fid);
528    }
529    x = pni->graph_start;
530    /* the path_bbox has 2 pixels around it */
531    y = pni->path_bbox.lty+2;
532 
533    box_w = ITEM_LEN*defaultFontWidth+6+(windowPadding<<1);
534    cursor_y = y;
535    if ((msgFontSet==NULL && msgFontPtr==NULL)) {
536       y += defaultFontAsc;
537    } else {
538       y += msgFontAsc;
539    }
540    box_h = (ROW_HEIGHT+3);
541    if (threeDLook) {
542       XSetForeground(mainDisplay, textMenuGC, myBgPixel);
543       XFillRectangle(mainDisplay, pni->base_win, textMenuGC, x, cursor_y-2,
544             box_w+(windowPadding<<1), box_h+(windowPadding<<1));
545       SetBBRec(&bbox, x, cursor_y-2, x+box_w+(windowPadding<<1),
546             cursor_y-2+box_h+(windowPadding<<1));
547       TgDrawThreeDButton(mainDisplay, pni->base_win, textMenuGC, &bbox,
548             TGBS_LOWRED, 2, FALSE);
549    } else {
550       XClearArea(mainDisplay, pni->base_win, x, cursor_y-2, box_w+1, box_h,
551             False);
552       XDrawRectangle(mainDisplay, pni->base_win, nameGC, x, cursor_y-2,
553             box_w+1, box_h);
554    }
555    if ((msgFontSet==NULL && msgFontPtr==NULL)) {
556       if (len > ITEM_LEN) {
557          c_ptr = &(pni->inbuf[len-ITEM_LEN]);
558          len = ITEM_LEN;
559       } else {
560          c_ptr = pni->inbuf;
561       }
562       cursor_x = x+2+len*defaultFontWidth;
563    } else {
564       int index=0;
565 
566       cursor_x = MsgTextWidth(msgFontPtr, pni->inbuf, len);
567       while (cursor_x > box_w-4) {
568          index++;
569          cursor_x = MsgTextWidth(msgFontPtr, &pni->inbuf[index], len-index);
570       }
571       c_ptr = &pni->inbuf[index];
572       len -= index;
573       cursor_x += x+2+1;
574    }
575    DrawMsgString(mainDisplay, pni->base_win, nameGC, x+2+windowPadding,
576          y+1+windowPadding, c_ptr, len);
577    XDrawLine(mainDisplay, pni->base_win, nameGC, cursor_x+windowPadding,
578          cursor_y+1+windowPadding, cursor_x+windowPadding,
579          cursor_y+box_h-5+windowPadding);
580 }
581 
582 static
RedrawNameBaseWindow()583 void RedrawNameBaseWindow()
584 {
585    struct NamesRec *pni=(&namesInfo);
586    int i, left, base_line;
587 
588    /* draw a frame around the window */
589    if (threeDLook) {
590       if (dialogboxUse3DBorder) {
591          struct BBRec bbox;
592 
593          SetBBRec(&bbox, 0, 0, pni->base_win_w, pni->base_win_h);
594          TgDrawThreeDButton(mainDisplay, pni->base_win, textMenuGC, &bbox,
595                TGBS_RAISED, 2, FALSE);
596       }
597    } else {
598       XDrawRectangle(mainDisplay, pni->base_win, nameGC, 0, 0,
599             pni->base_win_w-1, pni->base_win_h-1);
600    }
601    if (boldMsgFontSet == NULL && boldMsgFontPtr == NULL) {
602       base_line = defaultFontAsc+ROW_HEIGHT;
603       XSetFont(mainDisplay, nameGC, defaultFontPtr->fid);
604    } else {
605       base_line = boldMsgFontAsc+ROW_HEIGHT;
606       if (boldMsgFontPtr != NULL) {
607          XSetFont(mainDisplay, nameGC, boldMsgFontPtr->fid);
608       }
609    }
610    /* draw the title */
611    if (pni->tabbed_from_root) {
612       if (pni->title_num_lines <= 1) {
613          DrawBoldMsgString(mainDisplay, pni->base_win, nameGC, pni->title_start,
614                base_line, pni->title_str, strlen(pni->title_str));
615       } else {
616          char *psz_line=pni->formatted_title_str;
617          char *psz=strchr(pni->formatted_title_str, '\n');
618 
619          do {
620             if (psz != NULL) *psz = '\0';
621             DrawBoldMsgString(mainDisplay, pni->base_win, nameGC,
622                   pni->title_start, base_line, psz_line, strlen(psz_line));
623             base_line += ((boldMsgFontSet==NULL && boldMsgFontPtr==NULL) ?
624                   defaultFontHeight : boldMsgFontHeight);
625             if (psz != NULL) {
626                *psz++ = '\n';
627                psz_line = psz;
628                psz = strchr(psz_line, '\n');
629             } else {
630                break;
631             }
632          } while (psz_line != NULL);
633       }
634    } else {
635       int tmp_w, len, tmp_start;
636 
637       strcpy(gszMsgBox, TgLoadString(STID_TAB_FOR_FILE_COMPLETION));
638       len = strlen(gszMsgBox);
639       if (boldMsgFontSet == NULL && boldMsgFontPtr == NULL) {
640          tmp_w = defaultFontWidth * len;
641       } else {
642          tmp_w = BoldMsgTextWidth(boldMsgFontPtr, gszMsgBox, len);
643       }
644       tmp_start = ((pni->base_win_w-tmp_w)>>1);
645       DrawBoldMsgString(mainDisplay, pni->base_win, nameGC, tmp_start,
646             base_line, gszMsgBox, len);
647       if (pni->title_str != NULL && *pni->title_str != '\0') {
648          SetStringStatus(pni->title_str);
649       }
650    }
651    if (boldMsgFontSet != NULL || boldMsgFontPtr != NULL) {
652       if (msgFontPtr == NULL) {
653          XSetFont(mainDisplay, nameGC, defaultFontPtr->fid);
654       } else {
655          XSetFont(mainDisplay, nameGC, msgFontPtr->fid);
656       }
657    }
658    RedrawNamePath();
659 
660    /* draw the buttons */
661    left = pni->btn_start;
662    for (i=0; i < pni->num_btns; i++) {
663       int len=strlen(pni->btn_str[i]);
664       int button_w=ButtonWidth(pni->btn_str[i], 8, NULL), button_h=0;
665 
666       if (boldMsgFontSet == NULL && boldMsgFontPtr == NULL) {
667          button_h = defaultFontHeight + 4;
668       } else {
669          button_h = boldMsgFontHeight + 4;
670       }
671       pni->btn_bbox[i].ltx = left;
672       pni->btn_bbox[i].lty = (5+ITEM_DSPED)*ROW_HEIGHT + pni->title_h;
673       pni->btn_bbox[i].lty -= 1;
674       pni->btn_bbox[i].rbx = pni->btn_bbox[i].ltx+button_w;
675       pni->btn_bbox[i].rby = pni->btn_bbox[i].lty+button_h;
676       DisplayButtonInBBox(pni->base_win, pni->btn_str[i],
677             len, &(pni->btn_bbox[i]), BUTTON_NORMAL, FALSE, 0, NULL);
678       left = pni->btn_bbox[i].rbx + 1 + defaultFontWidth;
679    }
680 }
681 
682 static
RedrawNamesWindow()683 void RedrawNamesWindow()
684 {
685    RedrawNameBaseWindow();
686    RedrawNameScrollWin();
687    RedrawDspWindow();
688    RedrawDspBaseWindow();
689 }
690 
691 static
ExposeOrMapNames(input)692 int ExposeOrMapNames(input)
693    XEvent *input;
694 {
695    struct NamesRec *pni=(&namesInfo);
696    XEvent ev;
697 
698    if ((input->type==MapNotify && input->xany.window==pni->base_win) ||
699          (input->type==Expose && (input->xany.window==pni->base_win ||
700          input->xany.window==pni->scroll_win ||
701          input->xany.window==pni->dsp_win)) || (!pni->exposed &&
702          (XCheckWindowEvent(mainDisplay, pni->base_win, ExposureMask,
703          &ev) || XCheckWindowEvent(mainDisplay, pni->scroll_win,
704          ExposureMask, &ev) || XCheckWindowEvent(mainDisplay, pni->dsp_win,
705          ExposureMask, &ev) || XCheckWindowEvent(mainDisplay,
706          pni->base_win, StructureNotifyMask, &ev)))) {
707       while (XCheckWindowEvent(mainDisplay, pni->base_win,
708             ExposureMask, &ev)) ;
709       while (XCheckWindowEvent(mainDisplay, pni->scroll_win,
710             ExposureMask, &ev)) ;
711       while (XCheckWindowEvent(mainDisplay, pni->dsp_win,
712             ExposureMask, &ev)) ;
713       while (XCheckWindowEvent(mainDisplay, pni->base_win,
714             StructureNotifyMask, &ev)) ;
715 
716       RedrawNamesWindow();
717 
718       pni->exposed = TRUE;
719       XSync(mainDisplay, False);
720 
721       if ((input->type==MapNotify &&
722             input->xany.window==pni->base_win) ||
723             (input->type==Expose &&
724             (input->xany.window==pni->base_win ||
725             input->xany.window==pni->scroll_win ||
726             input->xany.window==pni->dsp_win))) {
727          return TRUE;
728       }
729    }
730    return FALSE;
731 }
732 
733 static
CreateNamesWindows(win_name)734 int CreateNamesWindows(win_name)
735    char *win_name;
736 {
737    struct NamesRec *pni=(&namesInfo);
738    int y, base_win_x, base_win_y;
739    int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
740    XWMHints wmhints;
741    XSizeHints sizehints;
742    XSetWindowAttributes win_attrs;
743 
744    base_win_x = (pni->base_win_w > pni->screen_w) ? 0 :
745          ((pni->screen_w-pni->base_win_w)>>1);
746    base_win_y = (pni->base_win_h > pni->screen_h) ? 0 :
747          ((pni->screen_h-pni->base_win_h)/3);
748 
749    if ((pni->base_win=XCreateSimpleWindow(mainDisplay, rootWindow,
750          base_win_x, base_win_y, pni->base_win_w, pni->base_win_h,
751          brdrW, myBorderPixel, bg_pixel)) == 0) {
752       return FailToCreateWindowMessage("CreateNamesWindows()", NULL, FALSE);
753    }
754    XDefineCursor(mainDisplay, pni->base_win, defaultCursor);
755 
756    y = (ROW_HEIGHT<<2)+pni->title_h;
757    if ((pni->dsp_base_win=XCreateSimpleWindow(mainDisplay, pni->base_win,
758          pni->graph_start, y, pni->dsp_base_win_w, pni->dsp_base_win_h,
759          0, myBorderPixel, bg_pixel)) == 0) {
760       XDestroyWindow(mainDisplay, pni->base_win);
761       return FailToCreateWindowMessage("CreateNamesWindows()", NULL, FALSE);
762    }
763    if ((pni->dsp_win=XCreateSimpleWindow(mainDisplay, pni->dsp_base_win,
764          windowPadding, windowPadding, pni->dsp_area_w, pni->dsp_area_h,
765          brdrW, myBorderPixel, bg_pixel)) == 0) {
766       XDestroyWindow(mainDisplay, pni->base_win);
767       return FailToCreateWindowMessage("CreateNamesWindows()", NULL, FALSE);
768    }
769    if ((pni->scroll_win=XCreateSimpleWindow(mainDisplay,
770          pni->dsp_base_win, windowPadding+pni->dsp_area_w+(brdrW<<1),
771          windowPadding, scrollBarW, pni->dsp_area_h,
772          brdrW, myBorderPixel, bg_pixel)) == 0) {
773       XDestroyWindow(mainDisplay, pni->base_win);
774       return FailToCreateWindowMessage("CreateNamesWindows()", NULL, FALSE);
775    }
776    win_attrs.save_under = True;
777    win_attrs.colormap = mainColormap;
778    XChangeWindowAttributes(mainDisplay, pni->base_win,
779          CWSaveUnder | CWColormap, &win_attrs);
780 
781    wmhints.flags = InputHint | StateHint;
782    wmhints.input = True;
783    wmhints.initial_state = NormalState;
784    XSetWMHints(mainDisplay, pni->base_win, &wmhints);
785 
786    sizehints.flags = PPosition | PSize | USPosition | PMinSize | PMaxSize;
787    sizehints.x = base_win_x;
788    sizehints.y = base_win_y;
789    sizehints.width = sizehints.min_width = sizehints.max_width =
790          pni->base_win_w;
791    sizehints.height = sizehints.min_height = sizehints.max_height =
792          pni->base_win_h;
793 #ifdef NOTR4MODE
794    XSetNormalHints(mainDisplay, pni->base_win, &sizehints);
795 #else
796    XSetWMNormalHints(mainDisplay, pni->base_win, &sizehints);
797 #endif
798    RegisterWM_DELETE_WINDOW(pni->base_win);
799    XStoreName(mainDisplay, pni->base_win, win_name);
800 
801    XSetTransientForHint(mainDisplay, pni->base_win, mainWindow);
802 
803 #ifdef MAPBEFORESELECT
804    XMapWindow(mainDisplay, pni->base_win);
805    XSelectInput(mainDisplay, pni->base_win,
806          KeyPressMask | ButtonPressMask | ExposureMask | StructureNotifyMask);
807    XMapWindow(mainDisplay, pni->dsp_base_win);
808    XSelectInput(mainDisplay, pni->dsp_base_win, ExposureMask);
809    XMapWindow(mainDisplay, pni->dsp_win);
810    XSelectInput(mainDisplay, pni->dsp_win,
811          KeyPressMask | ButtonPressMask | ExposureMask);
812    XMapWindow(mainDisplay, pni->scroll_win);
813    XSelectInput(mainDisplay, pni->scroll_win,
814          KeyPressMask | ButtonPressMask | ExposureMask);
815 #else
816    XSelectInput(mainDisplay, pni->base_win,
817          KeyPressMask | ButtonPressMask | ExposureMask | StructureNotifyMask);
818    XMapWindow(mainDisplay, pni->base_win);
819    XSelectInput(mainDisplay, pni->dsp_base_win, ExposureMask);
820    XMapWindow(mainDisplay, pni->dsp_base_win);
821    XSelectInput(mainDisplay, pni->dsp_win,
822          KeyPressMask | ButtonPressMask | ExposureMask);
823    XMapWindow(mainDisplay, pni->dsp_win);
824    XSelectInput(mainDisplay, pni->scroll_win,
825          KeyPressMask | ButtonPressMask | ExposureMask);
826    XMapWindow(mainDisplay, pni->scroll_win);
827 #endif
828 
829    if (warpToWinCenter) {
830       XWarpPointer(mainDisplay, None, pni->base_win, 0, 0, 0, 0,
831             (pni->base_win_w>>1), (pni->base_win_h>>1));
832    }
833    XSync(mainDisplay, False);
834 
835    Msg("");
836 
837    return TRUE;
838 }
839 
840 static
NamesUpdateIndices()841 void NamesUpdateIndices()
842 {
843    struct NamesRec *pni=(&namesInfo);
844 
845    pni->first_index = 0;
846    if (pni->marked_index == INVALID) {
847       if (pni->edit_style != NAMES_SELECT_FILE) {
848          *pni->inbuf = '\0';
849          pni->buf_index = 0;
850       }
851    } else {
852       if (pni->marked_index >= ITEM_DSPED) {
853          if (pni->marked_index < pni->num_entries-ITEM_DSPED) {
854             pni->first_index = pni->marked_index;
855          } else {
856             pni->first_index = pni->num_entries-ITEM_DSPED;
857          }
858       }
859       if (pni->edit_style != NAMES_SELECT_FILE) {
860          strcpy(pni->inbuf, &(pni->entries[pni->marked_index])[pni->leading]);
861          pni->buf_index = strlen(pni->inbuf);;
862       }
863    }
864 }
865 
866 static
IsFirstEqChar(s,index)867 int IsFirstEqChar(s, index)
868    char *s;
869    int index;
870 {
871    s = (&s[index]);
872    if (*s != '=') return FALSE;
873    for (--index, --s; index >= 0; index--, s--) {
874       if (*s == '=') {
875          return FALSE;
876       }
877    }
878    return TRUE;
879 }
880 
881 static
SetMarkedIndex()882 int SetMarkedIndex()
883 {
884    struct NamesRec *pni=(&namesInfo);
885    int i;
886 
887    if (*pni->name == '\0') return FALSE;
888    for (i=0; i < pni->num_entries; i++) {
889       if (strncmp(&(pni->entries[i])[pni->leading],
890             pni->name, pni->name_index) == 0) {
891          break;
892       }
893    }
894    if (i < pni->num_entries) {
895       if (i < pni->first_index) {
896          pni->first_index = i;
897       } else if (i >= pni->first_index+ITEM_DSPED) {
898          if (i < pni->num_entries-ITEM_DSPED) {
899             pni->first_index = i;
900          } else {
901             pni->first_index = pni->num_entries-ITEM_DSPED;
902          }
903       }
904       pni->marked_index = i;
905       return TRUE;
906    } else {
907       return FALSE;
908    }
909 }
910 
911 static
BackSpaceInNames(pn_changing,pn_selected_btn_index)912 void BackSpaceInNames(pn_changing, pn_selected_btn_index)
913    int *pn_changing, *pn_selected_btn_index;
914 {
915    struct NamesRec *pni=(&namesInfo);
916    int i;
917 
918    switch (pni->edit_style) {
919    case NAMES_SIMPLE_SELECT_NAME: return;
920    case NAMES_COMPLEX_SELECT_NAME:
921       if (pni->marked_index == INVALID || pni->buf_index <= 0) return;
922       pni->inbuf[--pni->buf_index] = '\0';
923       if (pni->buf_index != 0) {
924          int i;
925 
926          for (i=0; i < pni->num_entries; i++) {
927             if (strncmp(&(pni->entries[i])[pni->leading],
928                   pni->inbuf, pni->buf_index) == 0) {
929                break;
930             }
931          }
932          if (i < pni->num_entries) {
933             if (i < pni->first_index) {
934                pni->first_index = i;
935             } else if (i >= pni->first_index+ITEM_DSPED) {
936                if (i < pni->num_entries-ITEM_DSPED) {
937                   pni->first_index = i;
938                } else {
939                   pni->first_index = pni->num_entries-ITEM_DSPED;
940                }
941             }
942             pni->marked_index = i;
943          }
944       } else {
945          pni->first_index = 0;
946          pni->marked_index = INVALID;
947       }
948       break;
949    case NAMES_SELECT_FILE:
950       if (pni->name_index > 0) {
951          pni->name[--pni->name_index] = '\0';
952          sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
953          pni->buf_index = strlen(pni->inbuf);
954          if (pni->tabbed_from_root && pni->name_index != 0) {
955             for (i=0; i < pni->num_entries; i++) {
956                if (strncmp(&(pni->entries[i])[pni->leading],
957                      pni->name, pni->name_index) == 0) {
958                   pni->marked_index = i;
959                   break;
960                }
961             }
962          } else {
963             pni->marked_index = INVALID;
964          }
965       } else if (pni->change_to_root && *pni->dir_name == '\0' &&
966             *pni->saved_dir_name != '\0') {
967          pni->pop_from_root = TRUE;
968          strcpy(pni->dir_name, pni->saved_dir_name);
969          *pni->saved_dir_name = '\0';
970          pni->tabbed_from_root = TRUE;
971          pni->change_to_root = FALSE;
972          sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
973          pni->buf_index = strlen(pni->inbuf);
974          *pn_changing = FALSE;
975          *pn_selected_btn_index = INVALID;
976       } else {
977          /* fake as if "../" is selected */
978          sprintf(pni->name, "..%c", DIR_SEP);
979          pni->name_index = strlen(pni->name);
980          for (i=0; i < pni->num_entries; i++) {
981             if (strncmp(&(pni->entries[i])[pni->leading],
982                   pni->name, pni->name_index) == 0) {
983                pni->marked_index = i;
984                pni->faking_dot_dot = TRUE;
985                *pn_changing = FALSE;
986                *pn_selected_btn_index = i;
987                break;
988             }
989          }
990       }
991       break;
992    case NAMES_EDIT_ATTR:
993       if (pni->marked_index == INVALID || pni->buf_index <= 0) return;
994       if (pni->dsp_ptr == NULL ||
995             !pni->dsp_ptr[pni->marked_index].directory ||
996             !IsFirstEqChar(pni->inbuf, pni->buf_index-1)) {
997          pni->inbuf[--pni->buf_index] = '\0';
998          strcpy(&(pni->entries[pni->marked_index])[pni->leading],
999                pni->inbuf);
1000       }
1001       break;
1002    case NAMES_EDIT_NAME:
1003       if (pni->marked_index == INVALID || pni->buf_index <= 0) return;
1004       pni->inbuf[--pni->buf_index] = '\0';
1005       strcpy(&(pni->entries[pni->marked_index])[pni->leading],
1006             pni->inbuf);
1007       break;
1008    default: break;
1009    }
1010    if (pni->exposed) {
1011       RedrawNamePath();
1012       RedrawDspWindow();
1013    }
1014 }
1015 
1016 static
ParseFileName(FullName,DirName,Name)1017 void ParseFileName(FullName, DirName, Name)
1018    char *FullName, *DirName, *Name;
1019 {
1020    int i, len;
1021 
1022    len = strlen(FullName);
1023    strcpy(DirName, FullName);
1024    for (i=len-1; i>=0; i--) {
1025       if (DirName[i] == DIR_SEP) {
1026          strcpy(Name, &(DirName[i+1]));
1027          DirName[i] = '\0';
1028          return;
1029       }
1030    }
1031    *DirName = *Name = '\0';
1032 }
1033 
1034 static
TabInNames()1035 void TabInNames()
1036 {
1037    struct NamesRec *pni=(&namesInfo);
1038 
1039    if (pni->edit_style == NAMES_SELECT_FILE) {
1040       pni->tabbed_from_root = TRUE;
1041       pni->just_tabbed_from_root = TRUE;
1042       if (!FileIsRemote(pni->name)) {
1043          /* saved_name is used for just_tabbed_from_root */
1044          sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
1045          pni->buf_index = strlen(pni->inbuf);
1046          strcpy(pni->saved_name, pni->name);
1047          ParseFileName(pni->inbuf, pni->dir_name, pni->name);
1048       } else {
1049          pni->remote_file = TRUE;
1050       }
1051    }
1052 }
1053 
1054 static
CharInNames(buf,pn_changing,pn_selected_btn_index)1055 void CharInNames(buf, pn_changing, pn_selected_btn_index)
1056    char *buf;
1057    int *pn_changing, *pn_selected_btn_index;
1058 {
1059    struct NamesRec *pni=(&namesInfo);
1060    int i=INVALID;
1061 
1062    switch (pni->edit_style) {
1063    case NAMES_SIMPLE_SELECT_NAME:
1064       if (buf[0] == ' ' && buf[1] == '\0' &&
1065             pni->p_check_array != NULL && pni->p_check_array->num_cols == 1) {
1066          i = pni->marked_index;
1067          pni->p_check_array->value[0][i] = !(pni->p_check_array->value[0][i]);
1068          RedrawItem(pni, i);
1069       }
1070       return;
1071 
1072    case NAMES_COMPLEX_SELECT_NAME:
1073       if (buf[0] == '$') {
1074          i = pni->num_entries-1;
1075          strcpy(pni->inbuf, &(pni->entries[i])[pni->leading]);
1076       } else if (buf[0] == '^') {
1077          i = 0;
1078          strcpy(pni->inbuf, &(pni->entries[i])[pni->leading]);
1079       } else {
1080          pni->inbuf[pni->buf_index++] = buf[0];
1081          pni->inbuf[pni->buf_index] = '\0';
1082          for (i=0; i < pni->num_entries; i++) {
1083             if (strncmp(&(pni->entries[i])[pni->leading],
1084                   pni->inbuf, pni->buf_index) == 0) {
1085                break;
1086             }
1087          }
1088       }
1089       if (i < pni->num_entries) {
1090          if (i < pni->first_index) {
1091             pni->first_index = i;
1092          } else if (i >= pni->first_index+ITEM_DSPED) {
1093             if (i < pni->num_entries-ITEM_DSPED) {
1094                pni->first_index = i;
1095             } else {
1096                pni->first_index = pni->num_entries-ITEM_DSPED;
1097             }
1098          }
1099          pni->marked_index = i;
1100       } else {
1101          pni->inbuf[--pni->buf_index] = '\0';
1102       }
1103       break;
1104    case NAMES_SELECT_FILE:
1105       if (!pni->tabbed_from_root) {
1106          pni->name[pni->name_index++] = buf[0];
1107          pni->name[pni->name_index] = '\0';
1108          sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
1109          pni->buf_index = strlen(pni->inbuf);
1110       } else if (buf[0] == '$') {
1111          i = pni->num_entries-1;
1112          strcpy(pni->name, &(pni->entries[i])[pni->leading]);
1113          pni->name_index = strlen(pni->name);
1114       } else if (buf[0] == '^') {
1115          i = 0;
1116          strcpy(pni->name, &(pni->entries[i])[pni->leading]);
1117          pni->name_index = strlen(pni->name);
1118 #ifdef apollo
1119       } else if (pni->name_index == 0 && buf[0] == DIR_SEP &&
1120             *pni->dir_name == '\0') {
1121          strcpy(pni->dir_name, DIR_SEP_STR);
1122          pni->name[pni->name_index++] = buf[0];
1123          i = pni->num_entries;
1124          strcpy(pni->inbuf, "//");
1125 #endif /* apollo */
1126       } else if (pni->name_index == 0 && buf[0] == DIR_SEP) {
1127          if (*pni->saved_dir_name == '\0') {
1128             strcpy(pni->saved_dir_name, pni->dir_name);
1129             pni->num_entries = 0;
1130          }
1131          *pn_changing = FALSE;
1132          pni->change_to_root = TRUE;
1133          pni->tabbed_from_root = FALSE;
1134          *pn_selected_btn_index = INVALID;
1135          *pni->dir_name = *pni->name = '\0';
1136          pni->name_index = 0;
1137          sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
1138          pni->buf_index = strlen(pni->inbuf);
1139          break;
1140       } else {
1141          pni->name[pni->name_index++] = buf[0];
1142          pni->name[pni->name_index] = '\0';
1143          for (i=0; i < pni->num_entries; i++) {
1144             if (strncmp(&(pni->entries[i])[pni->leading],
1145                   pni->name, pni->name_index) == 0) {
1146                break;
1147             }
1148          }
1149       }
1150       if (pni->num_entries > 0) {
1151          if (i < pni->num_entries) {
1152             if (i < pni->first_index) {
1153                pni->first_index = i;
1154             } else if (i >= pni->first_index+ITEM_DSPED) {
1155                if (i < pni->num_entries-ITEM_DSPED) {
1156                   pni->first_index = i;
1157                } else {
1158                   pni->first_index = pni->num_entries-ITEM_DSPED;
1159                }
1160             }
1161             pni->marked_index = i;
1162             sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
1163             pni->buf_index = strlen(pni->inbuf);
1164             if (buf[0] == DIR_SEP) {
1165                *pn_changing = FALSE;
1166                *pn_selected_btn_index = INVALID;
1167             }
1168          } else {
1169             pni->name[--pni->name_index] = '\0';
1170          }
1171       }
1172       break;
1173    case NAMES_EDIT_ATTR:
1174       if (pni->marked_index == INVALID) return;
1175       pni->inbuf[pni->buf_index++] = buf[0];
1176       pni->inbuf[pni->buf_index] = '\0';
1177       strcpy(&(pni->entries[pni->marked_index])[pni->leading],
1178             pni->inbuf);
1179       break;
1180    case NAMES_EDIT_NAME:
1181       if (pni->marked_index == INVALID) return;
1182       pni->inbuf[pni->buf_index++] = buf[0];
1183       pni->inbuf[pni->buf_index] = '\0';
1184       strcpy(&(pni->entries[pni->marked_index])[pni->leading],
1185             pni->inbuf);
1186       break;
1187    default: break;
1188    }
1189    if (pni->exposed) {
1190       RedrawNamePath();
1191       RedrawDspWindow();
1192    }
1193 }
1194 
1195 static
GetNameEntryNum(RowOffset)1196 int GetNameEntryNum(RowOffset)
1197    int RowOffset;
1198 {
1199    struct NamesRec *pni=(&namesInfo);
1200    int index;
1201 
1202    index = pni->first_index + RowOffset;
1203    if (index >= pni->num_entries) return INVALID;
1204    return index;
1205 }
1206 
1207 static
ScrollItemCallback(pv_userdata)1208 int ScrollItemCallback(pv_userdata)
1209    void *pv_userdata;
1210    /* returns TRUE to cancel scrolling */
1211 {
1212    struct NamesRec *pni=((struct NamesRec *)pv_userdata);
1213 
1214    if (pni->scroll_dir == SCRL_UP) {
1215       if (pni->first_index == 0) return FALSE;
1216       pni->first_index--;
1217    } else {
1218       if (pni->num_entries <= ITEM_DSPED ||
1219             pni->first_index+ITEM_DSPED == pni->num_entries) {
1220          return FALSE;
1221       }
1222       pni->first_index++;
1223    }
1224    RedrawNameScrollWin();
1225    RedrawDspWindow();
1226    XSync(mainDisplay, False);
1227 
1228    return FALSE;
1229 }
1230 
1231 static
ScrollPageCallback(pv_userdata)1232 int ScrollPageCallback(pv_userdata)
1233    void *pv_userdata;
1234    /* returns TRUE to cancel scrolling */
1235 {
1236    struct NamesRec *pni=((struct NamesRec *)pv_userdata);
1237 
1238    if (pni->scroll_dir == SCRL_UP) {
1239       if (pni->first_index == 0) return FALSE;
1240       pni->first_index -= ITEM_DSPED;
1241       if (pni->first_index < 0) pni->first_index = 0;
1242    } else {
1243       if (pni->num_entries <= ITEM_DSPED ||
1244             pni->first_index+ITEM_DSPED == pni->num_entries) {
1245          return FALSE;
1246       }
1247       pni->first_index += ITEM_DSPED;
1248       if (pni->first_index+ITEM_DSPED >= pni->num_entries) {
1249          pni->first_index = pni->num_entries-ITEM_DSPED;
1250       }
1251    }
1252    RedrawNameScrollWin();
1253    RedrawDspWindow();
1254    XSync(mainDisplay, False);
1255 
1256    return FALSE;
1257 }
1258 
1259 static
DoNameBtnScroll(scroll_page,scroll_dir,pbbox,pni)1260 int DoNameBtnScroll(scroll_page, scroll_dir, pbbox, pni)
1261    int scroll_page, scroll_dir;
1262    struct BBRec *pbbox;
1263    struct NamesRec *pni;
1264    /* returns TRUE if done scrolling */
1265 {
1266    ScrollBtnCallbackInfo sbci;
1267 
1268    pni->scroll_dir = scroll_dir;
1269    memset(&sbci, 0, sizeof(ScrollBtnCallbackInfo));
1270 
1271    if (scroll_page) {
1272       sbci.ms = 200;
1273       sbci.pv_userdata = pni;
1274       sbci.pf_scroll_btn_callback = ScrollPageCallback;
1275       if (TgPressButtonLoop(mainDisplay, pni->scroll_win, NULL,
1276             &sbci)) {
1277          if (scroll_dir == SCRL_UP) {
1278             if (pni->first_index == 0) return TRUE;
1279             pni->first_index -= ITEM_DSPED;
1280             if (pni->first_index < 0) pni->first_index = 0;
1281          } else {
1282             if (pni->num_entries <= ITEM_DSPED ||
1283                   pni->first_index+ITEM_DSPED == pni->num_entries) {
1284                return TRUE;
1285             }
1286             pni->first_index += ITEM_DSPED;
1287             if (pni->first_index+ITEM_DSPED >= pni->num_entries) {
1288                pni->first_index = pni->num_entries-ITEM_DSPED;
1289             }
1290          }
1291       }
1292    } else {
1293       sbci.ms = 50;
1294       sbci.pv_userdata = pni;
1295       sbci.pf_scroll_btn_callback = ScrollItemCallback;
1296       if (TgPressButtonLoop(mainDisplay, pni->scroll_win, pbbox, &sbci)) {
1297          if (scroll_dir == SCRL_UP) {
1298             if (pni->first_index == 0) return TRUE;
1299             pni->first_index--;
1300          } else {
1301             if (pni->num_entries <= ITEM_DSPED ||
1302                   pni->first_index+ITEM_DSPED == pni->num_entries) {
1303                return TRUE;
1304             }
1305             pni->first_index++;
1306          }
1307       }
1308    }
1309    return FALSE;
1310 }
1311 
1312 static
NameScrollHandler(button_ev)1313 void NameScrollHandler(button_ev)
1314    XButtonEvent *button_ev;
1315 {
1316    struct NamesRec *pni=(&namesInfo);
1317    double frac, start_frac;
1318    int block_h, block_start, do_drag=FALSE, btn_offset=0;
1319 
1320    if (!threeDLook && button_ev->button == Button3 &&
1321          button_ev->type == ButtonPress) {
1322       if (DoNameBtnScroll(((button_ev->state & (ShiftMask|ControlMask)) != 0),
1323             SCRL_UP, NULL, pni)) {
1324          return;
1325       }
1326    } else if (!threeDLook && button_ev->button == Button1 &&
1327          button_ev->type == ButtonPress) {
1328       if (DoNameBtnScroll(((button_ev->state & (ShiftMask|ControlMask)) != 0),
1329             SCRL_DN, NULL, pni)) {
1330          return;
1331       }
1332    } else if (button_ev->button == Button1 && button_ev->type == ButtonPress) {
1333       if (button_ev->y < scrollBarW ||
1334             button_ev->y >= pni->scroll_area_h-scrollBarW) {
1335          int which=INVALID;
1336          struct BBRec bbox;
1337 
1338          if (button_ev->y < scrollBarW) {
1339             which = SCRL_UP;
1340             SetBBRec(&bbox, 0, 0, scrollBarW, scrollBarW);
1341          } else {
1342             which = SCRL_DN;
1343             SetBBRec(&bbox, 0, pni->scroll_area_h-scrollBarW, scrollBarW,
1344                   pni->scroll_area_h);
1345          }
1346          if (DoNameBtnScroll(FALSE, which, &bbox, pni)) {
1347             return;
1348          }
1349       } else {
1350          int hit=0;
1351 
1352          start_frac = (pni->num_entries > 0) ?
1353                (double)((double)(pni->first_index) /
1354                (double)(pni->num_entries)) : ((double)0.0);
1355          hit = TgGetScrollHit(button_ev->x, button_ev->y, VERT_SCROLLBAR,
1356                scrollBarW, pni->scroll_area_h, start_frac, ITEM_DSPED,
1357                pni->num_entries, &btn_offset);
1358          if (hit == 0) {
1359             do_drag = TRUE;
1360          } else {
1361             if (DoNameBtnScroll(TRUE, (hit < 0 ? SCRL_UP : SCRL_DN), NULL,
1362                   pni)) {
1363                return;
1364             }
1365          }
1366       }
1367    } else if (!threeDLook && button_ev->button == Button2 &&
1368          button_ev->type == ButtonPress) {
1369       do_drag = TRUE;
1370    }
1371    if (do_drag) {
1372       int done=FALSE;
1373       XEvent ev;
1374 
1375       if (pni->num_entries <= ITEM_DSPED) return;
1376 
1377       frac = (double)((double)ITEM_DSPED / (double)(pni->num_entries));
1378       block_h = (int)(pni->scroll_area_h * frac);
1379       if (threeDLook) {
1380          block_start = button_ev->y+btn_offset;;
1381          start_frac = (double)((double)(block_start-scrollBarW) /
1382                (double)(pni->scroll_area_h-(scrollBarW<<1)));
1383          if (block_start+block_h >= pni->scroll_area_h-scrollBarW) {
1384             pni->first_index = pni->num_entries - ITEM_DSPED;
1385          } else {
1386             pni->first_index = (int)(pni->num_entries * start_frac);
1387          }
1388       } else {
1389          block_start = button_ev->y;
1390          start_frac = (double)((double)(block_start) /
1391                (double)(pni->scroll_area_h));
1392          if (block_start+block_h >= pni->scroll_area_h) {
1393             pni->first_index = pni->num_entries - ITEM_DSPED;
1394          } else {
1395             pni->first_index = (int)(pni->num_entries * start_frac);
1396          }
1397       }
1398       RedrawNameScrollWin();
1399       RedrawDspWindow();
1400 
1401       XGrabPointer(mainDisplay, pni->scroll_win, False,
1402             PointerMotionMask | ButtonReleaseMask, GrabModeAsync,
1403             GrabModeAsync, None, handCursor, CurrentTime);
1404 
1405       while (!done) {
1406          XNextEvent(mainDisplay, &ev);
1407 
1408          if (ev.type == Expose || ev.type == VisibilityNotify) {
1409             ExposeEventHandler(&ev, TRUE);
1410          } else if (ev.type == ButtonRelease) {
1411             XUngrabPointer(mainDisplay, CurrentTime);
1412             if (debugNoPointerGrab) XSync(mainDisplay, False);
1413             done = TRUE;
1414          } else if (ev.type == MotionNotify) {
1415             int new_name_first=0, y=ev.xmotion.y;
1416 
1417             if (threeDLook) {
1418                y += btn_offset;
1419                start_frac = (double)(((double)(y-scrollBarW)) /
1420                     ((double)(pni->scroll_area_h-(scrollBarW<<1))));
1421 
1422                if (y <= scrollBarW) {
1423                   new_name_first = 0;
1424                } else if (y+block_h >= pni->scroll_area_h-scrollBarW) {
1425                   new_name_first = pni->num_entries - ITEM_DSPED;
1426                } else {
1427                   new_name_first = (int)(pni->num_entries * start_frac);
1428                }
1429             } else {
1430                start_frac = (double)(((double)y) /
1431                     ((double)pni->scroll_area_h));
1432 
1433                if (y <= 0) {
1434                   new_name_first = 0;
1435                } else if (y+block_h >= pni->scroll_area_h) {
1436                   new_name_first = pni->num_entries - ITEM_DSPED;
1437                } else {
1438                   new_name_first = (int)(pni->num_entries * start_frac);
1439                }
1440             }
1441             if (pni->first_index != new_name_first) {
1442                pni->first_index = new_name_first;
1443                RedrawNameScrollWin();
1444                RedrawDspWindow();
1445             }
1446             while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1447          }
1448       }
1449       return;
1450    }
1451    RedrawNameScrollWin();
1452    RedrawDspWindow();
1453 }
1454 
1455 static
NameDspHandler(button_ev)1456 int NameDspHandler(button_ev)
1457    XButtonEvent *button_ev;
1458 {
1459    struct NamesRec *pni=(&namesInfo);
1460    static Time last_click_time;
1461    static int last_name_marked;
1462    Time click_time;
1463    int checkbox_cols=0, box_offset=0, clicked_col=INVALID, check_updated=FALSE;
1464 
1465    if (enableMouseWheel &&
1466          (button_ev->button == Button4 || button_ev->button == Button5)) {
1467       int which=INVALID;
1468       struct BBRec bbox;
1469 
1470       if (button_ev->button == Button4) {
1471          which = SCRL_UP;
1472          SetBBRec(&bbox, 0, 0, scrollBarW, scrollBarW);
1473       } else if (button_ev->button == Button5) {
1474          which = SCRL_DN;
1475          SetBBRec(&bbox, 0, pni->scroll_area_h-scrollBarW, scrollBarW,
1476                pni->scroll_area_h);
1477       }
1478       if (which != INVALID) {
1479          DoNameBtnScroll(FALSE, which, &bbox, pni);
1480          RedrawNameScrollWin();
1481          RedrawDspWindow();
1482       }
1483       return INVALID;
1484    } else if (button_ev->button != Button1) {
1485       return INVALID;
1486    }
1487    if (pni->p_check_array != NULL && pni->p_check_array->num_cols > 0) {
1488       checkbox_cols = pni->p_check_array->num_cols;
1489       box_offset = 1;
1490       if (button_ev->x < checkbox_cols*ROW_HEIGHT) {
1491          clicked_col = (int)(button_ev->x / ROW_HEIGHT);
1492       }
1493    }
1494    if (pni->marked_index != INVALID &&
1495          pni->marked_index >= pni->first_index &&
1496          pni->marked_index < pni->first_index+ITEM_DSPED) {
1497       int saved_index=pni->marked_index;
1498 
1499       pni->marked_index = INVALID;
1500       RedrawItem(pni, saved_index);
1501       pni->marked_index = saved_index;
1502    }
1503    pni->marked_index = GetNameEntryNum((int)(button_ev->y / ROW_HEIGHT));
1504    if (pni->marked_index != INVALID) {
1505       if (clicked_col != INVALID) {
1506          int i=pni->marked_index;
1507 
1508          pni->p_check_array->value[clicked_col][i] =
1509                !(pni->p_check_array->value[clicked_col][i]);
1510          if (pni->pf_check_update != NULL) {
1511             /*
1512              * check_udpated set to TRUE if the callback function calls
1513              *       SetStringStatus()
1514              */
1515             check_updated = (pni->pf_check_update)(&pni->dsp_ptr,
1516                   &pni->entries, &pni->num_entries,
1517                   &pni->marked_index, &pni->p_check_array, pni->inbuf,
1518                   clicked_col, i, pni->userdata);
1519          }
1520       }
1521       RedrawItem(pni, pni->marked_index);
1522    }
1523    click_time = button_ev->time;
1524    if (pni->just_clicked && pni->marked_index != INVALID &&
1525          last_name_marked == pni->marked_index &&
1526          (click_time-last_click_time) < doubleClickInterval) {
1527       return TRUE;
1528    }
1529    pni->just_clicked = TRUE;
1530    last_click_time = click_time;
1531    last_name_marked = pni->marked_index;
1532 
1533    if (!check_updated) {
1534       if (pni->dsp_ptr != NULL && pni->marked_index != INVALID) {
1535          SetStringStatus(pni->dsp_ptr[pni->marked_index].pathstr);
1536       } else {
1537          SetStringStatus("");
1538       }
1539    }
1540    return INVALID;
1541 }
1542 
1543 static
ControlChar(key_ev,key_sym)1544 int ControlChar(key_ev, key_sym)
1545    XKeyEvent *key_ev;
1546    KeySym key_sym;
1547 {
1548    register int i;
1549    struct NamesRec *pni=(&namesInfo);
1550 
1551    if (key_ev->state & ControlMask) {
1552       switch (key_sym) {
1553       case XK_Left: return (BAD);
1554       case XK_KP_Left: return (BAD);
1555       case XK_Up: key_sym = ((unsigned long)'b')&0xff; break;
1556       case XK_KP_Up: key_sym = ((unsigned long)'b')&0xff; break;
1557       case XK_Right: return (BAD);
1558       case XK_KP_Right: return (BAD);
1559       case XK_Down: key_sym = ((unsigned long)'f')&0xff; break;
1560       case XK_KP_Down: key_sym = ((unsigned long)'f')&0xff; break;
1561       case XK_Page_Up: key_sym = ((unsigned long)'b')&0xff; break;
1562       case XK_KP_Page_Up: key_sym = ((unsigned long)'b')&0xff; break;
1563       case XK_Page_Down: key_sym = ((unsigned long)'f')&0xff; break;
1564       case XK_KP_Page_Down: key_sym = ((unsigned long)'f')&0xff; break;
1565       }
1566    } else {
1567       switch (key_sym) {
1568       case XK_Left: return BAD;
1569       case XK_KP_Left: return BAD;
1570       case XK_Up: key_sym = ((unsigned long)'k')&0xff; break;
1571       case XK_KP_Up: key_sym = ((unsigned long)'k')&0xff; break;
1572       case XK_Right: return BAD;
1573       case XK_KP_Right: return BAD;
1574       case XK_Down: key_sym = ((unsigned long)'j')&0xff; break;
1575       case XK_KP_Down: key_sym = ((unsigned long)'j')&0xff; break;
1576       case XK_Page_Up: key_sym = ((unsigned long)'b')&0xff; break;
1577       case XK_KP_Page_Up: key_sym = ((unsigned long)'b')&0xff; break;
1578       case XK_Page_Down: key_sym = ((unsigned long)'f')&0xff; break;
1579       case XK_KP_Page_Down: key_sym = ((unsigned long)'f')&0xff; break;
1580       }
1581    }
1582    switch (key_sym&0xff) {
1583    case 'w': /* erase */
1584    case 'y':
1585       return INVALID;
1586    case 'n': /* down one */
1587    case 'j':
1588       i = (pni->marked_index < pni->num_entries-1) ?
1589             pni->marked_index+1 : pni->num_entries-1;
1590       break;
1591    case 'p': /* up one */
1592    case 'k':
1593       i = (pni->marked_index>0) ? pni->marked_index-1 : 0;
1594       break;
1595    case 'd': /* down one page */
1596    case 'f':
1597       if (pni->marked_index==INVALID) {
1598          i = (pni->num_entries <= ITEM_DSPED) ?
1599                pni->num_entries-1 : ITEM_DSPED;
1600       } else if (pni->marked_index < pni->num_entries-ITEM_DSPED) {
1601          i = pni->marked_index+ITEM_DSPED;
1602       } else {
1603          i = pni->num_entries-1;
1604       }
1605       break;
1606    case 'u': /* up one page */
1607    case 'b':
1608       i = (pni->marked_index > (ITEM_DSPED-1)) ?
1609             pni->marked_index-ITEM_DSPED : 0;
1610       break;
1611    default: return BAD;
1612    }
1613    return i;
1614 }
1615 
1616 static
BackUpOneWord(pn_changing,pn_selected_btn_index)1617 void BackUpOneWord(pn_changing, pn_selected_btn_index)
1618    int *pn_changing, *pn_selected_btn_index;
1619 {
1620    struct NamesRec *pni=(&namesInfo);
1621    int new_dir=FALSE;
1622 
1623    if (pni->buf_index == 0) return;
1624 
1625    if (pni->inbuf[pni->buf_index-1] == DIR_SEP) {
1626       pni->inbuf[--pni->buf_index] = '\0';
1627       new_dir = TRUE;
1628    } else {
1629       while (pni->buf_index > 0) {
1630          if (pni->inbuf[(pni->buf_index)-1] == DIR_SEP) {
1631             pni->inbuf[pni->buf_index] = '\0';
1632             break;
1633          } else {
1634             pni->buf_index--;
1635          }
1636       }
1637       pni->inbuf[pni->buf_index] = '\0';
1638    }
1639    ParseFileName(pni->inbuf, pni->dir_name, pni->name);
1640    if (new_dir) {
1641       int i;
1642 
1643       sprintf(pni->name, "..%c", DIR_SEP);
1644       pni->name_index = strlen(pni->name);
1645       for (i=0; i < pni->num_entries; i++) {
1646          if (strncmp(&(pni->entries[i])[pni->leading],
1647                pni->name, pni->name_index) == 0) {
1648             pni->marked_index = i;
1649             pni->faking_dot_dot = TRUE;
1650             *pn_changing = FALSE;
1651             *pn_selected_btn_index = i;
1652             break;
1653          }
1654       }
1655    } else {
1656       pni->first_index = 0;
1657       pni->marked_index = INVALID;
1658    }
1659 }
1660 
1661 static
SpecialKeyInNames(key_ev,key_sym,pn_changing,pn_selected_btn_index)1662 void SpecialKeyInNames(key_ev, key_sym, pn_changing, pn_selected_btn_index)
1663    XKeyEvent *key_ev;
1664    KeySym key_sym;
1665    int *pn_changing, *pn_selected_btn_index;
1666 {
1667    struct NamesRec *pni=(&namesInfo);
1668    int i=ControlChar(key_ev, key_sym);
1669 
1670    if (i == BAD) return;
1671 
1672    if (i == INVALID) {
1673       if (pni->edit_style == NAMES_SELECT_FILE) {
1674          /* back-up one word */
1675          BackUpOneWord(pn_changing, pn_selected_btn_index);
1676          sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
1677          pni->buf_index = strlen(pni->inbuf);
1678       } else {
1679          *pni->inbuf = '\0';
1680          pni->buf_index = 0;
1681          pni->first_index = 0;
1682          pni->marked_index = INVALID;
1683       }
1684    } else if (i < pni->num_entries) {
1685       if (pni->edit_style == NAMES_SELECT_FILE) {
1686          strcpy(pni->name, &(pni->entries[i])[pni->leading]);
1687          pni->name_index = strlen(pni->name);
1688          sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
1689          pni->buf_index = strlen(pni->inbuf);
1690       } else {
1691          strcpy(pni->inbuf, &(pni->entries[i])[pni->leading]);
1692          pni->buf_index = strlen(pni->inbuf);
1693       }
1694       if (i < pni->first_index) {
1695          pni->first_index = i;
1696       } else if (i >= pni->first_index+ITEM_DSPED) {
1697          if (i < pni->num_entries-ITEM_DSPED) {
1698             pni->first_index = i;
1699          } else {
1700             pni->first_index = pni->num_entries-ITEM_DSPED;
1701          }
1702       }
1703       pni->marked_index = i;
1704    }
1705    if (pni->exposed) {
1706       RedrawNamePath();
1707       RedrawNameScrollWin();
1708       RedrawDspWindow();
1709       RedrawDspBaseWindow();
1710    }
1711    if (pni->dsp_ptr != NULL && pni->marked_index != INVALID) {
1712       SetStringStatus(pni->dsp_ptr[pni->marked_index].pathstr);
1713    } else {
1714       SetStringStatus("");
1715    }
1716 }
1717 
1718 static
GetBtnIndexFromBtnId(btn_id)1719 int GetBtnIndexFromBtnId(btn_id)
1720    int btn_id;
1721 {
1722    struct NamesRec *pni=(&namesInfo);
1723    int i;
1724 
1725    for (i=0; i < pni->num_btns; i++) {
1726       if (pni->btn_id[i] == btn_id) {
1727          return i;
1728       }
1729    }
1730 #ifdef _TGIF_DBG /* debug, do not translate */
1731    sprintf(gszMsgBox, "Programing error!\n\nCannot find a button with id=%1d.",
1732          btn_id);
1733    MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1734 #endif /* _TGIF_DBG */
1735    return INVALID;
1736 }
1737 
1738 static
KeyPressInNames(key_ev,pn_changing,pn_selected_btn_index)1739 void KeyPressInNames(key_ev, pn_changing, pn_selected_btn_index)
1740    XKeyEvent *key_ev;
1741    int *pn_changing, *pn_selected_btn_index;
1742 {
1743    struct NamesRec *pni=(&namesInfo);
1744    char buf[80];
1745    KeySym key_sym;
1746    int has_ch;
1747 
1748    has_ch = XLookupString(key_ev, buf, sizeof(buf), &key_sym, &c_stat);
1749    TranslateKeys(buf, &key_sym);
1750 
1751    if ((key_ev->state & ControlMask) && key_sym == XK_j) {
1752       SpecialKeyInNames(key_ev, key_sym, pn_changing, pn_selected_btn_index);
1753    } else if (CharIsCRorLF(key_ev, buf, key_sym, &has_ch)) {
1754       if (pni->edit_style == NAMES_SELECT_FILE) {
1755          if (!pni->tabbed_from_root) {
1756             TabInNames();
1757          }
1758          *pn_changing = FALSE;
1759          *pn_selected_btn_index = GetBtnIndexFromBtnId(pni->def_btn_id);
1760       } else {
1761          if (pni->def_btn_id != INVALID) {
1762             *pn_changing = FALSE;
1763             *pn_selected_btn_index = GetBtnIndexFromBtnId(pni->def_btn_id);
1764          }
1765       }
1766    } else if (CharIsESC(key_ev, buf, key_sym, &has_ch)) {
1767       *pn_changing = FALSE;
1768       *pn_selected_btn_index = GetBtnIndexFromBtnId(BUTTON_CANCEL);
1769    } else if (CharIsBSorDEL(key_ev, buf, key_sym, &has_ch, FALSE)) {
1770       if (pni->edit_style == NAMES_SELECT_FILE &&
1771             (pni->faking_dot_dot || pni->pop_from_root)) {
1772          *pn_changing = FALSE;
1773          *pn_selected_btn_index = INVALID;
1774       } else {
1775          BackSpaceInNames(pn_changing, pn_selected_btn_index);
1776       }
1777    } else if (CharIsTAB(key_ev, buf, key_sym, &has_ch)) {
1778       if (pni->edit_style == NAMES_SELECT_FILE && pni->change_to_root) {
1779          TabInNames();
1780          *pn_changing = FALSE;
1781          *pn_selected_btn_index = INVALID;
1782       }
1783    } else if ((!pni->tabbed_from_root || pni->num_entries != 0) &&
1784          ((key_sym>'\040' && key_sym<='\177' &&
1785          (key_ev->state & ControlMask)) || key_sym==XK_Up ||
1786          key_sym==XK_Down || key_sym==XK_KP_Up || key_sym==XK_KP_Down ||
1787          key_sym==XK_Page_Up || key_sym==XK_KP_Page_Up ||
1788          key_sym==XK_Page_Down || key_sym==XK_KP_Page_Down)) {
1789       SpecialKeyInNames(key_ev, key_sym, pn_changing, pn_selected_btn_index);
1790    } else if (key_sym>='\040' && key_sym<='\177' &&
1791          (!pni->tabbed_from_root || pni->num_entries != 0)) {
1792       CharInNames(buf, pn_changing, pn_selected_btn_index);
1793    }
1794 }
1795 
1796 static
ButtonPressInPath(button_ev)1797 void ButtonPressInPath(button_ev)
1798    XButtonEvent *button_ev;
1799 {
1800    struct NamesRec *pni=(&namesInfo);
1801 
1802    if (button_ev->button == Button1) {
1803    } else if (button_ev->button == Button2) {
1804       int buf_len=0, from_selection=FALSE;
1805       char *cut_buffer=NULL;
1806 
1807       switch (pni->edit_style) {
1808       case NAMES_SIMPLE_SELECT_NAME: return;
1809       case NAMES_COMPLEX_SELECT_NAME: return;
1810       case NAMES_SELECT_FILE:
1811          if (pni->tabbed_from_root) return;
1812          break;
1813       case NAMES_EDIT_ATTR: break;
1814       case NAMES_EDIT_NAME: break;
1815       }
1816       cut_buffer = FetchSelectionOrCutBuffer(&buf_len, &from_selection);
1817       if (cut_buffer != NULL) {
1818          char *c_ptr=cut_buffer;
1819          int max_len;
1820 
1821          if (pni->edit_style == NAMES_SELECT_FILE) {
1822             max_len = sizeof(pni->inbuf)-strlen(pni->dir_name)-3;
1823             while (pni->name_index < max_len &&
1824                   *c_ptr >= '\040' && *c_ptr < '\177') {
1825                pni->name[pni->name_index++] = (*c_ptr++);
1826             }
1827             pni->name[pni->name_index] = '\0';
1828             sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
1829             pni->buf_index = strlen(pni->inbuf);
1830          } else {
1831             max_len = sizeof(pni->inbuf)-strlen(pni->inbuf)-3;
1832             while (pni->buf_index < max_len &&
1833                   *c_ptr >= '\040' && *c_ptr < '\177') {
1834                pni->inbuf[pni->buf_index++] = (*c_ptr++);
1835             }
1836             pni->inbuf[pni->buf_index] = '\0';
1837             strcpy(&(pni->entries[pni->marked_index])[pni->leading],
1838                   pni->inbuf);
1839          }
1840          if (pni->exposed) {
1841             RedrawNamePath();
1842             RedrawDspWindow();
1843          }
1844          FreeSelectionOrCutBuffer(cut_buffer, from_selection);
1845       }
1846    } else if (button_ev->button == Button3) {
1847    }
1848 }
1849 
1850 static
ButtonPressInNames(button_ev,pn_changing,pn_selected_btn_index)1851 void ButtonPressInNames(button_ev, pn_changing, pn_selected_btn_index)
1852    XButtonEvent *button_ev;
1853    int *pn_changing, *pn_selected_btn_index;
1854 {
1855    struct NamesRec *pni=(&namesInfo);
1856 
1857    if (button_ev->window == pni->base_win) {
1858       int i;
1859 
1860       if (PointInBBox(button_ev->x, button_ev->y, pni->path_bbox)) {
1861          ButtonPressInPath(button_ev);
1862       } else {
1863          for (i=0; i < pni->num_btns; i++) {
1864             if (PointInBBox(button_ev->x, button_ev->y,
1865                   pni->btn_bbox[i])) {
1866                struct BBRec *bbox=(&(pni->btn_bbox[i]));
1867                char *btn_str=pni->btn_str[i];
1868                int looping=TRUE, selected=TRUE, len=strlen(btn_str);
1869                XEvent ev;
1870 
1871                XGrabPointer(mainDisplay, pni->base_win, False,
1872                      PointerMotionMask | ButtonReleaseMask, GrabModeAsync,
1873                      GrabModeAsync, None, handCursor, CurrentTime);
1874                DisplayButtonInBBox(pni->base_win, btn_str, len,
1875                      bbox, BUTTON_INVERT, FALSE, 0, NULL);
1876                while (looping) {
1877                   XNextEvent(mainDisplay, &ev);
1878 
1879                   if (ev.type == ButtonRelease) {
1880                      XUngrabPointer(mainDisplay, CurrentTime);
1881                      if (debugNoPointerGrab) XSync(mainDisplay, False);
1882                      looping = FALSE;
1883                   } else if (ev.type == MotionNotify) {
1884                      if (PointInBBox(ev.xmotion.x, ev.xmotion.y,
1885                            pni->btn_bbox[i])) {
1886                         if (!selected) {
1887                            selected = TRUE;
1888                            DisplayButtonInBBox(pni->base_win, btn_str, len,
1889                                  bbox, BUTTON_INVERT, FALSE, 0, NULL);
1890                         }
1891                      } else {
1892                         if (selected) {
1893                            selected = FALSE;
1894                            DisplayButtonInBBox(pni->base_win, btn_str, len,
1895                                  bbox, BUTTON_NORMAL, FALSE, 0, NULL);
1896                         }
1897                      }
1898                   }
1899                }
1900                if (selected) {
1901                   *pn_changing = FALSE;
1902                   *pn_selected_btn_index = i;
1903                   DisplayButtonInBBox(pni->base_win, btn_str, len, bbox,
1904                         BUTTON_NORMAL, FALSE, 0, NULL);
1905                }
1906                break;
1907             }
1908          }
1909       }
1910    } else if (button_ev->window == pni->scroll_win) {
1911       NameScrollHandler(button_ev);
1912    } else if (button_ev->window == pni->dsp_win) {
1913       int double_clicked=(NameDspHandler(button_ev)!=INVALID);
1914 
1915       if (pni->marked_index != INVALID) {
1916          if (pni->edit_style == NAMES_SELECT_FILE) {
1917             strcpy(pni->name,
1918                   &(pni->entries[pni->marked_index])[pni->leading]);
1919             pni->name_index = strlen(pni->name);
1920             sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
1921             pni->buf_index = strlen(pni->inbuf);
1922          } else {
1923             strcpy(pni->inbuf,
1924                   &(pni->entries[pni->marked_index])[pni->leading]);
1925             pni->buf_index = strlen(pni->inbuf);
1926          }
1927          RedrawNamePath();
1928          if (double_clicked && pni->double_click_btn_id != INVALID) {
1929             *pn_changing = FALSE;
1930             *pn_selected_btn_index =
1931                   GetBtnIndexFromBtnId(pni->double_click_btn_id);
1932          }
1933       }
1934    }
1935 }
1936 
NamesSetDefaultBtnId(def_btn_id,double_click_btn_id)1937 void NamesSetDefaultBtnId(def_btn_id, double_click_btn_id)
1938    int def_btn_id, double_click_btn_id;
1939 {
1940    struct NamesRec *pni=(&namesInfo);
1941 
1942    pni->def_btn_id = def_btn_id;
1943    pni->double_click_btn_id = double_click_btn_id;
1944 }
1945 
NamesSetStyle(edit_style,loop_once)1946 void NamesSetStyle(edit_style, loop_once)
1947    int edit_style, loop_once;
1948 {
1949    struct NamesRec *pni=(&namesInfo);
1950 
1951    pni->edit_style = edit_style;
1952    pni->loop_once = loop_once;
1953 }
1954 
NamesSetEntries(dsp_ptr,entries,num_entries,p_check_array,dont_free_entries,marked_index,leading)1955 void NamesSetEntries(dsp_ptr, entries, num_entries, p_check_array,
1956       dont_free_entries, marked_index, leading)
1957    DspList *dsp_ptr;
1958    char **entries;
1959    int num_entries, dont_free_entries, marked_index, leading;
1960    struct CheckArrayRec *p_check_array;
1961 {
1962    struct NamesRec *pni=(&namesInfo);
1963 
1964    pni->dsp_ptr = dsp_ptr;
1965    pni->entries = entries;
1966    pni->num_entries = num_entries;
1967    pni->p_check_array = p_check_array;
1968    pni->dont_free_entries = dont_free_entries;
1969    pni->marked_index = marked_index;
1970    pni->leading = leading;
1971 }
1972 
NamesSetCallback(pf_before_loop,pf_after_loop,pf_check_update)1973 void NamesSetCallback(pf_before_loop, pf_after_loop, pf_check_update)
1974    GetEntriesFunc *pf_before_loop;
1975    AfterLoopFunc *pf_after_loop;
1976    CheckUpdateFunc *pf_check_update;
1977 {
1978    struct NamesRec *pni=(&namesInfo);
1979 
1980    if (pni->dsp_ptr != NULL || pni->entries != NULL) {
1981 #ifdef _TGIF_DBG /* debug, do not translate */
1982       sprintf(gszMsgBox, "%s.",
1983             "dsp_ptr != NULL || entries != NULL in NamesSetCallback()");
1984       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1985 #endif /* _TGIF_DBG */
1986       if (pni->dsp_ptr != NULL) free(pni->dsp_ptr);
1987       if (pni->entries != NULL) {
1988          free(*(pni->entries));
1989          free(pni->entries);
1990       }
1991    }
1992    pni->dsp_ptr = NULL;
1993    pni->entries = NULL;
1994    pni->num_entries = 0;
1995    pni->pf_before_loop = pf_before_loop;
1996    pni->pf_after_loop = pf_after_loop;
1997    pni->pf_check_update = pf_check_update;
1998 }
1999 
NamesSetDir(dir_name)2000 void NamesSetDir(dir_name)
2001    char *dir_name;
2002 {
2003    struct NamesRec *pni=(&namesInfo);
2004 
2005    if (pni->edit_style != NAMES_SELECT_FILE) {
2006 #ifdef _TGIF_DBG /* debug, do not translate */
2007       sprintf(gszMsgBox, "%s!\n\nNamesSetDir() called with %s.",
2008             "Programing error", "pni->edit_style != NAMES_SELECT_FILE.");
2009       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2010 #endif /* _TGIF_DBG */
2011    }
2012    UtilStrCpyN(pni->dir_name, sizeof(pni->dir_name), dir_name);
2013 }
2014 
2015 static
BeforeLoopForSelectFile()2016 void BeforeLoopForSelectFile()
2017 {
2018    struct NamesRec *pni=(&namesInfo);
2019 
2020    if (pni->faking_dot_dot) {
2021       *pni->name = '\0';
2022       pni->name_index = 0;
2023    } else if (pni->tabbed_from_root &&
2024          !pni->just_tabbed_from_root) {
2025       pni->name[0] = '\0';
2026       pni->name_index = 0;
2027    } else if (pni->tabbed_from_root && pni->just_tabbed_from_root) {
2028       pni->name_index = strlen(pni->name);
2029       if (!SetMarkedIndex()) {
2030          pni->name[0] = '\0';
2031          pni->name_index = 0;
2032       }
2033    }
2034    sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
2035    pni->buf_index = strlen(pni->inbuf);
2036 
2037    if (pni->exposed) {
2038       XClearWindow(mainDisplay, pni->base_win);
2039       RedrawNameBaseWindow();
2040    }
2041    pni->pop_from_root = FALSE;
2042 }
2043 
2044 static
GetParentRealDir(dir,buf,buf_sz)2045 int GetParentRealDir(dir, buf, buf_sz)
2046    char *dir, *buf;
2047    int buf_sz;
2048 {
2049    int rc=FALSE;
2050    char saved_cur_dir[MAXPATHLENGTH];
2051 
2052    if (!GetWorkingDirectory(saved_cur_dir, sizeof(saved_cur_dir))) {
2053       *saved_cur_dir = '\0';
2054    }
2055    if (SetWorkingDirectory(dir) && SetWorkingDirectory("..")) {
2056       if (GetWorkingDirectory(buf, buf_sz)) {
2057          rc = TRUE;
2058       }
2059    }
2060    if (*saved_cur_dir != '\0') {
2061       SetWorkingDirectory(saved_cur_dir);
2062    }
2063    return rc;
2064 }
2065 
2066 static
BreakForSelectFileAfterLoop()2067 int BreakForSelectFileAfterLoop()
2068 {
2069    struct NamesRec *pni=(&namesInfo);
2070 
2071    if (pni->marked_index == INVALID && !pni->change_to_root &&
2072          !pni->pop_from_root && !pni->just_tabbed_from_root) {
2073       return TRUE;
2074    } else if (FileIsRemote(pni->name)) {
2075       pni->remote_file = TRUE;
2076       return TRUE;
2077    }
2078    if (pni->inbuf[pni->buf_index-1] != DIR_SEP) {
2079       if (!pni->just_tabbed_from_root) {
2080          return TRUE;
2081       }
2082    } else {
2083       if (pni->name[0] == '.' && pni->name[1] == '.' &&
2084             pni->name[2] == DIR_SEP) {
2085          /* need to find out what's the real directory */
2086          char parent_dir[MAXPATHLENGTH];
2087 
2088          if (GetParentRealDir(pni->dir_name, parent_dir, sizeof(parent_dir))) {
2089             int len=0;
2090 
2091             len = strlen(parent_dir);
2092             if (len > 0 && parent_dir[len-1] == DIR_SEP) {
2093                parent_dir[--len] = '\0';
2094             }
2095             sprintf(pni->inbuf, "%s%c..", parent_dir, DIR_SEP);
2096             pni->buf_index = strlen(pni->inbuf);
2097             ParseFileName(pni->inbuf, pni->dir_name, pni->name);
2098             return FALSE;
2099          }
2100       }
2101       pni->inbuf[--(pni->buf_index)] = '\0';
2102       if (pni->name[0] == '.' && pni->name[1] == '.' &&
2103             pni->name[2] == DIR_SEP) {
2104          /* saved_name is used for faking_dot_dot */
2105          int i;
2106 
2107          for (i=strlen(pni->dir_name)-1;
2108                i >= 0 && pni->dir_name[i] != DIR_SEP; i--) {
2109          }
2110          if (i < 0) {
2111             strcpy(pni->saved_name, pni->dir_name);
2112             *pni->dir_name = '\0';
2113          } else {
2114             strcpy(pni->saved_name, &(pni->dir_name[i+1]));
2115             pni->dir_name[i] = '\0';
2116          }
2117       } else {
2118          strcpy(&pni->inbuf[pni->buf_index++], DIR_SEP_STR);
2119          ParseFileName(pni->inbuf, pni->dir_name, pni->name);
2120       }
2121    }
2122    return FALSE;
2123 }
2124 
Names(win_name,pn_selected_index,selected_str,str_sz,p_void)2125 int Names(win_name, pn_selected_index, selected_str, str_sz, p_void)
2126    char *win_name, *selected_str;
2127    int *pn_selected_index, str_sz;
2128    void *p_void;
2129 {
2130    struct NamesRec *pni=(&namesInfo);
2131    int i, looping=TRUE, selected_btn_index=INVALID, left=0;
2132 
2133    if (selected_str != NULL) *selected_str = '\0';
2134    if (pn_selected_index != NULL) *pn_selected_index = INVALID;
2135 
2136    if (!CreateNamesWindows(win_name)) return INVALID;
2137 
2138    EndMeasureTooltip(FALSE);
2139 
2140    pni->userdata = p_void;
2141 
2142    if (pni->edit_style == NAMES_SELECT_FILE) {
2143       pni->faking_dot_dot = FALSE;
2144       pni->change_to_root = FALSE;
2145       pni->just_tabbed_from_root = FALSE;
2146       *pni->saved_dir_name = '\0';
2147    }
2148    left = pni->btn_start;
2149    for (i=0; i < pni->num_btns; i++) {
2150       int button_w=ButtonWidth(pni->btn_str[i], 8, NULL), button_h=0;
2151 
2152       if (boldMsgFontSet == NULL && boldMsgFontPtr == NULL) {
2153          pni->btn_bbox[i].lty = (6+ITEM_DSPED)*ROW_HEIGHT;
2154          button_h = defaultFontHeight + 4;
2155       } else {
2156          pni->btn_bbox[i].lty = (5+ITEM_DSPED)*ROW_HEIGHT +
2157                (boldMsgFontHeight+1);
2158          button_h = boldMsgFontHeight + 4;
2159       }
2160       pni->btn_bbox[i].ltx = left;
2161       pni->btn_bbox[i].lty -= 2;
2162       pni->btn_bbox[i].rbx = pni->btn_bbox[i].ltx+button_w;
2163       pni->btn_bbox[i].rby = pni->btn_bbox[i].lty+button_h;
2164       left = pni->btn_bbox[i].rbx + 1 + defaultFontWidth;
2165    }
2166    SaveStatusStrings();
2167    while (looping) {
2168       int changing=TRUE;
2169 
2170       if (pni->edit_style == NAMES_SELECT_FILE) {
2171          BeforeLoopForSelectFile();
2172       }
2173       if (pni->pf_before_loop != NULL) {
2174          int rc;
2175          char saved_ch='\0';
2176 
2177          SetWatchCursor(drawWindow);
2178          SetWatchCursor(mainWindow);
2179          SetWatchCursor(pni->base_win);
2180          if (pni->edit_style == NAMES_SELECT_FILE && !pni->tabbed_from_root &&
2181                !pni->just_tabbed_from_root) {
2182             saved_ch = *pni->inbuf;
2183             *pni->inbuf = '\0';
2184          }
2185          rc = (pni->pf_before_loop)(&pni->dsp_ptr,
2186                &pni->entries, &pni->num_entries,
2187                &pni->marked_index, &pni->p_check_array, pni->inbuf, p_void);
2188          if (pni->edit_style == NAMES_SELECT_FILE && !pni->tabbed_from_root &&
2189                !pni->just_tabbed_from_root) {
2190             *pni->inbuf = saved_ch;
2191          }
2192          if (pni->edit_style == NAMES_SELECT_FILE &&
2193                pni->just_tabbed_from_root) {
2194             /* saved_name is used for just_tabbed_from_root */
2195             *pni->dir_name = '\0';
2196             strcpy(pni->name, pni->saved_name);
2197             pni->name_index = strlen(pni->name);
2198             sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
2199             pni->buf_index = strlen(pni->inbuf);
2200             *pni->saved_name = '\0';
2201             ParseFileName(pni->inbuf, pni->dir_name, pni->name);
2202             pni->name_index = strlen(pni->name);
2203             if (!SetMarkedIndex()) {
2204                pni->name[0] = '\0';
2205                pni->name_index = 0;
2206             }
2207          }
2208          if (pni->edit_style == NAMES_SELECT_FILE && pni->faking_dot_dot) {
2209             /* saved_name is used for faking_dot_dot */
2210             strcpy(pni->name, pni->saved_name);
2211             pni->name_index = strlen(pni->name);
2212             sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
2213             pni->buf_index = strlen(pni->inbuf);
2214             *pni->saved_name = '\0';
2215             if (!SetMarkedIndex()) {
2216                pni->name[0] = '\0';
2217                pni->name_index = 0;
2218             }
2219          }
2220          SetDefaultCursor(mainWindow);
2221          ShowCursor();
2222          SetDrawCursor(pni->base_win);
2223          if (!rc) break;
2224       }
2225       if (pni->edit_style == NAMES_SELECT_FILE) {
2226          pni->just_tabbed_from_root = FALSE;
2227          pni->faking_dot_dot = FALSE;
2228       }
2229       NamesUpdateIndices();
2230 
2231       if (pni->pf_before_loop != NULL && pni->exposed) {
2232          RedrawNamePath();
2233          RedrawNameScrollWin();
2234          RedrawDspWindow();
2235          RedrawDspBaseWindow();
2236       }
2237       if (pni->dsp_ptr != NULL && pni->marked_index != INVALID) {
2238          SetStringStatus(pni->dsp_ptr[pni->marked_index].pathstr);
2239       }
2240       XSync(mainDisplay, False);
2241 
2242       selected_btn_index = INVALID;
2243       while (changing) {
2244          XEvent input, ev;
2245 
2246          XNextEvent(mainDisplay, &input);
2247 
2248          if (ExposeOrMapNames(&input)) {
2249             continue;
2250          }
2251          if (input.type == Expose) {
2252             ExposeEventHandler(&input, FALSE);
2253          } else if (input.type==VisibilityNotify &&
2254                input.xany.window==mainWindow &&
2255                input.xvisibility.state==VisibilityUnobscured) {
2256             int i;
2257 
2258             while (XCheckWindowEvent(mainDisplay, mainWindow,
2259                   VisibilityChangeMask, &ev)) ;
2260             if (pinnedMainMenu) XMapRaised(mainDisplay, mainMenuWindow);
2261             for (i=0; i < numExtraWins; i++) {
2262                if (extraWinInfo[i].mapped && extraWinInfo[i].raise &&
2263                      extraWinInfo[i].window != None) {
2264                   XMapRaised(mainDisplay, extraWinInfo[i].window);
2265                }
2266             }
2267             XMapRaised(mainDisplay, pni->base_win);
2268          } else if (input.type == KeyPress) {
2269             KeyPressInNames(&input.xkey, &changing, &selected_btn_index);
2270          } else if (input.type == ButtonPress) {
2271             ButtonPressInNames(&input.xbutton, &changing, &selected_btn_index);
2272          } else if ((input.xany.window==pni->base_win ||
2273                input.xany.window==pni->dsp_base_win ||
2274                input.xany.window==pni->dsp_win ||
2275                input.xany.window==pni->scroll_win) &&
2276                IsWM_DELETE_WINDOW(&input)) {
2277             KeyPressInNames(&input.xkey, &changing, &selected_btn_index);
2278             changing = FALSE;
2279             selected_btn_index = INVALID;
2280          }
2281       }
2282       if (pni->exposed && selected_btn_index != INVALID) {
2283          DisplayButtonInBBox(pni->base_win, pni->btn_str[selected_btn_index],
2284                strlen(pni->btn_str[selected_btn_index]),
2285                &(pni->btn_bbox[selected_btn_index]), BUTTON_INVERT, FALSE, 0,
2286                NULL);
2287          XSync(mainDisplay, False);
2288       }
2289       if (pni->edit_style == NAMES_SELECT_FILE) {
2290          if (pni->marked_index != INVALID) {
2291             strcpy(pni->name,
2292                   &(pni->entries[pni->marked_index])[pni->leading]);
2293             pni->name_index = strlen(pni->name);
2294             sprintf(pni->inbuf, "%s%c%s", pni->dir_name, DIR_SEP, pni->name);
2295             pni->buf_index = strlen(pni->inbuf);
2296          }
2297       }
2298       if (pni->pf_after_loop != NULL) {
2299          int btn_id=INVALID;
2300 
2301          if (selected_btn_index != INVALID) {
2302             btn_id = pni->btn_id[selected_btn_index];
2303          }
2304          if (!(pni->pf_after_loop)(&pni->dsp_ptr,
2305                &pni->entries, &pni->num_entries,
2306                &pni->marked_index, &pni->p_check_array, pni->inbuf, btn_id,
2307                pni->marked_index, p_void)) {
2308             looping = FALSE;
2309          }
2310       }
2311       if (selected_btn_index != INVALID) {
2312          if (pni->btn_id[selected_btn_index] == BUTTON_CANCEL) {
2313             looping = FALSE;
2314          }
2315       }
2316       if (pni->edit_style == NAMES_SELECT_FILE) {
2317          if (BreakForSelectFileAfterLoop()) {
2318             looping = FALSE;
2319          }
2320       }
2321       if (pni->loop_once == NAMES_LOOP_ONCE) {
2322          looping = FALSE;
2323       }
2324       if (pni->exposed && selected_btn_index != INVALID) {
2325          DisplayButtonInBBox(pni->base_win, pni->btn_str[selected_btn_index],
2326                strlen(pni->btn_str[selected_btn_index]),
2327                &(pni->btn_bbox[selected_btn_index]), BUTTON_NORMAL, FALSE, 0,
2328                NULL);
2329          XSync(mainDisplay, False);
2330       }
2331    }
2332    RestoreStatusStrings();
2333    XDestroyWindow(mainDisplay, pni->base_win);
2334    if (warpToWinCenter) {
2335       XWarpPointer(mainDisplay, None, drawWindow, 0, 0, 0, 0,
2336             (int)(ZOOMED_SIZE(drawWinW)>>1), (int)(ZOOMED_SIZE(drawWinH)>>1));
2337    }
2338    if (selected_str != NULL) {
2339       if (pni->remote_file) {
2340          UtilStrCpyN(selected_str, str_sz, pni->name);
2341       } else {
2342          UtilStrCpyN(selected_str, str_sz, pni->inbuf);
2343       }
2344    }
2345    pni->userdata = NULL;
2346 
2347    if (pn_selected_index != NULL) *pn_selected_index = pni->marked_index;
2348    if (selected_btn_index != INVALID) {
2349       return pni->btn_id[selected_btn_index];
2350    }
2351    return INVALID;
2352 }
2353