MatN prevents continuous reload of plugins for AppImage + Andrew libaom compile mod
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / mwindow.C
index c57c2ecf492e3943f0a7da3a0e5fc299f9a27685..b7af252fc68f0b9b7b00690d3427abfd92f4858f 100644 (file)
@@ -240,6 +240,7 @@ MWindow::MWindow()
        sighandler = 0;
        restart_status = 0;
        screens = 1;
+       appimageDir = getenv("APPDIR"); //NULL if not running as appimage
        in_destructor = 0;
        speed_edl = 0;
        beeper = 0;
@@ -296,6 +297,7 @@ MWindow::~MWindow()
        plugin_gui_lock->unlock();
        hide_keyframe_guis();
        clean_indexes();
+       clean_backups();
        save_defaults();
 // Give up and go to a movie
 //  cant run valgrind if this is used
@@ -555,21 +557,47 @@ void MWindow::get_plugin_path(char *path, const char *plug_dir, const char *fs_p
        delete [] base_path;
 }
 
-int MWindow::load_plugin_index(MWindow *mwindow, FILE *fp, const char *plugin_dir)
+/**
+* @brief Load plugins according to an index file.
+* 
+* @details Builds an ArrayList of plugin servers only if there is no
+* mismatch for file layout version, index identifier, or executable
+* timestamp mismatch for the built-in plugins. If OK, add the plugin
+* servers to the global list.
+* 
+* @note If an error is returned the index file needs to be rebuilt, and
+* then this function must be called again.
+* There are two types of index files, with the same layout internally.
+* One called "Cinelerra_plugins" for built-ins, ffmpeg and lv2 .
+* The other type "ladspa_plugins.index_id" where index_id is either the
+* path or the $CIN_BUILD identifier if the path is from the running
+* AppImage itself. If there are multiple ladspa directories in the
+* path, there will be multiple index files.
+* 
+* @return  -1 if file no open, 0 if OK, 1 if error. 
+*/
+int MWindow::load_plugin_index(MWindow *mwindow, FILE *fp, const char *plugin_dir, const char *index_id)
 {
        if( !fp ) return -1;
+       struct stat st;
+       fstat (fileno(fp), &st);        // don't bother if the file has just been created.
+       if( st.st_size < 4 ) return 1;
+       
 // load index
        fseek(fp, 0, SEEK_SET);
        int ret = 0;
        char index_line[BCTEXTLEN];
-       int index_version = -1, len = strlen(plugin_dir);
+       int index_version = -1, len = strlen(index_id);
        if( !fgets(index_line, BCTEXTLEN, fp) ||
            sscanf(index_line, "%d", &index_version) != 1 ||
            index_version != PLUGIN_FILE_VERSION ||
            !fgets(index_line, BCTEXTLEN, fp) ||
            (int)strlen(index_line)-1 != len || index_line[len] != '\n' ||
-           strncmp(index_line, plugin_dir, len) != 0 ) ret = 1;
-
+           strncmp(index_line, index_id, len) != 0 ) {
+//             printf("index file mismatch, version %d, index id length %d, expected id %s, file id %s\n", index_version, len, index_id, index_line);
+               ret = 1;
+       }
+       
        ArrayList<PluginServer*> plugins;
        while( !ret && !feof(fp) && fgets(index_line, BCTEXTLEN, fp) ) {
                if( index_line[0] == ';' ) continue;
@@ -578,6 +606,7 @@ int MWindow::load_plugin_index(MWindow *mwindow, FILE *fp, const char *plugin_di
                char path[BCTEXTLEN], title[BCTEXTLEN];
                int64_t mtime = 0;
                if( PluginServer::scan_table(index_line, type, path, title, mtime) ) {
+//                     printf("PluginServer::scan_table failed for %s\n", index_line);
                        ret = 1; continue;
                }
                PluginServer *server = 0;
@@ -588,6 +617,7 @@ int MWindow::load_plugin_index(MWindow *mwindow, FILE *fp, const char *plugin_di
                        char plugin_path[BCTEXTLEN];  struct stat st;
                        sprintf(plugin_path, "%s/%s", plugin_dir, path);
                        if( stat(plugin_path, &st) || st.st_mtime != mtime ) {
+//                             printf("Plugin %s index time %ld, file time %ld\n", plugin_path, mtime, st.st_mtime); 
                                ret = 1; continue;
                        }
                        server = new PluginServer(mwindow, plugin_path, type);
@@ -604,6 +634,7 @@ int MWindow::load_plugin_index(MWindow *mwindow, FILE *fp, const char *plugin_di
 // Create plugin server from index entry
                server->set_title(title);
                if( server->read_table(index_line) ) {
+//                     printf("server->read_table failed for title %s, %s\n", title, index_line);
                        ret = 1;  continue;
                }
        }
@@ -642,17 +673,24 @@ int MWindow::check_plugin_index(ArrayList<PluginServer*> &plugins,
        }
        return 0;
 }
-
-
+/*
+* @brief Load built-in and LV2 plugins as specified in index file,
+*        rebuild the index file if needed.
+*/
 int MWindow::init_plugins(MWindow *mwindow, Preferences *preferences)
 {
        if( !plugindb )
                plugindb = new ArrayList<PluginServer*>;
        init_ffmpeg();
-       char index_path[BCTEXTLEN], plugin_path[BCTEXTLEN];
+       char index_path[BCTEXTLEN], plugin_path[BCTEXTLEN], index_id[BCTEXTLEN];
        create_defaults_path(index_path, PLUGIN_FILE);
        char *plugin_dir = FileSystem::basepath(preferences->plugin_dir);
        strcpy(plugin_path, plugin_dir);  delete [] plugin_dir;
+       // index_id is 2nd line of the index file, normally full plugin path,
+       // but fixed value if AppImage because the path changes on each run.
+       // And if the second line does not match on the next run the index is rebuilt.
+       if( mwindow->appimageDir ) strcpy(index_id, getenv("CINGG_BUILD"));
+       else strcpy(index_id, plugin_path);
        FILE *fp = fopen(index_path,"a+");
        if( !fp ) {
                fprintf(stderr,_("MWindow::init_plugins: "
@@ -662,19 +700,19 @@ int MWindow::init_plugins(MWindow *mwindow, Preferences *preferences)
        int fd = fileno(fp), ret = -1;
        if( !flock(fd, LOCK_EX) ) {
                fseek(fp, 0, SEEK_SET);
-               ret = load_plugin_index(mwindow, fp, plugin_path);
+               ret = load_plugin_index(mwindow, fp, plugin_path, index_id);
        }
        if( ret > 0 ) {
                ftruncate(fd, 0);
                fseek(fp, 0, SEEK_SET);
-               printf("init plugin index: %s\n", plugin_path);
+               printf("build plugin index for: %s\n", plugin_path);
                fprintf(fp, "%d\n", PLUGIN_FILE_VERSION);
-               fprintf(fp, "%s\n", plugin_path);
+               fprintf(fp, "%s\n", index_id);
                init_plugin_index(mwindow, preferences, fp, plugin_path);
                init_ffmpeg_index(mwindow, preferences, fp);
                init_lv2_index(mwindow, preferences, fp);
                fseek(fp, 0, SEEK_SET);
-               ret = load_plugin_index(mwindow, fp, plugin_path);
+               ret = load_plugin_index(mwindow, fp, plugin_path, index_id);
        }
        if( ret ) {
                fprintf(stderr,_("MWindow::init_plugins: "
@@ -685,26 +723,38 @@ int MWindow::init_plugins(MWindow *mwindow, Preferences *preferences)
        return ret;
 }
 
+/*
+* @brief Load ladspa plugins as specified in index files, for each ladspa
+*        directory keep a separate index file. Rebuild index file(s) if needed.
+**/
 int MWindow::init_ladspa_plugins(MWindow *mwindow, Preferences *preferences)
 {
 #ifdef HAVE_LADSPA
        char *path = getenv("LADSPA_PATH");
        char ladspa_path[BCTEXTLEN];
-       if( !path ) {
+       if( !path ) {                   // if no env var, use CinGG's own ladspa dir
                strncpy(ladspa_path, File::get_ladspa_path(), sizeof(ladspa_path));
                path = ladspa_path;
        }
        for( int len=0; *path; path+=len ) {
                char *cp = strchr(path,':');
                len = !cp ? strlen(path) : cp-path;
-               char index_path[BCTEXTLEN], plugin_path[BCTEXTLEN];
+               char index_path[BCTEXTLEN], plugin_path[BCTEXTLEN], index_id[BCTEXTLEN];
                memcpy(plugin_path, path, len);  plugin_path[len] = 0;
                if( cp ) ++len;
                char *plugin_dir = FileSystem::basepath(plugin_path);
                strcpy(plugin_path, plugin_dir);  delete [] plugin_dir;
                create_defaults_path(index_path, LADSPA_FILE);
                cp = index_path + strlen(index_path);
-               for( char *bp=plugin_path; *bp!=0; ++bp )
+               // If the first part of the plugin_path matches the APPDIR, we are
+               // referring to CinGG's ladspa, replace the path by a fixed ID. APPDIR
+               // only exists if we are running as AppImage (with variable mount points).
+               if( mwindow->appimageDir && strncmp(plugin_path, mwindow->appimageDir, strlen(mwindow->appimageDir)) == 0 )
+                       strcpy(index_id, getenv("CINGG_BUILD"));
+               else strcpy(index_id, plugin_path);
+
+               // Concatenate the path, replacing '/' with '_'. 
+               for( char *bp=index_id; *bp!=0; ++bp )
                        *cp++ = *bp=='/' ? '_' : *bp;
                *cp = 0;
                FILE *fp = fopen(index_path,"a+");
@@ -716,14 +766,17 @@ int MWindow::init_ladspa_plugins(MWindow *mwindow, Preferences *preferences)
                int fd = fileno(fp), ret = -1;
                if( !flock(fd, LOCK_EX) ) {
                        fseek(fp, 0, SEEK_SET);
-                       ret = load_plugin_index(mwindow, fp, plugin_path);
+                       ret = load_plugin_index(mwindow, fp, plugin_path, index_id);
                }
                if( ret > 0 ) {
                        ftruncate(fd, 0);
                        fseek(fp, 0, SEEK_SET);
-                       init_ladspa_index(mwindow, preferences, fp, plugin_path);
+                       printf("build ladspa plugin index for: %s\n", plugin_path);
+                       fprintf(fp, "%d\n", PLUGIN_FILE_VERSION);
+                       fprintf(fp, "%s\n", index_id);
+                       init_plugin_index(mwindow, preferences, fp, plugin_path);
                        fseek(fp, 0, SEEK_SET);
-                       ret = load_plugin_index(mwindow, fp, plugin_path);
+                       ret = load_plugin_index(mwindow, fp, plugin_path, index_id);
                }
                if( ret ) {
                        fprintf(stderr,_("MWindow::init_ladspa_plugins: "
@@ -984,6 +1037,58 @@ void MWindow::init_preferences()
        YUV::yuv.yuv_set_colors(preferences->yuv_color_space, preferences->yuv_color_range);
 }
 
+void MWindow::clean_backups()
+{
+    FileSystem fs;
+    int total_excess;
+    long oldest = 0;
+    int oldest_item = -1;
+    char string[BCTEXTLEN];
+
+// Delete extra backups
+    fs.set_filter("backup*.prev_*");
+    fs.complete_path(preferences->index_directory);
+    fs.update(preferences->index_directory);
+
+    // set to 50 for now
+    // total_excess = fs.dir_list.total - preferences->index_count;
+    total_excess = fs.dir_list.total - 50;
+    printf("Total excess of backups: %i \n", total_excess);
+
+//printf("MWindow::clean_backups 1 %d\n", fs.dir_list.total);
+
+    while(total_excess > 0)
+    {
+// Get oldest
+       for(int i = 0; i < fs.dir_list.total; i++)
+       {
+           fs.join_names(string, preferences->index_directory, fs.dir_list[i]->name);
+
+           if(i == 0 || fs.get_date(string) <= oldest)
+           {
+               oldest = fs.get_date(string);
+               oldest_item = i;
+           }
+       }
+
+       if(oldest_item >= 0)
+       {
+// Remove backup file
+           fs.join_names(string,
+               preferences->index_directory,
+               fs.dir_list[oldest_item]->name);
+//printf("MWindow::clean_backups 1 %s\n", string);
+           if(remove(string))
+               perror("delete_backups");
+           delete fs.dir_list[oldest_item];
+           fs.dir_list.remove_number(oldest_item);
+
+       }
+
+       total_excess--;
+    }
+}
+
 void MWindow::clean_indexes()
 {
        FileSystem fs;
@@ -1489,6 +1594,7 @@ void MWindow::tile_mixers(int x1, int y1, int x2, int y2)
                if( x1 > x2 ) { int t = x1;  x1 = x2;  x2 = t; }
                if( y1 > y2 ) { int t = y1;  y1 = y2;  y2 = t; }
        }
+       int ow = edl->session->output_w, oh = edl->session->output_h;
        int nz = 0;
        for( int i=0; i<zwindows.size(); ++i ) {
                ZWindow *zwindow = zwindows[i];
@@ -1496,32 +1602,63 @@ void MWindow::tile_mixers(int x1, int y1, int x2, int y2)
                ++nz;
        }
        if( !nz ) return;
-       int zn = ceil(sqrt(nz));
-       int rw = gui->get_root_w(0), rh = gui->get_root_h(0);
-       if( x1 < 0 ) x1 = 0;
-       if( y1 < 0 ) y1 = 0;
-       if( x2 > rw ) x2 = rw;
-       if( y2 > rh ) y2 = rh;
-       int dx = x2 - x1, dy = y2 - y1;
-       int zw = dx / zn;
        int lt = BC_DisplayInfo::get_left_border();
        int top = BC_DisplayInfo::get_top_border();
        int bw = lt + BC_DisplayInfo::get_right_border();  // borders
        int bh = top + BC_DisplayInfo::get_bottom_border();
-       int zx = 0, zy = 0;  // window origins
        int mw = xS(10+10), mh = yS(10+10); // canvas margins
-       int rsz = 0, n = 0, dz = 0;
-       int ow = edl->session->output_w, oh = edl->session->output_h;
+       int dx = x2 - x1, dy = y2 - y1;
+       int64_t sz = dx * dy, best_r = sz;
+       int bx = 1, by = nz;
+       for( int nx=1; nx<=nz; ++nx ) {
+               int ny = ceil((double)nz / nx);
+               int zw = dx / nx;
+               int ww = zw - bw;
+               int hh = (ww - mw) * oh / ow + mh;
+               int zh = hh + bh;
+               int64_t za = zw*nx * zh*ny;
+               int64_t r = sz - za;
+               if( r < 0 ) continue;
+               if( r >= best_r ) continue;
+               best_r = r;
+               bx = nx;  by = ny;
+       }
+       for( int ny=1; ny<=nz; ++ny ) {
+               int nx = ceil((double)nz / ny);
+               int zh = dy / ny;
+               int hh = zh - bh;
+               int ww = (hh - mh) * ow / oh + mw;
+               int zw = ww + bw;
+               int64_t za = zw*nx * zh*ny;
+               int64_t r = sz - za;
+               if( r < 0 ) continue;
+               if( r >= best_r ) continue;
+               best_r = r;
+               bx = nx;  by = ny;
+       }
+       int zw, zh, ww, hh;
+       if( bx < by ) {
+               zh = dy / by;
+               hh = zh - bh;
+               ww = (hh - mh) * ow / oh + mw;
+               zw = ww + bw;
+       }
+       else {
+               zw = dx / bx;
+               ww = zw - bw;
+               hh = (ww - mw) * oh / ow + mh;
+               zh = hh + bh;
+       }
+
+       int zx = 0, zy = 0;  // window origins
+       int n = 0;
        for( int i=0; i<zwindows.size(); ++i ) {
                ZWindow *zwindow = zwindows[i];
                if( zwindow->idx < 0 ) continue;
-               int ww = zw - bw, hh = (ww - mw) * oh / ow + mh, zh = hh + bh;
-               if( rsz < hh ) rsz = hh;
                int xx = zx + x1, yy = zy + y1;
                int mx = x2 - zw, my = y2 - zh;
                if( xx > mx ) xx = mx;
                if( yy > my ) yy = my;
-               xx += lt + xS(dz);  yy += top + yS(dz);
                zwindow->reposition(xx,yy, ww,hh);
                if( zwindow->running() ) {
                        ZWindowGUI *gui = (ZWindowGUI *)zwindow->get_gui();
@@ -1529,11 +1666,9 @@ void MWindow::tile_mixers(int x1, int y1, int x2, int y2)
                        gui->BC_WindowBase::reposition_window(xx,yy, ww,hh);
                        gui->unlock_window();
                }
-               if( ++n >= zn ) {
-                       n = 0;  rsz += bh;
-                       if( (zy += rsz) > (dy - rsz) ) dz += 10;
-                       rsz = 0;
-                       zx = 0;
+               if( ++n >= bx ) {
+                       zx = 0;  zy += zh;
+                       n = 0;
                }
                else
                        zx += zw;
@@ -2967,6 +3102,25 @@ void MWindow::show_vwindow(int raise)
        gui->mainmenu->show_vwindow->set_checked(1);
 }
 
+
+void MWindow::hide_vwindow(int raise)
+{
+       session->show_vwindow = 0;
+       int total_running = 0;
+
+       for(int j = 0; j < vwindows.size(); j++) {
+               VWindow *vwindow = vwindows[j];
+               if( !vwindow->is_running() ) continue;
+               total_running++;
+               if( !raise && !vwindow->gui->is_hidden() ) continue;
+               vwindow->gui->lock_window("MWindow::show_vwindow");
+               vwindow->gui->hide_window(0);
+               vwindow->gui->unlock_window();
+       }
+       gui->mainmenu->show_vwindow->set_checked(0);
+}
+
+
 void MWindow::show_awindow()
 {
        session->show_awindow = 1;
@@ -2978,6 +3132,17 @@ void MWindow::show_awindow()
        gui->mainmenu->show_awindow->set_checked(1);
 }
 
+void MWindow::hide_awindow()
+{
+       session->show_awindow = 0;
+
+       awindow->gui->lock_window("MWindow::show_awindow");
+       awindow->gui->hide_window();
+       awindow->gui->unlock_window();
+       gui->mainmenu->show_awindow->set_checked(0);
+}
+
+
 char *MWindow::get_cwindow_display()
 {
        char *x11_host = screens < 2 || session->window_config == 0 ?
@@ -2993,6 +3158,18 @@ void MWindow::show_cwindow()
        gui->mainmenu->show_cwindow->set_checked(1);
 }
 
+
+void MWindow::hide_cwindow()
+{
+       session->show_cwindow = 0;
+
+       cwindow->gui->lock_window("MWindow::show_cwindow");
+       cwindow->gui->hide_window();
+       cwindow->gui->unlock_window();
+       gui->mainmenu->show_cwindow->set_checked(0);
+}
+
+
 void MWindow::show_gwindow()
 {
        session->show_gwindow = 1;
@@ -3005,6 +3182,7 @@ void MWindow::show_gwindow()
 
        gui->mainmenu->show_gwindow->set_checked(1);
 }
+
 void MWindow::hide_gwindow()
 {
        session->show_gwindow = 0;
@@ -3012,6 +3190,7 @@ void MWindow::hide_gwindow()
        gwindow->gui->lock_window("MWindow::show_gwindow");
        gwindow->gui->hide_window();
        gwindow->gui->unlock_window();
+       gui->mainmenu->show_gwindow->set_checked(0);
 }
 
 void MWindow::show_lwindow()
@@ -3025,6 +3204,17 @@ void MWindow::show_lwindow()
        gui->mainmenu->show_lwindow->set_checked(1);
 }
 
+void MWindow::hide_lwindow()
+{
+       session->show_lwindow = 0;
+
+       lwindow->gui->lock_window("MWindow::show_lwindow");
+       lwindow->gui->hide_window();
+       lwindow->gui->unlock_window();
+       gui->mainmenu->show_lwindow->set_checked(0);
+}
+
+
 void MWindow::restore_windows()
 {
        gui->unlock_window();
@@ -3054,7 +3244,7 @@ void MWindow::restore_windows()
                cwindow->gui->unlock_window();
        }
        else if( session->show_cwindow && cwindow->gui->is_hidden() )
-               cwindow->show_window();
+               show_cwindow();
 
        if( !session->show_gwindow && !gwindow->gui->is_hidden() ) {
                gwindow->gui->lock_window("MWindow::restore_windows");
@@ -4185,6 +4375,25 @@ void MWindow::get_backup_path(char *path, int len)
        cp += snprintf(cp, ep-cp, idx ? BACKUPn_FILE : BACKUP_FILE, idx);
 }
 
+void MWindow::create_timestamped_copy_from_previous_backup(char *previouspath)
+{
+  if (previouspath == NULL) return;
+  char backup_path[BCTEXTLEN];
+  backup_path[0] = 0;
+  time_t now = time(NULL);
+  struct tm* currenttime = localtime(&now);
+  snprintf(backup_path, sizeof(backup_path), 
+      "%s/%s_%d%.2d%.2d_%.2d%.2d%.2d",
+      File::get_config_path(), BACKUP_FILE1, 
+      currenttime->tm_year + 1900,
+      currenttime->tm_mon + 1,
+      currenttime->tm_mday,
+      currenttime->tm_hour,
+      currenttime->tm_min,
+      currenttime->tm_sec);
+       rename(previouspath, backup_path);
+}
+
 void MWindow::save_backup()
 {
        FileXML file;
@@ -4195,6 +4404,8 @@ void MWindow::save_backup()
        snprintf(backup_path1, sizeof(backup_path1), "%s/%s",
                File::get_config_path(), BACKUP_FILE1);
        get_backup_path(backup_path, sizeof(backup_path));
+       if( preferences->ongoing_backups )
+               create_timestamped_copy_from_previous_backup(backup_path1);
        rename(backup_path, backup_path1);
        edl->save_xml(&file, backup_path);
        file.terminate_string();
@@ -4463,11 +4674,14 @@ static inline int gcd(int m, int n)
 int MWindow::create_aspect_ratio(float &w, float &h, int width, int height)
 {
        w = 1;  h = 1;
+       double ar;
+       
        if(!width || !height) return 1;
        if( width == 720 && (height == 480 || height == 576) ) {
                w = 4;  h = 3;  return 0; // for NTSC and PAL
        }
-       double ar = (double)width / height;
+       
+       ar = (double)width / height;
 // square-ish pixels
        if( EQUIV(ar, 1.0000) ) return 0;
        if( EQUIV(ar, 1.3333) ) { w = 4;  h = 3;  return 0; }
@@ -4475,6 +4689,8 @@ int MWindow::create_aspect_ratio(float &w, float &h, int width, int height)
        if( EQUIV(ar, 2.1111) ) { w = 19; h = 9;  return 0; }
        if( EQUIV(ar, 2.2222) ) { w = 20; h = 9;  return 0; }
        if( EQUIV(ar, 2.3333) ) { w = 21; h = 9;  return 0; }
+       if( EQUIV(ar, 2.37037) ) { w = 64; h = 27;  return 0; }
+
        int ww = width, hh = height;
        // numerator, denominator must be under mx
        int mx = 255, n = gcd(ww, hh);
@@ -5018,12 +5234,26 @@ int MWindow::select_asset(Asset *asset, int vstream, int astream, int delete_tra
                session->output_w = width;
                session->output_h = height;
                session->frame_rate = framerate;
+               session->interlace_mode = asset->interlace_mode;
                // not, asset->actual_width/actual_height
                asset->width = session->output_w;
                asset->height = session->output_h;
                asset->frame_rate = session->frame_rate;
+               
                create_aspect_ratio(session->aspect_w, session->aspect_h,
                        session->output_w, session->output_h);
+       float ar = asset->aspect_ratio;
+       if (ar) {
+       //printf ("Aspect ratio from asset: %f \n", ar);
+       if( EQUIV(ar, 1.3333) ) { session->aspect_w = 4;  session->aspect_h = 3;  }
+       if( EQUIV(ar, 1.7777) ) { session->aspect_w = 16; session->aspect_h = 9;   }
+       if( EQUIV(ar, 2.1111) ) { session->aspect_w = 19; session->aspect_h = 9;  }
+       if( EQUIV(ar, 2.2222) ) { session->aspect_w = 20; session->aspect_h = 9;   }
+       if( EQUIV(ar, 2.3333) ) { session->aspect_w = 21; session->aspect_h = 9;   }
+       if( EQUIV(ar, 2.370370) ) { session->aspect_w = 64; session->aspect_h = 27; }
+       }
+                       
+                       
                Track *track = edl->tracks->first;
                for( Track *next_track=0; track; track=next_track ) {
                        next_track = track->next;
@@ -5207,6 +5437,8 @@ ConfirmRefWindow::ConfirmRefWindow(MWindow *mwindow, char *path,
 {
        this->mwindow = mwindow;
        this->path = path;
+// *** CONTEXT_HELP ***
+       context_help_set_keyword("File by Reference");
 }
 
 ConfirmRefWindow::~ConfirmRefWindow()