LCOV - code coverage report
Current view: top level - gdraw - gfilechooser.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 14 1189 1.2 %
Date: 2017-08-04 Functions: 4 75 5.3 %

          Line data    Source code
       1             : /* Copyright (C) 2000-2012 by George Williams */
       2             : /*
       3             :  * Redistribution and use in source and binary forms, with or without
       4             :  * modification, are permitted provided that the following conditions are met:
       5             : 
       6             :  * Redistributions of source code must retain the above copyright notice, this
       7             :  * list of conditions and the following disclaimer.
       8             : 
       9             :  * Redistributions in binary form must reproduce the above copyright notice,
      10             :  * this list of conditions and the following disclaimer in the documentation
      11             :  * and/or other materials provided with the distribution.
      12             : 
      13             :  * The name of the author may not be used to endorse or promote products
      14             :  * derived from this software without specific prior written permission.
      15             : 
      16             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      17             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      18             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      19             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      20             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      21             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      22             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      23             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      24             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      25             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : #include "gdraw.h"
      28             : #include "ggadgetP.h"
      29             : #include "gwidgetP.h"
      30             : #include "../gdraw/gdrawP.h"
      31             : #include "gio.h"
      32             : #include "gfile.h"
      33             : #include "ustring.h"
      34             : #include "utype.h"
      35             : #include "gicons.h"
      36             : 
      37             : #include <stdlib.h>
      38             : 
      39             : /* This isn't really a gadget, it's just a collection of gadgets with some glue*/
      40             : /*  to make them work together. Therefore there are no expose routines here, */
      41             : /*  nor mouse, nor key. That's all handled by the individual gadgets themselves*/
      42             : /* Instead we've got a bunch of routines that make them work as a whole */
      43             : static GBox gfilechooser_box = GBOX_EMPTY; /* no box */
      44             : static unichar_t *lastdir;
      45             : static int showhidden = false;
      46             : static enum { dirs_mixed, dirs_first, dirs_separate } dir_placement = dirs_mixed;
      47             : static unichar_t **bookmarks = NULL;
      48             : static void *prefs_changed_data = NULL;
      49             : static void (*prefs_changed)(void *) = NULL;
      50             : 
      51           0 : static unichar_t *SubMatch(unichar_t *pattern, unichar_t *eop, unichar_t *name,int ignorecase) {
      52             :     unichar_t ch, *ppt, *npt, *ept, *eon;
      53             : 
      54           0 :     while ( pattern<eop && ( ch = *pattern)!='\0' ) {
      55           0 :         if ( ch=='*' ) {
      56           0 :             if ( pattern[1]=='\0' )
      57           0 : return( name+u_strlen(name));
      58           0 :             for ( npt=name; ; ++npt ) {
      59           0 :                 if ( (eon = SubMatch(pattern+1,eop,npt,ignorecase))!= NULL )
      60           0 : return( eon );
      61           0 :                 if ( *npt=='\0' )
      62           0 : return( NULL );
      63           0 :             }
      64           0 :         } else if ( ch=='?' ) {
      65           0 :             if ( *name=='\0' )
      66           0 : return( NULL );
      67           0 :             ++name;
      68           0 :         } else if ( ch=='[' ) {
      69             :             /* [<char>...] matches the chars
      70             :              * [<char>-<char>...] matches any char within the range (inclusive)
      71             :              * the above may be concattenated and the resultant pattern matches
      72             :              *          anything thing which matches any of them.
      73             :              * [^<char>...] matches any char which does not match the rest of
      74             :              *          the pattern
      75             :              * []...] as a special case a ']' immediately after the '[' matches
      76             :              *          itself and does not end the pattern
      77             :              */
      78           0 :             int found = 0, not=0;
      79           0 :             ++pattern;
      80           0 :             if ( pattern[0]=='^' ) { not = 1; ++pattern; }
      81           0 :             for ( ppt = pattern; (ppt!=pattern || *ppt!=']') && *ppt!='\0' ; ++ppt ) {
      82           0 :                 ch = *ppt;
      83           0 :                 if ( ppt[1]=='-' && ppt[2]!=']' && ppt[2]!='\0' ) {
      84           0 :                     unichar_t ch2 = ppt[2];
      85           0 :                     if ( (*name>=ch && *name<=ch2) ||
      86           0 :                             (ignorecase && islower(ch) && islower(ch2) &&
      87           0 :                                     *name>=toupper(ch) && *name<=toupper(ch2)) ||
      88           0 :                             (ignorecase && isupper(ch) && isupper(ch2) &&
      89           0 :                                     *name>=tolower(ch) && *name<=tolower(ch2))) {
      90           0 :                         if ( !not ) {
      91           0 :                             found = 1;
      92           0 :             break;
      93             :                         }
      94             :                     } else {
      95           0 :                         if ( not ) {
      96           0 :                             found = 1;
      97           0 :             break;
      98             :                         }
      99             :                     }
     100           0 :                     ppt += 2;
     101           0 :                 } else if ( ch==*name || (ignorecase && tolower(ch)==tolower(*name)) ) {
     102           0 :                     if ( !not ) {
     103           0 :                         found = 1;
     104           0 :             break;
     105             :                     }
     106             :                 } else {
     107           0 :                     if ( not ) {
     108           0 :                         found = 1;
     109           0 :             break;
     110             :                     }
     111             :                 }
     112             :             }
     113           0 :             if ( !found )
     114           0 : return( NULL );
     115           0 :             while ( *ppt!=']' && *ppt!='\0' ) ++ppt;
     116           0 :             pattern = ppt;
     117           0 :             ++name;
     118           0 :         } else if ( ch=='{' ) {
     119             :             /* matches any of a comma separated list of substrings */
     120           0 :             for ( ppt = pattern+1; *ppt!='\0' ; ppt = ept ) {
     121           0 :                 for ( ept=ppt; *ept!='}' && *ept!=',' && *ept!='\0'; ++ept );
     122           0 :                 npt = SubMatch(ppt,ept,name,ignorecase);
     123           0 :                 if ( npt!=NULL ) {
     124           0 :                     unichar_t *ecurly = ept;
     125           0 :                     while ( *ecurly!='}' && ecurly<eop && *ecurly!='\0' ) ++ecurly;
     126           0 :                     if ( (eon=SubMatch(ecurly+1,eop,npt,ignorecase))!=NULL )
     127           0 : return( eon );
     128             :                 }
     129           0 :                 if ( *ept=='}' )
     130           0 : return( NULL );
     131           0 :                 if ( *ept==',' ) ++ept;
     132             :             }
     133           0 :         } else if ( ch==*name ) {
     134           0 :             ++name;
     135           0 :         } else if ( ignorecase && tolower(ch)==tolower(*name)) {
     136           0 :             ++name;
     137             :         } else
     138           0 : return( NULL );
     139           0 :         ++pattern;
     140             :     }
     141           0 : return( name );
     142             : }
     143             : 
     144             : /* Handles *?{}[] wildcards */
     145           0 : int GGadgetWildMatch(unichar_t *pattern, unichar_t *name,int ignorecase) {
     146           0 :     if ( pattern==NULL )
     147           0 : return( true );
     148             : 
     149           0 :     unichar_t *eop = pattern + u_strlen(pattern);
     150             : 
     151           0 :     name = SubMatch(pattern,eop,name,ignorecase);
     152           0 :     if ( name==NULL )
     153           0 : return( false );
     154           0 :     if ( *name=='\0' )
     155           0 : return( true );
     156             : 
     157           0 : return( false );
     158             : }
     159             : 
     160           0 : enum fchooserret GFileChooserDefFilter(GGadget *g,GDirEntry *ent,const unichar_t *dir) {
     161           0 :     GFileChooser *gfc = (GFileChooser *) g;
     162             :     int i;
     163             :     char *mime;
     164             : 
     165           0 :     if ( uc_strcmp(ent->name,".")==0 )     /* Don't show the current directory entry */
     166           0 :         return( fc_hide );
     167           0 :     if ( gfc->wildcard!=NULL && *gfc->wildcard=='.' )
     168             :         /* If they asked for hidden files, show them */;
     169           0 :     else if ( !showhidden && ent->name[0]=='.' && uc_strcmp(ent->name,"..")!=0 )
     170           0 :         return( fc_hide );
     171           0 :     if ( ent->isdir )                        /* Show all other directories */
     172           0 :         return( fc_show );
     173           0 :     if ( gfc->wildcard==NULL && gfc->mimetypes==NULL )
     174           0 :         return( fc_show );
     175             :     /* If we've got a wildcard, and it matches, then show */
     176           0 :     if ( gfc->wildcard!=NULL && GGadgetWildMatch(gfc->wildcard,ent->name,true))
     177           0 :         return( fc_show );
     178             :     /* If no mimetypes then we're done */
     179           0 :     if ( gfc->mimetypes==NULL )
     180           0 :         return( fc_hide );
     181             :     /* match the mimetypes */
     182           0 :     if( ent->mimetype )
     183           0 :         mime = copy(u_to_c(ent->mimetype));
     184             :     else {
     185             :         char utf8_ent_name[PATH_MAX+1];
     186           0 :         strncpy(utf8_ent_name,u_to_c( ent->name ),PATH_MAX);
     187           0 :         utf8_ent_name[PATH_MAX]=0;
     188           0 :         mime = GIOGetMimeType(utf8_ent_name);
     189             :     }
     190             : 
     191           0 :     if ( mime ) {
     192           0 :         for ( i=0; gfc->mimetypes[i]!=NULL; ++i )
     193           0 :             if ( strcasecmp(u_to_c(gfc->mimetypes[i]),mime)==0 ) {
     194           0 :                 free(mime);
     195           0 :                 return( fc_show );
     196             :             }
     197           0 :         free(mime);
     198             :     }
     199             : 
     200           0 :     return( fc_hide );
     201             : }
     202             : 
     203           0 : static GImage *GFileChooserPickIcon(GDirEntry *e) {
     204             :     char mime[100];
     205             :     char utf8_ent_name[PATH_MAX+1];
     206           0 :     mime[0] = mime[99] = utf8_ent_name[PATH_MAX] = 0;
     207           0 :     strncpy(utf8_ent_name,u_to_c(e->name),PATH_MAX);
     208             : 
     209           0 :     InitChooserIcons();
     210             : 
     211           0 :     if ( e->isdir ) {
     212           0 :         if ( !strcmp(utf8_ent_name,"..") )
     213           0 :             return( &_GIcon_updir );
     214           0 :         return( &_GIcon_dir );
     215             :     }
     216           0 :     if ( e->mimetype ) {
     217           0 :         strncpy(mime,u_to_c(e->mimetype),99);
     218             :     } else {
     219             :         char *temp;
     220           0 :         if ( (temp=GIOguessMimeType(utf8_ent_name)) || (temp=GIOGetMimeType(utf8_ent_name)) ) {
     221           0 :             e->mimetype=u_copy(c_to_u(temp));
     222           0 :             strncpy(mime,temp,99);
     223           0 :             free(temp);
     224             :         } else
     225           0 :             return( &_GIcon_unknown );
     226             :     }
     227           0 :     if (strncasecmp("text/", mime, 5) == 0) {
     228           0 :         if (strcasecmp("text/html", mime) == 0)
     229           0 :             return( &_GIcon_texthtml );
     230           0 :         if (strcasecmp("text/xml", mime) == 0)
     231           0 :             return( &_GIcon_textxml );
     232           0 :         if (strcasecmp("text/css", mime) == 0)
     233           0 :             return( &_GIcon_textcss );
     234           0 :         if (strcasecmp("text/c", mime) == 0)
     235           0 :             return( &_GIcon_textc );
     236           0 :         if (strcasecmp("text/java", mime) == 0)
     237           0 :             return( &_GIcon_textjava );
     238           0 :         if (strcasecmp("text/x-makefile", mime) == 0)
     239           0 :             return( &_GIcon_textmake );
     240           0 :         if (strcasecmp("text/fontps", mime) == 0)
     241           0 :             return( &_GIcon_textfontps );
     242           0 :         if (strcasecmp("text/font", mime) == 0)
     243           0 :             return( &_GIcon_textfontbdf );
     244           0 :         if (strcasecmp("text/ps", mime) == 0)
     245           0 :             return( &_GIcon_textps );
     246             : 
     247           0 :         return( &_GIcon_textplain );
     248             :     }
     249             : 
     250           0 :     if (strncasecmp("image/", mime, 6) == 0)
     251           0 :         return( &_GIcon_image );
     252           0 :     if (strncasecmp("video/", mime, 6) == 0)
     253           0 :         return( &_GIcon_video );
     254           0 :     if (strncasecmp("audio/", mime, 6) == 0)
     255           0 :         return( &_GIcon_audio );
     256           0 :     if (strcasecmp("application/x-navidir", mime) == 0 ||
     257           0 :         strcasecmp("inode/directory", mime) == 0)
     258           0 :         return( &_GIcon_dir );
     259           0 :     if (strcasecmp("application/x-object", mime) == 0)
     260           0 :         return( &_GIcon_object );
     261           0 :     if (strcasecmp("application/x-core", mime) == 0)
     262           0 :         return( &_GIcon_core );
     263           0 :     if (strcasecmp("application/x-tar", mime) == 0)
     264           0 :         return( &_GIcon_tar );
     265           0 :     if (strcasecmp("application/x-compressed", mime) == 0)
     266           0 :         return( &_GIcon_compressed );
     267           0 :     if (strcasecmp("application/pdf", mime) == 0)
     268           0 :         return( &_GIcon_texthtml );
     269           0 :     if (strcasecmp("application/vnd.font-fontforge-sfd", mime) == 0)
     270           0 :         return( &_GIcon_textfontsfd );
     271           0 :     if (strcasecmp("application/x-font-type1", mime) == 0)
     272           0 :         return( &_GIcon_textfontps );
     273           0 :     if (strcasecmp("application/x-font-ttf", mime) == 0 ||
     274           0 :         strcasecmp("application/x-font-otf", mime) == 0) {
     275           0 :         return( &_GIcon_ttf );
     276             :     }
     277           0 :     if (strcasecmp("application/x-font-cid", mime) == 0 )
     278           0 :         return( &_GIcon_cid );
     279           0 :     if (strcasecmp("application/x-macbinary", mime) == 0 ||
     280           0 :         strcasecmp("application/x-mac-binhex40", mime) == 0 ) {
     281           0 :         return( &_GIcon_mac );
     282             :     }
     283           0 :     if (strcasecmp("application/x-mac-dfont", mime) == 0 ||
     284           0 :         strcasecmp("application/x-mac-suit", mime) == 0 ) {
     285           0 :         return( &_GIcon_macttf );
     286             :     }
     287           0 :     if (strcasecmp("application/x-font-pcf", mime) == 0 ||
     288           0 :         strcasecmp("application/x-font-snf", mime) == 0) {
     289           0 :         return( &_GIcon_textfontbdf );
     290             :     }
     291             : 
     292           0 :     return( &_GIcon_unknown );
     293             : }
     294             : 
     295           0 : static void GFileChooserFillList(GFileChooser *gfc,GDirEntry *first,
     296             :         const unichar_t *dir) {
     297             :     GDirEntry *e;
     298             :     int len, dlen;
     299             :     GTextInfo **ti, **dti;
     300             : 
     301           0 :     len = dlen = 0;
     302           0 :     for ( e=first; e!=NULL; e=e->next ) {
     303           0 :         e->fcdata = (gfc->filter)(&gfc->g,e,dir);
     304           0 :         if ( e->fcdata!=fc_hide ) {
     305           0 :             if ( e->isdir )
     306           0 :                 ++dlen;
     307             :             else
     308           0 :                 ++len;
     309             :         }
     310             :     }
     311             : 
     312           0 :     if ( dir_placement == dirs_separate ) {
     313           0 :         ti = malloc((len+1)*sizeof(GTextInfo *));
     314           0 :         dti = malloc((dlen+1)*sizeof(GTextInfo *));
     315           0 :         len = dlen = 0;
     316           0 :         for ( e=first; e!=NULL; e=e->next ) {
     317           0 :             if ( e->fcdata!=fc_hide ) {
     318             :                 GTextInfo **me;
     319           0 :                 if ( e->isdir )
     320           0 :                     me = &dti[dlen++];
     321             :                 else
     322           0 :                     me = &ti[len++];
     323             : 
     324           0 :                 *me = calloc(1,sizeof(GTextInfo));
     325           0 :                 (*me)->text = u_copy(e->name);
     326           0 :                 (*me)->image = GFileChooserPickIcon(e);
     327           0 :                 (*me)->fg = COLOR_DEFAULT;
     328           0 :                 (*me)->bg = COLOR_DEFAULT;
     329           0 :                 (*me)->font = NULL;
     330           0 :                 (*me)->disabled = e->fcdata==fc_showdisabled;
     331           0 :                 (*me)->image_precedes = true;
     332           0 :                 (*me)->checked = e->isdir;
     333             :             }
     334             :         }
     335           0 :         ti[len] = calloc(1,sizeof(GTextInfo));
     336           0 :         dti[dlen] = calloc(1,sizeof(GTextInfo));
     337           0 :         GGadgetSetList(&gfc->files->g,ti,false);
     338           0 :         GGadgetSetList(&gfc->subdirs->g,dti,false);
     339             :     } else {
     340           0 :         ti = malloc((len+dlen+1)*sizeof(GTextInfo *));
     341           0 :         len = 0;
     342           0 :         for ( e=first; e!=NULL; e=e->next ) {
     343           0 :             if ( e->fcdata!=fc_hide ) {
     344           0 :                 ti[len] = calloc(1,sizeof(GTextInfo));
     345           0 :                 ti[len]->text = u_copy(e->name);
     346           0 :                 ti[len]->image = GFileChooserPickIcon(e);
     347           0 :                 ti[len]->fg = COLOR_DEFAULT;
     348           0 :                 ti[len]->bg = COLOR_DEFAULT;
     349           0 :                 ti[len]->font = NULL;
     350           0 :                 ti[len]->disabled = e->fcdata==fc_showdisabled;
     351           0 :                 ti[len]->image_precedes = true;
     352           0 :                 ti[len]->checked = e->isdir;
     353           0 :                 if ( dir_placement==dirs_first && e->isdir )
     354           0 :                     ((GTextInfo2 *) ti[len])->sort_me_first_in_list = true;
     355           0 :                 ++len;
     356             :             }
     357             :         }
     358           0 :         ti[len] = calloc(1,sizeof(GTextInfo));
     359           0 :         GGadgetSetList(&gfc->files->g,ti,false);
     360             :     }
     361             : 
     362           0 :     GGadgetScrollListToText(&gfc->files->g,u_GFileNameTail(_GGadgetGetTitle(&gfc->name->g)),true);
     363           0 : }
     364             : 
     365           0 : static void GFileChooserIntermediateDir(GIOControl *gc) {
     366           0 :     GFileChooser *gfc = (GFileChooser *) (gc->userdata);
     367             : 
     368           0 :     GFileChooserFillList(gfc,GIOgetDirData(gc),gc->path);
     369           0 : }
     370             : 
     371           0 : static void GFileChooserReceiveDir(GIOControl *gc) {
     372           0 :     GFileChooser *gfc = (GFileChooser *) (gc->userdata);
     373             : 
     374           0 :     GGadgetSetEnabled(&gfc->files->g,true);
     375           0 :     GGadgetSetEnabled(&gfc->subdirs->g,true);
     376           0 :     if ( gfc->lastname!=NULL ) {
     377           0 :         GGadgetSetTitle(&gfc->name->g,gfc->lastname);
     378           0 :         free(gfc->lastname);
     379           0 :         gfc->lastname=NULL;
     380             :     }
     381           0 :     GFileChooserFillList(gfc,GIOgetDirData(gc),gc->path);
     382           0 :     GIOclose(gc);
     383           0 :     gfc->outstanding = NULL;
     384           0 :     GDrawSetCursor(gfc->g.base,gfc->old_cursor);
     385           0 : }
     386             : 
     387           0 : static void GFileChooserErrorDir(GIOControl *gc) {
     388           0 :     GFileChooser *gfc = (GFileChooser *) (gc->userdata);
     389             :     GTextInfo *ti[3], _ti[3];
     390             :     static unichar_t nullstr[] = { 0 };
     391             : 
     392           0 :     memset(_ti,'\0',sizeof(_ti));
     393           0 :     _ti[0].text = gc->error;
     394           0 :     if ( gc->status[0]!='\0' )
     395           0 :         _ti[1].text = gc->status;
     396           0 :     _ti[0].fg = _ti[0].bg = _ti[1].fg = _ti[1].bg = COLOR_DEFAULT;
     397           0 :     ti[0] = _ti; ti[1] = _ti+1; ti[2] = _ti+2;
     398           0 :     GGadgetSetEnabled(&gfc->files->g,false);
     399           0 :     GGadgetSetList(&gfc->files->g,ti,true);
     400           0 :     GGadgetSetEnabled(&gfc->subdirs->g,false);
     401           0 :     GGadgetSetList(&gfc->subdirs->g,ti,true);
     402           0 :     if ( gfc->lastname!=NULL ) {
     403           0 :         GGadgetSetTitle(&gfc->name->g,gfc->lastname);
     404           0 :         free(gfc->lastname);
     405           0 :         gfc->lastname=NULL;
     406             :     } else
     407           0 :         GGadgetSetTitle(&gfc->name->g,nullstr);
     408           0 :     if ( gfc->filterb!=NULL && gfc->ok!=NULL )
     409           0 :         _GWidget_MakeDefaultButton(&gfc->ok->g);
     410           0 :     GIOcancel(gc);
     411           0 :     gfc->outstanding = NULL;
     412           0 :     GDrawSetCursor(gfc->g.base,gfc->old_cursor);
     413           0 : }
     414             : 
     415           0 : static void GFileChooserScanDir(GFileChooser *gfc,unichar_t *dir) {
     416           0 :     GTextInfo **ti=NULL;
     417           0 :     int cnt, tot=0;
     418             :     unichar_t *pt, *ept, *freeme;
     419             : 
     420           0 :     dir = u_GFileNormalize(dir);
     421             :     while ( 1 ) {
     422           0 :         ept = dir;
     423           0 :         cnt = 0;
     424           0 :         if ( (pt=uc_strstr(dir,"://"))!=NULL ) {
     425           0 :             ept = u_strchr(pt+3,'/');
     426           0 :             if ( ept==NULL )
     427           0 :                 ept = pt+u_strlen(pt);
     428             :             else
     429           0 :                 ++ept;
     430           0 :         } else if ( *dir=='/' )
     431           0 :             ept = dir+1;
     432           0 :         if ( ept!=dir ) {
     433           0 :             if ( ti!=NULL ) {
     434           0 :                 ti[tot-cnt] = calloc(1,sizeof(GTextInfo));
     435           0 :                 ti[tot-cnt]->text = u_copyn(dir,ept-dir);
     436           0 :                 ti[tot-cnt]->fg = ti[tot-cnt]->bg = COLOR_DEFAULT;
     437             :             }
     438           0 :             cnt = 1;
     439             :         }
     440           0 :         for ( pt = ept; *pt!='\0'; pt = ept ) {
     441           0 :             for ( ept = pt; *ept!='/' && *ept!='\0'; ++ept );
     442           0 :             if ( ti!=NULL ) {
     443           0 :                 ti[tot-cnt] = calloc(1,sizeof(GTextInfo));
     444           0 :                 ti[tot-cnt]->text = u_copyn(pt,ept-pt);
     445           0 :                 ti[tot-cnt]->fg = ti[tot-cnt]->bg = COLOR_DEFAULT;
     446             :             }
     447           0 :             ++cnt;
     448           0 :             if ( *ept=='/' ) ++ept;
     449             :         }
     450           0 :         if ( ti!=NULL )
     451           0 :     break;
     452           0 :         ti = malloc((cnt+1)*sizeof(GTextInfo *));
     453           0 :         tot = cnt-1;
     454           0 :     }
     455           0 :     ti[cnt] = calloc(1,sizeof(GTextInfo));
     456             : 
     457           0 :     GGadgetSetList(&gfc->directories->g,ti,false);
     458           0 :     GGadgetSelectOneListItem(&gfc->directories->g,0);
     459             : 
     460             :     /* Password management for URLs */
     461           0 :     if ( (pt = uc_strstr(dir,"://"))!=NULL ) {
     462             :         int port;
     463             :         char proto[40];
     464             :         char *host, *username, *password;
     465           0 :         free( _GIO_decomposeURL(dir,&host,&port,&username,&password));
     466           0 :         if ( username!=NULL && password==NULL ) {
     467           0 :             password = gwwv_ask_password(_("Password?"),"",_("Enter password for %s@%s"), username, host );
     468           0 :             cu_strncpy(proto,dir,pt-dir<sizeof(proto)?pt-dir:sizeof(proto));
     469           0 :             password = GIO_PasswordCache(proto,host,username,password);
     470             :         }
     471           0 :         free(host); free(username); free(password);
     472             :     }
     473             : 
     474           0 :     if ( gfc->outstanding!=NULL ) {
     475           0 :         GIOcancel(gfc->outstanding);
     476           0 :         gfc->outstanding = NULL;
     477             :     } else {
     478           0 :         gfc->old_cursor = GDrawGetCursor(gfc->g.base);
     479           0 :         GDrawSetCursor(gfc->g.base,ct_watch);
     480             :     }
     481             : 
     482           0 :     gfc->outstanding = GIOCreate(dir,gfc,GFileChooserReceiveDir,
     483             :             GFileChooserErrorDir);
     484           0 :     gfc->outstanding->receiveintermediate = GFileChooserIntermediateDir;
     485           0 :     GIOdir(gfc->outstanding);
     486             : 
     487           0 :     freeme = NULL;
     488           0 :     if ( dir[u_strlen(dir)-1]!='/' ) {
     489           0 :         freeme = malloc((u_strlen(dir)+3)*sizeof(unichar_t));
     490           0 :         u_strcpy(freeme,dir);
     491           0 :         uc_strcat(freeme,"/");
     492           0 :         dir = freeme;
     493             :     }
     494           0 :     if ( gfc->hpos+1>=gfc->hmax ) {
     495           0 :         gfc->hmax = gfc->hmax+20;
     496           0 :         gfc->history = realloc(gfc->history,(gfc->hmax)*sizeof(unichar_t *));
     497             :     }
     498           0 :     if ( gfc->hcnt==0 ) {
     499           0 :         gfc->history[gfc->hcnt++] = u_copy(dir);
     500           0 :     } else if ( u_strcmp(gfc->history[gfc->hpos],dir)==0 )
     501             :         /* Just a refresh */;
     502             :     else {
     503           0 :         gfc->history[++gfc->hpos] = u_copy(dir);
     504           0 :         gfc->hcnt = gfc->hpos+1;
     505             :     }
     506           0 :     free(freeme);
     507           0 : }
     508             : 
     509             : /* Handle events from the text field */
     510           0 : static int GFileChooserTextChanged(GGadget *t,GEvent *e) {
     511             :     GFileChooser *gfc;
     512           0 :     GGadget *g = (GGadget *)GGadgetGetUserData(t);
     513             : 
     514             :     const unichar_t *pt, *spt;
     515           0 :     unichar_t * pt_toFree = 0, *local_toFree = 0;
     516           0 :     if ( e->type!=et_controlevent || e->u.control.subtype!=et_textchanged )
     517           0 : return( true );
     518           0 :     spt = pt = _GGadgetGetTitle(t);
     519             : #ifdef _WIN32
     520             :     local_toFree = u_GFileNormalizePath(u_copy(spt));
     521             :     pt = spt = local_toFree;
     522             : #endif    
     523             :     
     524           0 :     if ( pt==NULL )
     525           0 : return( true );
     526           0 :     gfc = (GFileChooser *) GGadgetGetUserData(t);
     527             : 
     528           0 :     if( GFileChooserGetInputFilenameFunc(g)(g, &pt,gfc->inputfilenameprevchar)) {
     529           0 :         pt_toFree = (unichar_t*)pt;
     530           0 :         spt = pt;
     531           0 :         GGadgetSetTitle(g, pt);
     532             :     }
     533             : 
     534           0 :     while ( *pt && *pt!='*' && *pt!='?' && *pt!='[' && *pt!='{' )
     535           0 :         ++pt;
     536           0 :     if ( *spt!='\0' && spt[u_strlen(spt)-1]=='/' )
     537           0 :         pt = spt+u_strlen(spt)-1;
     538             : 
     539             :     /* if there are no wildcards and no directories in the filename */
     540             :     /*  then as it gets changed the list box should show the closest */
     541             :     /*  approximation to it */
     542           0 :     if ( *pt=='\0' ) {
     543           0 :         GGadgetScrollListToText(&gfc->files->g,spt,true);
     544           0 :         if ( gfc->filterb!=NULL && gfc->ok!=NULL )
     545           0 :             _GWidget_MakeDefaultButton(&gfc->ok->g);
     546           0 :     } else if ( *pt=='/' && e->u.control.u.tf_changed.from_pulldown!=-1 ) {
     547             :         GEvent e;
     548           0 :         e.type = et_controlevent;
     549           0 :         e.u.control.subtype = et_buttonactivate;
     550           0 :         e.u.control.g = (gfc->ok!=NULL?&gfc->ok->g:&gfc->g);
     551           0 :         e.u.control.u.button.clicks = 0;
     552           0 :         e.w = e.u.control.g->base;
     553           0 :         if ( e.u.control.g->handle_controlevent != NULL )
     554           0 :             (e.u.control.g->handle_controlevent)(e.u.control.g,&e);
     555             :         else
     556           0 :             GDrawPostEvent(&e);
     557             :     } else {
     558           0 :         if ( gfc->filterb!=NULL && gfc->ok!=NULL )
     559           0 :             _GWidget_MakeDefaultButton(&gfc->filterb->g);
     560             :     }
     561           0 :     free(gfc->lastname); gfc->lastname = NULL;
     562           0 :     if(pt_toFree)
     563           0 :         free(pt_toFree);
     564             :     
     565           0 :     if (local_toFree)
     566           0 :         free(local_toFree);
     567             : 
     568           0 :     if(gfc->inputfilenameprevchar)
     569           0 :         free(gfc->inputfilenameprevchar);
     570           0 :     gfc->inputfilenameprevchar = u_copy(_GGadgetGetTitle(t));
     571             : 
     572           0 : return( true );
     573             : }
     574             : 
     575           0 : static unichar_t **GFileChooserCompletion(GGadget *t,int from_tab) {
     576             :     GFileChooser *gfc;
     577             :     const unichar_t *pt, *spt; unichar_t **ret;
     578             :     GTextInfo **ti;
     579             :     int32 len;
     580             :     int i, cnt, doit, match_len;
     581             : 
     582           0 :     pt = spt = _GGadgetGetTitle(t);
     583           0 :     if ( pt==NULL )
     584           0 : return( NULL );
     585           0 :     while ( *pt && *pt!='/' && *pt!='*' && *pt!='?' && *pt!='[' && *pt!='{' )
     586           0 :         ++pt;
     587           0 :     if ( *pt!='\0' )
     588           0 : return( NULL );         /* Can't complete if not in cur directory or has wildcards */
     589             : 
     590           0 :     match_len = u_strlen(spt);
     591           0 :     gfc = (GFileChooser *) GGadgetGetUserData(t);
     592           0 :     ti = GGadgetGetList(&gfc->files->g,&len);
     593           0 :     ret = NULL;
     594           0 :     for ( doit=0; doit<2; ++doit ) {
     595           0 :         cnt=0;
     596           0 :         for ( i=0; i<len; ++i ) {
     597           0 :             if ( u_strncmp(ti[i]->text,spt,match_len)==0 ) {
     598           0 :                 if ( doit ) {
     599           0 :                     if ( ti[i]->checked /* isdirectory */ ) {
     600           0 :                         int len = u_strlen(ti[i]->text);
     601           0 :                         ret[cnt] = malloc((len+2)*sizeof(unichar_t));
     602           0 :                         u_strcpy(ret[cnt],ti[i]->text);
     603           0 :                         ret[cnt][len] = '/';
     604           0 :                         ret[cnt][len+1] = '\0';
     605             :                     } else
     606           0 :                         ret[cnt] = u_copy(ti[i]->text);
     607             :                 }
     608           0 :                 ++cnt;
     609             :             }
     610             :         }
     611           0 :         if ( doit )
     612           0 :             ret[cnt] = NULL;
     613           0 :         else if ( cnt==0 )
     614           0 : return( NULL );
     615             :         else
     616           0 :             ret = malloc((cnt+1)*sizeof(unichar_t *));
     617             :     }
     618           0 : return( ret );
     619             : }
     620             : 
     621           0 : static unichar_t *GFileChooserGetCurDir(GFileChooser *gfc,int dirindex) {
     622             :     GTextInfo **ti;
     623             :     int32 len; int j, cnt;
     624             :     unichar_t *dir, *pt;
     625             : 
     626           0 :     ti = GGadgetGetList(&gfc->directories->g,&len);
     627           0 :     if ( dirindex==-1 )
     628           0 :         dirindex = 0;
     629           0 :     dirindex = dirindex;
     630             : 
     631           0 :     for ( j=len-1, cnt=0; j>=dirindex; --j )
     632           0 :         cnt += u_strlen(ti[j]->text)+1;
     633           0 :     pt = dir = malloc((cnt+1)*sizeof(unichar_t));
     634           0 :     for ( j=len-1; j>=dirindex; --j ) {
     635           0 :         u_strcpy(pt,ti[j]->text);
     636           0 :         pt += u_strlen(pt);
     637           0 :         if ( pt[-1]!='/' )
     638           0 :             *pt++ = '/';
     639             :     }
     640           0 :     *pt = '\0';
     641           0 : return( dir );
     642             : }
     643             : 
     644             : /* Handle events from the directory dropdown list */
     645           0 : static int GFileChooserDListChanged(GGadget *pl,GEvent *e) {
     646             :     GFileChooser *gfc;
     647             :     int i; /*int32 len;*/
     648             :     unichar_t *dir;
     649             :     /*GTextInfo **ti;*/
     650             : 
     651           0 :     if ( e->type!=et_controlevent || e->u.control.subtype!=et_listselected )
     652           0 : return( true );
     653           0 :     i = GGadgetGetFirstListSelectedItem(pl);
     654           0 :     if ( i==-1 )
     655           0 : return(true);
     656             :     /*ti = GGadgetGetList(pl,&len);*/
     657           0 :     if ( i==0 )         /* Nothing changed */
     658           0 : return( true );
     659             : 
     660           0 :     gfc = (GFileChooser *) GGadgetGetUserData(pl);
     661           0 :     dir = GFileChooserGetCurDir(gfc,i);
     662           0 :     GFileChooserScanDir(gfc,dir);
     663           0 :     free(dir);
     664           0 : return( true );
     665             : }
     666             : 
     667             : /* Handle events from the file list list */
     668           0 : static int GFileChooserFListSelected(GGadget *gl,GEvent *e) {
     669             :     GFileChooser *gfc;
     670             :     int i;
     671             :     int32 listlen; int len, cnt, dirpos, apos;
     672             :     unichar_t *dir, *newdir;
     673             :     GTextInfo *ti, **all;
     674             : 
     675           0 :     if ( e->type!=et_controlevent ||
     676           0 :             ( e->u.control.subtype!=et_listselected &&
     677           0 :               e->u.control.subtype!=et_listdoubleclick ))
     678           0 : return( true );
     679           0 :     if ( ((GList *) gl)->multiple_sel ) {
     680           0 :         all = GGadgetGetList(gl,&listlen);
     681           0 :         len = cnt = 0;
     682           0 :         dirpos = apos = -1;
     683           0 :         for ( i=0; i<listlen; ++i ) {
     684           0 :             if ( !all[i]->selected )
     685             :                 /* Not selected? ignore it */;
     686           0 :             else if ( all[i]->checked )              /* Directory */
     687           0 :                 dirpos = i;
     688             :             else {
     689           0 :                 len += u_strlen( all[i]->text ) + 2;
     690           0 :                 ++cnt;
     691           0 :                 apos = i;
     692             :             }
     693             :         }
     694           0 :         if ( dirpos!=-1 && cnt>0 ) {
     695             :             /* If a directory was selected, clear everthing else */
     696           0 :             for ( i=0; i<listlen; ++i ) if ( i!=dirpos )
     697           0 :                 all[i]->selected = false;
     698           0 :             _ggadget_redraw(gl);
     699             :         }
     700           0 :         if ( dirpos!=-1 ) { cnt = 1; apos = dirpos; }
     701             :     } else {
     702           0 :         cnt = 1;
     703           0 :         apos = GGadgetGetFirstListSelectedItem(gl);
     704             :     }
     705           0 :     if ( apos==-1 )
     706           0 : return(true);
     707           0 :     gfc = (GFileChooser *) GGadgetGetUserData(gl);
     708           0 :     ti = GGadgetGetListItem(gl,apos);
     709           0 :     if ( e->u.control.subtype==et_listselected && cnt==1 ) {
     710             :         /* Nope, quite doesn't work. Goal is to remember first filename. But */
     711             :         /*  if user types into the list box we'll (probably) get several diff*/
     712             :         /*  filenames before we hit the directory. So we just ignore the typ-*/
     713             :         /*  ing case for now. */
     714           0 :         if ( ti->checked /* it's a directory */ && e->u.control.u.list.from_mouse &&
     715           0 :                 gfc->lastname==NULL )
     716           0 :             gfc->lastname = GGadgetGetTitle(&gfc->name->g);
     717           0 :         if ( ti->checked ) {
     718           0 :             unichar_t *val = malloc((u_strlen(ti->text)+2)*sizeof(unichar_t));
     719           0 :             u_strcpy(val,ti->text);
     720           0 :             uc_strcat(val,"/");
     721           0 :             GGadgetSetTitle(&gfc->name->g,val);
     722           0 :             free(val);
     723           0 :             if ( gfc->filterb!=NULL && gfc->ok!=NULL )
     724           0 :                 _GWidget_MakeDefaultButton(&gfc->filterb->g);
     725             :         } else {
     726           0 :             GGadgetSetTitle(&gfc->name->g,ti->text);
     727           0 :             if ( gfc->filterb!=NULL && gfc->ok!=NULL )
     728           0 :                 _GWidget_MakeDefaultButton(&gfc->ok->g);
     729           0 :             free(gfc->lastname);
     730           0 :             gfc->lastname = NULL;
     731             :         }
     732           0 :     } else if ( e->u.control.subtype==et_listselected ) {
     733           0 :         unichar_t *val, *upt = malloc((len+1)*sizeof(unichar_t));
     734           0 :         val = upt;
     735           0 :         for ( i=0; i<listlen; ++i ) {
     736           0 :             if ( all[i]->selected ) {
     737           0 :                 u_strcpy(upt,all[i]->text);
     738           0 :                 upt += u_strlen(upt);
     739           0 :                 if ( --cnt>0 ) {
     740           0 :                     uc_strcpy(upt,"; ");
     741           0 :                     upt += 2;
     742             :                 }
     743             :             }
     744             :         }
     745           0 :         GGadgetSetTitle(&gfc->name->g,val);
     746           0 :         free(val);
     747           0 :     } else if ( ti->checked /* it's a directory */ ) {
     748           0 :         dir = GFileChooserGetCurDir(gfc,-1);
     749           0 :         newdir = u_GFileAppendFile(dir,ti->text,true);
     750           0 :         GFileChooserScanDir(gfc,newdir);
     751           0 :         free(dir); free(newdir);
     752             :     } else {
     753             :         /* Post the double click (on a file) to the parent */
     754             :         /*  if we know what the ok button is then pretend it got pressed */
     755             :         /*  otherwise just send a list double click from ourselves */
     756           0 :         if ( gfc->ok!=NULL ) {
     757           0 :             e->u.control.subtype = et_buttonactivate;
     758           0 :             e->u.control.g = &gfc->ok->g;
     759           0 :             e->u.control.u.button.clicks = 0;
     760           0 :             e->w = e->u.control.g->base;
     761             :         } else
     762           0 :             e->u.control.g = &gfc->g;
     763           0 :         if ( e->u.control.g->handle_controlevent != NULL )
     764           0 :             (e->u.control.g->handle_controlevent)(e->u.control.g,e);
     765             :         else
     766           0 :             GDrawPostEvent(e);
     767             :     }
     768           0 : return( true );
     769             : }
     770             : 
     771           0 : static void GFCHideToggle(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     772           0 :     GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
     773             :     unichar_t *dir;
     774             : 
     775           0 :     showhidden = !showhidden;
     776             : 
     777           0 :     dir = GFileChooserGetCurDir(gfc,-1);
     778           0 :     GFileChooserScanDir(gfc,dir);
     779           0 :     free(dir);
     780             : 
     781           0 :     if ( prefs_changed!=NULL )
     782           0 :         (prefs_changed)(prefs_changed_data);
     783           0 : }
     784             : 
     785           0 : static void GFCRemetric(GFileChooser *gfc) {
     786             :     GRect size;
     787             : 
     788           0 :     GGadgetGetSize(&gfc->topbox->g,&size);
     789           0 :     GGadgetResize(&gfc->topbox->g,size.width,size.height);
     790           0 : }
     791             : 
     792           0 : static void GFCDirsAmidToggle(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     793           0 :     GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
     794             :     unichar_t *dir;
     795             : 
     796           0 :     if ( dir_placement==dirs_separate ) {
     797           0 :         GGadgetSetVisible(&gfc->subdirs->g,false);
     798           0 :         GFCRemetric(gfc);
     799             :     }
     800           0 :     dir_placement = dirs_mixed;
     801             : 
     802           0 :     dir = GFileChooserGetCurDir(gfc,-1);
     803           0 :     GFileChooserScanDir(gfc,dir);
     804           0 :     free(dir);
     805             : 
     806           0 :     if ( prefs_changed!=NULL )
     807           0 :         (prefs_changed)(prefs_changed_data);
     808           0 : }
     809             : 
     810           0 : static void GFCDirsFirstToggle(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     811           0 :     GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
     812             :     unichar_t *dir;
     813             : 
     814           0 :     if ( dir_placement==dirs_separate ) {
     815           0 :         GGadgetSetVisible(&gfc->subdirs->g,false);
     816           0 :         GFCRemetric(gfc);
     817             :     }
     818           0 :     dir_placement = dirs_first;
     819             : 
     820           0 :     dir = GFileChooserGetCurDir(gfc,-1);
     821           0 :     GFileChooserScanDir(gfc,dir);
     822           0 :     free(dir);
     823             : 
     824           0 :     if ( prefs_changed!=NULL )
     825           0 :         (prefs_changed)(prefs_changed_data);
     826           0 : }
     827             : 
     828           0 : static void GFCDirsSeparateToggle(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     829           0 :     GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
     830             :     unichar_t *dir;
     831             : 
     832           0 :     if ( dir_placement!=dirs_separate ) {
     833           0 :         GGadgetSetVisible(&gfc->subdirs->g,true);
     834           0 :         GFCRemetric(gfc);
     835             :     }
     836           0 :     dir_placement = dirs_separate;
     837             : 
     838           0 :     dir = GFileChooserGetCurDir(gfc,-1);
     839           0 :     GFileChooserScanDir(gfc,dir);
     840           0 :     free(dir);
     841             : 
     842           0 :     if ( prefs_changed!=NULL )
     843           0 :         (prefs_changed)(prefs_changed_data);
     844           0 : }
     845             : 
     846           0 : static void GFCRefresh(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     847           0 :     GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
     848             :     unichar_t *dir;
     849             : 
     850           0 :     dir = GFileChooserGetCurDir(gfc,-1);
     851           0 :     GFileChooserScanDir(gfc,dir);
     852           0 :     free(dir);
     853           0 : }
     854             : 
     855           0 : static int GFileChooserHome(GGadget *g, GEvent *e) {
     856           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     857           0 :         unichar_t* homedir = u_GFileGetHomeDocumentsDir();
     858           0 :         if ( homedir==NULL )
     859           0 :             GGadgetSetEnabled(g,false);
     860             :         else {
     861           0 :             GFileChooser *gfc = (GFileChooser *) GGadgetGetUserData(g);
     862           0 :             GFileChooserScanDir(gfc,homedir);
     863           0 :             free(homedir);
     864             :         }
     865             :     }
     866           0 : return( true );
     867             : }
     868             : 
     869           0 : static int GFileChooserUpDirButton(GGadget *g, GEvent *e) {
     870           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
     871           0 :         GFileChooser *gfc = (GFileChooser *) GGadgetGetUserData(g);
     872             :         unichar_t *dir, *newdir;
     873             :         static unichar_t dotdot[] = { '.', '.',  0 };
     874           0 :         dir = GFileChooserGetCurDir(gfc,-1);
     875           0 :         newdir = u_GFileAppendFile(dir,dotdot,true);
     876           0 :         GFileChooserScanDir(gfc,newdir);
     877           0 :         free(dir); free(newdir);
     878             :     }
     879           0 : return( true );
     880             : }
     881             : 
     882             : static GMenuItem gfcpopupmenu[] = {
     883             :     { { (unichar_t *) N_("Show Hidden Files"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 1, 0, 0, 0, 1, 0, 0, 'H' }, '\0', ksm_control, NULL, NULL, GFCHideToggle, 0 },
     884             :     { { (unichar_t *) N_("Directories Amid Files"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 1, 0, 0, 0, 1, 0, 0, 'H' }, '\0', ksm_control, NULL, NULL, GFCDirsAmidToggle, 0 },
     885             :     { { (unichar_t *) N_("Directories First"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 1, 0, 0, 0, 1, 0, 0, 'H' }, '\0', ksm_control, NULL, NULL, GFCDirsFirstToggle, 0 },
     886             :     { { (unichar_t *) N_("Directories Separate"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 1, 0, 0, 0, 1, 0, 0, 'H' }, '\0', ksm_control, NULL, NULL, GFCDirsSeparateToggle, 0 },
     887             :     { { (unichar_t *) N_("Refresh File List"), NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, 'H' }, '\0', ksm_control, NULL, NULL, GFCRefresh, 0 },
     888             :     GMENUITEM_EMPTY
     889             : };
     890             : static int gotten=false;
     891             : 
     892           0 : static void GFCPopupMenu(GGadget *g, GEvent *e) {
     893             :     int i;
     894             :     // The reason this casting works is a bit of a hack.
     895             :     // If this was initiated from a right click, `g` will be the GFC GGadget.
     896             :     // Then its userdata would be the initiator's, and NOT the GFC struct.
     897             :     // Thus we cannot call GGadgetGetUserData.
     898             :     // However, since in the GFC struct, its GGadget comes first, effectively
     899             :     // the pointer to its GGadget will equal the pointer to its GFC struct.
     900             :     // I have ensured that all calls to this function pass the GFC GGadget.
     901           0 :     GFileChooser *gfc = (GFileChooser *) g;
     902             : 
     903           0 :     for ( i=0; gfcpopupmenu[i].ti.text!=NULL || gfcpopupmenu[i].ti.line; ++i )
     904           0 :         gfcpopupmenu[i].ti.userdata = gfc;
     905           0 :     gfcpopupmenu[0].ti.checked = showhidden;
     906           0 :     gfcpopupmenu[1].ti.checked = dir_placement == dirs_mixed;
     907           0 :     gfcpopupmenu[2].ti.checked = dir_placement == dirs_first;
     908           0 :     gfcpopupmenu[3].ti.checked = dir_placement == dirs_separate;
     909           0 :     if ( !gotten ) {
     910           0 :         gotten = true;
     911           0 :         for ( i=0; gfcpopupmenu[i].ti.text!=NULL || gfcpopupmenu[i].ti.line; ++i )
     912           0 :             gfcpopupmenu[i].ti.text = (unichar_t *) _( (char *) gfcpopupmenu[i].ti.text);
     913             :     }
     914           0 :     GMenuCreatePopupMenu(g->base,e, gfcpopupmenu);
     915           0 : }
     916             : 
     917           0 : static int GFileChooserConfigure(GGadget *g, GEvent *e) {
     918           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonpress ) {
     919             :         GEvent fake;
     920             :         GRect pos;
     921           0 :         GGadgetGetSize(g,&pos);
     922           0 :         memset(&fake,0,sizeof(fake));
     923           0 :         fake.type = et_mousedown;
     924           0 :         fake.w = g->base;
     925           0 :         fake.u.mouse.x = pos.x;
     926           0 :         fake.u.mouse.y = pos.y+pos.height;
     927           0 :         GFCPopupMenu((GGadget*)GGadgetGetUserData(g),&fake);
     928             :     }
     929           0 : return( true );
     930             : }
     931             : 
     932           0 : static void GFCBack(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     933           0 :     GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
     934             : 
     935           0 :     if ( gfc->hpos<=0 )
     936           0 : return;
     937           0 :     --gfc->hpos;
     938           0 :     GFileChooserScanDir(gfc,gfc->history[gfc->hpos]);
     939             : }
     940             : 
     941           0 : static void GFCForward(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     942           0 :     GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
     943             : 
     944           0 :     if ( gfc->hpos+1>=gfc->hcnt )
     945           0 : return;
     946           0 :     ++gfc->hpos;
     947           0 :     GFileChooserScanDir(gfc,gfc->history[gfc->hpos]);
     948             : }
     949             : 
     950           0 : static void GFCAddCur(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     951           0 :     GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
     952             :     unichar_t *dir;
     953             :     int bcnt;
     954             : 
     955           0 :     dir = GFileChooserGetCurDir(gfc,-1);
     956           0 :     bcnt = 0;
     957           0 :     if ( bookmarks!=NULL )
     958           0 :         for ( ; bookmarks[bcnt]!=NULL; ++bcnt );
     959           0 :     bookmarks = realloc(bookmarks,(bcnt+2)*sizeof(unichar_t *));
     960           0 :     bookmarks[bcnt] = dir;
     961           0 :     bookmarks[bcnt+1] = NULL;
     962             : 
     963           0 :     if ( prefs_changed!=NULL )
     964           0 :         (prefs_changed)(prefs_changed_data);
     965           0 : }
     966             : 
     967           0 : static void GFCRemoveBook(GWindow gw,struct gmenuitem *mi,GEvent *e) {
     968             :     int i,bcnt;
     969             :     char **books;
     970             :     char *sel;
     971             :     char *buts[2];
     972             : 
     973           0 :     if ( bookmarks==NULL || bookmarks[0]==NULL )
     974           0 : return;         /* All gone */
     975           0 :     for ( bcnt=0; bookmarks[bcnt]!=NULL; ++bcnt );
     976           0 :     sel = calloc(bcnt,1);
     977           0 :     books = calloc(bcnt+1,sizeof(char *));
     978           0 :     for ( bcnt=0; bookmarks[bcnt]!=NULL; ++bcnt )
     979           0 :         books[bcnt] = u2utf8_copy(bookmarks[bcnt]);
     980           0 :     books[bcnt] = NULL;
     981           0 :     buts[0] = _("_Remove");
     982           0 :     buts[1] = _("_Cancel");
     983           0 :     if ( GWidgetChoicesBM8( _("Remove bookmarks"),(const char **) books,sel,bcnt,buts,
     984           0 :             _("Remove selected bookmarks"))==0 ) {
     985           0 :         for ( i=bcnt=0; bookmarks[bcnt]!=NULL; ++bcnt ) {
     986           0 :             if ( sel[bcnt] ) {
     987           0 :                 free(bookmarks[bcnt]);
     988             :             } else {
     989           0 :                 bookmarks[i++] = bookmarks[bcnt];
     990             :             }
     991             :         }
     992           0 :         bookmarks[i] = NULL;
     993             : 
     994           0 :         if ( prefs_changed!=NULL )
     995           0 :             (prefs_changed)(prefs_changed_data);
     996             :     }
     997           0 :     for ( i=0; books[i]!=NULL; ++i )
     998           0 :         free(books[i]);
     999           0 :     free(books);
    1000           0 :     free(sel);
    1001             : }
    1002             : 
    1003           0 : static void GFCBookmark(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1004           0 :     GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
    1005             :     char *home;
    1006             : 
    1007           0 :     if ( *bookmarks[mi->mid]=='~' && bookmarks[mi->mid][1]=='/' &&
    1008           0 :             (home = getenv("HOME"))!=NULL ) {
    1009             :         unichar_t *space;
    1010           0 :         space = malloc((strlen(home)+u_strlen(bookmarks[mi->mid])+2)*sizeof(unichar_t));
    1011           0 :         uc_strcpy(space,home);
    1012           0 :         u_strcat(space,bookmarks[mi->mid]+1);
    1013           0 :         GFileChooserScanDir(gfc,space);
    1014           0 :         free(space);
    1015             :     } else
    1016           0 :         GFileChooserScanDir(gfc,bookmarks[mi->mid]);
    1017           0 : }
    1018             : 
    1019           0 : static void GFCPath(GWindow gw,struct gmenuitem *mi,GEvent *e) {
    1020           0 :     GFileChooser *gfc = (GFileChooser *) (mi->ti.userdata);
    1021             :     char *home;
    1022             : 
    1023           0 :     if ( *gfc->paths[mi->mid]=='~' && gfc->paths[mi->mid][1]=='/' &&
    1024           0 :             (home = getenv("HOME"))!=NULL ) {
    1025             :         unichar_t *space;
    1026           0 :         space = malloc((strlen(home)+u_strlen(bookmarks[mi->mid])+2)*sizeof(unichar_t));
    1027           0 :         uc_strcpy(space,home);
    1028           0 :         u_strcat(space,gfc->paths[mi->mid]+1);
    1029           0 :         GFileChooserScanDir(gfc,space);
    1030           0 :         free(space);
    1031             :     } else
    1032           0 :         GFileChooserScanDir(gfc,gfc->paths[mi->mid]);
    1033           0 : }
    1034             : 
    1035             : static GMenuItem gfcbookmarkmenu[] = {
    1036             :     { { (unichar_t *) N_("Directory|Back"), &_GIcon_backarrow, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' }, '\0', ksm_control, NULL, NULL, GFCBack, 0 },
    1037             :     { { (unichar_t *) N_("Directory|Forward"), &_GIcon_forwardarrow, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' }, '\0', ksm_control, NULL, NULL, GFCForward, 0 },
    1038             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 1, 0, 0, 0, '\0' }, '\0', 0, NULL, NULL, NULL, 0 }, /* line */
    1039             :     { { (unichar_t *) N_("Bookmark Current Dir"), &_GIcon_bookmark, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' }, '\0', ksm_control, NULL, NULL, GFCAddCur, 0 },
    1040             :     { { (unichar_t *) N_("Remove Bookmark..."), &_GIcon_nobookmark, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 0, 1, 0, 0, '\0' }, '\0', ksm_control, NULL, NULL, GFCRemoveBook, 0 },
    1041             :     { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 0, 0, 0, 0, 1, 0, 0, 0, '\0' }, '\0', 0, NULL, NULL, NULL, 0 }, /* line */
    1042             :     GMENUITEM_EMPTY
    1043             : };
    1044             : static int bgotten=false;
    1045             : 
    1046           0 : static int GFileChooserBookmarks(GGadget *g, GEvent *e) {
    1047           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonpress ) {
    1048           0 :         GFileChooser *gfc = (GFileChooser *) GGadgetGetUserData(g);
    1049             :         GMenuItem *mi;
    1050             :         int i, bcnt, mcnt, pcnt;
    1051             :         GEvent fake;
    1052             :         GRect pos;
    1053             : 
    1054           0 :         if ( !bgotten ) {
    1055           0 :             bgotten = true;
    1056           0 :             for ( i=0; gfcbookmarkmenu[i].ti.text!=NULL || gfcbookmarkmenu[i].ti.line; ++i )
    1057           0 :                 if ( gfcbookmarkmenu[i].ti.text!=NULL )
    1058           0 :                     gfcbookmarkmenu[i].ti.text = (unichar_t *) S_( (char *) gfcbookmarkmenu[i].ti.text);
    1059             :         }
    1060           0 :         for ( mcnt=0; gfcbookmarkmenu[mcnt].ti.text!=NULL || gfcbookmarkmenu[mcnt].ti.line; ++mcnt );
    1061           0 :         bcnt = 0;
    1062           0 :         if ( bookmarks!=NULL )
    1063           0 :             for ( ; bookmarks[bcnt]!=NULL; ++bcnt );
    1064           0 :         if ( gfc->paths!=NULL ) {
    1065           0 :             for ( pcnt=0; gfc->paths[pcnt]!=NULL; ++pcnt );
    1066           0 :             if ( pcnt!=0 && bcnt!=0 ) ++pcnt;
    1067           0 :             bcnt += pcnt;
    1068             :         }
    1069           0 :         mi = calloc((mcnt+bcnt+1),sizeof(GMenuItem));
    1070           0 :         for ( mcnt=0; gfcbookmarkmenu[mcnt].ti.text!=NULL || gfcbookmarkmenu[mcnt].ti.line; ++mcnt ) {
    1071           0 :             mi[mcnt] = gfcbookmarkmenu[mcnt];
    1072           0 :             mi[mcnt].ti.text = (unichar_t *) copy( (char *) mi[mcnt].ti.text);
    1073           0 :             mi[mcnt].ti.userdata = gfc;
    1074             :         }
    1075           0 :         if ( gfc->hpos==0 )
    1076           0 :             mi[0].ti.disabled = true;           /* can't go further back */
    1077           0 :         if ( gfc->hpos+1>=gfc->hcnt )
    1078           0 :             mi[1].ti.disabled = true;           /* can't go further forward */
    1079           0 :         if ( bookmarks==NULL )
    1080           0 :             mi[4].ti.disabled = true;           /* can't remove bookmarks, already none */
    1081             :         else {
    1082           0 :             if ( gfc->paths!=NULL ) {
    1083           0 :                 for ( bcnt=0; gfc->paths[bcnt]!=NULL; ++bcnt ) {
    1084           0 :                     mi[mcnt+bcnt].ti.text = u_copy(gfc->paths[bcnt]);
    1085           0 :                     mi[mcnt+bcnt].ti.fg = mi[mcnt+bcnt].ti.bg = COLOR_DEFAULT;
    1086           0 :                     mi[mcnt+bcnt].ti.userdata = gfc;
    1087           0 :                     mi[mcnt+bcnt].mid = bcnt;
    1088           0 :                     mi[mcnt+bcnt].invoke = GFCPath;
    1089             :                 }
    1090           0 :                 mcnt+=bcnt;
    1091           0 :                 if ( bookmarks!=NULL && bookmarks[0]!=NULL ) {
    1092           0 :                     mi[mcnt].ti.line = true;
    1093           0 :                     mi[mcnt].ti.fg = mi[mcnt].ti.bg = COLOR_DEFAULT;
    1094           0 :                     ++mcnt;
    1095             :                 }
    1096             :             }
    1097           0 :             for ( bcnt=0; bookmarks[bcnt]!=NULL; ++bcnt ) {
    1098           0 :                 mi[mcnt+bcnt].ti.text = u_copy(bookmarks[bcnt]);
    1099           0 :                 mi[mcnt+bcnt].ti.fg = mi[mcnt+bcnt].ti.bg = COLOR_DEFAULT;
    1100           0 :                 mi[mcnt+bcnt].ti.userdata = gfc;
    1101           0 :                 mi[mcnt+bcnt].mid = bcnt;
    1102           0 :                 mi[mcnt+bcnt].invoke = GFCBookmark;
    1103             :             }
    1104             :         }
    1105           0 :         GGadgetGetSize(g,&pos);
    1106           0 :         memset(&fake,0,sizeof(fake));
    1107           0 :         fake.type = et_mousedown;
    1108           0 :         fake.w = g->base;
    1109           0 :         fake.u.mouse.x = pos.x;
    1110           0 :         fake.u.mouse.y = pos.y+pos.height;
    1111           0 :         GMenuCreatePopupMenu(gfc->g.base,&fake, mi);
    1112           0 :         GMenuItemArrayFree(mi);
    1113             :     }
    1114           0 : return( true );
    1115             : }
    1116             : 
    1117             : /* Routine to be called as the mouse moves across the dlg */
    1118           0 : void GFileChooserPopupCheck(GGadget *g,GEvent *e) {
    1119           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1120           0 :     int inside=false;
    1121             : 
    1122           0 :     if ( e->type == et_mousemove && (e->u.mouse.state&ksm_buttons)==0 ) {
    1123           0 :         GGadgetEndPopup();
    1124           0 :         for ( g=((GContainerD *) (gfc->g.base->widget_data))->gadgets; g!=NULL; g=g->prev ) {
    1125           0 :             if ( g!=(GGadget *) gfc && g!=(GGadget *) (gfc->filterb) &&
    1126           0 :                      g!=(GGadget *) (gfc->files) &&
    1127           0 :                      g->takes_input &&
    1128           0 :                      e->u.mouse.x >= g->r.x &&
    1129           0 :                      e->u.mouse.x<g->r.x+g->r.width &&
    1130           0 :                      e->u.mouse.y >= g->r.y &&
    1131           0 :                      e->u.mouse.y<g->r.y+g->r.height ) {
    1132           0 :                 inside = true;
    1133           0 :         break;
    1134             :             }
    1135             :         }
    1136           0 :         if ( !inside )
    1137           0 :             GGadgetPreparePopup(gfc->g.base,gfc->wildcard);
    1138           0 :     } else if ( e->type == et_mousedown && e->u.mouse.button==3 ) {
    1139           0 :         GFCPopupMenu(g,e);
    1140             :     }
    1141           0 : }
    1142             : 
    1143             : /* Routine to be called by the filter button */
    1144           0 : void GFileChooserFilterIt(GGadget *g) {
    1145           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1146             :     unichar_t *pt, *spt, *slashpt, *dir, *temp;
    1147           0 :     unichar_t *tofree = NULL;
    1148             :     int wasdir;
    1149             : 
    1150           0 :     wasdir = gfc->lastname!=NULL;
    1151             : 
    1152           0 :     spt = (unichar_t *) _GGadgetGetTitle(&gfc->name->g);
    1153             : #ifdef _WIN32
    1154             :     spt = tofree = u_GFileNormalizePath(u_copy(spt));
    1155             : #endif
    1156           0 :     if ( *spt=='\0' ) {         /* Werner tells me that pressing the Filter button with nothing should show the default filter mask */
    1157           0 :         if ( gfc->wildcard!=NULL )
    1158           0 :             GGadgetSetTitle(&gfc->name->g,gfc->wildcard);
    1159           0 : return;
    1160             :     }
    1161             : 
    1162           0 :     if (( slashpt = u_strrchr(spt,'/'))==NULL )
    1163           0 :         slashpt = spt;
    1164             :     else
    1165           0 :         ++slashpt;
    1166           0 :     pt = slashpt;
    1167           0 :     while ( *pt && *pt!='*' && *pt!='?' && *pt!='[' && *pt!='{' )
    1168           0 :         ++pt;
    1169           0 :     if ( *pt!='\0' ) {
    1170           0 :         free(gfc->wildcard);
    1171           0 :         gfc->wildcard = u_copy(slashpt);
    1172           0 :     } else if ( gfc->lastname==NULL )
    1173           0 :         gfc->lastname = u_copy(slashpt);
    1174           0 :     if( u_GFileIsAbsolute(spt) )
    1175           0 :         dir = u_copyn(spt,slashpt-spt);
    1176             :     else {
    1177           0 :         unichar_t *curdir = GFileChooserGetCurDir(gfc,-1);
    1178           0 :         if ( slashpt!=spt ) {
    1179           0 :             temp = u_copyn(spt,slashpt-spt);
    1180           0 :             dir = u_GFileAppendFile(curdir,temp,true);
    1181           0 :             free(temp);
    1182           0 :         } else if ( wasdir && *pt=='\0' )
    1183           0 :             dir = u_GFileAppendFile(curdir,spt,true);
    1184             :         else
    1185           0 :             dir = curdir;
    1186           0 :         if ( dir!=curdir )
    1187           0 :             free(curdir);
    1188             :     }
    1189           0 :     GFileChooserScanDir(gfc,dir);
    1190           0 :     free(dir);
    1191           0 :     free(tofree);
    1192             : }
    1193             : 
    1194             : /* A function that may be connected to a filter button as its handle_controlevent */
    1195           0 : int GFileChooserFilterEh(GGadget *g, GEvent *e) {
    1196           0 :     if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate )
    1197           0 :         GFileChooserFilterIt(GGadgetGetUserData(g));
    1198           0 : return( true );
    1199             : }
    1200             : 
    1201           0 : void GFileChooserConnectButtons(GGadget *g,GGadget *ok, GGadget *filter) {
    1202           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1203           0 :     gfc->ok = (GButton *) ok;
    1204           0 :     gfc->filterb = (GButton *) filter;
    1205           0 : }
    1206             : 
    1207           0 : void GFileChooserSetFilterText(GGadget *g,const unichar_t *wildcard) {
    1208           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1209           0 :     free(gfc->wildcard);
    1210           0 :     gfc->wildcard = u_copy(wildcard);
    1211           0 : }
    1212             : 
    1213           0 : unichar_t *GFileChooserGetFilterText(GGadget *g) {
    1214           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1215           0 : return( gfc->wildcard );
    1216             : }
    1217             : 
    1218           0 : void GFileChooserSetFilterFunc(GGadget *g,GFileChooserFilterType filter) {
    1219           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1220           0 :     if ( filter==NULL )
    1221           0 :         filter = GFileChooserDefFilter;
    1222           0 :     gfc->filter = filter;
    1223           0 : }
    1224             : 
    1225           0 : GFileChooserFilterType GFileChooserGetFilterFunc(GGadget *g) {
    1226           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1227           0 : return( gfc->filter );
    1228             : }
    1229             : 
    1230             : /**
    1231             :  * no change to the current filename by default
    1232             :  *
    1233             :  * if a change is desired, then currentFilename should point to the
    1234             :  * new string and return 1 to allow the caller to free this new
    1235             :  * string.
    1236             :  */
    1237           0 : int GFileChooserDefInputFilenameFunc( GGadget *g,
    1238             :                                       const unichar_t ** currentFilename,
    1239             :                                       unichar_t* oldfilename ) {
    1240           0 :     return 0;
    1241             : }
    1242             : 
    1243           0 : void GFileChooserSetInputFilenameFunc(GGadget *g,GFileChooserInputFilenameFuncType func) {
    1244           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1245           0 :     if ( func==NULL )
    1246           0 :         func = GFileChooserDefInputFilenameFunc;
    1247           0 :     gfc->inputfilenamefunc = func;
    1248           0 : }
    1249             : 
    1250           0 : GFileChooserInputFilenameFuncType GFileChooserGetInputFilenameFunc(GGadget *g) {
    1251           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1252           0 :     if ( gfc->inputfilenamefunc==NULL )
    1253           0 :         return GFileChooserDefInputFilenameFunc;
    1254           0 :     return( gfc->inputfilenamefunc );
    1255             : }
    1256             : 
    1257             : 
    1258           0 : void GFileChooserSetFilename(GGadget *g,const unichar_t *defaultfile)
    1259             : {
    1260           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1261             : 
    1262           0 :     GGadgetSetTitle(g,defaultfile);
    1263             : 
    1264             :     // if this is the first time we are here, we assume
    1265             :     // the current filename is what it was before. Less NULL
    1266             :     // checks in the callback function below.
    1267           0 :     if(!gfc->inputfilenameprevchar)
    1268           0 :         gfc->inputfilenameprevchar = u_copy(_GGadgetGetTitle(&gfc->name->g));
    1269             : 
    1270           0 : }
    1271             : 
    1272             : 
    1273           0 : void GFileChooserSetMimetypes(GGadget *g,unichar_t **mimetypes) {
    1274           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1275             :     int i;
    1276             : 
    1277           0 :     if ( gfc->mimetypes ) {
    1278           0 :         for ( i=0; gfc->mimetypes[i]!=NULL; ++i )
    1279           0 :             free( gfc->mimetypes[i]);
    1280           0 :         free(gfc->mimetypes);
    1281             :     }
    1282           0 :     if ( mimetypes ) {
    1283           0 :         for ( i=0; mimetypes[i]!=NULL; ++i );
    1284           0 :         gfc->mimetypes = malloc((i+1)*sizeof(unichar_t *));
    1285           0 :         for ( i=0; mimetypes[i]!=NULL; ++i )
    1286           0 :             gfc->mimetypes[i] = u_copy(mimetypes[i]);
    1287           0 :         gfc->mimetypes[i] = NULL;
    1288             :     } else
    1289           0 :         gfc->mimetypes = NULL;
    1290           0 : }
    1291             : 
    1292           0 : unichar_t **GFileChooserGetMimetypes(GGadget *g) {
    1293           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1294           0 : return( gfc->mimetypes );
    1295             : }
    1296             : 
    1297             : /* Change the current file, or the current directory/file */
    1298           0 : static void GFileChooserSetTitle(GGadget *g,const unichar_t *tit) {
    1299           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1300             :     unichar_t *pt, *curdir, *temp, *dir, *base;
    1301             : 
    1302           0 :     if ( tit==NULL ) {
    1303           0 :         curdir = GFileChooserGetCurDir(gfc,-1);
    1304           0 :         GFileChooserScanDir(gfc,curdir);
    1305           0 :         free(curdir);
    1306           0 : return;
    1307             :     }
    1308             : 
    1309           0 :     pt = u_strrchr(tit,'/');
    1310           0 :     free(gfc->lastname);
    1311           0 :     gfc->lastname = NULL;
    1312             : 
    1313           0 :     if ( u_GFileIsAbsolute(tit) ){
    1314           0 :         base = uc_strstr(tit, "://");
    1315           0 :         if(!base) base = (unichar_t*) tit;
    1316           0 :         if(pt > base && pt[1] && (pt[1]!='.' || pt[2]!='\0')){
    1317           0 :             gfc->lastname = u_copy(pt+1);
    1318           0 :             dir = u_copyn(tit, pt-tit);
    1319             :         }
    1320             :         else{
    1321           0 :             dir = u_copy(tit);
    1322             :         }
    1323           0 :         GFileChooserScanDir(gfc,dir);
    1324           0 :         free(dir);
    1325           0 :     } else if ( pt==NULL ) {
    1326           0 :         GGadgetSetTitle(&gfc->name->g,tit);
    1327           0 :         curdir = GFileChooserGetCurDir(gfc,-1);
    1328           0 :         GFileChooserScanDir(gfc,curdir);
    1329           0 :         free(curdir);
    1330             :     } else {
    1331           0 :         curdir = GFileChooserGetCurDir(gfc,-1);
    1332           0 :         temp = u_copyn(tit,pt-tit);
    1333           0 :         dir = u_GFileAppendFile(curdir,temp,true);
    1334           0 :         free(temp); free(curdir);
    1335           0 :         free(gfc->lastname);
    1336           0 :         if ( pt[1]!='\0' )
    1337           0 :             gfc->lastname = u_copy(pt+1);
    1338           0 :         GFileChooserScanDir(gfc,dir);
    1339           0 :         free(dir);
    1340             :     }
    1341             : }
    1342             : 
    1343           0 : void GFileChooserRefreshList(GGadget *g) {
    1344           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1345             :     unichar_t *curdir;
    1346             : 
    1347           0 :     curdir = GFileChooserGetCurDir(gfc,-1);
    1348           0 :     GFileChooserScanDir(gfc,curdir);
    1349           0 :     free(curdir);
    1350           0 : }
    1351             : 
    1352             : /* Get the current directory/file */
    1353           0 : static unichar_t *GFileChooserGetTitle(GGadget *g) {
    1354           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1355             :     unichar_t *spt, *curdir, *file;
    1356             : 
    1357           0 :     spt = u_GFileNormalizePath(u_copy((unichar_t *)_GGadgetGetTitle(&gfc->name->g)));
    1358           0 :     if ( u_GFileIsAbsolute(spt) )
    1359           0 :         file = spt;
    1360             :     else {
    1361           0 :         curdir = GFileChooserGetCurDir(gfc,-1);
    1362           0 :         file = u_GFileAppendFile(curdir,spt,gfc->lastname!=NULL);
    1363           0 :         free(curdir);
    1364             :     }
    1365           0 :     if (file != spt) {
    1366           0 :         free(spt);
    1367             :     }
    1368           0 : return( file );
    1369             : }
    1370             : 
    1371           0 : static void GFileChooser_destroy(GGadget *g) {
    1372           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1373             :     int i;
    1374             : 
    1375           0 :     free(lastdir);
    1376           0 :     lastdir = GFileChooserGetCurDir(gfc,-1);
    1377             : 
    1378           0 :     if ( gfc->outstanding )
    1379           0 :         GIOcancel(gfc->outstanding);
    1380           0 :     GGadgetDestroy(&gfc->topbox->g);  /* destroys everything */
    1381           0 :     if ( gfc->paths!=NULL ) {
    1382           0 :         for ( i=0; gfc->paths[i]!=NULL; ++i )
    1383           0 :             free(gfc->paths[i]);
    1384           0 :         free(gfc->paths);
    1385             :     }
    1386           0 :     free(gfc->wildcard);
    1387           0 :     free(gfc->lastname);
    1388           0 :     if ( gfc->mimetypes ) {
    1389           0 :         for ( i=0; gfc->mimetypes[i]!=NULL; ++i )
    1390           0 :             free( gfc->mimetypes[i]);
    1391           0 :         free(gfc->mimetypes);
    1392             :     }
    1393           0 :     for ( i=0; i<gfc->hcnt; ++i )
    1394           0 :         free(gfc->history[i]);
    1395           0 :     free(gfc->history);
    1396           0 :     _ggadget_destroy(&gfc->g);
    1397           0 : }
    1398             : 
    1399           0 : static int gfilechooser_expose(GWindow pixmap, GGadget *g, GEvent *event) {
    1400           0 : return( true );
    1401             : }
    1402             : 
    1403           0 : static int gfilechooser_mouse(GGadget *g, GEvent *event) {
    1404           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1405             : 
    1406           0 :     if (( event->type==et_mouseup || event->type==et_mousedown ) &&
    1407           0 :             (event->u.mouse.button>=4 && event->u.mouse.button<=7) ) {
    1408           0 :         if ( gfc->files->vsb!=NULL )
    1409           0 : return( GGadgetDispatchEvent(&gfc->files->vsb->g,event));
    1410             :         else
    1411           0 : return( true );
    1412             :     }
    1413             : 
    1414           0 : return( false );
    1415             : }
    1416             : 
    1417           0 : static int gfilechooser_noop(GGadget *g, GEvent *event) {
    1418           0 : return( false );
    1419             : }
    1420             : 
    1421           0 : static int gfilechooser_timer(GGadget *g, GEvent *event) {
    1422           0 : return( false );
    1423             : }
    1424             : 
    1425           0 : static void gfilechooser_move(GGadget *g, int32 x, int32 y ) {
    1426           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1427             : 
    1428           0 :     GGadgetMove(&gfc->topbox->g,x,y);
    1429           0 :     _ggadget_move(g,x,y);
    1430           0 : }
    1431             : 
    1432           0 : static void gfilechooser_resize(GGadget *g, int32 width, int32 height ) {
    1433           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1434             : 
    1435           0 :     GGadgetResize(&gfc->topbox->g,width,height);
    1436           0 :     _ggadget_resize(g,width,height);
    1437           0 : }
    1438             : 
    1439           0 : static void gfilechooser_setvisible(GGadget *g, int visible ) {
    1440           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1441           0 :     GGadgetSetVisible(&gfc->files->g,visible);
    1442           0 :     GGadgetSetVisible(&gfc->directories->g,visible);
    1443           0 :     GGadgetSetVisible(&gfc->name->g,visible);
    1444           0 :     GGadgetSetVisible(&gfc->up->g,visible);
    1445           0 :     GGadgetSetVisible(&gfc->home->g,visible);
    1446           0 :     GGadgetSetVisible(&gfc->bookmarks->g,visible);
    1447           0 :     GGadgetSetVisible(&gfc->config->g,visible);
    1448           0 :     GGadgetSetVisible(&gfc->topbox->g,visible);
    1449           0 :     _ggadget_setvisible(g,visible);
    1450           0 : }
    1451             : 
    1452           0 : static void gfilechooser_setenabled(GGadget *g, int enabled ) {
    1453           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1454           0 :     GGadgetSetEnabled(&gfc->files->g,enabled);
    1455           0 :     GGadgetSetEnabled(&gfc->subdirs->g,enabled);
    1456           0 :     GGadgetSetEnabled(&gfc->directories->g,enabled);
    1457           0 :     GGadgetSetEnabled(&gfc->name->g,enabled);
    1458           0 :     GGadgetSetEnabled(&gfc->up->g,enabled);
    1459           0 :     GGadgetSetEnabled(&gfc->home->g,enabled);
    1460           0 :     GGadgetSetEnabled(&gfc->bookmarks->g,enabled);
    1461           0 :     GGadgetSetEnabled(&gfc->config->g,enabled);
    1462           0 :     GGadgetSetEnabled(&gfc->topbox->g,enabled);
    1463           0 :     _ggadget_setenabled(g,enabled);
    1464           0 : }
    1465             : 
    1466           0 : static void GFileChooserGetDesiredSize(GGadget *g,GRect *outer,GRect *inner) {
    1467           0 :     if ( inner!=NULL ) {
    1468           0 :         int bp = GBoxBorderWidth(g->base,g->box);
    1469           0 :         inner->x = inner->y = 0;
    1470           0 :         inner->width = g->desired_width - 2*bp;
    1471           0 :         inner->height = g->desired_height - 2*bp;
    1472             :     }
    1473           0 :     if ( outer!=NULL ) {
    1474           0 :         outer->x = outer->y = 0;
    1475           0 :         outer->width = g->desired_width;
    1476           0 :         outer->height = g->desired_height;
    1477             :     }
    1478           0 : }
    1479             : 
    1480           0 : static int gfilechooser_FillsWindow(GGadget *g) {
    1481           0 : return( g->prev==NULL &&
    1482           0 :         (_GWidgetGetGadgets(g->base)==g ||
    1483           0 :          _GWidgetGetGadgets(g->base)==(GGadget *) ((GFileChooser *) g)->up ));
    1484             : }
    1485             : 
    1486             : struct gfuncs GFileChooser_funcs = {
    1487             :     0,
    1488             :     sizeof(struct gfuncs),
    1489             : 
    1490             :     gfilechooser_expose,
    1491             :     gfilechooser_mouse,
    1492             :     gfilechooser_noop,
    1493             :     NULL,
    1494             :     NULL,
    1495             :     gfilechooser_timer,
    1496             :     NULL,
    1497             : 
    1498             :     _ggadget_redraw,
    1499             :     gfilechooser_move,
    1500             :     gfilechooser_resize,
    1501             :     gfilechooser_setvisible,
    1502             :     gfilechooser_setenabled,
    1503             :     _ggadget_getsize,
    1504             :     _ggadget_getinnersize,
    1505             : 
    1506             :     GFileChooser_destroy,
    1507             : 
    1508             :     GFileChooserSetTitle,
    1509             :     NULL,
    1510             :     GFileChooserGetTitle,
    1511             :     NULL,
    1512             :     NULL,
    1513             :     NULL,
    1514             :     NULL,
    1515             :     NULL,
    1516             : 
    1517             :     NULL,
    1518             :     NULL,
    1519             :     NULL,
    1520             :     NULL,
    1521             :     NULL,
    1522             :     NULL,
    1523             :     NULL,
    1524             :     NULL,
    1525             :     NULL,
    1526             :     NULL,
    1527             : 
    1528             :     GFileChooserGetDesiredSize,
    1529             :     _ggadget_setDesiredSize,
    1530             :     gfilechooser_FillsWindow,
    1531             :     NULL
    1532             : };
    1533             : 
    1534           0 : static void GFileChooserCreateChildren(GFileChooser *gfc, int flags) {
    1535             :     GGadgetCreateData gcd[9], boxes[4], *varray[9], *harray[12], *harray2[4];
    1536             :     GTextInfo label[9];
    1537           0 :     int k=0, l=0, homek, upk, bookk, confk, dirsk, subdirsk, filesk, textk;
    1538             : 
    1539           0 :     memset(&gcd,'\0',sizeof(gcd));
    1540           0 :     memset(&boxes,'\0',sizeof(boxes));
    1541           0 :     memset(&label,'\0',sizeof(label));
    1542             : 
    1543           0 :     gcd[k].gd.flags = gg_visible|gg_enabled|gg_utf8_popup;
    1544           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Home Folder");
    1545           0 :     label[k].image = &_GIcon_homefolder;
    1546           0 :     gcd[k].gd.label = &label[k];
    1547           0 :     gcd[k].gd.handle_controlevent = GFileChooserHome;
    1548           0 :     homek = k;
    1549           0 :     gcd[k++].creator = GButtonCreate;
    1550           0 :     harray[l++] = &gcd[k-1]; harray[l++] = GCD_Glue;
    1551             : 
    1552           0 :     gcd[k].gd.flags = gg_visible|gg_enabled|gg_utf8_popup;
    1553           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Bookmarks");
    1554           0 :     label[k].image = &_GIcon_bookmark;
    1555           0 :     gcd[k].gd.label = &label[k];
    1556           0 :     gcd[k].gd.handle_controlevent = GFileChooserBookmarks;
    1557           0 :     bookk = k;
    1558           0 :     gcd[k++].creator = GButtonCreate;
    1559           0 :     harray[l++] = &gcd[k-1]; harray[l++] = GCD_Glue;
    1560             : 
    1561           0 :     gcd[k].gd.flags = gg_visible|gg_enabled|gg_list_exactlyone;
    1562           0 :     gcd[k].gd.handle_controlevent = GFileChooserDListChanged;
    1563           0 :     dirsk = k;
    1564           0 :     gcd[k++].creator = GListButtonCreate;
    1565           0 :     harray[l++] = &gcd[k-1]; harray[l++] = GCD_Glue;
    1566             : 
    1567           0 :     gcd[k].gd.flags = gg_visible|gg_enabled|gg_utf8_popup;
    1568           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Parent Folder");
    1569           0 :     label[k].image = &_GIcon_updir;
    1570           0 :     gcd[k].gd.label = &label[k];
    1571           0 :     gcd[k].gd.handle_controlevent = GFileChooserUpDirButton;
    1572           0 :     upk = k;
    1573           0 :     gcd[k++].creator = GButtonCreate;
    1574           0 :     harray[l++] = &gcd[k-1]; harray[l++] = GCD_Glue;
    1575             : 
    1576           0 :     gcd[k].gd.flags = gg_visible|gg_enabled|gg_utf8_popup;
    1577           0 :     gcd[k].gd.popup_msg = (unichar_t *) _("Configure");
    1578           0 :     label[k].image = &_GIcon_configtool;
    1579           0 :     gcd[k].gd.label = &label[k];
    1580           0 :     gcd[k].gd.handle_controlevent = GFileChooserConfigure;
    1581           0 :     confk = k;
    1582           0 :     gcd[k++].creator = GButtonCreate;
    1583           0 :     harray[l++] = &gcd[k-1]; harray[l++] = NULL;
    1584             : 
    1585           0 :     boxes[2].gd.flags = gg_enabled|gg_visible;
    1586           0 :     boxes[2].gd.u.boxelements = harray;
    1587           0 :     boxes[2].creator = GHBoxCreate;
    1588             : 
    1589           0 :     l=0;
    1590           0 :     varray[l++] = &boxes[2];
    1591             : 
    1592           0 :     if ( dir_placement==dirs_separate )
    1593           0 :         gcd[k].gd.flags = gg_visible|gg_enabled|gg_list_alphabetic|gg_list_exactlyone;
    1594             :     else
    1595           0 :         gcd[k].gd.flags =            gg_enabled|gg_list_alphabetic|gg_list_exactlyone;
    1596           0 :     gcd[k].gd.handle_controlevent = GFileChooserFListSelected;
    1597           0 :     subdirsk = k;
    1598           0 :     gcd[k++].creator = GListCreate;
    1599           0 :     harray2[0] = &gcd[k-1];
    1600             : 
    1601           0 :     if ( flags & gg_file_multiple )
    1602           0 :         gcd[k].gd.flags = gg_visible|gg_enabled|gg_list_alphabetic|gg_list_multiplesel;
    1603             :     else
    1604           0 :         gcd[k].gd.flags = gg_visible|gg_enabled|gg_list_alphabetic|gg_list_exactlyone;
    1605           0 :     gcd[k].gd.handle_controlevent = GFileChooserFListSelected;
    1606           0 :     filesk = k;
    1607           0 :     gcd[k++].creator = GListCreate;
    1608           0 :     harray2[1] = &gcd[k-1]; harray2[2] = NULL;
    1609             : 
    1610           0 :     boxes[3].gd.flags = gg_enabled|gg_visible;
    1611           0 :     boxes[3].gd.u.boxelements = harray2;
    1612           0 :     boxes[3].creator = GHBoxCreate;
    1613           0 :     varray[l++] = &boxes[3];
    1614             : 
    1615           0 :     gcd[k].gd.flags = gg_visible|gg_enabled;
    1616           0 :     gcd[k].gd.handle_controlevent = GFileChooserTextChanged;
    1617           0 :     textk = k;
    1618           0 :     if ( flags&gg_file_pulldown )
    1619           0 :         gcd[k++].creator = GListFieldCreate;
    1620             :     else
    1621           0 :         gcd[k++].creator = GTextCompletionCreate;
    1622           0 :     varray[l++] = &gcd[k-1]; varray[l] = NULL;
    1623             : 
    1624           0 :     boxes[0].gd.pos.x = gfc->g.r.x;
    1625           0 :     boxes[0].gd.pos.y = gfc->g.r.y;
    1626           0 :     boxes[0].gd.pos.width  = gfc->g.r.width;
    1627           0 :     boxes[0].gd.pos.height = gfc->g.r.height;
    1628           0 :     boxes[0].gd.flags = gg_enabled|gg_visible;
    1629           0 :     boxes[0].gd.u.boxelements = varray;
    1630           0 :     boxes[0].creator = GVBoxCreate;
    1631             : 
    1632           0 :     for ( l=0; l<k; ++l )
    1633           0 :         gcd[l].data = gfc;
    1634             : 
    1635           0 :     GGadgetsCreate(gfc->g.base,boxes);
    1636             : 
    1637           0 :     gfc->topbox      = (GHVBox *)      boxes[0].ret;
    1638           0 :     gfc->home        = (GButton *)     gcd[homek].ret;
    1639           0 :     gfc->bookmarks   = (GButton *)     gcd[bookk].ret;
    1640           0 :     gfc->directories = (GListButton *) gcd[dirsk].ret;
    1641           0 :     gfc->up          = (GButton *)     gcd[upk  ].ret;
    1642           0 :     gfc->config      = (GButton *)     gcd[confk].ret;
    1643           0 :     gfc->subdirs     = (GList *)       gcd[subdirsk].ret;
    1644           0 :     gfc->files       = (GList *)       gcd[filesk].ret;
    1645           0 :     gfc->name        = (GTextField *)  gcd[textk].ret;
    1646             : 
    1647           0 :     gfc->home->g.contained = true;
    1648           0 :     gfc->bookmarks->g.contained = true;
    1649           0 :     gfc->directories->g.contained = true;
    1650           0 :     gfc->up->g.contained = true;
    1651           0 :     gfc->config->g.contained = true;
    1652           0 :     gfc->subdirs->g.contained = true;
    1653           0 :     gfc->files->g.contained = true;
    1654           0 :     gfc->name->g.contained = true;
    1655           0 :     gfc->topbox->g.contained = true;
    1656             : 
    1657           0 :     GCompletionFieldSetCompletion(&gfc->name->g,GFileChooserCompletion);
    1658           0 :     GCompletionFieldSetCompletionMode(&gfc->name->g,true);
    1659             : 
    1660           0 :     GHVBoxSetExpandableRow(boxes[0].ret,1);
    1661           0 :     GHVBoxSetExpandableCol(boxes[2].ret,4);
    1662           0 :     if ( boxes[0].gd.pos.width!=0 && boxes[0].gd.pos.height!=0 )
    1663           0 :         GGadgetResize(boxes[0].ret,boxes[0].gd.pos.width,boxes[0].gd.pos.height);
    1664           0 : }
    1665             : 
    1666           0 : GGadget *GFileChooserCreate(struct gwindow *base, GGadgetData *gd,void *data) {
    1667           0 :     GFileChooser *gfc = (GFileChooser *) calloc(1,sizeof(GFileChooser));
    1668             : 
    1669           0 :     gfc->g.funcs = &GFileChooser_funcs;
    1670           0 :     _GGadget_Create(&gfc->g,base,gd,data,&gfilechooser_box);
    1671           0 :     gfc->g.takes_input = gfc->g.takes_keyboard = false; gfc->g.focusable = false;
    1672           0 :     if ( gfc->g.r.width == 0 )
    1673           0 :         gfc->g.r.width = GGadgetScale(GDrawPointsToPixels(base,140));
    1674           0 :     if ( gfc->g.r.height == 0 )
    1675           0 :         gfc->g.r.height = GDrawPointsToPixels(base,100);
    1676           0 :     gfc->g.desired_width = gfc->g.r.width;
    1677           0 :     gfc->g.desired_height = gfc->g.r.height;
    1678           0 :     gfc->g.inner = gfc->g.r;
    1679           0 :     _GGadget_FinalPosition(&gfc->g,base,gd);
    1680             : 
    1681           0 :     GFileChooserCreateChildren(gfc, gd->flags);
    1682           0 :     gfc->filter = GFileChooserDefFilter;
    1683           0 :     GFileChooserSetInputFilenameFunc( (GGadget*)gfc, 0 );
    1684           0 :     if ( gd->flags & gg_group_end )
    1685           0 :         _GGadgetCloseGroup(&gfc->g);
    1686             : 
    1687           0 :     if ( lastdir==NULL ) {
    1688             :         static unichar_t dot[] = { '.', '\0' };
    1689             :         unichar_t buffer[1025];
    1690           0 :         lastdir = u_copy(u_GFileGetAbsoluteName(dot,buffer,sizeof(buffer)/sizeof(unichar_t)));
    1691             :     }
    1692           0 :     if ( gd->label==NULL || gd->label->text==NULL )
    1693           0 :         GFileChooserSetTitle(&gfc->g,lastdir);
    1694           0 :     else if ( u_GFileIsAbsolute(gd->label->text) )
    1695           0 :         GFileChooserSetTitle(&gfc->g,gd->label->text);
    1696             :     else {
    1697           0 :         unichar_t *temp = u_GFileAppendFile(lastdir,gd->label->text,false);
    1698           0 :         temp = u_GFileNormalize(temp);
    1699           0 :         GFileChooserSetTitle(&gfc->g,temp);
    1700           0 :         free(temp);
    1701             :     }
    1702             : 
    1703           0 : return( &gfc->g );
    1704             : }
    1705             : 
    1706           0 : void GFileChooserSetDir(GGadget *g,unichar_t *dir) {
    1707           0 :     GFileChooserScanDir((GFileChooser *) g,dir);
    1708           0 : }
    1709             : 
    1710           0 : unichar_t *GFileChooserGetDir(GGadget *g) {
    1711           0 : return( GFileChooserGetCurDir((GFileChooser *) g,-1));
    1712             : }
    1713             : 
    1714           0 : GIOControl *GFileChooserReplaceIO(GGadget *g,GIOControl *gc) {
    1715           0 :     GFileChooser *gfc = (GFileChooser *)g;
    1716             : 
    1717           0 :     if ( gfc->outstanding!=NULL ) {
    1718           0 :         GIOclose(gfc->outstanding);
    1719           0 :         gfc->outstanding = NULL;
    1720           0 :         GDrawSetCursor(gfc->g.base,gfc->old_cursor);
    1721             :     }
    1722           0 :     if ( gc!=NULL ) {
    1723           0 :         gfc->old_cursor = GDrawGetCursor(gfc->g.base);
    1724           0 :         GDrawSetCursor(gfc->g.base,ct_watch);
    1725           0 :         gfc->outstanding = gc;
    1726             :     }
    1727           0 : return( gc );
    1728             : }
    1729             : 
    1730           0 : void GFileChooserGetChildren(GGadget *g,GGadget **pulldown, GGadget **list, GGadget **tf) {
    1731           0 :     GFileChooser *gfc = (GFileChooser *)g;
    1732             : 
    1733           0 :     if ( pulldown!=NULL ) *pulldown = &gfc->directories->g;
    1734           0 :     if ( tf!=NULL )       *tf = &gfc->name->g;
    1735           0 :     if ( list!=NULL )     *list = &gfc->files->g;
    1736           0 : }
    1737             : 
    1738           0 : int GFileChooserPosIsDir(GGadget *g, int pos) {
    1739           0 :     GFileChooser *gfc = (GFileChooser *)g;
    1740           0 :     GGadget *list = &gfc->files->g;
    1741             :     GTextInfo *ti;
    1742             : 
    1743           0 :     ti = GGadgetGetListItem(list,pos);
    1744           0 :     if ( ti==NULL )
    1745           0 : return( false );
    1746             : 
    1747           0 : return( ti->checked );
    1748             : }
    1749             : 
    1750           0 : unichar_t *GFileChooserFileNameOfPos(GGadget *g, int pos) {
    1751           0 :     GFileChooser *gfc = (GFileChooser *)g;
    1752           0 :     GGadget *list = &gfc->files->g;
    1753             :     GTextInfo *ti;
    1754             :     unichar_t *curdir, *file;
    1755             : 
    1756           0 :     ti = GGadgetGetListItem(list,pos);
    1757           0 :     if ( ti==NULL )
    1758           0 : return( NULL );
    1759             : 
    1760           0 :     curdir = GFileChooserGetCurDir(gfc,-1);
    1761           0 :     file = u_GFileAppendFile(curdir,ti->text,false);
    1762           0 :     free(curdir);
    1763           0 : return( file );
    1764             : }
    1765             : 
    1766           1 : void GFileChooserSetShowHidden(int sh) {
    1767           1 :     showhidden = sh;
    1768           1 : }
    1769             : 
    1770           0 : int GFileChooserGetShowHidden(void) {
    1771           0 : return( showhidden );
    1772             : }
    1773             : 
    1774           1 : void GFileChooserSetDirectoryPlacement(int dp) {
    1775           1 :     dir_placement = dp;
    1776           1 : }
    1777             : 
    1778           0 : int GFileChooserGetDirectoryPlacement(void) {
    1779           0 : return( dir_placement );
    1780             : }
    1781             : 
    1782           1 : void GFileChooserSetBookmarks(unichar_t **b) {
    1783           1 :     if ( bookmarks!=NULL && bookmarks!=b ) {
    1784             :         int i;
    1785             : 
    1786           0 :         for ( i=0; bookmarks[i]!=NULL; ++i )
    1787           0 :             free(bookmarks[i]);
    1788           0 :         free(bookmarks);
    1789             :     }
    1790           1 :     bookmarks = b;
    1791           1 : }
    1792             : 
    1793           0 : unichar_t **GFileChooserGetBookmarks(void) {
    1794           0 : return( bookmarks );
    1795             : }
    1796             : 
    1797           1 : void GFileChooserSetPrefsChangedCallback(void *data, void (*p_c)(void *)) {
    1798           1 :     prefs_changed = p_c;
    1799           1 :     prefs_changed_data = data;
    1800           1 : }
    1801             : 
    1802           0 : void GFileChooserSetPaths(GGadget *g, const char* const* path) {
    1803           0 :     unichar_t **dirs = NULL;
    1804             :     int dcnt;
    1805           0 :     GFileChooser *gfc = (GFileChooser *) g;
    1806             : 
    1807           0 :     if ( gfc->paths!=NULL ) {
    1808           0 :         for ( dcnt=0; gfc->paths[dcnt]!=NULL; ++dcnt )
    1809           0 :             free( gfc->paths[dcnt] );
    1810           0 :         free(gfc->paths);
    1811           0 :         gfc->paths = NULL;
    1812             :     }
    1813           0 :     if ( path==NULL || path[0]==NULL )
    1814           0 : return;
    1815             : 
    1816           0 :     for ( dcnt=0; path[dcnt]!=NULL; ++dcnt );
    1817           0 :     gfc->paths = dirs = malloc((dcnt+1)*sizeof(unichar_t *));
    1818           0 :     for ( dcnt=0; path[dcnt]!=NULL; ++dcnt )
    1819           0 :         dirs[dcnt] = utf82u_copy(path[dcnt]);
    1820           0 :     dirs[dcnt] = NULL;
    1821             : }

Generated by: LCOV version 1.10