/* * dialog.c: Event-handlers & initialization for user-interface. This is probably the most * ugly part of VideoteXt :-) * * $Id$ * * Copyright (c) 1994-97 Martin Buck * Read COPYING for more information * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vtx_assert.h" #include "safe_malloc.h" #include "tilde.h" #include "wmgr_deco.h" #include "misc.h" #include "vtxtools.h" #include "config.h" #include "cct.h" #include "tuner.h" #include "tvchannels.h" #include "fileio.h" #include "postscript.h" #include "vtxdecode.h" #include "vtxqueue.h" #include "cache.h" #include "spool.h" #include "search.h" #include "toptext.h" #include "fastext.h" #include "hotlist.h" #include "selection.h" #include "xvtools.h" #include "xinit.h" #include "xevents.h" #include "dialog.h" static const char *ftype_ext[] = { "txt", #ifdef GIF_SUPPORT "gif", "gif", #endif "ppm", #ifdef PNG_SUPPORT "png", "png", #endif "ps", "ps", "ps" }; static const char *ftype_strings[] = { "ASCII", #ifdef GIF_SUPPORT "GIF", "GIF (interlaced)", #endif "PPM", #ifdef PNG_SUPPORT "PNG", "PNG (interlaced)", #endif "Color (E)PS", "B&W (E)PS", "B&W (E)PS (inv.)" }; typedef enum { FTYPE_ASCII = 0, #ifdef GIF_SUPPORT FTYPE_GIF, FTYPE_GIFINT, #endif FTYPE_PPM, #ifdef PNG_SUPPORT FTYPE_PNG, FTYPE_PNGINT, #endif FTYPE_CPS, FTYPE_PS, FTYPE_IPS, FTYPE_COUNT } ftype_t; enum { APPLY_BUTTON = 1, CLOSE_BUTTON, CHGNAME_BUTTON, RDHEADER_BUTTON, UP_BUTTON, DOWN_BUTTON, ADD_BUTTON, ADDPG_BUTTON, REMOVE_BUTTON, GOTO_BUTTON, PREV_BUTTON, NEXT_BUTTON, STOP_BUTTON, INDEX_BUTTON, NEXTGRP_BUTTON, NEXTBLK_BUTTON, COPY_SET_BUTTON, COPY_BUTTON, SELALL_BUTTON, CLRALL_BUTTON, SEARCH_BUTTON, BGSEARCH_BUTTON }; enum { KEEP_MENU, REMOVE_MENU }; #define BORDER_DISTANCE 20 #define BUTTON_DISTANCE 20 #define WM_SMALL_BORDER 10 #define WM_LARGE_BORDER 30 #define BELL_DELAY 5 popups_t popups[POPUP_COUNT]; int station_selected = FALSE; wmgr_deco_t wmgr; static Panel selst_panel; static Panel_item st_buttons[3], tt_buttons[4], ov_menubutton, hier_menubutton; static Panel_item top_msgs[5], export_subpg_checkmark, save_subpg_checkmark; static Frame st_frame; static Menu ov_menu, hier_menu; static ttdesc_t *tt_desctable = NULL; static int tt_desccount; static void stname_cb_proc(Panel_item item, const Event *event); static Panel_setting set_station_name(void); static void sel_st_apply(int selected); static void sel_st_cb_proc(Panel_item item, const Event *event); static void tune_new_station(const char *chan, int freq, int prog); static void hotlist_goto(int selected); static void hot_cb_proc(Panel_item item, const Event *event); static void hotlist_add_proc(Frame parent_frame); static Panel_setting hotadd_cb_proc(Panel_item item, const Event *event); static void search_cb_proc(Panel_item item, const Event *event); static Notify_value search_check_hotkeys(Panel panel, const Event *event, Notify_arg arg, Notify_event_type type); static void search_list_menu(Menu menu, Menu_item item); static void search_match_btn_cb(Panel_item item, Event *event); static Menu search_match_menu_gen(Menu menu, Menu_generate op); static void search_match_menu_cb(Menu menu, Menu_item menu_item); static void search_add_reqlist(int reqid, const char *text, int fg); static void search_update_listimg(int reqid); static void search_update_matchinfo(void); static void search_show_results(int reqid, int page, int subpage); static void history_goto(int selected); static void hist_cb_proc(Panel_item item, const Event *event); static void toptext_cb_proc(Panel_item item, const Event *event); static void topmenu_update(const ttdesc_t *desctable, int desccount); static void toptext_menu_cb_proc(Menu menu, Menu_item menu_item); static void fastext_cb_proc(Panel_item item, const Event *event); static void fastext_button_proc(Panel_item item, const Event *event); static void layout_cb_proc(Panel_item item, const Event *event); static void tvopt_cb_proc(Panel_item item, const Event *event); static void psopt_cb_proc(Panel_item item, const Event *event); static void miscopt_cb_proc(Panel_item item, const Event *event); static void so_cb_proc(Panel_item item, const Event *event); static void station_opt_activate(void); static void tun_cb_proc(Panel_item item, const Event *event); static Panel_setting tun_chantxt_proc(Panel_item item, const Event *event); static void tun_chanmenu_proc(Menu menu, Menu_item menu_item); static void tun_chanbtn_proc(Panel_item item, const Event *event); static void tun_freqbtn_proc(Panel_item item, const Event *event); static Panel_setting tun_freqtxt_proc(Panel_item item, const Event *event); static Panel_setting tun_progtxt_proc(Panel_item item, const Event *event); static void sp_cb_proc(Panel_item item, const Event *event); static void copy_set_proc(Frame parent_frame); static void cs_cb_proc(Panel_item item, const Event *event); static void cs_chooseall(Menu menu, Menu_item menu_item); static void copy_set_update(void); void position_popups(void) { Window wdummy; int popup, x = 0, y = 0, xf, yf, wf, hf, idummy, newpos = FALSE; int lypos, rypos, txpos, bxpos; if ((int)xv_get(frame, FRAME_CLOSED)) return; XGetGeometry(dpy, frameid, &wdummy, &idummy, &idummy, &wf, &hf, &idummy, &idummy); XTranslateCoordinates(dpy, frameid, rootid, 0, 0, &xf, &yf, &wdummy); lypos = rypos = yf - config_get_wmdeco(WM_TB); txpos = bxpos = xf - config_get_wmdeco(WM_LB); for (popup = 0; popup < POPUP_COUNT; popup++) { if (popups[popup].frame && (int)xv_get(popups[popup].frame, XV_SHOW) && !(int)xv_get(popups[popup].frame, FRAME_CLOSED)) { switch (config_get_placement(popup)) { case PLACEMENT_LEFT: x = xf - config_get_wmdeco(WM_LB) - config_get_wmdeco(WM_RB) - (int)xv_get(popups[popup].frame, XV_WIDTH) + config_get_wmdeco(WM_OFS_X); y = lypos + config_get_wmdeco(WM_TB) + config_get_wmdeco(WM_OFS_Y); lypos += (int)xv_get(popups[popup].frame, XV_HEIGHT) + config_get_wmdeco(WM_TB) + config_get_wmdeco(WM_BB); newpos = TRUE; break; case PLACEMENT_RIGHT: x = xf + wf + config_get_wmdeco(WM_RB) + config_get_wmdeco(WM_LB) + config_get_wmdeco(WM_OFS_X); y = rypos + config_get_wmdeco(WM_TB) + config_get_wmdeco(WM_OFS_Y); rypos += (int)xv_get(popups[popup].frame, XV_HEIGHT) + config_get_wmdeco(WM_TB) + config_get_wmdeco(WM_BB); newpos = TRUE; break; case PLACEMENT_TOP: x = txpos + config_get_wmdeco(WM_LB) + config_get_wmdeco(WM_OFS_X); y = yf + - config_get_wmdeco(WM_TB) - config_get_wmdeco(WM_BB) - (int)xv_get(popups[popup].frame, XV_HEIGHT) + config_get_wmdeco(WM_OFS_Y); txpos += (int)xv_get(popups[popup].frame, XV_WIDTH) + config_get_wmdeco(WM_LB) + config_get_wmdeco(WM_RB); newpos = TRUE; break; case PLACEMENT_BOTTOM: x = bxpos + config_get_wmdeco(WM_LB) + config_get_wmdeco(WM_OFS_X); y = yf + hf + config_get_wmdeco(WM_BB) + config_get_wmdeco(WM_TB) + config_get_wmdeco(WM_OFS_Y); bxpos += (int)xv_get(popups[popup].frame, XV_WIDTH) + config_get_wmdeco(WM_LB) + config_get_wmdeco(WM_RB); newpos = TRUE; break; case PLACEMENT_CENTER: break; default: assert(0); break; } if (newpos) { Window win; win = xv_get(popups[popup].frame, XV_XID); XMoveWindow(dpy, win, x, y); wmgr_prepare_get_offset(x, y, win, &wmgr); newpos = FALSE; } } } } void iconify_popups(int state) { int popup; for (popup = 0; popup < POPUP_COUNT; popup++) { if (popups[popup].frame) { xv_set(popups[popup].frame, FRAME_CLOSED, state, NULL); } } } static void popup_frame_proc(Xv_window window, const Event *event) { int popup, rows; switch (event_action(event)) { case WIN_STRUCTURE_NOTIFY: /* A synthetic XConfigureEvent hopefully means that the wm has honoured our request * to move one of the popups, so we check if it was the one we're interested in. We may * have to skip some events because we always get a synthetic XConfigureEvent after opening * a new window due to the center_frame()-call. The event we're interested in arrives after * it (maybe much later if automatic positioning was turned off when the window was first * opened). If it's the right event, we try to find out the XMoveWindow-offset. It's also a * good time to find out the size of the wm's decoration, because if we arrive here, the * main window should already have been reparented. */ if (!config_get_wmdeco(WM_ADJUSTED) && event_xevent(event)->xconfigure.send_event && !wmgr_dec_ignore_xconfigure(&wmgr) && WMGR_CHECK_CALL_OFFSET(event_xevent(event)->xconfigure.window, wmgr)) { config_set_wmdeco(WM_ADJUSTED, WM_ADJ_AUTO); if (wmgr_get_offset(event_xevent(event)->xconfigure.x, event_xevent(event)->xconfigure.y, event_xevent(event)->xconfigure.window, &wmgr) != WMGR_OK) { wmgr.ofs_x = WM_SMALL_BORDER; wmgr.ofs_y = WM_LARGE_BORDER; confirm_notice(frame, TRUE, "Warning: Can't determine\noffset for window positions."); } config_set_wmdeco(WM_OFS_X, wmgr.ofs_x); config_set_wmdeco(WM_OFS_Y, wmgr.ofs_y); if (wmgr_get_size(dpy, frameid, &wmgr) != WMGR_OK) { confirm_notice(frame, TRUE, "Warning: Can't determine size\nof window manager's decoration."); wmgr.lb = wmgr.rb = wmgr.bb = WM_SMALL_BORDER; wmgr.tb = WM_LARGE_BORDER; } config_set_wmdeco(WM_LB, wmgr.lb); config_set_wmdeco(WM_RB, wmgr.rb); config_set_wmdeco(WM_TB, wmgr.tb); config_set_wmdeco(WM_BB, wmgr.bb); /* Repostion popups because now we hopefully know the right XMoveWindow-offset */ position_popups(); } /* Check if the size of one of the popups containing a PANEL_LIST has changed & adjust number * of rows for PANEL_LIST if necessary. */ for (popup = 0; popup < POPUP_COUNT; popup++) { if (window == popups[popup].frame) break; } assert(popup != POPUP_COUNT); if (!popups[popup].list || !popups[popup].rowht) return; rows = (event_xevent(event)->xconfigure.height - popups[popup].borderht) / popups[popup].rowht; /* Check number of rows in case some stupid window manager ignores our size hints */ rows = (rows >= 3) ? rows : 3; if (rows != (int)xv_get(popups[popup].list, PANEL_LIST_DISPLAY_ROWS)) { xv_set(popups[popup].list, PANEL_LIST_DISPLAY_ROWS, rows, NULL); config_set_popup_rows(popup, rows); if (popup == POPUP_SELST) { int button; for (button = 0; button < NELEM(st_buttons); button++) { xv_set(st_buttons[button], XV_Y, rows * popups[POPUP_SELST].rowht + popups[POPUP_SELST].borderht - 32, NULL); } panel_paint(selst_panel, PANEL_CLEAR); } position_popups(); } break; case WIN_PROPERTY_NOTIFY: /* If we receive a WIN_PROPERTY_NOTIFY, a popup *might* have been (de)iconified, so * we call position_popups to make sure the popup-layout is OK. */ position_popups(); break; } } static void popup_frame_done(Frame frame) { xv_set(frame, XV_SHOW, FALSE, NULL); position_popups(); } /* Ask the user for confirmation to overwrite a file. If can_append is true, also ask if * the user wants to append to an existing file. */ int chk_conf_overwrite(const char *path, int can_append, int can_merge) { Xv_notice notice; char *catmsg; int retval; struct stat st; if (stat(path, &st) < 0) return 0; catmsg = sstrdup("The file \""); catmsg = sstrapp(catmsg, path); catmsg = sstrapp(catmsg, "\" already exists.\n"); if (can_append || can_merge) { catmsg = sstrapp(catmsg, "Do you want to overwrite it\nor "); catmsg = sstrapp(catmsg, (can_append ? "append the new data to it?" : "merge the new data?")); notice = (Xv_notice)xv_create(frame, NOTICE, NOTICE_MESSAGE_STRING, catmsg, NOTICE_BUTTON_YES, "Overwrite", NOTICE_BUTTON, (can_append ? "Append" : "Merge"), 2, NOTICE_BUTTON_NO, "Cancel", XV_SHOW, TRUE, NULL); } else { catmsg = sstrapp(catmsg, "Do you want to overwrite it?"); notice = (Xv_notice)xv_create(frame, NOTICE, NOTICE_MESSAGE_STRING, catmsg, NOTICE_BUTTON_YES, "Overwrite", NOTICE_BUTTON_NO, "Cancel", XV_SHOW, TRUE, NULL); } switch ((int)xv_get(notice, NOTICE_STATUS)) { case NOTICE_YES: retval = 0; break; case NOTICE_NO: retval = -1; break; case 2: retval = 1; break; default: assert(0); break; } xv_destroy_safe(notice); free(catmsg); return retval; } void about_proc(void) { confirm_notice(frame, FALSE, VTXWINNAME " Version " VTXVERSION "\n" "© 1994-99 Martin Buck \n" "\n" "Please check VideoteXt's WWW-page\n" "http://home.pages.de/~videotext/\n" "for the latest news about VideoteXt.\n" "\n" "This program is free software and is distributed under\n" "the terms of the GNU General Public License."); } void stat_proc(void) { int norm_count, multi_count, multi_complete_count, subpg_count, subpages, page; char *msg; char tmpstr[20]; msg = sstrdup("Statistics for station "); msg = sstrapp(msg, hotlist_get_name()); norm_count = multi_count = multi_complete_count = 0; if (toptext_ok) { for (page = 100; page <= 899; page++) { switch (toptext_numsubpg(vtx_dec2hex(page))) { case 0: break; case 1: norm_count++; break; default: multi_count++; break; } } } msg = sstrapp(msg, ":\n\nNumber of normal pages in TOP-Table: "); sprintf(tmpstr, "%d", norm_count); msg = sstrapp(msg, tmpstr); msg = sstrapp(msg, "\nNumber of multi-pages in TOP-Table: "); sprintf(tmpstr, "%d", multi_count); msg = sstrapp(msg, tmpstr); norm_count = multi_count = subpg_count = 0; for (page = 100; page <= 899; page++) { if (cache_query(vtx_dec2hex(page), 0, 0, NULL, NULL)) { norm_count++; } else if ((subpages = cache_count_subpg(vtx_dec2hex(page)))) { multi_count++; subpg_count += subpages; if (cache_query(vtx_dec2hex(page), -1, 0, NULL, NULL) == 2) multi_complete_count++; } } msg = sstrapp(msg, "\nNumber of normal pages in cache: "); sprintf(tmpstr, "%d", norm_count); msg = sstrapp(msg, tmpstr); msg = sstrapp(msg, "\nNumber of multi-pages in cache: "); sprintf(tmpstr, "%d", multi_count); msg = sstrapp(msg, tmpstr); msg = sstrapp(msg, "\nNumber of complete multi-pages in cache: "); sprintf(tmpstr, "%d", multi_complete_count); msg = sstrapp(msg, tmpstr); msg = sstrapp(msg, "\nTotal number of pages in cache: "); sprintf(tmpstr, "%d", subpg_count + norm_count); msg = sstrapp(msg, tmpstr); msg = sstrapp(msg, "\nMemory used by cache: "); sprintf(tmpstr, "%d", ((subpg_count + norm_count) * sizeof(cache_t)) / 1024); msg = sstrapp(msg, tmpstr); msg = sstrapp(msg, " kB"); if (vtx_dev_open) { msg = sstrapp(msg, "\n\nUsing videotext driver version "); sprintf(tmpstr, "%d.%d", vtx_info.version_major, vtx_info.version_minor); msg = sstrapp(msg, tmpstr); msg = sstrapp(msg, ",\nvideotext-chip "); switch (vtx_info.cct_type) { case SAA5243: msg = sstrapp(msg, "SAA5243, "); break; case SAA5246: msg = sstrapp(msg, "SAA5246, "); break; case XSTV5346: msg = sstrapp(msg, "XSTV5346, "); break; case SAA5248: msg = sstrapp(msg, "SAA5248, "); break; case SAA5249: msg = sstrapp(msg, "SAA5249, "); break; default: msg = sstrapp(msg, "unknown, "); break; } sprintf(tmpstr, "%d", vtx_info.numpages); msg = sstrapp(msg, tmpstr); msg = sstrapp(msg, " DAUs\non device "); msg = sstrapp(msg, cct_device); } confirm_notice(frame, FALSE, msg); free(msg); } static int list_dbl_click(Panel_item item, const char *entry_name, Xv_opaque client_data, Panel_list_op op, const Event *event, int row) { int selected; if (op == PANEL_LIST_OP_DBL_CLICK) { selected = (int)xv_get(item, PANEL_LIST_FIRST_SELECTED); if (item == popups[POPUP_HISTORY].list) { history_goto(selected); } else if (item == popups[POPUP_HOTLIST].list) { hotlist_goto(selected); } else if (item == popups[POPUP_SELST].list) { sel_st_apply(selected); } else if (item == popups[POPUP_SEARCH].list) { search_show_results( (int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_CLIENT_DATA, selected), -1, -1); } else { assert(0); } } return XV_OK; } static Panel_item station_name_text, station_hdr_text; void station_name_proc(int station) { Panel st_panel; if (!st_frame) { st_frame = (Frame)xv_create(frame, FRAME, XV_LABEL, "Set station name", NULL); st_panel = (Panel)xv_create(st_frame, PANEL, XV_HELP_DATA, "videotext:station_name", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); station_name_text = (Panel_item)xv_create(st_panel, PANEL_TEXT, XV_X, 30, XV_Y, 15, PANEL_LABEL_STRING, "Station name:", PANEL_VALUE_STORED_LENGTH, STATIONNAME_MAXLEN, PANEL_VALUE_DISPLAY_WIDTH, 180, PANEL_NOTIFY_PROC, set_station_name, NULL); station_hdr_text = (Panel_item)xv_create(st_panel, PANEL_TEXT, XV_X, 21, XV_Y, 40, PANEL_LABEL_STRING, "Station header:", PANEL_VALUE_STORED_LENGTH, STATIONNAME_MAXLEN, PANEL_VALUE_DISPLAY_WIDTH, 180, PANEL_NOTIFY_PROC, set_station_name, NULL); xv_create(st_panel, PANEL_BUTTON, XV_X, 65, XV_Y, 80, PANEL_LABEL_STRING, "Apply", PANEL_NOTIFY_PROC, stname_cb_proc, PANEL_CLIENT_DATA, APPLY_BUTTON, NULL); xv_create(st_panel, PANEL_BUTTON, XV_X, 125, XV_Y, 80, PANEL_LABEL_STRING, "Read header", PANEL_NOTIFY_PROC, stname_cb_proc, PANEL_CLIENT_DATA, RDHEADER_BUTTON, NULL); xv_create(st_panel, PANEL_BUTTON, XV_X, 225, XV_Y, 80, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, stname_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); window_fit(st_panel); window_fit(st_frame); set_frame_constraints(st_frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(st_frame, XV_SHOW)) center_frame(popups[POPUP_SELST].frame, st_frame); xv_set(station_name_text, PANEL_VALUE, hotlist_get_name_n(station), PANEL_CLIENT_DATA, station, NULL); xv_set(station_hdr_text, PANEL_VALUE, hotlist_get_header_n(station), NULL); xv_set(st_frame, XV_SHOW, TRUE, NULL); } static void stname_cb_proc(Panel_item item, const Event *event) { switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case APPLY_BUTTON: set_station_name(); break; case RDHEADER_BUTTON: { char header_str[STATIONNAME_MAXLEN + 1]; int pos, strpos; strpos = 0; for (pos = 0; pos <= STATIONNAME_MAXLEN - 1; pos++) { if (vtx2iso_table[vtxwin.page->chr[pos + 8]] != ' ' || strpos) { header_str[strpos++] = vtx2iso_table[vtxwin.page->chr[pos + 8]]; } } header_str[strpos] = '\0'; for (pos = strpos - 1; pos >= 0; pos--) { if (header_str[pos] == ' ') { header_str[pos] = '\0'; } else { break; } } xv_set(station_hdr_text, PANEL_VALUE, header_str, NULL); } break; case CLOSE_BUTTON: xv_set(st_frame, WIN_SHOW, FALSE, NULL); break; default: assert(0); break; } } static Panel_setting set_station_name(void) { char hdr[STATIONNAME_MAXLEN + 1], *tmp_name, *tmp_hdr; int pos; tmp_name = (char*)xv_get(station_name_text, PANEL_VALUE); tmp_hdr = (char*)xv_get(station_hdr_text, PANEL_VALUE); strcpy(hdr, tmp_hdr + strspn(tmp_hdr, " ")); for (pos = strlen(hdr) - 1; pos >= 0; pos--) { if (hdr[pos] == ' ') { hdr[pos] = '\0'; } else { break; } } hotlist_new_name((char*)xv_get(station_name_text, PANEL_VALUE), (char*)xv_get(station_hdr_text, PANEL_VALUE), (int)xv_get(station_name_text, PANEL_CLIENT_DATA)); sel_st_update(FALSE); copy_set_update(); return PANEL_NONE; } void sel_station_proc(void) { popups_t *cpop = popups + POPUP_SELST; if (!cpop->frame) { cpop->frame = (Frame)xv_create(frame, FRAME, XV_LABEL, "Select station", WIN_CONSUME_EVENTS, WIN_STRUCTURE_NOTIFY, WIN_PROPERTY_NOTIFY, NULL, WIN_EVENT_PROC, popup_frame_proc, FRAME_DONE_PROC, popup_frame_done, NULL); selst_panel = (Panel)xv_create(cpop->frame, PANEL, XV_HELP_DATA, "videotext:select_station", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); notify_interpose_event_func(selst_panel, check_hotkeys_nometa, NOTIFY_SAFE); cpop->list = (Panel_item)xv_create(selst_panel, PANEL_LIST, XV_X, 15, XV_Y, 15, PANEL_LIST_TITLE, "Stations available", PANEL_LIST_WIDTH, 215, PANEL_LIST_DISPLAY_ROWS, config_get_popup_rows(POPUP_SELST), PANEL_READ_ONLY, TRUE, PANEL_LIST_DO_DBL_CLICK, TRUE, PANEL_NOTIFY_PROC, list_dbl_click, NULL); st_buttons[0] = xv_create(selst_panel, PANEL_BUTTON, XV_X, 20, PANEL_NEXT_ROW, -1, PANEL_LABEL_STRING, "Apply", PANEL_NOTIFY_PROC, sel_st_cb_proc, PANEL_CLIENT_DATA, APPLY_BUTTON, NULL); st_buttons[1] = xv_create(selst_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "Change Name", PANEL_NOTIFY_PROC, sel_st_cb_proc, PANEL_CLIENT_DATA, CHGNAME_BUTTON, NULL); st_buttons[2] = xv_create(selst_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, sel_st_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); window_fit(selst_panel); window_fit(cpop->frame); cpop->rowht = (int)xv_get(cpop->list, PANEL_LIST_ROW_HEIGHT); cpop->borderht = (int)xv_get(cpop->frame, XV_HEIGHT) - config_get_popup_rows(POPUP_SELST) * cpop->rowht; set_frame_constraints(cpop->frame, 0, 0, 5 * cpop->rowht + cpop->borderht, 0, FRC_HSHRINK | FRC_HGROW); } if (!(int)xv_get(cpop->frame, XV_SHOW)) { wmgr_inc_ignore_xconfigure(&wmgr); center_frame(frame, cpop->frame); } sel_st_update(TRUE); xv_set(cpop->list, PANEL_LIST_SELECT, hotlist_get_current(), TRUE, NULL); xv_set(cpop->frame, XV_SHOW, TRUE, NULL); position_popups(); } static void sel_st_apply(int selected) { if (selected != -1) { new_station(selected, TRUE); station_selected = TRUE; tune_new_station(hotlist_get_channel(), hotlist_get_freq(), hotlist_get_prog()); } } static void sel_st_cb_proc(Panel_item item, const Event *event) { int selected; selected = (int)xv_get(popups[POPUP_SELST].list, PANEL_LIST_FIRST_SELECTED); switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case APPLY_BUTTON: sel_st_apply(selected); break; case CHGNAME_BUTTON: if (selected != -1) { station_name_proc(selected); } break; case CLOSE_BUTTON: popup_frame_done(popups[POPUP_SELST].frame); break; default: assert(0); break; } } void sel_st_update(int update_sel) { char **station_list; int station_count; int entry, selected = -1; if (!popups[POPUP_SELST].frame) return; if ((station_count = (int)xv_get(popups[POPUP_SELST].list, PANEL_LIST_NROWS))) { selected = (int)xv_get(popups[POPUP_SELST].list, PANEL_LIST_FIRST_SELECTED); xv_set(popups[POPUP_SELST].list, PANEL_LIST_DELETE_ROWS, 0, station_count, NULL); } station_count = hotlist_get_stcount(); station_list = smalloc((station_count + 1) * sizeof(*station_list)); station_list[station_count] = NULL; for (entry = 0; entry < station_count; entry++) { station_list[entry] = hotlist_get_name_n(entry); } xv_set(popups[POPUP_SELST].list, XV_SHOW, FALSE, PANEL_LIST_INSERT_STRINGS, 0, station_list, NULL); free(station_list); for (entry = 0; entry < station_count; entry++) { xv_set(popups[POPUP_SELST].list, PANEL_LIST_GLYPH, entry, tvset_image[hotlist_get_tunset_n(entry)].image, PANEL_LIST_MASK_GLYPH, entry, tvset_image[hotlist_get_tunset_n(entry)].image, NULL); } xv_set(popups[POPUP_SELST].list, XV_SHOW, TRUE, NULL); if (update_sel) { xv_set(popups[POPUP_SELST].list, PANEL_LIST_SELECT, hotlist_get_current(), TRUE, NULL); } else if (selected != -1) { xv_set(popups[POPUP_SELST].list, PANEL_LIST_SELECT, selected, TRUE, NULL); } } static void tune_new_station(const char *chan, int freq, int prog) { int err; #ifdef NEED_KERNELD_WORKAROUND sigset_t mask, oldmask; #endif static tuner_info_t tuner_info; if ((!(chan && *chan) && !freq && !prog) || keep_closed) { return; } if (!tuner_dev_open) { /* All the sigprocmask-stuff is used to work around a bug in Linux's kerneld. * If signals are enabled, open() might receive a signal and return before the module * is actually loaded which causes ENODEV to be returned. The module gets loaded * nevertheless, but then it's too late :-( */ #ifdef NEED_KERNELD_WORKAROUND sigemptyset(&mask); sigaddset(&mask, SIGIO); sigaddset(&mask, SIGALRM); sigprocmask(SIG_BLOCK, &mask, &oldmask); #endif if ((err = tuner_open(REQ_MAJOR, REQ_MINOR, &tuner_info)) < 0) { #ifdef NEED_KERNELD_WORKAROUND sigprocmask(SIG_SETMASK, &oldmask, NULL); #endif if (err == TUNEVERSION) { confirm_notice_v(frame, TRUE, "Can't open tuner-device ", tuner_device, ":\nIncompatible driver version (need " STRINGIFY(REQ_MAJOR) "." STRINGIFY(REQ_MINOR) ").", (char *)0); } else { confirm_notice_v(frame, TRUE, "Can't open tuner-device ", tuner_device, ":\n", strerror(errno), (char *)0); } return; } #ifdef NEED_KERNELD_WORKAROUND sigprocmask(SIG_SETMASK, &oldmask, NULL); #endif if ((err = tuner_reset()) < 0) { report_tuner_error(err, "tuner_reset"); tuner_close(); return; } tuner_dev_open = TRUE; } if (((chan && *chan) || freq) && tuner_info.freq) { const char *tvsys = NULL; if (chan && *chan && (freq = tvch_chan2freq(config_get_tvsystem(), chan, &tvsys, NULL)) < 0) { confirm_notice_v(frame, TRUE, "Can't tune to new station:\nChannel ", chan, " unknown for\nTV system ", tvsys ? tvsys : config_get_tvsystem(), (char *)0); } if (freq > 0 && (err = tuner_setfreq(freq)) < 0) { report_tuner_error(err, "tuner_setfreq"); } } else if (prog && tuner_info.prog) { if ((err = tuner_setprog(prog)) < 0) { report_tuner_error(err, "tuner_setprog"); } } else { confirm_notice_v(frame, TRUE, "Can't tune to new station:\nTuner doesn't support setting ", tuner_info.prog ? "frequencies" : "programs", (char *)0); } } void hotlist_proc(void) { Panel hot_panel; popups_t *cpop = popups + POPUP_HOTLIST; if (!cpop->frame) { cpop->frame = (Frame)xv_create(frame, FRAME, XV_LABEL, "Hotlist", WIN_CONSUME_EVENTS, WIN_STRUCTURE_NOTIFY, WIN_PROPERTY_NOTIFY, NULL, WIN_EVENT_PROC, popup_frame_proc, FRAME_DONE_PROC, popup_frame_done, NULL); hot_panel = (Panel)xv_create(cpop->frame, PANEL, XV_HELP_DATA, "videotext:hotlist", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); notify_interpose_event_func(hot_panel, check_hotkeys_nometa, NOTIFY_SAFE); cpop->list = (Panel_item)xv_create(hot_panel, PANEL_LIST, XV_X, 15, XV_Y, 15, PANEL_LIST_WIDTH, 55, PANEL_LIST_DISPLAY_ROWS, config_get_popup_rows(POPUP_HOTLIST), PANEL_READ_ONLY, TRUE, PANEL_LIST_DO_DBL_CLICK, TRUE, PANEL_NOTIFY_PROC, list_dbl_click, NULL); xv_create(hot_panel, PANEL_BUTTON, XV_X, 110, XV_Y, 15, PANEL_LABEL_STRING, " Go to", PANEL_LABEL_WIDTH, 80, PANEL_NOTIFY_PROC, hot_cb_proc, PANEL_CLIENT_DATA, GOTO_BUTTON, NULL); xv_create(hot_panel, PANEL_BUTTON, XV_X, 110, XV_Y, 50, PANEL_LABEL_STRING, " Move up", PANEL_LABEL_WIDTH, 80, PANEL_NOTIFY_PROC, hot_cb_proc, PANEL_CLIENT_DATA, UP_BUTTON, NULL); xv_create(hot_panel, PANEL_BUTTON, XV_X, 110, XV_Y, 80, PANEL_LABEL_STRING, " Move down", PANEL_LABEL_WIDTH, 80, PANEL_NOTIFY_PROC, hot_cb_proc, PANEL_CLIENT_DATA, DOWN_BUTTON, NULL); xv_create(hot_panel, PANEL_BUTTON, XV_X, 110, XV_Y, 110, PANEL_LABEL_STRING, "Add current", PANEL_LABEL_WIDTH, 80, PANEL_NOTIFY_PROC, hot_cb_proc, PANEL_CLIENT_DATA, ADD_BUTTON, NULL); xv_create(hot_panel, PANEL_BUTTON, XV_X, 110, XV_Y, 140, PANEL_LABEL_STRING, " Add page", PANEL_LABEL_WIDTH, 80, PANEL_NOTIFY_PROC, hot_cb_proc, PANEL_CLIENT_DATA, ADDPG_BUTTON, NULL); xv_create(hot_panel, PANEL_BUTTON, XV_X, 110, XV_Y, 170, PANEL_LABEL_STRING, " Remove", PANEL_LABEL_WIDTH, 80, PANEL_NOTIFY_PROC, hot_cb_proc, PANEL_CLIENT_DATA, REMOVE_BUTTON, NULL); xv_create(hot_panel, PANEL_BUTTON, XV_X, 110, XV_Y, 205, PANEL_LABEL_STRING, " Close", PANEL_LABEL_WIDTH, 80, PANEL_NOTIFY_PROC, hot_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); window_fit(hot_panel); window_fit(cpop->frame); cpop->rowht = (int)xv_get(cpop->list, PANEL_LIST_ROW_HEIGHT); cpop->borderht = (int)xv_get(cpop->frame, XV_HEIGHT) - config_get_popup_rows(POPUP_HOTLIST) * cpop->rowht; set_frame_constraints(cpop->frame, 0, 0, 11 * cpop->rowht + cpop->borderht, 0, FRC_HSHRINK | FRC_HGROW); } if (!(int)xv_get(cpop->frame, XV_SHOW)) { wmgr_inc_ignore_xconfigure(&wmgr); center_frame(frame, cpop->frame); } hot_update(); xv_set(cpop->frame, XV_SHOW, TRUE, NULL); position_popups(); } static void hotlist_goto(int selected) { if (selected != -1) { get_page(PRI_FGROUND, hotlist_get(selected), 0, 0, vtx_buffer, &vtxwin); } } static void hot_cb_proc(Panel_item item, const Event *event) { int selected; selected = (int)xv_get(popups[POPUP_HOTLIST].list, PANEL_LIST_FIRST_SELECTED); switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case GOTO_BUTTON: hotlist_goto(selected); break; case UP_BUTTON: if (selected > 0) { xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_SELECT, selected, FALSE, NULL); hotlist_add(hotlist_remove(selected), selected - 1); xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_SELECT, selected - 1, TRUE, NULL); hot_update(); } break; case DOWN_BUTTON: if (selected != -1) { xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_SELECT, selected, FALSE, NULL); hotlist_add(hotlist_remove(selected), selected + 1); xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_SELECT, selected + 1, TRUE, NULL); hot_update(); } break; case ADD_BUTTON: if (selected == -1) selected = 0; xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_SELECT, selected, FALSE, NULL); hotlist_add(vtxwin.pgnum, selected + 1); hot_update(); xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_SELECT, selected + 1, TRUE, NULL); break; case ADDPG_BUTTON: hotlist_add_proc(popups[POPUP_HOTLIST].frame); break; case REMOVE_BUTTON: if (selected != -1) { hotlist_remove(selected); if (selected >= hotlist_get_count(hotlist_get_current())) xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_SELECT, selected - 1, TRUE, NULL); hot_update(); } break; case CLOSE_BUTTON: popup_frame_done(popups[POPUP_HOTLIST].frame); break; default: assert(0); break; } } void hot_update(void) { static int hot_list_count; int selected = -1; if (!popups[POPUP_HOTLIST].list) return; if (hot_list_count) { selected = (int)xv_get(popups[POPUP_HOTLIST].list, PANEL_LIST_FIRST_SELECTED); xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_DELETE_ROWS, 0, hot_list_count, NULL); } xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_INSERT_STRINGS, 0, hotlist_mkstr(&hot_list_count), NULL); if (selected != -1) xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_SELECT, selected, TRUE, NULL); } static Frame hotadd_frame; static Panel_item hotadd_num; static void hotlist_add_proc(Frame parent_frame) { Panel hotadd_panel; if (!hotadd_frame) { hotadd_frame = (Frame)xv_create(frame, FRAME, XV_LABEL, "Add page to hotlist", NULL); hotadd_panel = (Panel)xv_create(hotadd_frame, PANEL, XV_HELP_DATA, "videotext:hotlist_add", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); notify_interpose_event_func(hotadd_panel, check_hotkeys_nometa, NOTIFY_SAFE); hotadd_num = (Panel_item)xv_create(hotadd_panel, PANEL_TEXT, XV_X, 30, XV_Y, 30, PANEL_LABEL_STRING, "Page to add to hotlist:", PANEL_VALUE_DISPLAY_WIDTH, 35, PANEL_VALUE_STORED_LENGTH, 3, PANEL_NOTIFY_PROC, hotadd_cb_proc, PANEL_CLIENT_DATA, APPLY_BUTTON, NULL); xv_create(hotadd_panel, PANEL_BUTTON, XV_X, 70, XV_Y, 70, PANEL_LABEL_STRING, "Apply", PANEL_NOTIFY_PROC, hotadd_cb_proc, PANEL_CLIENT_DATA, APPLY_BUTTON, NULL); xv_create(hotadd_panel, PANEL_BUTTON, XV_X, 130, XV_Y, 70, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, hotadd_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); window_fit(hotadd_panel); window_fit(hotadd_frame); set_frame_constraints(hotadd_frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(hotadd_frame, XV_SHOW)) center_frame(parent_frame, hotadd_frame); xv_set(hotadd_frame, XV_SHOW, TRUE, NULL); } static Panel_setting hotadd_cb_proc(Panel_item item, const Event *event) { int add_page, selected; switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case APPLY_BUTTON: selected = (int)xv_get(popups[POPUP_HOTLIST].list, PANEL_LIST_FIRST_SELECTED); add_page = strtol((char*)xv_get(hotadd_num, PANEL_VALUE), NULL, 16); if (!vtx_chkpgnum(add_page, FALSE)) { confirm_notice(hotadd_frame, TRUE, "Invalid page number.\nValid range is 100-899 (decimal)."); } else { if (selected == -1) selected = 0; xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_SELECT, selected, FALSE, NULL); hotlist_add(add_page, selected + 1); hot_update(); xv_set(popups[POPUP_HOTLIST].list, PANEL_LIST_SELECT, selected + 1, TRUE, NULL); xv_set(hotadd_num, PANEL_VALUE, "", NULL); } break; case CLOSE_BUTTON: xv_set(hotadd_frame, XV_SHOW, FALSE, NULL); break; default: assert(0); break; } return PANEL_NONE; } static Panel_item search_text, search_opt_checkbox, search_pagelevel_choice; static Panel_item search_bg_button; static int search_init_done, search_curr_reqid = -1, search_curr_page, search_curr_subpage; void search_proc(void) { popups_t *cpop = popups + POPUP_SEARCH; Menu match_menu; if (!search_init_done) { search_init_done = TRUE; xv_set(cpop->frame, XV_LABEL, "Text Search", WIN_CONSUME_EVENTS, WIN_STRUCTURE_NOTIFY, WIN_PROPERTY_NOTIFY, NULL, WIN_EVENT_PROC, popup_frame_proc, FRAME_DONE_PROC, popup_frame_done, FRAME_SHOW_FOOTER, TRUE, NULL); xv_set(search_panel, XV_HELP_DATA, "videotext:search", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); notify_interpose_event_func(search_panel, search_check_hotkeys, NOTIFY_SAFE); search_text = (Panel_item)xv_create(search_panel, PANEL_TEXT, XV_X, 15, XV_Y, 15, PANEL_LABEL_STRING, "Search expression", PANEL_VALUE_DISPLAY_WIDTH, 205, PANEL_VALUE_STORED_LENGTH, HOTLIST_VALUE_MAXLEN, PANEL_NOTIFY_PROC, search_cb_proc, PANEL_CLIENT_DATA, SEARCH_BUTTON, NULL); search_opt_checkbox = (Panel_item)xv_create(search_panel, PANEL_CHECK_BOX, XV_X, 15, XV_Y, 45, PANEL_LAYOUT, PANEL_VERTICAL, PANEL_CHOICE_STRINGS, "Case sensitve", "Use (extended) regular expressions", "Match whole words only", "Matches may span multiple lines", "Ring bell on background match", NULL, NULL); search_pagelevel_choice = (Panel_item)xv_create(search_panel, PANEL_CHOICE, XV_X, 15, XV_Y, 209, PANEL_LABEL_STRING, "Pages to search:", PANEL_CHOICE_STRINGS, "Current", "+ cached", "+ spooled", NULL, NULL); xv_set(cpop->list, XV_X, 380, XV_Y, 15, PANEL_LABEL_STRING, "Active requests", PANEL_LIST_WIDTH, 170, PANEL_LIST_DISPLAY_ROWS, 10, PANEL_LAYOUT, PANEL_VERTICAL, PANEL_READ_ONLY, TRUE, PANEL_LIST_DO_DBL_CLICK, TRUE, PANEL_NOTIFY_PROC, list_dbl_click, NULL); xv_set((Menu)xv_get(cpop->list, PANEL_ITEM_MENU), MENU_ITEM, MENU_STRING, "Keep request", MENU_NOTIFY_PROC, search_list_menu, MENU_CLIENT_DATA, KEEP_MENU, NULL, MENU_ITEM, MENU_STRING, "Remove request", MENU_NOTIFY_PROC, search_list_menu, MENU_CLIENT_DATA, REMOVE_MENU, NULL, NULL); xv_create(search_panel, PANEL_BUTTON, XV_X, 70, XV_Y, 250, PANEL_LABEL_STRING, "Search", PANEL_NOTIFY_PROC, search_cb_proc, PANEL_CLIENT_DATA, SEARCH_BUTTON, NULL); search_bg_button = (Panel_item)xv_create(search_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "Search bg", PANEL_NOTIFY_PROC, search_cb_proc, PANEL_CLIENT_DATA, BGSEARCH_BUTTON, NULL); xv_create(search_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, search_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); match_menu = (Menu)xv_create(XVNULL, MENU, MENU_NROWS, 10, MENU_GEN_PROC, search_match_menu_gen, MENU_NOTIFY_PROC, search_match_menu_cb, NULL); xv_create(search_panel, PANEL_ABBREV_MENU_BUTTON, XV_X, 380, XV_Y, 252, PANEL_ITEM_MENU, match_menu, PANEL_LABEL_STRING, "Matches", NULL); xv_create(search_panel, PANEL_BUTTON, XV_Y, 250, PANEL_ITEM_X_GAP, 30, PANEL_LABEL_STRING, "<", PANEL_NOTIFY_PROC, search_match_btn_cb, PANEL_CLIENT_DATA, PREV_BUTTON, NULL); xv_create(search_panel, PANEL_BUTTON, XV_Y, 250, PANEL_LABEL_STRING, ">", PANEL_NOTIFY_PROC, search_match_btn_cb, PANEL_CLIENT_DATA, NEXT_BUTTON, NULL); window_fit(search_panel); window_fit(cpop->frame); set_frame_constraints(cpop->frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(cpop->frame, XV_SHOW)) { wmgr_inc_ignore_xconfigure(&wmgr); center_frame(frame, cpop->frame); } xv_set(popups[POPUP_SEARCH].frame, FRAME_LEFT_FOOTER, "", NULL); xv_set(cpop->frame, XV_SHOW, TRUE, NULL); position_popups(); } static void search_cb_proc(Panel_item item, const Event *event) { const char *errmsg = NULL; search_data_t data; int button, opt, level, reqid; switch (button = (int)xv_get(item, PANEL_CLIENT_DATA)) { case SEARCH_BUTTON: case BGSEARCH_BUTTON: data.str = (char *)xv_get(search_text, PANEL_VALUE); opt = (int)xv_get(search_opt_checkbox, PANEL_VALUE); data.case_sens = !!(opt & 1); data.is_regexp = !!(opt & 2); data.whole_words = !!(opt & 4); data.multi_line = !!(opt & 8); data.bell = !!(opt & 0x10); level = (int)xv_get(search_pagelevel_choice, PANEL_VALUE); if (button == SEARCH_BUTTON) { xv_set(popups[POPUP_SEARCH].frame, FRAME_LEFT_FOOTER, "Searching...", NULL); if ((reqid = search_page(vtx_buffer, &vtxwin.page->info, &data, level, &errmsg)) >= 0) { xv_set(popups[POPUP_SEARCH].frame, FRAME_LEFT_FOOTER, "", NULL); if (search_get_result(reqid)) { search_add_reqlist(reqid, data.str, TRUE); search_show_results(reqid, -1, -1); } else { xv_set(popups[POPUP_SEARCH].frame, FRAME_LEFT_FOOTER, "No matches.", NULL); } } else { xv_set(popups[POPUP_SEARCH].frame, FRAME_LEFT_FOOTER, "", NULL); } } else { xv_set(popups[POPUP_SEARCH].frame, FRAME_LEFT_FOOTER, "", NULL); if ((reqid = search_add_req(&data, FALSE, &errmsg)) >= 0) { search_add_reqlist(reqid, data.str, FALSE); } } if (errmsg) { xv_set(popups[POPUP_SEARCH].frame, FRAME_LEFT_FOOTER, errmsg, NULL); } break; case CLOSE_BUTTON: popup_frame_done(popups[POPUP_SEARCH].frame); break; default: assert(0); break; } } static Notify_value search_check_hotkeys(Panel panel, const Event *event, Notify_arg arg, Notify_event_type type) { XKeyEvent *xev = (XKeyEvent*)event->ie_xevent; KeySym keysym; char buf[2]; int len; if (xev && xev->type == KeyPress) { len = XLookupString(xev, buf, sizeof buf, &keysym, &compose_status); if ((xev->state & Mod1Mask) && len == 1 && (buf[0] == '\r' || buf[0] == '\n')) { search_cb_proc(search_bg_button, event); return NOTIFY_DONE; } } return check_hotkeys_meta(panel, event, arg, type); } static void search_list_menu(Menu menu, Menu_item item) { int sel, req; xv_set(popups[POPUP_SEARCH].frame, FRAME_LEFT_FOOTER, "", NULL); sel = (int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_FIRST_SELECTED); switch ((int)xv_get(item, MENU_CLIENT_DATA)) { case KEEP_MENU: if (sel >= 0) { req = (int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_CLIENT_DATA, sel); if (search_get_fg(req)) { xv_set(popups[POPUP_SEARCH].frame, FRAME_LEFT_FOOTER, "Can't keep foreground request.", NULL); } else { search_set_keepreq(req); search_update_listimg(req); } } else { xv_set(popups[POPUP_SEARCH].frame, FRAME_LEFT_FOOTER, "No search request selected.", NULL); } break; case REMOVE_MENU: if (sel >= 0) { req = (int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_CLIENT_DATA, sel); if (req == search_curr_reqid) { search_curr_reqid = -1; search_update_matchinfo(); } search_rm_req(req); xv_set(popups[POPUP_SEARCH].list, PANEL_LIST_DELETE, sel, NULL); } else { xv_set(popups[POPUP_SEARCH].frame, FRAME_LEFT_FOOTER, "No search request selected.", NULL); } break; default: assert(0); break; } } static void search_match_btn_cb(Panel_item item, Event *event) { int loop, btn; search_result_t **result; btn = (int)xv_get(item, PANEL_CLIENT_DATA); if (search_curr_reqid < 0 || !(result = search_get_result(search_curr_reqid))) { return; } for (loop = 0; result[loop]; loop++) { if (result[loop]->pginf.pagenum == search_curr_page && result[loop]->pginf.minute == search_curr_subpage) { if (btn == PREV_BUTTON) { if (loop > 0) { loop--; } search_show_results(search_curr_reqid, result[loop]->pginf.pagenum, result[loop]->pginf.minute); } else if (btn == NEXT_BUTTON) { if (result[loop + 1]) { loop++; } search_show_results(search_curr_reqid, result[loop]->pginf.pagenum, result[loop]->pginf.minute); } break; } } } static Menu search_match_menu_gen(Menu menu, Menu_generate op) { int item, loop, default_set = FALSE; Menu_item menu_item; search_result_t **result; static char matchstr[SEARCH_MAXRESULTS][7]; if (op == MENU_DISPLAY) { for (item = (int)xv_get(menu, MENU_NITEMS); item > 0; item--) { menu_item = (Menu_item)xv_get(menu, MENU_NTH_ITEM, item); xv_set(menu, MENU_REMOVE, item, NULL); xv_destroy(menu_item); } if ((result = search_get_result(search_curr_reqid))) { for (loop = 0; result[loop]; loop++) { assert(loop < SEARCH_MAXRESULTS); sprintf(matchstr[loop], "%X.%X", result[loop]->pginf.pagenum, result[loop]->pginf.minute); xv_set(menu, MENU_APPEND_ITEM, (Menu_item)xv_create(XVNULL, MENUITEM, MENU_STRING, matchstr[loop], MENU_CLIENT_DATA, loop, NULL), NULL); if (!default_set && !result[loop]->read) { default_set = TRUE; xv_set(menu, MENU_DEFAULT, loop + 1, NULL); } } if (!default_set) { xv_set(menu, MENU_DEFAULT, loop, NULL); } } } return menu; } static void search_match_menu_cb(Menu menu, Menu_item menu_item) { int match, loop; search_result_t **result; if (search_curr_reqid < 0 || !(result = search_get_result(search_curr_reqid))) { return; } match = (int)xv_get(menu_item, MENU_CLIENT_DATA); for (loop = 0; result[loop]; loop++) { if (loop == match) { search_show_results(search_curr_reqid, result[match]->pginf.pagenum, result[match]->pginf.minute); break; } } } static void search_add_reqlist(int reqid, const char *text, int fg) { int listcount, ent, loop; listcount = (int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_NROWS); if (fg) { ent = 0; for (loop = 0; loop < listcount; loop++) { if (search_get_fg((int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_CLIENT_DATA, loop))) { ent = loop + 1; } else { break; } } } else { ent = listcount; } xv_set(popups[POPUP_SEARCH].list, PANEL_LIST_INSERT, ent, PANEL_LIST_STRING, ent, text, PANEL_LIST_CLIENT_DATA, ent, reqid, NULL); search_update_listimg(reqid); } static void search_update_listimg(int reqid) { int loop, listcount, img; listcount = (int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_NROWS); for (loop = 0; loop < listcount; loop++) { if ((int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_CLIENT_DATA, loop) == reqid) { img = search_get_currimg(reqid); xv_set(popups[POPUP_SEARCH].list, PANEL_LIST_GLYPH, loop, search_image[img].image, PANEL_LIST_MASK_GLYPH, loop, search_image[img].image, NULL); return; } } } static void search_update_matchinfo(void) { char matchinfo[256]; search_result_t **result; int current, total, unread, loop; if (search_curr_reqid >= 0 && (result = search_get_result(search_curr_reqid))) { current = total = unread = 0; for (loop = 0; result[loop]; loop++) { total++; if (!result[loop]->read) { unread++; } if (result[loop]->pginf.pagenum == search_curr_page && result[loop]->pginf.minute == search_curr_subpage) { current = loop + 1; } } if (current) { sprintf(matchinfo, "%X.%X: Match %d of %d, %d unread", search_curr_page, search_curr_subpage, current, total, unread); xv_set(popups[POPUP_SEARCH].frame, FRAME_RIGHT_FOOTER, matchinfo, NULL); return; } } xv_set(popups[POPUP_SEARCH].frame, FRAME_RIGHT_FOOTER, "", NULL); } void search_notify_cb(int reqid, int bell) { time_t curr_time; static time_t last_time; if (config_get_auto_search()) { search_proc(); } search_update_listimg(reqid); if (reqid == search_curr_reqid) { search_update_matchinfo(); } if (bell) { curr_time = time(NULL); if (curr_time - last_time >= BELL_DELAY) { last_time = curr_time; /* Don't use window_bell, because it can be disabled by the user */ XBell(dpy, 0); } } } static void search_show_results(int reqid, int page, int subpage) { search_result_t **result; int inv, match, loop, read, listcount, new_req; if (!(result = search_get_result(reqid))) { return; } listcount = (int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_NROWS); for (loop = 0; loop < listcount; loop++) { if ((int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_CLIENT_DATA, loop) == reqid) { break; } } xv_set(popups[POPUP_SEARCH].list, PANEL_LIST_SELECT, loop, TRUE, NULL); if (page < 0) { for (loop = 0; result[loop]; loop++) { page = result[loop]->pginf.pagenum; subpage = result[loop]->pginf.minute; if (!result[loop]->read) { break; } } } new_req = (reqid != search_curr_reqid); search_curr_reqid = reqid; search_curr_page = page; search_curr_subpage = subpage; read = TRUE; for (loop = 0; result[loop]; loop++) { if (result[loop]->pginf.pagenum == page && result[loop]->pginf.minute == subpage) { result[loop]->read = TRUE; memcpy(vtx_buffer, result[loop]->pgbuf, VTX_PAGESIZE); memset(vtx_buffer, vtx_mkparity(7), 8); vtxwin.page->info = result[loop]->pginf; selection_hide(&vtxwin); decode_page(vtx_buffer, vtxwin.page, 0, 23); for (match = 0; match < result[loop]->count; match++) { for (inv = result[loop]->match[match].ofs; inv < result[loop]->match[match].ofs + result[loop]->match[match].len; inv++) { vtxwin.page->attrib[inv] |= VTX_INVERT; } } xv_set(checkbox, PANEL_VALUE, (int)xv_get(checkbox, PANEL_VALUE) | 1, NULL); vtxwin.stopped = TRUE; vtxwin.update = SCR_UPDATE; update_pagenumdisp(vtxwin.page->info.pagenum, vtxwin.page->info.minute, 1, 1); } else if (!result[loop]->read) { read = FALSE; } } if (read) { search_set_allread(reqid); search_update_listimg(reqid); } search_update_matchinfo(); } void search_reset(void) { int loop, listcount, reqid; search_data_t data; hotlist_clear_searchdata(); listcount = (int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_NROWS); for (loop = 0; loop < listcount; loop++) { reqid = (int)xv_get(popups[POPUP_SEARCH].list, PANEL_LIST_CLIENT_DATA, loop); if (search_get_keep(reqid)) { search_get_data(reqid, &data); hotlist_add_searchdata(&data); } search_rm_req(reqid); } xv_set(popups[POPUP_SEARCH].list, PANEL_LIST_DELETE_ROWS, 0, listcount, NULL); if (search_init_done) { search_curr_reqid = -1; search_update_matchinfo(); } } void search_new_station(void) { const char *errmsg; int loop, reqid; search_data_t *data; xv_set(popups[POPUP_SEARCH].list, XV_SHOW, FALSE, NULL); for (loop = 0; (data = hotlist_get_searchdata(loop)); loop++) { if ((reqid = search_add_req(data, FALSE, &errmsg)) >= 0) { search_set_keepreq(reqid); search_add_reqlist(reqid, data->str, FALSE); } } xv_set(popups[POPUP_SEARCH].list, XV_SHOW, TRUE, NULL); } void history_proc(void) { static int init_done; popups_t *cpop = popups + POPUP_HISTORY; if (!init_done) { init_done = TRUE; xv_set(cpop->frame, XV_LABEL, "Page history", WIN_CONSUME_EVENTS, WIN_STRUCTURE_NOTIFY, WIN_PROPERTY_NOTIFY, NULL, WIN_EVENT_PROC, popup_frame_proc, FRAME_DONE_PROC, popup_frame_done, NULL); xv_set(hist_panel, PANEL_ACCEPT_KEYSTROKE, TRUE, XV_HELP_DATA, "videotext:history", NULL); notify_interpose_event_func(hist_panel, check_hotkeys_nometa, NOTIFY_SAFE); xv_set(cpop->list, XV_X, 15, XV_Y, 15, PANEL_LIST_WIDTH, 75, PANEL_LIST_DISPLAY_ROWS, config_get_popup_rows(POPUP_HISTORY), PANEL_LIST_DO_DBL_CLICK, TRUE, PANEL_NOTIFY_PROC, list_dbl_click, NULL); xv_create(hist_panel, PANEL_BUTTON, XV_X, 130, XV_Y, 15, PANEL_LABEL_STRING, " Go to", PANEL_LABEL_WIDTH, 55, PANEL_NOTIFY_PROC, hist_cb_proc, PANEL_CLIENT_DATA, GOTO_BUTTON, NULL); xv_create(hist_panel, PANEL_BUTTON, XV_X, 130, XV_Y, 45, PANEL_LABEL_STRING, "Previous", PANEL_LABEL_WIDTH, 55, PANEL_NOTIFY_PROC, hist_cb_proc, PANEL_CLIENT_DATA, PREV_BUTTON, NULL); xv_create(hist_panel, PANEL_BUTTON, XV_X, 130, XV_Y, 75, PANEL_LABEL_STRING, " Next", PANEL_LABEL_WIDTH, 55, PANEL_NOTIFY_PROC, hist_cb_proc, PANEL_CLIENT_DATA, NEXT_BUTTON, NULL); xv_create(hist_panel, PANEL_BUTTON, XV_X, 130, XV_Y, 105, PANEL_LABEL_STRING, " Stop", PANEL_LABEL_WIDTH, 55, PANEL_NOTIFY_PROC, hist_cb_proc, PANEL_CLIENT_DATA, STOP_BUTTON, NULL); xv_create(hist_panel, PANEL_BUTTON, XV_X, 130, XV_Y, 135, PANEL_LABEL_STRING, "Index pg", PANEL_LABEL_WIDTH, 55, PANEL_NOTIFY_PROC, hist_cb_proc, PANEL_CLIENT_DATA, INDEX_BUTTON, NULL); xv_create(hist_panel, PANEL_BUTTON, XV_X, 130, XV_Y, 175, PANEL_LABEL_STRING, " Close", PANEL_LABEL_WIDTH, 55, PANEL_NOTIFY_PROC, hist_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); window_fit(hist_panel); window_fit(cpop->frame); cpop->rowht = (int)xv_get(cpop->list, PANEL_LIST_ROW_HEIGHT); cpop->borderht = (int)xv_get(cpop->frame, XV_HEIGHT) - config_get_popup_rows(POPUP_HISTORY) * cpop->rowht; set_frame_constraints(cpop->frame, 0, 0, 9 * cpop->rowht + cpop->borderht, 0, FRC_HSHRINK | FRC_HGROW); } if (!(int)xv_get(cpop->frame, XV_SHOW)) { wmgr_inc_ignore_xconfigure(&wmgr); center_frame(frame, cpop->frame); } xv_set(cpop->frame, XV_SHOW, TRUE, NULL); position_popups(); } void history_move(int direction) { int selected; if (!popups[POPUP_HISTORY].frame) return; if ((selected = (int)xv_get(popups[POPUP_HISTORY].list, PANEL_LIST_FIRST_SELECTED)) != -1) { xv_set(popups[POPUP_HISTORY].list, PANEL_LIST_SELECT, selected, FALSE, NULL); selected += direction; xv_set(popups[POPUP_HISTORY].list, PANEL_LIST_SELECT, selected, TRUE, NULL); selected = (int)xv_get(popups[POPUP_HISTORY].list, PANEL_LIST_FIRST_SELECTED); if (selected != -1) { get_page(PRI_FGROUND_NH, strtol((char*)xv_get(popups[POPUP_HISTORY].list, PANEL_LIST_STRING, selected), NULL, 16), 0, 0, vtx_buffer, &vtxwin); } } } static void history_goto(int selected) { if (selected != -1) { get_page(PRI_FGROUND_NH, strtol((char*)xv_get(popups[POPUP_HISTORY].list, PANEL_LIST_STRING, selected), NULL, 16), 0, 0, vtx_buffer, &vtxwin); } } static void history_stop(int selected) { if (selected != -1) { stop_search(strtol((char*)xv_get(popups[POPUP_HISTORY].list, PANEL_LIST_STRING, selected), NULL, 16)); } } static void hist_cb_proc(Panel_item item, const Event *event) { switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case GOTO_BUTTON: history_goto((int)xv_get(popups[POPUP_HISTORY].list, PANEL_LIST_FIRST_SELECTED)); break; case PREV_BUTTON: history_move(-1); break; case NEXT_BUTTON: history_move(+1); break; case STOP_BUTTON: history_stop((int)xv_get(popups[POPUP_HISTORY].list, PANEL_LIST_FIRST_SELECTED)); break; case INDEX_BUTTON: get_page(PRI_FGROUND, hotlist_get_index_page(), 0, 0, vtx_buffer, &vtxwin); break; case CLOSE_BUTTON: popup_frame_done(popups[POPUP_HISTORY].frame); break; default: assert(0); break; } } void toptext_proc(void) { popups_t *cpop = popups + POPUP_TOPTEXT; Panel toptext_panel; if (!cpop->frame) { ov_menu = (Menu)xv_create(XVNULL, MENU, MENU_GEN_PIN_WINDOW, frame, "TOP-Text overview", MENU_NOTIFY_PROC, toptext_menu_cb_proc, NULL); hier_menu = (Menu)xv_create(XVNULL, MENU, MENU_GEN_PIN_WINDOW, frame, "TOP-Text hierarchy", MENU_NOTIFY_PROC, toptext_menu_cb_proc, NULL); cpop->frame = (Frame)xv_create(frame, FRAME, XV_LABEL, "TOP-Text", WIN_CONSUME_EVENTS, WIN_STRUCTURE_NOTIFY, WIN_PROPERTY_NOTIFY, NULL, WIN_EVENT_PROC, popup_frame_proc, FRAME_DONE_PROC, popup_frame_done, NULL); toptext_panel = (Panel)xv_create(cpop->frame, PANEL, XV_WIDTH, 350, XV_HEIGHT, 185, XV_HELP_DATA, "videotext:toptext", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); notify_interpose_event_func(toptext_panel, check_hotkeys_nometa, NOTIFY_SAFE); ov_menubutton = (Panel_item)xv_create(toptext_panel, PANEL_BUTTON, XV_X, 15, XV_Y, 15, PANEL_LABEL_STRING, "Overview", PANEL_ITEM_MENU, ov_menu, NULL); hier_menubutton = (Panel_item)xv_create(toptext_panel, PANEL_BUTTON, XV_X, 125, XV_Y, 15, PANEL_LABEL_STRING, "Hierarchy", PANEL_ITEM_MENU, hier_menu, NULL); xv_create(toptext_panel, PANEL_BUTTON, XV_X, 285, XV_Y, 15, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, toptext_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); xv_create(toptext_panel, PANEL_MESSAGE, XV_X, 15, XV_Y, 50, PANEL_LABEL_BOLD, TRUE, PANEL_LABEL_STRING, "Current page:", NULL); tt_buttons[0] = (Panel_item)xv_create(toptext_panel, PANEL_BUTTON, XV_X, 15, XV_Y, 72, PANEL_LABEL_STRING, "Next page:", PANEL_NOTIFY_PROC, toptext_cb_proc, PANEL_CLIENT_DATA, NEXT_BUTTON, NULL); tt_buttons[1] = (Panel_item)xv_create(toptext_panel, PANEL_BUTTON, XV_X, 15, XV_Y, 97, PANEL_LABEL_STRING, "Prev. page:", PANEL_NOTIFY_PROC, toptext_cb_proc, PANEL_CLIENT_DATA, PREV_BUTTON, NULL); tt_buttons[2] = (Panel_item)xv_create(toptext_panel, PANEL_BUTTON, XV_X, 15, XV_Y, 122, PANEL_LABEL_STRING, "Next group:", PANEL_NOTIFY_PROC, toptext_cb_proc, PANEL_CLIENT_DATA, NEXTGRP_BUTTON, NULL); tt_buttons[3] = (Panel_item)xv_create(toptext_panel, PANEL_BUTTON, XV_X, 15, XV_Y, 147, PANEL_LABEL_STRING, "Next block:", PANEL_NOTIFY_PROC, toptext_cb_proc, PANEL_CLIENT_DATA, NEXTBLK_BUTTON, NULL); top_msgs[0] = (Panel_item)xv_create(toptext_panel, PANEL_MESSAGE, XV_X, 120, XV_Y, 50, PANEL_LABEL_STRING, "", NULL); top_msgs[1] = (Panel_item)xv_create(toptext_panel, PANEL_MESSAGE, XV_X, 120, XV_Y, 75, PANEL_LABEL_STRING, "", PANEL_CLIENT_DATA, 0, NULL); top_msgs[2] = (Panel_item)xv_create(toptext_panel, PANEL_MESSAGE, XV_X, 120, XV_Y, 100, PANEL_LABEL_STRING, "", PANEL_CLIENT_DATA, 0, NULL); top_msgs[3] = (Panel_item)xv_create(toptext_panel, PANEL_MESSAGE, XV_X, 120, XV_Y, 125, PANEL_LABEL_STRING, "", PANEL_CLIENT_DATA, 0, NULL); top_msgs[4] = (Panel_item)xv_create(toptext_panel, PANEL_MESSAGE, XV_X, 120, XV_Y, 150, PANEL_LABEL_STRING, "", PANEL_CLIENT_DATA, 0, NULL); window_fit(cpop->frame); set_frame_constraints(cpop->frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(cpop->frame, XV_SHOW)) { wmgr_inc_ignore_xconfigure(&wmgr); center_frame(frame, cpop->frame); } pgdesc_update(-1); topmenu_update(tt_desctable, tt_desccount); xv_set(cpop->frame, XV_SHOW, TRUE, NULL); position_popups(); } void get_next_toppage(int history) { int page; if (popups[POPUP_TOPTEXT].frame && (page = (int)xv_get(top_msgs[1], PANEL_CLIENT_DATA))) { get_page(history ? PRI_FGROUND : PRI_FGROUND_NH, page, 0, 0, vtx_buffer, &vtxwin); } else { get_page(history ? PRI_FGROUND : PRI_FGROUND_NH, inc_vtxpage(vtxwin.pgnum), 0, 0, vtx_buffer, &vtxwin); } } void toptext_go_nextpage(void) { get_next_toppage(FALSE); } void get_prev_toppage(int history) { int page; if (popups[POPUP_TOPTEXT].frame && (page = (int)xv_get(top_msgs[2], PANEL_CLIENT_DATA))) { get_page(history ? PRI_FGROUND : PRI_FGROUND_NH, page, 0, 0, vtx_buffer, &vtxwin); } else { get_page(history ? PRI_FGROUND : PRI_FGROUND_NH, dec_vtxpage(vtxwin.pgnum), 0, 0, vtx_buffer, &vtxwin); } } void toptext_go_prevpage(void) { get_prev_toppage(FALSE); } void toptext_go_nextgrp(void) { int page; if (!popups[POPUP_TOPTEXT].frame) return; if ((page = (int)xv_get(top_msgs[3], PANEL_CLIENT_DATA))) { get_page(PRI_FGROUND_NH, page, 0, 0, vtx_buffer, &vtxwin); } } void toptext_go_nextblk(void) { int page; if (!popups[POPUP_TOPTEXT].frame) return; if ((page = (int)xv_get(top_msgs[4], PANEL_CLIENT_DATA))) { get_page(PRI_FGROUND_NH, page, 0, 0, vtx_buffer, &vtxwin); } } static void toptext_cb_proc(Panel_item item, const Event *event) { switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case NEXT_BUTTON: toptext_go_nextpage(); break; case PREV_BUTTON: toptext_go_prevpage(); break; case NEXTGRP_BUTTON: toptext_go_nextgrp(); break; case NEXTBLK_BUTTON: toptext_go_nextblk(); break; case CLOSE_BUTTON: popup_frame_done(popups[POPUP_TOPTEXT].frame); break; default: assert(0); break; } } static void toptext_menu_cb_proc(Menu menu, Menu_item menu_item) { int page; if ((page = (int)xv_get(menu_item, MENU_CLIENT_DATA))) { get_page(PRI_FGROUND, page, 0, 0, vtx_buffer, &vtxwin); } } void toptext_ok_notify(void) { ttdesc_t *next; /* Destroy old overview- & hierarchy-menus and recreate them (empty) */ if (popups[POPUP_TOPTEXT].frame) { int item; Frame pin_frame; Menu menu; /* We have to remove the menu from the PANEL_BUTTON before destroying it, because XView is way * too clever to allow us to destroy a menu that is still attached to something... */ xv_set(ov_menubutton, PANEL_ITEM_MENU, NULL, NULL); pin_frame = (Frame)xv_get(ov_menu, MENU_PIN_WINDOW); assert(!xv_destroy(ov_menu)); if (pin_frame) { assert(!xv_destroy(pin_frame)); } ov_menu = (Menu)xv_create(XVNULL, MENU, MENU_GEN_PIN_WINDOW, frame, "TOP-Text overview", MENU_NOTIFY_PROC, toptext_menu_cb_proc, NULL); xv_set(ov_menubutton, PANEL_ITEM_MENU, ov_menu, NULL); xv_set(hier_menubutton, PANEL_ITEM_MENU, NULL, NULL); for (item = (int)xv_get(hier_menu, MENU_NITEMS); item >= 1; item--) { if ((menu = (Menu)xv_get((Menu_item)xv_get(hier_menu, MENU_NTH_ITEM, item), MENU_PULLRIGHT))) { xv_set((Menu_item)xv_get(hier_menu, MENU_NTH_ITEM, item), MENU_PULLRIGHT, NULL, NULL); assert(!xv_destroy(menu)); } } pin_frame = (Frame)xv_get(hier_menu, MENU_PIN_WINDOW); assert(!xv_destroy(hier_menu)); if (pin_frame) { assert(!xv_destroy(pin_frame)); } hier_menu = (Menu)xv_create(XVNULL, MENU, MENU_GEN_PIN_WINDOW, frame, "TOP-Text hierarchy", MENU_NOTIFY_PROC, toptext_menu_cb_proc, NULL); xv_set(hier_menubutton, PANEL_ITEM_MENU, hier_menu, NULL); } /* Free old TOP-text page descriptions */ while (tt_desctable) { next = tt_desctable->next; free(tt_desctable); tt_desctable = next; } /* Get new TOP-text page descriptions and insert them into overview- and hierarchy-menus */ if ((tt_desctable = toptext_mkdesctable(&tt_desccount)) && popups[POPUP_TOPTEXT].frame) { topmenu_update(tt_desctable, tt_desccount); } /* Update buttons in TOP-text window (next/prev. page, next group/block) */ pgdesc_update(-1); /* If auto_top is set, open/close TOP-text window depending on new TOP-text state */ if (config_get_auto_top()) { if (toptext_ok) { if (!popups[POPUP_TOPTEXT].frame) { toptext_proc(); } else { xv_set(popups[POPUP_TOPTEXT].frame, XV_SHOW, TRUE, NULL); position_popups(); } } else if (popups[POPUP_TOPTEXT].frame) { popup_frame_done(popups[POPUP_TOPTEXT].frame); } } } void pgdesc_update(int page) { char *text; static int lastpage = 0x100; int msg, button; if (page < 0) { page = lastpage; } lastpage = page; if (!popups[POPUP_TOPTEXT].frame) return; xv_set(ov_menubutton, PANEL_INACTIVE, !toptext_ok, NULL); xv_set(hier_menubutton, PANEL_INACTIVE, !toptext_ok, NULL); for (button = 0; button < NELEM(tt_buttons); button++) { xv_set(tt_buttons[button], PANEL_INACTIVE, !toptext_ok, NULL); } if ((text = toptext_pgdesc(page))) { xv_set(top_msgs[0], PANEL_LABEL_STRING, text, NULL); } else { xv_set(top_msgs[0], PANEL_LABEL_STRING, "No TOP-Text active\n", NULL); for (msg = 1; msg < NELEM(top_msgs); msg++) { xv_set(top_msgs[msg], PANEL_LABEL_STRING, "", PANEL_CLIENT_DATA, 0, NULL); } return; } if (!(page = toptext_pginc(lastpage))) { page = lastpage; } xv_set(top_msgs[1], PANEL_LABEL_STRING, toptext_pgdesc(page), PANEL_CLIENT_DATA, page, NULL); if (!(page = toptext_pgdec(lastpage))) { page = lastpage; } xv_set(top_msgs[2], PANEL_LABEL_STRING, toptext_pgdesc(page), PANEL_CLIENT_DATA, page, NULL); if (!(page = toptext_nextgrppg(lastpage))) { page = lastpage; } xv_set(top_msgs[3], PANEL_LABEL_STRING, toptext_pgdesc(page), PANEL_CLIENT_DATA, page, NULL); if (!(page = toptext_nextblkpg(lastpage))) { page = lastpage; } xv_set(top_msgs[4], PANEL_LABEL_STRING, toptext_pgdesc(page), PANEL_CLIENT_DATA, page, NULL); } static void topmenu_update(const ttdesc_t *desctable, int desccount) { const ttdesc_t *desc; if (desctable) { /* Create overview-/hierarchy-menu */ for (desc = desctable; desc; desc = desc->next) { xv_set(ov_menu, MENU_APPEND_ITEM, (Menu_item)xv_create(XVNULL, MENUITEM, MENU_STRING, desc->fullname, MENU_CLIENT_DATA, desc->page, MENU_RELEASE, NULL), NULL); if (desc->is_block) { if (desc->next && !desc->next->is_block) { /* If page is a blockpage followed by other non-blockpages, create pullright-menu & add * blockpage as first entry */ xv_set(hier_menu, MENU_APPEND_ITEM, (Menu_item)xv_create(XVNULL, MENUITEM, MENU_STRING, desc->pagename, MENU_PULLRIGHT, (Menu)xv_create(XVNULL, MENU, MENU_NOTIFY_PROC, toptext_menu_cb_proc, MENU_ITEM, MENU_STRING, desc->fullname, MENU_CLIENT_DATA, desc->page, MENU_RELEASE, NULL, NULL), MENU_RELEASE, NULL), NULL); } else { /* If page is a blockpage followed by another blockpage, there's no need for a pullright- * menu, so just insert it into the toplevel-menu */ xv_set(hier_menu, MENU_APPEND_ITEM, (Menu_item)xv_create(XVNULL, MENUITEM, MENU_STRING, desc->fullname, MENU_CLIENT_DATA, desc->page, MENU_RELEASE, NULL), NULL); } } else { /* If page is a non-blockpage, insert it into the last pullright-menu or into the toplevel- * menu, if no pullright-menu has been created up to now */ Menu_item item; item = (Menu_item)xv_get(hier_menu, MENU_NTH_ITEM, (int)xv_get(hier_menu, MENU_NITEMS)); if ((Menu)xv_get(item, MENU_PULLRIGHT)) { xv_set((Menu)xv_get(item, MENU_PULLRIGHT), MENU_APPEND_ITEM, (Menu_item)xv_create(XVNULL, MENUITEM, MENU_STRING, desc->pagename, MENU_CLIENT_DATA, desc->page, MENU_RELEASE, NULL), NULL); } else { xv_set(hier_menu, MENU_APPEND_ITEM, (Menu_item)xv_create(XVNULL, MENUITEM, MENU_STRING, desc->pagename, MENU_CLIENT_DATA, desc->page, MENU_RELEASE, NULL), NULL); } } } /* Try to determine the number of rows/columns so that the height of the popup-menu equals * approxmiately its width. The width and height of a single entry are about 250 and 20 pixels. */ xv_set(ov_menu, MENU_NCOLS, (int)ceil(sqrt(20.0 / 250.0 * desccount)), NULL); } else { xv_set(ov_menu, MENU_APPEND_ITEM, (Menu_item)xv_create(XVNULL, MENUITEM, MENU_STRING, "No pages available", MENU_CLIENT_DATA, 0, MENU_RELEASE, NULL), NULL); xv_set(hier_menu, MENU_APPEND_ITEM, (Menu_item)xv_create(XVNULL, MENUITEM, MENU_STRING, "No pages available", MENU_CLIENT_DATA, 0, MENU_RELEASE, NULL), NULL); } } #define FT_DEFAULT_CLOSE_POS 550 static Panel fastext_panel; static Panel_item ft_buttons[5], fastext_close_button, fastext_inactive_text; static Panel_item fastext_disabled_text; void fastext_proc(void) { popups_t *cpop = popups + POPUP_FASTEXT; int a; if (!cpop->frame) { cpop->frame = (Frame)xv_create(frame, FRAME, XV_LABEL, "FASTEXT", WIN_CONSUME_EVENTS, WIN_STRUCTURE_NOTIFY, WIN_PROPERTY_NOTIFY, NULL, WIN_EVENT_PROC, popup_frame_proc, FRAME_DONE_PROC, popup_frame_done, NULL); fastext_panel = (Panel)xv_create(cpop->frame, PANEL, XV_HELP_DATA, "videotext:fastext", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); notify_interpose_event_func(fastext_panel, check_hotkeys_nometa, NOTIFY_SAFE); for (a = 0; a < NELEM(ft_buttons); a++) { ft_buttons[a] = xv_create(fastext_panel, PANEL_BUTTON, XV_X, 15, XV_Y, 15, PANEL_LABEL_STRING, "", PANEL_NOTIFY_PROC, fastext_button_proc, PANEL_CLIENT_DATA, a, XV_SHOW, FALSE, NULL); } xv_set(ft_buttons[NELEM(ft_buttons) - 1], PANEL_LABEL_STRING, "FAST Index", NULL); fastext_inactive_text = xv_create(fastext_panel, PANEL_MESSAGE, XV_X, 15, XV_Y, 18, PANEL_LABEL_STRING, "No FASTEXT active for current page", XV_SHOW, FALSE, NULL); fastext_disabled_text = xv_create(fastext_panel, PANEL_MESSAGE, XV_X, 15, XV_Y, 18, PANEL_LABEL_STRING, "FASTEXT disabled", XV_SHOW, FALSE, NULL); fastext_close_button = xv_create(fastext_panel, PANEL_BUTTON, XV_X, FT_DEFAULT_CLOSE_POS, XV_Y, 15, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, fastext_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); window_fit(fastext_panel); window_fit(cpop->frame); set_frame_constraints(cpop->frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(cpop->frame, XV_SHOW)) { wmgr_inc_ignore_xconfigure(&wmgr); center_frame(frame, cpop->frame); } xv_set(cpop->frame, XV_SHOW, TRUE, NULL); fastext_new_buttons(vtxwin.page->info.pagenum, vtxwin.page->info.minute); position_popups(); } static void fastext_cb_proc(Panel_item item, const Event *event) { switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case CLOSE_BUTTON: popup_frame_done(popups[POPUP_FASTEXT].frame); break; default: assert(0); break; } } static void fastext_button_proc(Panel_item item, const Event *event) { int btndat, page, subpage; btndat = xv_get(item, PANEL_CLIENT_DATA); page = btndat >> 16; subpage = btndat & 0xffff; if (subpage == 0x3f7f) { subpage = 0; } /* VideoteXt currently doesn't support subpage-numbers > 7 bit */ subpage &= 0x7f; get_page(PRI_FGROUND_NH, page, subpage, 0, vtx_buffer, &vtxwin); } void fastext_new_buttons(int page, int subpage) { static int last_close_pos = FT_DEFAULT_CLOSE_POS, old_ft_dis = -1; static byte_t old_packet24[40], old_packet27[4 * 40]; int btn, btn_pos, new_close_pos, ft_dis; const fastext_buttons_t *buttons; const fastext_links_t *links; const byte_t *packet24, *packet27; if (!popups[POPUP_FASTEXT].frame) return; ft_dis = hotlist_get_fastdisable(); if (page && !ft_dis && fastext_get_pginfo(page, subpage, &buttons, &links, &packet24, &packet27)) { if (!fastext_cmp_packets(packet24, packet27, old_packet24, old_packet27) || !(int)xv_get(ft_buttons[0], XV_SHOW)) { memcpy(old_packet24, packet24, sizeof(old_packet24)); memcpy(old_packet27, packet27, sizeof(old_packet27)); old_ft_dis = -1; xv_set(fastext_inactive_text, XV_SHOW, FALSE, NULL); xv_set(fastext_disabled_text, XV_SHOW, FALSE, NULL); btn_pos = 15; for (btn = 0; btn < NELEM(ft_buttons) - 1; btn++) { if (buttons->button[btn] >= 0) { xv_set(ft_buttons[btn], XV_X, btn_pos, XV_SHOW, TRUE, PANEL_LABEL_STRING, buttons->btnbuf + buttons->button[btn], PANEL_CLIENT_DATA, (links->link[btn].page << 16) | (links->link[btn].hour << 8) | links->link[btn].minute, NULL); btn_pos = rect_right((Rect *)xv_get(ft_buttons[btn], XV_RECT)) + 5; } else { xv_set(ft_buttons[btn], XV_SHOW, FALSE, NULL); } } xv_set(ft_buttons[btn], XV_X, btn_pos, XV_SHOW, TRUE, PANEL_CLIENT_DATA, (links->link[5].page << 16) | (links->link[5].hour << 8) | links->link[5].minute, NULL); new_close_pos = MAX(rect_right((Rect *)xv_get(ft_buttons[btn], XV_RECT)) + 20, FT_DEFAULT_CLOSE_POS); if (new_close_pos != last_close_pos) { xv_set(fastext_close_button, XV_X, new_close_pos, NULL); window_fit(fastext_panel); window_fit(popups[POPUP_FASTEXT].frame); last_close_pos = new_close_pos; } panel_paint(fastext_panel, PANEL_CLEAR); position_popups(); } } else if (ft_dis != old_ft_dis) { for (btn = 0; btn < NELEM(ft_buttons); btn++) { xv_set(ft_buttons[btn], XV_SHOW, FALSE, NULL); } xv_set(fastext_inactive_text, XV_SHOW, !ft_dis, NULL); xv_set(fastext_disabled_text, XV_SHOW, ft_dis, NULL); old_ft_dis = ft_dis; } } void fastext_ok_notify(void) { if (!config_get_auto_top()) return; if (!hotlist_get_fastdisable()) { if (fastext_ok) { if (!popups[POPUP_FASTEXT].frame) { fastext_proc(); } else { xv_set(popups[POPUP_FASTEXT].frame, XV_SHOW, TRUE, NULL); fastext_new_buttons(vtxwin.page->info.pagenum, vtxwin.page->info.minute); position_popups(); } } else { fastext_new_buttons(0, 0); } } else if (popups[POPUP_FASTEXT].frame) { popup_frame_done(popups[POPUP_FASTEXT].frame); } } static Frame layout_frame; static Panel_item lay_search_choice, lay_hot_choice, lay_top_choice, lay_fast_choice, lay_hist_choice, lay_stat_choice, lay_visible_toggle, lay_checkmarks; void layout_proc(void) { int popup, val = 0; Panel layout_panel; if (!layout_frame) { layout_frame = (Frame)xv_create(frame, FRAME, XV_LABEL, "Window layout", NULL); layout_panel = (Panel)xv_create(layout_frame, PANEL, XV_HELP_DATA, "videotext:win_layout", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); xv_create(layout_panel, PANEL_MESSAGE, XV_X, 145, XV_Y, 15, PANEL_LABEL_STRING, "Popup-window placement", PANEL_LABEL_BOLD, TRUE, NULL); lay_search_choice = (Panel_item)xv_create(layout_panel, PANEL_CHOICE, PANEL_VALUE_X, 145, PANEL_VALUE_Y, 40, PANEL_LABEL_STRING, "Search", PANEL_CHOICE_STRINGS, "Centered", "Left", "Right", "Top", "Bottom", NULL, NULL); lay_hist_choice = (Panel_item)xv_create(layout_panel, PANEL_CHOICE, PANEL_VALUE_X, 145, PANEL_VALUE_Y, 80, PANEL_LABEL_STRING, "Page history", PANEL_CHOICE_STRINGS, "Centered", "Left", "Right", "Top", "Bottom", NULL, NULL); lay_top_choice = (Panel_item)xv_create(layout_panel, PANEL_CHOICE, PANEL_VALUE_X, 145, PANEL_VALUE_Y, 120, PANEL_LABEL_STRING, "TOP-Text", PANEL_CHOICE_STRINGS, "Centered", "Left", "Right", "Top", "Bottom", NULL, NULL); lay_fast_choice = (Panel_item)xv_create(layout_panel, PANEL_CHOICE, PANEL_VALUE_X, 145, PANEL_VALUE_Y, 160, PANEL_LABEL_STRING, "FASTEXT", PANEL_CHOICE_STRINGS, "Centered", "Left", "Right", "Top", "Bottom", NULL, NULL); lay_hot_choice = (Panel_item)xv_create(layout_panel, PANEL_CHOICE, PANEL_VALUE_X, 145, PANEL_VALUE_Y, 200, PANEL_LABEL_STRING, "Hotlist", PANEL_CHOICE_STRINGS, "Centered", "Left", "Right", "Top", "Bottom", NULL, NULL); lay_stat_choice = (Panel_item)xv_create(layout_panel, PANEL_CHOICE, PANEL_VALUE_X, 145, PANEL_VALUE_Y, 240, PANEL_LABEL_STRING, "Station list", PANEL_CHOICE_STRINGS, "Centered", "Left", "Right", "Top", "Bottom", NULL, NULL); lay_visible_toggle = (Panel_item)xv_create(layout_panel, PANEL_TOGGLE, PANEL_VALUE_X, 145, PANEL_VALUE_Y, 290, PANEL_LABEL_STRING, "Visible on startup", PANEL_CHOICE_STRINGS, "Page history", "TOP-Text", "FASTEXT", "Search", "Hotlist", "Station list", NULL, PANEL_CHOICE_NROWS, 2, NULL); lay_checkmarks = (Panel_item)xv_create(layout_panel, PANEL_CHECK_BOX, PANEL_VALUE_X, 75, PANEL_VALUE_Y, 355, PANEL_LAYOUT, PANEL_VERTICAL, PANEL_CHOICE_STRINGS, "Open TOP-Text/FASTEXT window when active", "Open search window on matches", "Sticky filechoosers", "Group iconify", NULL, NULL); xv_create(layout_panel, PANEL_BUTTON, XV_X, 170, XV_Y, 485, PANEL_LABEL_STRING, "Apply", PANEL_NOTIFY_PROC, layout_cb_proc, PANEL_CLIENT_DATA, APPLY_BUTTON, NULL); xv_create(layout_panel, PANEL_BUTTON, XV_X, 230, XV_Y, 485, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, layout_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); window_fit(layout_panel); window_fit(layout_frame); set_frame_constraints(layout_frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(layout_frame, XV_SHOW)) center_frame(frame, layout_frame); xv_set(lay_search_choice, PANEL_VALUE, config_get_placement(POPUP_SEARCH), NULL); xv_set(lay_hot_choice, PANEL_VALUE, config_get_placement(POPUP_HOTLIST), NULL); xv_set(lay_top_choice, PANEL_VALUE, config_get_placement(POPUP_TOPTEXT), NULL); xv_set(lay_fast_choice, PANEL_VALUE, config_get_placement(POPUP_FASTEXT), NULL); xv_set(lay_hist_choice, PANEL_VALUE, config_get_placement(POPUP_HISTORY), NULL); xv_set(lay_stat_choice, PANEL_VALUE, config_get_placement(POPUP_SELST), NULL); for (popup = 0; popup < POPUP_COUNT; popup++) { val |= (config_get_startup(popup) ? (1 << popup) : 0); } xv_set(lay_visible_toggle, PANEL_VALUE, val, NULL); xv_set(lay_checkmarks, PANEL_VALUE, config_get_auto_top() | config_get_auto_search() << 1 | config_get_sticky_fcs() << 2 | config_get_group_iconify() << 3, NULL); xv_set(layout_frame, XV_SHOW, TRUE, NULL); } static void layout_cb_proc(Panel_item item, const Event *event) { int popup, val; switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case APPLY_BUTTON: config_set_placement(POPUP_SEARCH, (int)xv_get(lay_search_choice, PANEL_VALUE)); config_set_placement(POPUP_HOTLIST, (int)xv_get(lay_hot_choice, PANEL_VALUE)); config_set_placement(POPUP_TOPTEXT, (int)xv_get(lay_top_choice, PANEL_VALUE)); config_set_placement(POPUP_FASTEXT, (int)xv_get(lay_fast_choice, PANEL_VALUE)); config_set_placement(POPUP_HISTORY, (int)xv_get(lay_hist_choice, PANEL_VALUE)); config_set_placement(POPUP_SELST, (int)xv_get(lay_stat_choice, PANEL_VALUE)); for (popup = 0; popup < POPUP_COUNT; popup++) { config_set_startup(popup, ((int)xv_get(lay_visible_toggle, PANEL_VALUE) & (1 << popup)) ? TRUE : FALSE); } val = (int)xv_get(lay_checkmarks, PANEL_VALUE); config_set_auto_top(val & 1); config_set_auto_search(val & 2); config_set_sticky_fcs(val & 4); config_set_group_iconify(val & 8); toptext_ok_notify(); fastext_ok_notify(); position_popups(); break; case CLOSE_BUTTON: xv_set(layout_frame, XV_SHOW, FALSE, NULL); break; default: assert(0); break; } } static Frame tvopt_frame; static Panel_item tvopt_disp_checkbox, tvopt_int_checkbox, tvopt_mode_choice; static void tvopt_activate(void) { xv_set(tvopt_int_checkbox, PANEL_INACTIVE, !(int)xv_get(tvopt_disp_checkbox, PANEL_VALUE), NULL); xv_set(tvopt_mode_choice, PANEL_INACTIVE, !(int)xv_get(tvopt_disp_checkbox, PANEL_VALUE), NULL); } void tvopt_proc(void) { Panel tvopt_panel; if (!tvopt_frame) { tvopt_frame = (Frame)xv_create(frame, FRAME, XV_LABEL, "TV options", NULL); tvopt_panel = (Panel)xv_create(tvopt_frame, PANEL, XV_HELP_DATA, "videotext:tv_options", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); tvopt_disp_checkbox = (Panel_item)xv_create(tvopt_panel, PANEL_CHECK_BOX, XV_X, 55, XV_Y, 20, PANEL_CHOICE_STRINGS, "Display videotext-pages on TV", NULL, PANEL_NOTIFY_PROC, tvopt_activate, NULL); tvopt_int_checkbox = (Panel_item)xv_create(tvopt_panel, PANEL_CHECK_BOX, XV_X, 55, XV_Y, 55, PANEL_CHOICE_STRINGS, "Always use interlace", NULL, NULL); tvopt_mode_choice = (Panel_item)xv_create(tvopt_panel, PANEL_CHOICE, XV_X, 15, XV_Y, 95, PANEL_LABEL_STRING, "Display mode", /* The order of these strings must be the same as in enum vtxdisp_t (vtx.h) */ PANEL_CHOICE_STRINGS, "Normal", "Transparent", "Insert", NULL, NULL); xv_create(tvopt_panel, PANEL_BUTTON, XV_X, 115, XV_Y, 145, PANEL_LABEL_STRING, "Apply", PANEL_NOTIFY_PROC, tvopt_cb_proc, PANEL_CLIENT_DATA, APPLY_BUTTON, NULL); xv_create(tvopt_panel, PANEL_BUTTON, XV_X, 175, XV_Y, 145, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, tvopt_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); window_fit(tvopt_panel); window_fit(tvopt_frame); set_frame_constraints(tvopt_frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(tvopt_frame, XV_SHOW)) center_frame(frame, tvopt_frame); xv_set(tvopt_disp_checkbox, PANEL_VALUE, config_get_tv_disp(), NULL); xv_set(tvopt_int_checkbox, PANEL_VALUE, config_get_interlace(), NULL); xv_set(tvopt_mode_choice, PANEL_VALUE, config_get_display_mode() - 1, NULL); tvopt_activate(); xv_set(tvopt_frame, XV_SHOW, TRUE, NULL); } static void tvopt_cb_proc(Panel_item item, const Event *event) { switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case APPLY_BUTTON: config_set_tv_disp((int)xv_get(tvopt_disp_checkbox, PANEL_VALUE)); config_set_interlace((int)xv_get(tvopt_int_checkbox, PANEL_VALUE)); config_set_display_mode((int)xv_get(tvopt_mode_choice, PANEL_VALUE) + 1); if (vtx_dev_open) { CCTCHK(cct_set_display(config_get_tv_disp() ? (config_get_display_mode() + config_get_interlace() * INTERLACE_OFFSET) : DISPOFF), "cct_set_display", return); } break; case CLOSE_BUTTON: xv_set(tvopt_frame, XV_SHOW, FALSE, NULL); break; default: assert(0); break; } } static Frame psopt_frame; static Panel_item layout_choice, paper_choice; void psopt_proc(void) { Panel psopt_panel; if (!psopt_frame) { int item; psopt_frame = (Frame)xv_create(frame, FRAME, XV_LABEL, "PostScript options", NULL); psopt_panel = (Panel)xv_create(psopt_frame, PANEL, XV_HELP_DATA, "videotext:postscript_options", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); layout_choice = (Panel_item)xv_create(psopt_panel, PANEL_CHOICE, XV_X, 15, XV_Y, 20, PANEL_LABEL_STRING, "Page layout", PANEL_LAYOUT, PANEL_HORIZONTAL, PANEL_CHOICE_NROWS, 2, NULL); for (item = 0; pglayout_data[item].bits; item++) { xv_set(layout_choice, PANEL_CHOICE_IMAGE, item, (Server_image)xv_create(XVNULL, SERVER_IMAGE, XV_WIDTH, pglayout_data[item].width, XV_HEIGHT, pglayout_data[item].height, SERVER_IMAGE_X_BITS, pglayout_data[item].bits, NULL), NULL); } paper_choice = (Panel_item)xv_create(psopt_panel, PANEL_CHOICE, PANEL_VALUE_X, (int)xv_get(layout_choice, PANEL_VALUE_X), PANEL_VALUE_Y, 135, PANEL_LABEL_STRING, "Paper size", PANEL_LAYOUT, PANEL_HORIZONTAL, NULL); for (item = 0; ps_paperdata[item].name; item++) { xv_set(paper_choice, PANEL_CHOICE_STRING, item, ps_paperdata[item].name, NULL); } xv_create(psopt_panel, PANEL_BUTTON, XV_X, 125, XV_Y, 185, PANEL_LABEL_STRING, "Apply", PANEL_NOTIFY_PROC, psopt_cb_proc, PANEL_CLIENT_DATA, APPLY_BUTTON, NULL); xv_create(psopt_panel, PANEL_BUTTON, XV_X, 185, XV_Y, 185, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, psopt_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); window_fit(psopt_panel); window_fit(psopt_frame); set_frame_constraints(psopt_frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(psopt_frame, XV_SHOW)) center_frame(frame, psopt_frame); xv_set(layout_choice, PANEL_VALUE, config_get_layout(), NULL); xv_set(paper_choice, PANEL_VALUE, config_get_papersize(), NULL); xv_set(psopt_frame, XV_SHOW, TRUE, NULL); } static void psopt_cb_proc(Panel_item item, const Event *event) { switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case APPLY_BUTTON: config_set_layout((int)xv_get(layout_choice, PANEL_VALUE)); config_set_papersize((int)xv_get(paper_choice, PANEL_VALUE)); break; case CLOSE_BUTTON: xv_set(psopt_frame, XV_SHOW, FALSE, NULL); break; default: assert(0); break; } } static Frame miscopt_frame; static Panel_item miscopt_checkbox, miscopt_cps_text, miscopt_ps_text, miscopt_ascii_text; static Panel_item miscopt_bm_text, miscopt_spooldir_text, miscopt_tvsys_choice; static int miscopt_tvsys_count; static char const * const *miscopt_tvsys_names; void miscopt_proc(void) { Panel miscopt_panel; int entry; if (!miscopt_frame) { miscopt_frame = (Frame)xv_create(frame, FRAME, XV_LABEL, "Miscellaneous options", NULL); miscopt_panel = (Panel)xv_create(miscopt_frame, PANEL, XV_HELP_DATA, "videotext:misc_options", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); miscopt_checkbox = (Panel_item)xv_create(miscopt_panel, PANEL_CHECK_BOX, XV_X, 15, XV_Y, 20, PANEL_LAYOUT, PANEL_VERTICAL, PANEL_CHOICE_STRINGS, "Auto-reset on station-change", "Continue searching for queued pages in background", "Continue searching for all pages in background", "Sorted search-order for TOP-Text pages", "Don't open device, only use spool-dir", "Disable blinking", NULL, NULL); xv_create(miscopt_panel, PANEL_MESSAGE, XV_X, 125, XV_Y, 205, PANEL_LABEL_STRING, "Printing commands:", PANEL_LABEL_BOLD, TRUE, NULL); miscopt_cps_text = (Panel_item)xv_create(miscopt_panel, PANEL_TEXT, PANEL_VALUE_X, 140, PANEL_VALUE_Y, 225, PANEL_LABEL_STRING, "Color-PostScript:", PANEL_VALUE_DISPLAY_WIDTH, 215, PANEL_VALUE_STORED_LENGTH, 99, NULL); miscopt_ps_text = (Panel_item)xv_create(miscopt_panel, PANEL_TEXT, PANEL_VALUE_X, 140, PANEL_VALUE_Y, 245, PANEL_LABEL_STRING, "B/W-PostScript:", PANEL_VALUE_DISPLAY_WIDTH, 215, PANEL_VALUE_STORED_LENGTH, 99, NULL); miscopt_ascii_text = (Panel_item)xv_create(miscopt_panel, PANEL_TEXT, PANEL_VALUE_X, 140, PANEL_VALUE_Y, 265, PANEL_LABEL_STRING, "ASCII:", PANEL_VALUE_DISPLAY_WIDTH, 215, PANEL_VALUE_STORED_LENGTH, 99, NULL); miscopt_bm_text = (Panel_item)xv_create(miscopt_panel, PANEL_TEXT, PANEL_VALUE_X, 140, PANEL_VALUE_Y, 285, PANEL_LABEL_STRING, "Bitmap:", PANEL_VALUE_DISPLAY_WIDTH, 215, PANEL_VALUE_STORED_LENGTH, 99, NULL); miscopt_spooldir_text = (Panel_item)xv_create(miscopt_panel, PANEL_TEXT, PANEL_VALUE_X, 140, PANEL_VALUE_Y, 315, PANEL_LABEL_STRING, "Private spooldir:", PANEL_VALUE_DISPLAY_WIDTH, 215, PANEL_VALUE_STORED_LENGTH, 99, NULL); miscopt_tvsys_choice = (Panel_item)xv_create(miscopt_panel, PANEL_CHOICE_STACK, XV_X, 60, XV_Y, 340, PANEL_LABEL_STRING, "TV system", PANEL_LAYOUT, PANEL_HORIZONTAL, NULL); miscopt_tvsys_count = tvch_get_systems(&miscopt_tvsys_names); for (entry = 0; entry < miscopt_tvsys_count; entry++) { xv_set(miscopt_tvsys_choice, PANEL_CHOICE_STRING, entry, miscopt_tvsys_names[entry], NULL); } if ((entry = tvch_chan2freq(config_get_tvsystem(), NULL, NULL, NULL)) < 0) { entry = 0; } xv_set(miscopt_tvsys_choice, PANEL_VALUE, entry, NULL); xv_create(miscopt_panel, PANEL_BUTTON, XV_X, 125, XV_Y, 380, PANEL_LABEL_STRING, "Apply", PANEL_NOTIFY_PROC, miscopt_cb_proc, PANEL_CLIENT_DATA, APPLY_BUTTON, NULL); xv_create(miscopt_panel, PANEL_BUTTON, XV_X, 185, XV_Y, 380, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, miscopt_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); window_fit(miscopt_panel); window_fit(miscopt_frame); set_frame_constraints(miscopt_frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(miscopt_frame, XV_SHOW)) center_frame(frame, miscopt_frame); xv_set(miscopt_checkbox, PANEL_VALUE, config_get_auto_reset() | (config_get_cont_queue_search() << 1) | (config_get_cont_search() << 2) | (config_get_top_sorted() << 3) | (config_get_spool_only() << 4 | (config_get_blinkdis() << 5)), NULL); xv_set(miscopt_cps_text, PANEL_VALUE, config_get_printer(PRN_CPS), NULL); xv_set(miscopt_ps_text, PANEL_VALUE, config_get_printer(PRN_PS), NULL); xv_set(miscopt_ascii_text, PANEL_VALUE, config_get_printer(PRN_ASCII), NULL); xv_set(miscopt_bm_text, PANEL_VALUE, config_get_printer(PRN_BM), NULL); xv_set(miscopt_spooldir_text, PANEL_VALUE, config_get_spooldir(), NULL); xv_set(miscopt_frame, XV_SHOW, TRUE, NULL); } static void miscopt_cb_proc(Panel_item item, const Event *event) { const char *dir; int spool_last, tvsys; switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case APPLY_BUTTON: spool_last = config_get_spool_only(); config_set_auto_reset((int)xv_get(miscopt_checkbox, PANEL_VALUE) & 1); config_set_cont_queue_search((int)xv_get(miscopt_checkbox, PANEL_VALUE) & 2); config_set_cont_search((int)xv_get(miscopt_checkbox, PANEL_VALUE) & 4); config_set_top_sorted((int)xv_get(miscopt_checkbox, PANEL_VALUE) & 8); config_set_spool_only((int)xv_get(miscopt_checkbox, PANEL_VALUE) & 16); config_set_blinkdis((int)xv_get(miscopt_checkbox, PANEL_VALUE) & 32); config_set_printer(PRN_CPS, (char *)xv_get(miscopt_cps_text, PANEL_VALUE)); config_set_printer(PRN_PS, (char *)xv_get(miscopt_ps_text, PANEL_VALUE)); config_set_printer(PRN_ASCII, (char *)xv_get(miscopt_ascii_text, PANEL_VALUE)); config_set_printer(PRN_BM, (char *)xv_get(miscopt_bm_text, PANEL_VALUE)); dir = (const char *)xv_get(miscopt_spooldir_text, PANEL_VALUE); config_set_spooldir(dir); if (strcmp(dir, "") && (dir = tilde_expand(dir)) && access(dir, W_OK | X_OK) < 0) { confirm_notice_v(miscopt_frame, TRUE, "Warning: Directory ", dir, "\ndoes not exist or is not writable by you.", (char *)0); } if (!spool_last && spool_last != config_get_spool_only() && vtx_dev_open) { cct_close(); vtx_dev_open = FALSE; remove_priority(PRI_ALL); } tvsys = xv_get(miscopt_tvsys_choice, PANEL_VALUE); if (tvsys < miscopt_tvsys_count) { config_set_tvsystem(miscopt_tvsys_names[tvsys]); } tuning_update(FALSE); break; case CLOSE_BUTTON: xv_set(miscopt_frame, XV_SHOW, FALSE, NULL); break; default: assert(0); break; } } static Frame so_frame; static Panel_item so_to_slider, so_il_slider, so_la_num, so_ip_num, so_tf_checkbox, so_as_choice; void station_opt_proc(void) { Panel so_panel; if (!so_frame) { so_frame = (Frame)xv_create(frame, FRAME, NULL); so_panel = (Panel)xv_create(so_frame, PANEL, XV_HELP_DATA, "videotext:station_options", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); so_to_slider = (Panel_item)xv_create(so_panel, PANEL_SLIDER, XV_X, 33, XV_Y, 20, PANEL_LABEL_STRING, "Page-Timeout (sec.)", PANEL_MIN_VALUE, 10, PANEL_MAX_VALUE, 180, PANEL_SLIDER_WIDTH, 170, PANEL_TICKS, 18, PANEL_SLIDER_END_BOXES, TRUE, NULL); so_il_slider = (Panel_item)xv_create(so_panel, PANEL_SLIDER, XV_X, 15, XV_Y, 60, PANEL_LABEL_STRING, "TOP-Text interleave", PANEL_MIN_VALUE, -100, PANEL_MAX_VALUE, 100, PANEL_SLIDER_WIDTH, 170, PANEL_TICKS, 11, PANEL_SLIDER_END_BOXES, TRUE, NULL); so_tf_checkbox = (Panel_item)xv_create(so_panel, PANEL_CHECK_BOX, XV_X, 160, XV_Y, 95, PANEL_LAYOUT, PANEL_VERTICAL, PANEL_CHOICE_STRINGS, "Don't search for TOP-Text", "Don't search for FASTEXT", NULL, PANEL_NOTIFY_PROC, station_opt_activate, NULL); so_as_choice = (Panel_item)xv_create(so_panel, PANEL_CHOICE, PANEL_VALUE_X, 160, PANEL_VALUE_Y, 155, PANEL_LABEL_STRING, "Auto-search pages", PANEL_CHOICE_STRINGS, "None", "Blocks", "Groups", "Normal", "Subpages", NULL, NULL); so_la_num = (Panel_item)xv_create(so_panel, PANEL_NUMERIC_TEXT, XV_X, 75, XV_Y, 205, PANEL_LABEL_STRING, "Page-lookahead", PANEL_MIN_VALUE, 0, PANEL_MAX_VALUE, 5, PANEL_VALUE_DISPLAY_WIDTH, 20, PANEL_VALUE_STORED_LENGTH, 1, NULL); so_ip_num = (Panel_item)xv_create(so_panel, PANEL_TEXT, XV_X, 290, XV_Y, 205, PANEL_LABEL_STRING, "Index page", PANEL_VALUE_DISPLAY_WIDTH, 35, PANEL_VALUE_STORED_LENGTH, 3, NULL); xv_create(so_panel, PANEL_BUTTON, XV_X, 180, XV_Y, 250, PANEL_LABEL_STRING, "Apply", PANEL_NOTIFY_PROC, so_cb_proc, PANEL_CLIENT_DATA, APPLY_BUTTON, NULL); xv_create(so_panel, PANEL_BUTTON, XV_X, 240, XV_Y, 250, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, so_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); xv_create(so_panel, PANEL_BUTTON, XV_X, 350, XV_Y, 250, PANEL_LABEL_STRING, "Copy settings...", PANEL_NOTIFY_PROC, so_cb_proc, PANEL_CLIENT_DATA, COPY_SET_BUTTON, NULL); window_fit(so_panel); window_fit(so_frame); set_frame_constraints(so_frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(so_frame, XV_SHOW)) center_frame(frame, so_frame); station_opt_update(); xv_set(so_frame, XV_SHOW, TRUE, NULL); } static void so_cb_proc(Panel_item item, const Event *event) { int index_page; switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case APPLY_BUTTON: index_page = strtol((char*)xv_get(so_ip_num, PANEL_VALUE), NULL, 16); if (!vtx_chkpgnum(index_page, TRUE)) { confirm_notice(so_frame, TRUE, "Invalid index-page number.\nValid range is 100-8FF (hexadecimal)."); } else { hotlist_set_timeout((int)xv_get(so_to_slider, PANEL_VALUE)); hotlist_set_interleave((int)xv_get(so_il_slider, PANEL_VALUE)); hotlist_set_topdisable((int)xv_get(so_tf_checkbox, PANEL_VALUE) & 1); hotlist_set_fastdisable((int)xv_get(so_tf_checkbox, PANEL_VALUE) & 2); hotlist_set_searchlevel((tt_pageclass_t)xv_get(so_as_choice, PANEL_VALUE)); hotlist_set_lookahead((int)xv_get(so_la_num, PANEL_VALUE)); hotlist_set_index_page(index_page); if (vtx_dev_open) { CCTCHK(cct_set_virtual(!hotlist_get_fastdisable()), "cct_set_virtual", {}); } } break; case CLOSE_BUTTON: xv_set(so_frame, WIN_SHOW, FALSE, NULL); break; case COPY_SET_BUTTON: copy_set_proc(so_frame); break; default: assert(0); break; } } static void station_opt_activate(void) { int tdisable, fdisable; tdisable = (int)xv_get(so_tf_checkbox, PANEL_VALUE) & 1; fdisable = (int)xv_get(so_tf_checkbox, PANEL_VALUE) & 2; xv_set(so_il_slider, PANEL_INACTIVE, tdisable, NULL); xv_set(so_as_choice, PANEL_INACTIVE, tdisable && fdisable, NULL); } void station_opt_update(void) { char *title, page_str[4]; if (!so_frame) return; title = sstrdup("Options for station "); title = sstrapp(title, hotlist_get_name()); xv_set(so_frame, XV_LABEL, title, NULL); free(title); xv_set(so_to_slider, PANEL_VALUE, hotlist_get_timeout(), NULL); xv_set(so_il_slider, PANEL_VALUE, hotlist_get_interleave(), NULL); xv_set(so_tf_checkbox, PANEL_VALUE, hotlist_get_topdisable() | (hotlist_get_fastdisable() << 1), NULL); xv_set(so_as_choice, PANEL_VALUE, (int)hotlist_get_searchlevel(), NULL); station_opt_activate(); xv_set(so_la_num, PANEL_VALUE, hotlist_get_lookahead(), NULL); sprintf(page_str, "%X", hotlist_get_index_page()); xv_set(so_ip_num, PANEL_VALUE, page_str, NULL); } static Frame tun_frame; static Panel_item tun_chan_text, tun_chan_menubtn, tun_fr_text, tun_prog_num; static char const * const *tun_ch_names; static int tun_ch_count, tun_ch_num; void tuning_proc(void) { Panel tun_panel; if (!tun_frame) { tun_frame = (Frame)xv_create(frame, FRAME, NULL); tun_panel = (Panel)xv_create(tun_frame, PANEL, XV_HELP_DATA, "videotext:tuning_info", PANEL_ACCEPT_KEYSTROKE, TRUE, PANEL_LAYOUT, PANEL_HORIZONTAL, NULL); tun_chan_text = (Panel_item)xv_create(tun_panel, PANEL_TEXT, XV_X, 20, XV_Y, 15, PANEL_LABEL_STRING, "Channel:", PANEL_VALUE_DISPLAY_WIDTH, 70, PANEL_VALUE_STORED_LENGTH, 20, PANEL_NOTIFY_PROC, tun_chantxt_proc, NULL); tun_chan_menubtn = (Panel_item)xv_create(tun_panel, PANEL_ABBREV_MENU_BUTTON, NULL); xv_create(tun_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "-", PANEL_NOTIFY_PROC, tun_chanbtn_proc, PANEL_CLIENT_DATA, -1, NULL); xv_create(tun_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "+", PANEL_NOTIFY_PROC, tun_chanbtn_proc, PANEL_CLIENT_DATA, 1, NULL); tun_fr_text = (Panel_item)xv_create(tun_panel, PANEL_TEXT, XV_X, 45, XV_Y, 55, PANEL_LABEL_STRING, "Frequency (MHz):", PANEL_VALUE_DISPLAY_WIDTH, 70, PANEL_VALUE_STORED_LENGTH, 20, PANEL_NOTIFY_PROC, tun_freqtxt_proc, NULL); xv_create(tun_panel, PANEL_BUTTON, XV_X, 15, XV_Y, 80, PANEL_LABEL_STRING, "<", PANEL_NOTIFY_PROC, tun_freqbtn_proc, PANEL_CLIENT_DATA, 0, NULL); xv_create(tun_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "<<", PANEL_NOTIFY_PROC, tun_freqbtn_proc, PANEL_CLIENT_DATA, 1, NULL); xv_create(tun_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "<<<", PANEL_NOTIFY_PROC, tun_freqbtn_proc, PANEL_CLIENT_DATA, 2, NULL); xv_create(tun_panel, PANEL_BUTTON, PANEL_LABEL_STRING, ">>>", PANEL_NOTIFY_PROC, tun_freqbtn_proc, PANEL_CLIENT_DATA, 3, NULL); xv_create(tun_panel, PANEL_BUTTON, PANEL_LABEL_STRING, ">>", PANEL_NOTIFY_PROC, tun_freqbtn_proc, PANEL_CLIENT_DATA, 4, NULL); xv_create(tun_panel, PANEL_BUTTON, PANEL_LABEL_STRING, ">", PANEL_NOTIFY_PROC, tun_freqbtn_proc, PANEL_CLIENT_DATA, 5, NULL); tun_prog_num = (Panel_item)xv_create(tun_panel, PANEL_NUMERIC_TEXT, XV_X, 70, XV_Y, 120, PANEL_LABEL_STRING, "Program:", PANEL_MIN_VALUE, 0, PANEL_MAX_VALUE, INT_MAX, PANEL_VALUE_DISPLAY_WIDTH, 30, PANEL_VALUE_STORED_LENGTH, 20, PANEL_NOTIFY_PROC, tun_progtxt_proc, NULL); xv_create(tun_panel, PANEL_BUTTON, XV_X, 17, XV_Y, 155, PANEL_LABEL_STRING, "Apply", PANEL_NOTIFY_PROC, tun_cb_proc, PANEL_CLIENT_DATA, APPLY_BUTTON, NULL); xv_create(tun_panel, PANEL_BUTTON, XV_X, 77, XV_Y, 155, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, tun_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); xv_create(tun_panel, PANEL_BUTTON, XV_X, 152, XV_Y, 155, PANEL_LABEL_STRING, "Copy settings...", PANEL_NOTIFY_PROC, tun_cb_proc, PANEL_CLIENT_DATA, COPY_SET_BUTTON, NULL); window_fit(tun_panel); window_fit(tun_frame); set_frame_constraints(tun_frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(tun_frame, XV_SHOW)) center_frame(frame, tun_frame); tuning_update(TRUE); xv_set(tun_frame, XV_SHOW, TRUE, NULL); } static void tun_cb_proc(Panel_item item, const Event *event) { int freq, prog; const char *chan, *orig_chan, *fstr; char *tail; switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case APPLY_BUTTON: chan = (const char *)xv_get(tun_chan_text, PANEL_VALUE); if (tvch_chan2freq(config_get_tvsystem(), chan, NULL, &orig_chan) >= 0) { chan = orig_chan; xv_set(tun_chan_text, PANEL_VALUE, chan, NULL); } hotlist_set_channel(chan); fstr = (char *)xv_get(tun_fr_text, PANEL_VALUE); freq = (int)ceil(strtod(fstr, &tail) * 1000); if (*tail != '\0') { confirm_notice(tun_frame, TRUE, "Warning: Invalid frequency-syntax.\nCan't set new value."); freq = hotlist_get_freq(); } else { hotlist_set_freq(freq); } prog = (int)xv_get(tun_prog_num, PANEL_VALUE); hotlist_set_prog(prog); tune_new_station(chan, freq, prog); break; case CLOSE_BUTTON: xv_set(tun_frame, WIN_SHOW, FALSE, NULL); break; case COPY_SET_BUTTON: copy_set_proc(tun_frame); break; default: assert(0); break; } } static Panel_setting tun_chantxt_proc(Panel_item item, const Event *event) { const char *chan, *orig_chan; int entry; chan = (const char *)xv_get(tun_chan_text, PANEL_VALUE); if (tvch_chan2freq(config_get_tvsystem(), chan, NULL, &orig_chan) >= 0) { chan = orig_chan; xv_set(tun_chan_text, PANEL_VALUE, chan, NULL); for (entry = 0; entry < tun_ch_count; entry++) { if (!strcmp(chan, tun_ch_names[entry])) { tun_ch_num = entry; break; } } } tune_new_station(chan, 0, 0); return PANEL_NONE; } static void tun_chanmenu_proc(Menu menu, Menu_item menu_item) { tun_ch_num = (int)xv_get(menu_item, MENU_CLIENT_DATA); xv_set(tun_chan_text, PANEL_VALUE, tun_ch_names[tun_ch_num], NULL); tune_new_station(tun_ch_names[tun_ch_num], 0, 0); } static void tun_chanbtn_proc(Panel_item item, const Event *event) { tun_ch_num += (int)xv_get(item, PANEL_CLIENT_DATA); tun_ch_num = MAX(tun_ch_num, 0); tun_ch_num = MIN(tun_ch_num, tun_ch_count - 1); xv_set(tun_chan_text, PANEL_VALUE, tun_ch_names[tun_ch_num], NULL); tune_new_station(tun_ch_names[tun_ch_num], 0, 0); } static void tun_freqbtn_proc(Panel_item item, const Event *event) { const int incr[] = { -250, -1000, -5000, 5000, 1000, 250 }; int freq; char *fstr, *tail, freqstr[30]; fstr = (char *)xv_get(tun_fr_text, PANEL_VALUE); freq = (int)ceil(strtod(fstr, &tail) * 1000); if (*tail != '\0') { confirm_notice(tun_frame, TRUE, "Warning: Invalid frequency-syntax.\nCan't set new value."); } else { freq += incr[(int)xv_get(item, PANEL_CLIENT_DATA)]; if (freq < 0) { freq = 0; } sprintf(freqstr, "%.3f", (double)freq / 1000); xv_set(tun_fr_text, PANEL_VALUE, freqstr, NULL); tune_new_station(NULL, freq, 0); } } static Panel_setting tun_freqtxt_proc(Panel_item item, const Event *event) { int freq; char *fstr, *tail; fstr = (char *)xv_get(tun_fr_text, PANEL_VALUE); freq = (int)ceil(strtod(fstr, &tail) * 1000); if (*tail != '\0') { confirm_notice(tun_frame, TRUE, "Warning: Invalid frequency-syntax.\nCan't set new value."); } else { tune_new_station(NULL, freq, 0); } return PANEL_NONE; } static Panel_setting tun_progtxt_proc(Panel_item item, const Event *event) { tune_new_station(NULL, 0, xv_get(tun_prog_num, PANEL_VALUE)); return PANEL_NONE; } void tuning_update(int doinit) { char *title, freqstr[30]; static Menu menu; Frame pin_frame; int entry; if (!tun_frame) return; if (doinit) { title = sstrdup("Tuning info for station "); title = sstrapp(title, hotlist_get_name()); xv_set(tun_frame, XV_LABEL, title, NULL); free(title); sprintf(freqstr, "%.3f", (double)hotlist_get_freq() / 1000); xv_set(tun_chan_text, PANEL_VALUE, hotlist_get_channel(), NULL); xv_set(tun_fr_text, PANEL_VALUE, freqstr, NULL); xv_set(tun_prog_num, PANEL_VALUE, hotlist_get_prog(), NULL); } /* We have to remove the menu from the PANEL_BUTTON before destroying it, because XView is way * too clever to allow us to destroy a menu that is still attached to something... */ xv_set(tun_chan_menubtn, PANEL_ITEM_MENU, NULL, NULL); if (menu) { pin_frame = (Frame)xv_get(menu, MENU_PIN_WINDOW); assert(!xv_destroy(menu)); if (pin_frame) { assert(!xv_destroy(pin_frame)); } } menu = (Menu)xv_create(XVNULL, MENU, MENU_GEN_PIN_WINDOW, frame, "TV channels", MENU_NOTIFY_PROC, tun_chanmenu_proc, NULL); if ((tun_ch_count = tvch_get_channels(config_get_tvsystem(), &tun_ch_names)) >= 0) { for (entry = 0; entry < tun_ch_count; entry++) { xv_set(menu, MENU_APPEND_ITEM, (Menu_item)xv_create(XVNULL, MENUITEM, MENU_STRING, tun_ch_names[entry], MENU_CLIENT_DATA, entry, MENU_RELEASE, NULL), NULL); } xv_set(menu, MENU_NCOLS, (int)ceil(sqrt(20.0 / 60.0 * tun_ch_count)), NULL); } xv_set(tun_chan_menubtn, PANEL_ITEM_MENU, menu, NULL); } static Frame sp_frame; static Panel_item sp_dir_checkbox, sp_inc_text, sp_ex_text, sp_exp_days, sp_exp_hours; void spool_opt_proc(void) { Panel sp_panel; if (!sp_frame) { sp_frame = (Frame)xv_create(frame, FRAME, NULL); sp_panel = (Panel)xv_create(sp_frame, PANEL, XV_HELP_DATA, "videotext:spool_options", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); sp_dir_checkbox = (Panel_item)xv_create(sp_panel, PANEL_CHECK_BOX, XV_X, 15, XV_Y, 15, PANEL_LAYOUT, PANEL_VERTICAL, PANEL_CHOICE_STRINGS, "Read from private spooldir", "Write to private spooldir", NULL, NULL); sp_inc_text = (Panel_item)xv_create(sp_panel, PANEL_TEXT, PANEL_VALUE_X, 125, PANEL_VALUE_Y, 85, PANEL_LABEL_STRING, "Include pages:", PANEL_VALUE_DISPLAY_WIDTH, 350, PANEL_VALUE_STORED_LENGTH, HOTLIST_VALUE_MAXLEN, NULL); sp_ex_text = (Panel_item)xv_create(sp_panel, PANEL_TEXT, PANEL_VALUE_X, 125, PANEL_VALUE_Y, 120, PANEL_LABEL_STRING, "Exclude pages:", PANEL_VALUE_DISPLAY_WIDTH, 350, PANEL_VALUE_STORED_LENGTH, HOTLIST_VALUE_MAXLEN, NULL); xv_create(sp_panel, PANEL_MESSAGE, XV_X, 15, XV_Y, 160, PANEL_LABEL_STRING, "Pages expire after", NULL); sp_exp_days = (Panel_item)xv_create(sp_panel, PANEL_NUMERIC_TEXT, PANEL_VALUE_DISPLAY_WIDTH, 25, PANEL_VALUE_STORED_LENGTH, 2, PANEL_MIN_VALUE, 0, PANEL_MAX_VALUE, 99, NULL); xv_create(sp_panel, PANEL_MESSAGE, PANEL_LABEL_STRING, "days,", NULL); sp_exp_hours = (Panel_item)xv_create(sp_panel, PANEL_NUMERIC_TEXT, PANEL_VALUE_DISPLAY_WIDTH, 25, PANEL_VALUE_STORED_LENGTH, 2, PANEL_MIN_VALUE, 0, PANEL_MAX_VALUE, 23, NULL); xv_create(sp_panel, PANEL_MESSAGE, PANEL_LABEL_STRING, "hours", NULL); xv_create(sp_panel, PANEL_BUTTON, XV_X, 180, XV_Y, 200, PANEL_LABEL_STRING, "Apply", PANEL_NOTIFY_PROC, sp_cb_proc, PANEL_CLIENT_DATA, APPLY_BUTTON, NULL); xv_create(sp_panel, PANEL_BUTTON, XV_X, 240, XV_Y, 200, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, sp_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); xv_create(sp_panel, PANEL_BUTTON, XV_X, 350, XV_Y, 200, PANEL_LABEL_STRING, "Copy settings...", PANEL_NOTIFY_PROC, sp_cb_proc, PANEL_CLIENT_DATA, COPY_SET_BUTTON, NULL); window_fit(sp_panel); window_fit(sp_frame); set_frame_constraints(sp_frame, 0, 0, 0, 0, 0); } if (!(int)xv_get(sp_frame, XV_SHOW)) center_frame(frame, sp_frame); spool_opt_update(); xv_set(sp_frame, XV_SHOW, TRUE, NULL); } static void sp_cb_proc(Panel_item item, const Event *event) { switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case APPLY_BUTTON: hotlist_set_spoolflag(TRUE, !!((int)xv_get(sp_dir_checkbox, PANEL_VALUE) & 1)); hotlist_set_spoolflag(FALSE, !!((int)xv_get(sp_dir_checkbox, PANEL_VALUE) & 2)); if (!hotlist_set_includelist((char *)xv_get(sp_inc_text, PANEL_VALUE))) { confirm_notice(sp_frame, TRUE, "Parse-error in line \"Include pages\":\nCan't set new value."); } if (!hotlist_set_excludelist((char *)xv_get(sp_ex_text, PANEL_VALUE))) { confirm_notice(sp_frame, TRUE, "Parse-error in line \"Exclude pages\":\nCan't set new value.\n\n"); } hotlist_set_expire((int)xv_get(sp_exp_days, PANEL_VALUE) * 24 + (int)xv_get(sp_exp_hours, PANEL_VALUE)); break; case CLOSE_BUTTON: xv_set(sp_frame, WIN_SHOW, FALSE, NULL); break; case COPY_SET_BUTTON: copy_set_proc(sp_frame); break; default: assert(0); break; } } void spool_opt_update(void) { char *title; if (!sp_frame) return; title = sstrdup("Spool options for station "); title = sstrapp(title, hotlist_get_name()); xv_set(sp_frame, XV_LABEL, title, NULL); free(title); xv_set(sp_dir_checkbox, PANEL_VALUE, !!hotlist_get_spoolflag(TRUE, TRUE) | !!hotlist_get_spoolflag(TRUE, FALSE) << 1, NULL); xv_set(sp_inc_text, PANEL_VALUE, hotlist_get_includelist(), NULL); xv_set(sp_ex_text, PANEL_VALUE, hotlist_get_excludelist(), NULL); xv_set(sp_exp_days, PANEL_VALUE, hotlist_get_expire() / 24, NULL); xv_set(sp_exp_hours, PANEL_VALUE, hotlist_get_expire() % 24, NULL); } static Frame cs_frame; static Panel_item cs_checkbox1, cs_checkbox2, cs_list; void copy_set_menu_proc(void) { copy_set_proc(frame); } static void copy_set_proc(Frame parent_frame) { Panel cs_panel; if (!cs_frame) { cs_frame = (Frame)xv_create(frame, FRAME, XV_LABEL, "Copy settings", NULL); cs_panel = (Panel)xv_create(cs_frame, PANEL, XV_HELP_DATA, "videotext:copy_settings", PANEL_ACCEPT_KEYSTROKE, TRUE, NULL); xv_create(cs_panel, PANEL_MESSAGE, XV_X, 15, XV_Y, 15, PANEL_LABEL_STRING, "Copy these settings...", PANEL_LABEL_BOLD, TRUE, NULL); cs_checkbox1 = (Panel_item)xv_create(cs_panel, PANEL_CHECK_BOX, XV_X, 15, XV_Y, 45, PANEL_LAYOUT, PANEL_VERTICAL, PANEL_CHOICE_STRINGS, "Hotlist", "Page-Timeout", "TOP-Text interleave", "TOP-Text disabled", "FASTEXT disabled", "Auto-search pages", "Page-lookahead", "Index page", NULL, NULL); cs_checkbox2 = (Panel_item)xv_create(cs_panel, PANEL_CHECK_BOX, XV_X, 210, XV_Y, 45, PANEL_LAYOUT, PANEL_VERTICAL, PANEL_CHOICE_STRINGS, "Read spooldir", "Write spooldir", "Exclude-/Include-list", "Spool-expiration", "Channel", "Frequency", "Program", "Search requests", NULL, NULL); xv_create(cs_panel, PANEL_BUTTON, XV_X, 95, XV_Y, 280, PANEL_LABEL_STRING, "Select all", PANEL_NOTIFY_PROC, cs_cb_proc, PANEL_CLIENT_DATA, SELALL_BUTTON, NULL); xv_create(cs_panel, PANEL_BUTTON, XV_X, 185, XV_Y, 280, PANEL_LABEL_STRING, "Clear all", PANEL_NOTIFY_PROC, cs_cb_proc, PANEL_CLIENT_DATA, CLRALL_BUTTON, NULL); xv_create(cs_panel, PANEL_MESSAGE, XV_X, 390, XV_Y, 15, PANEL_LABEL_STRING, "...to these station(s)", PANEL_LABEL_BOLD, TRUE, NULL); cs_list = (Panel_item)xv_create(cs_panel, PANEL_LIST, XV_X, 390, XV_Y, 45, PANEL_LIST_WIDTH, 215, PANEL_LIST_DISPLAY_ROWS, 11, PANEL_READ_ONLY, TRUE, PANEL_CHOOSE_ONE, FALSE, NULL); xv_set((Menu)xv_get(cs_list, PANEL_ITEM_MENU), MENU_ACTION_ITEM, "Choose All", cs_chooseall, NULL); xv_create(cs_panel, PANEL_BUTTON, XV_X, 260, XV_Y, 320, PANEL_LABEL_STRING, "Copy", PANEL_NOTIFY_PROC, cs_cb_proc, PANEL_CLIENT_DATA, COPY_BUTTON, NULL); xv_create(cs_panel, PANEL_BUTTON, XV_X, 320, XV_Y, 320, PANEL_LABEL_STRING, "Close", PANEL_NOTIFY_PROC, cs_cb_proc, PANEL_CLIENT_DATA, CLOSE_BUTTON, NULL); window_fit(cs_panel); window_fit(cs_frame); set_frame_constraints(cs_frame, 0, 0, 0, 0, 0); } copy_set_update(); if (!(int)xv_get(cs_frame, XV_SHOW)) center_frame(parent_frame, cs_frame); xv_set(cs_frame, XV_SHOW, TRUE, NULL); } static void cs_cb_proc(Panel_item item, const Event *event) { int sel, entry; switch ((int)xv_get(item, PANEL_CLIENT_DATA)) { case SELALL_BUTTON: xv_set(cs_checkbox1, PANEL_VALUE, ~0, NULL); xv_set(cs_checkbox2, PANEL_VALUE, ~0, NULL); break; case CLRALL_BUTTON: xv_set(cs_checkbox1, PANEL_VALUE, 0, NULL); xv_set(cs_checkbox2, PANEL_VALUE, 0, NULL); break; case COPY_BUTTON: sel = (int)xv_get(cs_checkbox1, PANEL_VALUE) + HL_READSPOOL * (int)xv_get(cs_checkbox2, PANEL_VALUE); entry = 0; if ((int)xv_get(cs_list, PANEL_LIST_SELECTED, entry)) { hotlist_copy(entry, sel); } while ((entry = (int)xv_get(cs_list, PANEL_LIST_NEXT_SELECTED, entry)) >= 0) { hotlist_copy(entry, sel); } break; case CLOSE_BUTTON: xv_set(cs_frame, WIN_SHOW, FALSE, NULL); break; default: assert(0); break; } } static void cs_chooseall(Menu menu, Menu_item menu_item) { int entry; xv_set(cs_list, XV_SHOW, FALSE, NULL); for (entry = hotlist_get_stcount() - 1; entry >= 0; entry--) { xv_set(cs_list, PANEL_LIST_SELECT, entry, TRUE, NULL); } xv_set(cs_list, XV_SHOW, TRUE, NULL); } static void copy_set_update(void) { static char **station_list = NULL; static int station_count = 0; int entry; if (!cs_frame) return; if (station_list) { xv_set(cs_list, PANEL_LIST_DELETE_ROWS, 0, station_count, NULL); free(station_list); } station_count = hotlist_get_stcount(); station_list = smalloc((station_count + 1) * sizeof(char*)); station_list[station_count] = NULL; for (entry = 0; entry < station_count; entry++) { station_list[entry] = hotlist_get_name_n(entry); } xv_set(cs_list, PANEL_LIST_INSERT_STRINGS, 0, station_list, NULL); } /***************************************************************************** * File_choosers & file-I/O */ static File_chooser load_fc, save_fc, export_fc; static Panel_item export_ftype_item; static const char* check_pipe(const char *path) { const char *path_loop, *fname; for (path_loop = fname = path; *path_loop; path_loop++) { if (*path_loop == '/') { fname = path_loop + 1; } else if (*path_loop == ' ') { break; } } if (*fname == '|') { return fname + 1; } return NULL; } static FILE* fpopen(const char *path, int do_write, int can_append, Frame frame) { FILE *file; const char *fname; int do_overwrite; /* Read/write from/to pipe */ if ((fname = check_pipe(path))) { if (!((file = xv_popen(fname, (do_write ? "w" : "r"))))) { confirm_notice_v(frame, TRUE, "Can't exec ", fname, ":\n", strerror(errno), (char *)0); return NULL; } } else { if (do_write) { /* Write plain file */ if ((do_overwrite = chk_conf_overwrite(path, can_append, FALSE)) < 0) return NULL; if (!((file = fopen(path, do_overwrite == 1 ? "a" : "w")))) { confirm_notice_v(frame, TRUE, "Can't open ", path, " for writing:\n", strerror(errno), (char *)0); return NULL; } } else { /* Read plain file */ if (!((file = fopen(path, "r")))) { confirm_notice_v(frame, TRUE, "Can't open ", path, " for reading:\n", strerror(errno), (char *)0); return NULL; } } } return file; } static int fpclose(const char *path, FILE *file, int do_write, Frame frame) { const char *fname; if ((fname = check_pipe(path))) { if (ferror(file)) { if (frame) { if (do_write) { confirm_notice_v(frame, TRUE, "Error while writing to ", fname, ":\n", strerror(errno), (char *)0); } else { confirm_notice_v(frame, TRUE, "Error while reading from ", fname, ":\n", strerror(errno), (char *)0); } } xv_pclose(frame, file); return -1; } else if (xv_pclose(frame, file)) { if (frame) { confirm_notice_v(frame, TRUE, "Warning: ", fname, " returned\nnon-zero exit-status.", (char *)0); } return -1; } } else { if (ferror(file) || fclose(file) < 0) { if (frame) { if (do_write) { confirm_notice_v(frame, TRUE, "Error while writing ", path, ":\n", strerror(errno), (char *)0); } else { confirm_notice_v(frame, TRUE, "Error while reading ", path, ":\n", strerror(errno), (char *)0); } } fclose(file); return -1; } } return 0; } static void create_filename(char *fname, int page, int subpage, const char *suffix) { int pos; if (!intv_fname) { strcpy(fname, hotlist_get_name()); for (pos = strlen(fname); pos >= 0; pos--) { if (fname[pos] == '/') { fname[pos] = '_'; } } if (subpage < 0) { sprintf(fname + strlen(fname), ":%X_%%d.%s", page, suffix); } else { sprintf(fname + strlen(fname), ":%X_%02X.%s", page, subpage, suffix); } } else { sprintf(fname, "%X.%s", page, suffix); } } static char * replace_path_tmpl(const char *tmpl, int num) { const char *last = NULL, *next; char *retstr; /* Find rightmost %d in tmpl */ for (next = tmpl; (next = strstr(next, "%d")); last = next++); if (!last) { return NULL; } retstr = smalloc(strlen(tmpl) - 2 + 16 + 1); /* Max. 16 digits for number */ memcpy(retstr, tmpl, last - tmpl); sprintf(retstr + (last - tmpl), "%02X%s", num, last + 2); return srealloc(retstr, strlen(retstr) + 1); } static int check_font_bitmap(Frame frame) { if (vtxfonts[vtxwin.font].bmfont) return 0; if (!(vtxfonts[vtxwin.font].bmfont = read_font(vtxfonts[vtxwin.font].width, vtxfonts[vtxwin.font].height))) { confirm_notice(frame, TRUE, "Installation problem: Can't load\nfont-bitmap; no exporting possible.\n" "Please check your fonts in " VTX_LIBDIR ",\nuse -P or set $VTX_FONTPATH."); return -1; } return 0; } static int common_file_proc(Frame fc, const char *path) { FILE *file = NULL; int next, allsub, pagecount = 0; char *newpath = NULL, msgstr[256]; byte_t tmpbuf[VTX_PAGESIZE]; vtxpage_t tmppage; if (fc == load_fc) { const char *prefix, *fname; int status; xv_set(fc, FRAME_LEFT_FOOTER, "Loading...", NULL); /* The fpopen is currently useless, because it's impossible to type in a file to load. * Thus you're unable to tell VideoteXt which pipe to read from. */ if (!(file = fpopen(path, FALSE, FALSE, fc))) return XV_ERROR; if ((fname = check_pipe(path))) { prefix = "from "; } else { prefix = ""; fname = path; } switch ((status = load_vtx(file, vtx_buffer, &vtxwin.page->info, NULL))) { case LOADERR: confirm_notice_v(fc, TRUE, "Error while reading ", prefix, fname, ":\n", strerror(errno), (char *)0); break; case LOADEMAGIC: confirm_notice_v(fc, TRUE, "Error while reading ", prefix, fname, ":\n" "Magic number missing. This is no VideoteXt- or INtv-file.", (char *)0); break; case LOADEVERSION: confirm_notice_v(fc, TRUE, "Error while reading ", prefix, fname, ":\n" "Incompatible file format, possibly written by old version.", (char *)0); break; case LOADECORRUPT: confirm_notice_v(fc, TRUE, "Error while reading ", prefix, fname, ":\n" "File is corrupt.", (char *)0); break; } if (status >= 0) { selection_hide(&vtxwin); decode_page(vtx_buffer, vtxwin.page, 0, 23); xv_set(checkbox, PANEL_VALUE, (int)xv_get(checkbox, PANEL_VALUE) | 1, NULL); vtxwin.stopped = TRUE; vtxwin.update = SCR_UPDATE; update_pagenumdisp(vtxwin.page->info.pagenum, vtxwin.page->info.minute, 1, 1); } if (fpclose(path, file, FALSE, (status >= 0) ? fc : XVNULL) < 0) return XV_ERROR; xv_set(fc, FRAME_LEFT_FOOTER, "", NULL); } else if (fc == save_fc) { xv_set(fc, FRAME_LEFT_FOOTER, "Saving...", NULL); allsub = (int)xv_get(save_subpg_checkmark, PANEL_VALUE); if (cache_count_subpg(vtxwin.page->info.pagenum) <= 1 || !allsub || !cache_query(vtxwin.page->info.pagenum, -1, 0, tmpbuf, &tmppage.info)) { allsub = FALSE; memcpy(tmpbuf, vtx_buffer, sizeof(tmpbuf)); memcpy(&tmppage.info, &vtxwin.page->info, sizeof(tmppage.info)); } while (1) { if (!(newpath = replace_path_tmpl(path, tmppage.info.minute))) { if (!allsub) { newpath = sstrdup(path); } else { confirm_notice(fc, TRUE, "Error: Invalid filename-template.\n" "Make sure to insert %d somewhere in the\n" "filename when saving multiple subpages."); return XV_ERROR; } } if (!(file = fpopen(newpath, TRUE, FALSE, fc))) { free(newpath); return XV_ERROR; } save_vtx(file, tmpbuf, &tmppage.info, FALSE); pagecount++; if (fpclose(newpath, file, TRUE, fc) < 0) { free(newpath); return XV_ERROR; } free(newpath); if (!allsub || (next = cache_next_subpage(tmppage.info.pagenum, tmppage.info.minute + 1)) < 0) break; assert(cache_query(tmppage.info.pagenum, next, 0, tmpbuf, &tmppage.info)); } sprintf(msgstr, "%d page%s saved successfully.", pagecount, (pagecount > 1 ? "s" : "")); if (config_get_sticky_fcs()) { xv_set(fc, FRAME_LEFT_FOOTER, msgstr, NULL); } else { confirm_notice(fc, FALSE, msgstr); } } else if (fc == export_fc) { ftype_t ftype; xv_set(fc, FRAME_LEFT_FOOTER, "Exporting...", NULL); allsub = (int)xv_get(export_subpg_checkmark, PANEL_VALUE); switch (ftype = (int)xv_get(export_ftype_item, PANEL_VALUE)) { case FTYPE_ASCII: { int singlefile = FALSE; if (cache_count_subpg(vtxwin.page->info.pagenum) <= 1 || !allsub || !cache_query(vtxwin.page->info.pagenum, -1, 0, tmpbuf, &tmppage.info)) { allsub = FALSE; memcpy(tmpbuf, vtx_buffer, sizeof(tmpbuf)); memcpy(&tmppage.info, &vtxwin.page->info, sizeof(tmppage.info)); } file = NULL; while (1) { if (!singlefile && !(newpath = replace_path_tmpl(path, tmppage.info.minute))) { newpath = sstrdup(path); singlefile = TRUE; } if (!file && !(file = fpopen(newpath, TRUE, TRUE, fc))) { free(newpath); return XV_ERROR; } decode_page(tmpbuf, &tmppage, 0, 23); export_ascii(file, &tmppage, !vtxwin.hidden); pagecount++; if (!singlefile) { if (fpclose(newpath, file, TRUE, fc) < 0) { free(newpath); return XV_ERROR; } file = NULL; free(newpath); } if (!allsub || (next = cache_next_subpage(tmppage.info.pagenum, tmppage.info.minute + 1)) < 0) break; assert(cache_query(tmppage.info.pagenum, next, 0, tmpbuf, &tmppage.info)); if (singlefile) fputs("\n", file); } if (singlefile) { if (fpclose(newpath, file, TRUE, fc) < 0) { free(newpath); return XV_ERROR; } free(newpath); } } break; #ifdef GIF_SUPPORT case FTYPE_GIF: case FTYPE_GIFINT: #endif case FTYPE_PPM: #ifdef PNG_SUPPORT case FTYPE_PNG: case FTYPE_PNGINT: #endif { int err_found = FALSE; if (check_font_bitmap(fc)) return XV_ERROR; if (cache_count_subpg(vtxwin.page->info.pagenum) <= 1 || !allsub || !cache_query(vtxwin.page->info.pagenum, -1, 0, tmpbuf, &tmppage.info)) { allsub = FALSE; memcpy(tmpbuf, vtx_buffer, sizeof(tmpbuf)); memcpy(&tmppage.info, &vtxwin.page->info, sizeof(tmppage.info)); } while (1) { if (!(newpath = replace_path_tmpl(path, tmppage.info.minute))) { if (!allsub) { newpath = sstrdup(path); } else { confirm_notice(fc, TRUE, "Error: Invalid filename-template.\n" "Make sure to insert %d somewhere in the\n" "filename when exporting multiple subpages."); return XV_ERROR; } } if (!(file = fpopen(newpath, TRUE, FALSE, fc))) { free(newpath); return XV_ERROR; } decode_page(tmpbuf, &tmppage, 0, 23); if (ftype == FTYPE_PPM) { export_ppm(file, &tmppage, vtxfonts[vtxwin.font].bmfont, !vtxwin.hidden); #ifdef PNG_SUPPORT } else if (ftype == FTYPE_PNG || ftype == FTYPE_PNGINT) { char **msg, *notice; const char *fname; err_found = !!export_png(file, &tmppage, vtxfonts[vtxwin.font].bmfont, (ftype == FTYPE_PNGINT), !vtxwin.hidden, &msg); if (msg) { if (err_found) { notice = sstrdup("Error(s)"); } else { notice = sstrdup("Warning(s)"); } notice = sstrapp(notice, " while writing "); if ((fname = check_pipe(path))) { notice = sstrapp(notice, "to "); notice = sstrapp(notice, fname); } else { notice = sstrapp(notice, path); } notice = sstrapp(notice, ":\n"); for (; *msg; msg++) { notice = sstrapp(notice, *msg); notice = sstrapp(notice, "\n"); } confirm_notice(fc, TRUE, notice); free(notice); } #endif #ifdef GIF_SUPPORT } else if (ftype == FTYPE_GIF || ftype == FTYPE_GIFINT) { export_gif(file, &tmppage, vtxfonts[vtxwin.font].bmfont, (ftype == FTYPE_GIFINT), !vtxwin.hidden); #endif } else { assert(0); } pagecount++; if (fpclose(newpath, file, TRUE, !err_found ? frame : XVNULL) < 0 || err_found) { free(newpath); return XV_ERROR; } free(newpath); if (!allsub || (next = cache_next_subpage(tmppage.info.pagenum, tmppage.info.minute + 1)) < 0) break; assert(cache_query(tmppage.info.pagenum, next, 0, tmpbuf, &tmppage.info)); } } break; case FTYPE_CPS: case FTYPE_PS: case FTYPE_IPS: { int do_overwrite, layout, subpgcount, pgnum = 0, singlefile = FALSE; char *tmppath = NULL; FILE *tmpfile = NULL; if ((subpgcount = cache_count_subpg(vtxwin.page->info.pagenum)) <= 1 || !allsub || !cache_query(vtxwin.page->info.pagenum, -1, 0, tmpbuf, &tmppage.info)) { allsub = FALSE; subpgcount = 1; memcpy(tmpbuf, vtx_buffer, sizeof(tmpbuf)); memcpy(&tmppage.info, &vtxwin.page->info, sizeof(tmppage.info)); } file = NULL; while (1) { if (!singlefile && !(newpath = replace_path_tmpl(path, tmppage.info.minute))) { newpath = sstrdup(path); singlefile = TRUE; } if (!file) { if (!check_pipe(newpath)) { if ((do_overwrite = chk_conf_overwrite(newpath, FALSE, TRUE)) < 0) { free(newpath); return XV_ERROR; } if (do_overwrite) { tmppath = sstrdup(newpath); tmppath = sstrapp(tmppath, "_vtx_tmp"); if (rename(newpath, tmppath) < 0) { confirm_notice_v(fc, TRUE, "Can't rename ", newpath, "\nto ", tmppath, ":\n", strerror(errno), (char *)0); free(tmppath); free(newpath); return XV_ERROR; } if (!(tmpfile = fopen(tmppath, "r"))) { confirm_notice_v(fc, TRUE, "Can't open ", newpath, "\nfor reading: ", strerror(errno), (char *)0); rename(tmppath, newpath); /* Ignore failure when restoring old state */ free(tmppath); free(newpath); return XV_ERROR; } /* Count pages in old file */ for (pgnum = 0; ; pgnum++) { if (ps_seek_page(tmpfile, pgnum + 1) < 0 && errno == ENOENT) { break; } } rewind(tmpfile); } else { if (unlink(newpath) < 0 && errno != ENOENT) { confirm_notice_v(fc, TRUE, "Can't overwrite ", newpath, ":\n", strerror(errno), (char *)0); free(newpath); return XV_ERROR; } } } if (!(file = fpopen(newpath, TRUE, FALSE, fc))) { free(newpath); return XV_ERROR; } layout = config_get_layout(); /* Only create EPSF, if we will write at most one page */ ps_write_header(file, newpath, (subpgcount + pgnum <= pglayout_data[layout].xpages * pglayout_data[layout].ypages), pglayout_data[layout].xpages, pglayout_data[layout].ypages, config_get_papersize(), pglayout_data[layout].landscape); /* Copy pages from old file */ if (tmpfile) { int pgnum; unsigned char *srcpage; for (pgnum = 1; ; pgnum++) { if (ps_read_page(tmpfile, pgnum, &srcpage) < 0) { if (errno == ENOENT) { break; } else if (errno == EFBIG) { confirm_notice_v(fc, TRUE, "File ", newpath, "\ncontains invalid pages. Can't merge.\n", (char *)0); fclose(tmpfile); fpclose(newpath, file, FALSE, XVNULL); rename(tmppath, newpath); /* Ignore failure when restoring old state */ free(tmppath); free(newpath); return XV_ERROR; } else { confirm_notice_v(fc, TRUE, "Can't read from ", newpath, ":\n", strerror(errno), (char *)0); fclose(tmpfile); fpclose(newpath, file, FALSE, XVNULL); rename(tmppath, newpath); /* Ignore failure when restoring old state */ free(tmppath); free(newpath); return XV_ERROR; } } ps_copy_page(srcpage); free(srcpage); } if (pgnum == 1) { confirm_notice_v(fc, TRUE, "Can't find any pages in ", newpath, "\nFile was probably written by an incompatible version.", (char *)0); fclose(tmpfile); fpclose(newpath, file, FALSE, XVNULL); rename(tmppath, newpath); /* Ignore failure when restoring old state */ free(tmppath); free(newpath); return XV_ERROR; } fclose(tmpfile); unlink(tmppath); free(tmppath); } } decode_page(tmpbuf, &tmppage, 0, 23); ps_write_page(&tmppage, hotlist_get_name(), !vtxwin.hidden, (ftype == FTYPE_CPS), (ftype == FTYPE_IPS)); pagecount++; if (!singlefile) { ps_write_trailer(); if (fpclose(newpath, file, TRUE, frame) < 0) { free(newpath); return XV_ERROR; } file = NULL; free(newpath); } if (!allsub || (next = cache_next_subpage(tmppage.info.pagenum, tmppage.info.minute + 1)) < 0) break; assert(cache_query(tmppage.info.pagenum, next, 0, tmpbuf, &tmppage.info)); } if (singlefile) { ps_write_trailer(); if (fpclose(newpath, file, TRUE, frame) < 0) { free(newpath); return XV_ERROR; } free(newpath); } } break; default: assert(0); break; } sprintf(msgstr, "%d page%s exported successfully.", pagecount, (pagecount > 1 ? "s" : "")); if (config_get_sticky_fcs()) { xv_set(fc, FRAME_LEFT_FOOTER, msgstr, NULL); } else { confirm_notice(fc, FALSE, msgstr); } } else { assert(0); } return XV_OK; } void load_proc(void) { if (!load_fc) { load_fc = (File_chooser)xv_create(frame, FILE_CHOOSER_OPEN_DIALOG, FRAME_LABEL, "Load VTX File", FILE_CHOOSER_NOTIFY_FUNC, common_file_proc, FILE_CHOOSER_NO_CONFIRM, TRUE, FRAME_LEFT_FOOTER, "", NULL); } if (!(int)xv_get(load_fc, XV_SHOW)) center_frame(frame, load_fc); xv_set(load_fc, FILE_CHOOSER_UPDATE, FRAME_CMD_PIN_STATE, (config_get_sticky_fcs() ? FRAME_CMD_PIN_IN : FRAME_CMD_PIN_OUT), XV_SHOW, TRUE, NULL); } static char *save_fc_orgname; static int save_ext_func(File_chooser fc, const Rect *frame_rect, const Rect *exten_rect, int left_edge, int right_edge, int max_height) { xv_set(save_subpg_checkmark, XV_Y, exten_rect->r_top - 20, NULL); return -1; } void save_proc(void) { Panel fc_panel; if (!save_fc) { save_fc = (File_chooser)xv_create(frame, FILE_CHOOSER_SAVEAS_DIALOG, FRAME_LABEL, "Save VTX File", FILE_CHOOSER_NOTIFY_FUNC, common_file_proc, FILE_CHOOSER_NO_CONFIRM, TRUE, FILE_CHOOSER_EXTEN_HEIGHT, -10, FILE_CHOOSER_EXTEN_FUNC, save_ext_func, FRAME_LEFT_FOOTER, "", NULL); fc_panel = (Panel)xv_get(save_fc, FRAME_CMD_PANEL); save_subpg_checkmark = (Panel_item)xv_create(fc_panel, PANEL_CHECK_BOX, XV_X, 15, PANEL_CHOICE_STRINGS, "Save all received subpages", NULL, PANEL_NOTIFY_PROC, fcs_update_name, NULL); } if (!(int)xv_get(save_fc, XV_SHOW)) center_frame(frame, save_fc); xv_set(save_fc, FILE_CHOOSER_UPDATE, FRAME_CMD_PIN_STATE, (config_get_sticky_fcs() ? FRAME_CMD_PIN_IN : FRAME_CMD_PIN_OUT), XV_SHOW, TRUE, NULL); if (save_fc_orgname) { free(save_fc_orgname); save_fc_orgname = NULL; } fcs_update_name(); } static Panel_item export_prn_button, export_psopt_button; static char *export_fc_orgname; static char * change_ext(const char *oldname, const char *newext) { int len, extlen, fmt; char *newname; len = strlen(oldname); for (fmt = 0; fmt < sizeof(ftype_ext) / sizeof(ftype_ext[0]); fmt++) { extlen = strlen(ftype_ext[fmt]); if (len > extlen && oldname[len - extlen - 1] == '.' && !strcmp(ftype_ext[fmt], oldname + len - extlen)) { newname = sstrdup(oldname); newname[len - extlen] = '\0'; return sstrapp(newname, newext); } } return NULL; } static void export_ftype_proc(Panel_item item, int value, const Event *event) { char *newname; if ((newname = change_ext((char *)xv_get(export_fc, FILE_CHOOSER_DOC_NAME), ftype_ext[value]))) { xv_set(export_fc, FILE_CHOOSER_DOC_NAME, newname, NULL); free(newname); } if ((newname = change_ext(export_fc_orgname, ftype_ext[value]))) { free(export_fc_orgname); export_fc_orgname = newname; } xv_set(export_psopt_button, PANEL_INACTIVE, (value != FTYPE_CPS && value != FTYPE_PS && value != FTYPE_IPS), NULL); } static void export_defprint_proc(Panel_item item, const Event *event) { const char *prn_name; switch ((int)xv_get(export_ftype_item, PANEL_VALUE)) { case FTYPE_ASCII: prn_name = config_get_printer(PRN_ASCII); break; #ifdef GIF_SUPPORT case FTYPE_GIF: case FTYPE_GIFINT: #endif case FTYPE_PPM: #ifdef PNG_SUPPORT case FTYPE_PNG: case FTYPE_PNGINT: #endif prn_name = config_get_printer(PRN_BM); break; case FTYPE_CPS: prn_name = config_get_printer(PRN_CPS); break; case FTYPE_PS: case FTYPE_IPS: prn_name = config_get_printer(PRN_PS); break; default: assert(0); break; } xv_set(export_fc, FILE_CHOOSER_DOC_NAME, prn_name, NULL); } static int export_ext_func(File_chooser fc, const Rect *frame_rect, const Rect *exten_rect, int left_edge, int right_edge, int max_height) { int prn_width, psopt_width, button_width; prn_width = (int)xv_get(export_prn_button, XV_WIDTH); psopt_width = (int)xv_get(export_psopt_button, XV_WIDTH); button_width = prn_width + BUTTON_DISTANCE + psopt_width; xv_set(export_subpg_checkmark, XV_Y, exten_rect->r_top - 20, NULL); xv_set(export_ftype_item, XV_Y, exten_rect->r_top + 10, NULL); xv_set(export_prn_button, XV_X, (frame_rect->r_width - button_width) / 2, XV_Y, exten_rect->r_top + 45, NULL); xv_set(export_psopt_button, XV_X, (frame_rect->r_width - button_width) / 2 + prn_width + BUTTON_DISTANCE, XV_Y, exten_rect->r_top + 45, NULL); return -1; } void export_proc(void) { Panel fc_panel; ftype_t ftype; if (!export_fc) { export_fc = (File_chooser)xv_create(frame, FILE_CHOOSER_SAVEAS_DIALOG, FRAME_LABEL, "Export File", FILE_CHOOSER_NOTIFY_FUNC, common_file_proc, FILE_CHOOSER_NO_CONFIRM, TRUE, FILE_CHOOSER_EXTEN_HEIGHT, 30, FILE_CHOOSER_EXTEN_FUNC, export_ext_func, FRAME_LEFT_FOOTER, "", NULL); fc_panel = (Panel)xv_get(export_fc, FRAME_CMD_PANEL); export_subpg_checkmark = (Panel_item)xv_create(fc_panel, PANEL_CHECK_BOX, XV_X, 15, PANEL_CHOICE_STRINGS, "Export all received subpages", NULL, PANEL_NOTIFY_PROC, fcs_update_name, NULL); export_ftype_item = (Panel_item)xv_create(fc_panel, PANEL_CHOICE_STACK, XV_X, 15, PANEL_LABEL_STRING, "Export format", PANEL_CHOICE_NCOLS, 2, PANEL_CHOICE_NROWS, (FTYPE_COUNT + 1) / 2, PANEL_LAYOUT, PANEL_HORIZONTAL, PANEL_NOTIFY_PROC, export_ftype_proc, PANEL_VALUE, FTYPE_ASCII, NULL); for (ftype = 0; ftype < FTYPE_COUNT; ftype++) { xv_set(export_ftype_item, PANEL_CHOICE_STRING, ftype, ftype_strings[ftype], NULL); } export_prn_button = (Panel_item)xv_create(fc_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "Use default printer", PANEL_NOTIFY_PROC, export_defprint_proc, NULL); export_psopt_button = (Panel_item)xv_create(fc_panel, PANEL_BUTTON, PANEL_LABEL_STRING, "PostScript options...", PANEL_NOTIFY_PROC, psopt_proc, PANEL_INACTIVE, TRUE, NULL); } if (!(int)xv_get(export_fc, XV_SHOW)) center_frame(frame, export_fc); xv_set(export_fc, FILE_CHOOSER_UPDATE, FRAME_CMD_PIN_STATE, (config_get_sticky_fcs() ? FRAME_CMD_PIN_IN : FRAME_CMD_PIN_OUT), XV_SHOW, TRUE, NULL); if (export_fc_orgname) { free(export_fc_orgname); export_fc_orgname = NULL; } fcs_update_name(); } void fcs_update_name(void) { char fname[36]; /* 24 chars for name, 3 for page, 2 for subpage, */ /* 2 for delimiters, 4 for extension, 1 for '\0' */ if (save_fc && (int)xv_get(save_fc, XV_SHOW) && (!save_fc_orgname || !strcmp((char *)xv_get(save_fc, FILE_CHOOSER_DOC_NAME), save_fc_orgname))) { if (save_fc_orgname) { free(save_fc_orgname); } create_filename(fname, vtxwin.page->info.pagenum, ((int)xv_get(save_subpg_checkmark, PANEL_VALUE) ? -1 : vtxwin.page->info.minute), "vtx"); save_fc_orgname = sstrdup(fname); xv_set(save_fc, FILE_CHOOSER_DOC_NAME, fname, NULL); } if (export_fc && (int)xv_get(export_fc, XV_SHOW) && (!export_fc_orgname || !strcmp((char *)xv_get(export_fc, FILE_CHOOSER_DOC_NAME), export_fc_orgname))) { if (export_fc_orgname) { free(export_fc_orgname); } create_filename(fname, vtxwin.page->info.pagenum, ((int)xv_get(export_subpg_checkmark, PANEL_VALUE) ? -1 : vtxwin.page->info.minute), ftype_ext[(int)xv_get(export_ftype_item, PANEL_VALUE)]); export_fc_orgname = sstrdup(fname); xv_set(export_fc, FILE_CHOOSER_DOC_NAME, fname, NULL); } }