/* twpsk: PSK31 for Linux with a Lesstif interface * Copyright (C) 1999 Ted Williams WA0EIR * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, * USA. * * Version: 2.1 - Aug 2002 */ #include "twpskCB.h" extern XtAppContext ac; extern AppRes appRes; extern Position winlocs[3][2]; extern Wids pskwids; extern TwpskCB twpskCB; extern Disp disp; extern Scope scope; extern int netmode; Pixel darkBG, lightBG; enum { MODE_RX, MODE_TX, MODE_TUNE }; int rxtxmode=MODE_RX; /* * bordersCB - used to get the window managers borders */ void bordersCB (Widget w, XtPointer cdata, XtPointer cbs) { Position x,y; XtVaGetValues (w, XmNx, &x, XmNy, &y, NULL); twpskCB.setBorders(x, y); XtUnmapWidget (XtParent(w)); } /* * appendRXtext - not really a callback, but fit well here. * adds characters to the end of the RX text widget * and puts cursor to the last position. Called by workProc() * userData is the widget id of the scrollbar. * * Underline == 1 to underline transmitted text, but it adds * too much flicker right now. */ void appendRXtext (Widget w, char ch, int zero, XmHighlightMode highlight_mode) { char str[2]; XmTextPosition lastPos; int flag; XtPointer *obj = NULL; DecoderWid *dec; str[0] = ch; /* Build a string */ str[1] = '\0'; XmTextDisableRedisplay (w); /* stop redisplay */ lastPos = XmTextGetLastPosition(w); if (str[0] == '0' && zero == 1) /* Print zero with a slash? */ { str[0] = '\330'; } if (str[0] == 0x7F || str[0] == '\b') /* If a DEL or BS char */ { XmTextReplace (w, lastPos-1, lastPos, "\0"); } else { XmTextInsert (w, lastPos, str); } /* get the object and check its rxScrollFlag field */ XtVaGetValues (w, XmNuserData, &obj, NULL); if (obj == (XtPointer)&pskwids) /* for main window */ { flag = pskwids.getRxScrollFlag(); } else { dec = (DecoderWid *) obj; /* for secondary window */ flag = dec->getRxScrollFlag(); } if (flag != SCROLLING) { XmTextShowPosition (w, lastPos); XmTextSetCursorPosition (w, lastPos); } #if 1 /* * highlight text according to highlight_mode * underline for transmitted and plain for received * Flickers too much!!! * WELL! openMotif fixed the flicker! * Should add a resource??? */ if (str[0] != '\n') { XmTextSetHighlight(w, lastPos, lastPos+1, highlight_mode); } #endif XmTextEnableRedisplay (w); } /* * appendTXtext - not really a callback, but fit well here. * Adds characters to the end of the TX text widget * Called by procMacroText and procFileData work proceedure. */ void appendTXtext (char ch, int zero) { Widget w = pskwids.getTxText(); char str[2]; XmTextPosition lastPos; str[0] = ch; /* Build a string */ str[1] = '\0'; lastPos = XmTextGetLastPosition(w); //XmTextSetCursorPosition (w, lastPos); /* keep cursor at the end */ XmTextInsert (w, lastPos, str); } /* * Callbacks */ /* * controlsBtnCB - callback for Recv, Xmit, Tune, * Wide, Medium, Narrow, Waterfall and Sepctrum main * menu buttons. Set the toggle button and let the * valueChanged callbacks do the rest. */ void controlsBtnCB (Widget w, XtPointer cdata, XtPointer cbs) { Widget wid = (Widget)cdata; XmToggleButtonSetState (wid, True, True); } /* * tuneCB - value changed callback for tune toggle button */ void tuneCB (Widget w, XtPointer cdata, XtPointer cbs) { Widget wid = (Widget) cdata; if(rxtxmode == MODE_TUNE) { /* Already in Tune, i.e. nothing to do... */ return; } if (wid != NULL) /* TB set by menubar*/ { XmToggleButtonSetState (wid, True, True); return; } commControl(COMM_TXCH, COMM_MODE, MO_TUNE ); if(rxtxmode == MODE_RX) commControl(COMM_TXCH, COMM_PTT, PTTON | PTTFORCE); rxtxmode = MODE_TUNE; changeBG (); } /* * rxCB - value changed callback for Recv radio box togglebutton * 'R' and 'T' are passed in the client data. */ void rxCB (Widget w, XtPointer cdata, XtPointer cbs) { char cwStr[20]; int phase; Widget wid = (Widget) cdata; /* Going into receive mode */ if( rxtxmode == MODE_RX ) { /* Already receiving, i.e. nothing to do... */ /* Maybe we should "force" rx if we are still transmitting? */ return; } if (wid != NULL) /* TB set by menubar */ { XmToggleButtonSetState (wid, True, True); return; } /* if CW ID needed? */ if (rxtxmode!=MODE_TUNE && (XmToggleButtonGetState(pskwids.getCwidTB()) == 1) ) { strcpy (cwStr, " de "); /* Build cw id string */ strncat (cwStr, appRes.call, 15); phase = 0; scope.drawline(phase, 35, GREEN); // switch to CW; PTT is already on commControl(COMM_TXCH, COMM_MODE, MO_CWSEND); commPutData(cwStr, 0); } // and send Postamble+schedule PTT off commControl(COMM_TXCH, COMM_PTT, PTTOFF); // turn off CW/Tune mode if necesary commControl(COMM_TXCH, COMM_MODE, MO_NORMAL); phase = 0; scope.drawline(phase, 35, GREEN); /* Now force focus to the xmit Text Widget */ XmProcessTraversal (pskwids.getTxText(), XmTRAVERSE_CURRENT); rxtxmode = MODE_RX; changeBG (); } /* * txCB - value changed callback for Recv radio box togglebuttons * 'R' and 'T' are passed in the client data. */ void txCB (Widget w, XtPointer cdata, XtPointer cbs) { String str; int freq; int phase; Widget wid = (Widget) cdata; /* Going into transmit mode */ if(rxtxmode==MODE_TX) { /* Already transmitting, nothing to do * Maybe we should FORCE TX here (if we do a DCD schedule TX * otherwise) ? Then we would have to take care about two * TX commands in the queue! (Maybe server/psk31tx does not yet * handle this correctly */ return; } if (wid != NULL) /* TB set by menubar */ { XmToggleButtonSetState (wid, True, True); return; } /* Going to tx from rx or tune mode */ if(netmode) { XtVaGetValues (pskwids.getRxFreqTF(), /* get the rx freq */ XmNvalue, &str, NULL); XmTextFieldSetString (pskwids.getTxFreqTF(), str); freq = atoi(str); commControl(COMM_TXCH, COMM_FREQ, (int)(100*freq)); } phase = 128; scope.drawline(phase, 35, GREEN); if(rxtxmode==MODE_RX) { commControl(COMM_TXCH, COMM_MODE, MO_NORMAL); commControl(COMM_TXCH, COMM_PTT, PTTON); } else { // disable TUNE commControl(COMM_TXCH, COMM_MODE, MO_NORMAL); } /* Now force focus to the xmit Text Widget */ XmProcessTraversal (pskwids.getTxText(), XmTRAVERSE_CURRENT); rxtxmode = MODE_TX; changeBG (); } /* * changeBG - changes widget w's background to light or dark */ void changeBG (void) { int i; Widget *w; w = pskwids.get_rxtTB(); for (i=0; i<3; i++) { if (XmToggleButtonGetState(w[i]) == 0) { XtVaSetValues (w[i], XmNbackground, lightBG, NULL); XmToggleButtonSetState (w[i], False, True); } else { XtVaSetValues (w[i], XmNbackground, darkBG, NULL); XmToggleButtonSetState (w[i], True, True); } } } /* * changeDisplayCB value changed callback - changes display * from spectrum to waterfall */ void changeDisplayCB (Widget w, XtPointer cdata, XtPointer cbs) { disp.changeDisplay ((int)cdata); } /* * txTextCB - modify/verify and cursor motion callback for * transmit text widget */ void txTextCB (Widget w, XtPointer cdata, XtPointer cbs) { int i; XmTextVerifyCallbackStruct *pt = (XmTextVerifyCallbackStruct *) cbs; switch (pt->reason) { case XmCR_MODIFYING_TEXT_VALUE: if (pt->text->length == 0) /* Got a backspace */ { commPutData("\b", 1); } else { for (i = 0; i < pt->text->length; i++) { if (pt->text->ptr[i] == 0) { commPutData("\x7F", 1); } else { commPutData(pt->text->ptr+i, 1); } /* Should we print zero with a slash? */ if (pt->text->ptr[i] == '0' && appRes.zero == 1 ) pt->text->ptr[i] = '\330'; } } break; case XmCR_MOVING_INSERT_CURSOR: /* * If text len == 0, then we probably just cleared the widget * so allow the cursor movement. If the move is back one char * then allow it - probably just a backspace key but could be mouse. * Any thing else is a mouse click inside the text, so don't do it. * Why doesn't the CB have an Xevent pointer? Commented code will * always print null. */ // XButtonPressedEvent *e = (XButtonPressedEvent *) pt->event; // if (e == NULL) //{ //printf ("null\n"); //} if (strlen (XmTextGetString(w)) == 0) { pt->doit = True; /* This is OK - just cleared the widget*/ break; } if (pt->newInsert < pt->currInsert - 1) { pt->doit = False; } else { pt->doit = True; } break; default: fprintf (stderr, "Unexpected TxText callback reason\n"); break; } } /* * arrowCB - handles the Up/Down arrows for Rx and Tx freq changes. * The cdata is the associated textfield widget and userData indicates * 'R' or 'T' for recv or xmit freq. */ void arrowCB (Widget w, XtPointer cdata, XtPointer cbs) { float freq, delta; XtPointer userData; String str; unsigned char direction; Widget textF = (Widget)cdata; XmArrowButtonCallbackStruct *cbsPtr = (XmArrowButtonCallbackStruct *)cbs; XButtonPressedEvent *event = (XButtonPressedEvent *) cbsPtr->event; XtVaGetValues (w, XmNuserData, &userData, XmNarrowDirection, &direction, NULL); if (event->state & ShiftMask) /* if shifted click */ delta = 8.0; /* change by 8 */ else delta = 1.0; /* else change by 1 */ if (cbsPtr->click_count == 2) /* if double click, changes by 7 */ delta = 7.0; /* cuz already been changed by 1 */ XtVaGetValues (textF, /* Get the freq */ XmNvalue, &str, NULL); freq = atof(str); /* convert to a float */ if (direction == XmARROW_UP) freq = freq + delta; else freq = freq - delta; if (freq < 0) /* no negative freqs */ freq = 0.0; if (freq > 4000.0) /* nothing over 4kc */ freq = 4000.0; sprintf (str, "%4.1f", freq); /* float to a char */ XmTextFieldSetString (textF, str); if ((int)userData == 'R') { /* Set new rx freq or */ commControl(COMM_RXCH, COMM_FREQ, (int)(freq*100)); } else { /* Set new tx freq */ commControl(COMM_TXCH, COMM_FREQ, (int)(freq*100)); } } /* * freqTextCB - handles keyboard mod/ver and value changed callbacks * for rx and tx freq textfields. userData is 'R' or 'T' for rx or tx * text widget or pointer to DecoderWid object for subwindows */ void freqTextCB (Widget w, XtPointer cdata, XtPointer cbs) { int i; float freq; String str; XtPointer userData; XmTextVerifyCallbackStruct *pt = (XmTextVerifyCallbackStruct *)cbs; /* Switch on the type of callback */ switch (pt->reason) { /* Activate Callback */ /* you typed in a new freq */ case XmCR_ACTIVATE: XtVaGetValues (w, XmNuserData, &userData, XmNvalue, &str, NULL); freq = atof(str); /* first, make sure new (0 >= freq <= 4000) */ if (freq < 0 || freq >4000) { if (freq < 0.0) { freq = 0.0; strcpy (str, "0.0"); } else { freq = 4000.0; strcpy (str, "4000.0"); } XtVaSetValues (w, XmNvalue, str, NULL); } if ((int)userData == 'R') { /* Set new rx freq */ commControl(COMM_RXCH, COMM_FREQ, (int)(freq*100)); /* Now force focus to the xmit Text Widget */ XmProcessTraversal (pskwids.getTxText(), XmTRAVERSE_CURRENT); } else if ((int)userData == 'T') { /* Set new tx freq */ commControl(COMM_TXCH, COMM_FREQ, (int)(freq*100)); /* Now force focus to the xmit Text Widget */ XmProcessTraversal (pskwids.getTxText(), XmTRAVERSE_CURRENT); } else { DecoderWid *dec = (DecoderWid *)cdata; if(dec==NULL) { fprintf (stderr,"callback with cdata==NULL and userData=" "%p (%c)\n", userData, (int)userData); break; } commControl(dec->commChannel, COMM_FREQ, (int)(freq*100)); /* Now force focus to the Swap Button Widget */ XmProcessTraversal(dec->getSwapBtn(), XmTRAVERSE_CURRENT); } break; /* Modify/Verify Callback */ /* allow only digits or "." in freq text widgets */ case XmCR_MODIFYING_TEXT_VALUE: for (i = 0; i < pt->text->length; i++) { if (isdigit (pt->text->ptr[i]) || (pt->text->ptr[i] == '.')) pt->doit = True; else pt->doit = False; } break; default: fprintf (stderr, "freqTextCB - unexpected callback type\n"); break; } } /* * afcCB - value changed callback - sets/clears the afc mode */ void afcCB (Widget /*w*/, XtPointer /*cdata*/, XtPointer cbs) { XmToggleButtonCallbackStruct *ptr = (XmToggleButtonCallbackStruct *) cbs; /* set AFC to toggle button state */ commControl(COMM_RXCH, COMM_AFC, ptr->set); } /* * netCB - sets/clears the net mode * should xfer rx freq to tx freq too??? */ void netCB (Widget /*w*/, XtPointer /*cdata*/, XtPointer cbs) { XmToggleButtonCallbackStruct *pt = (XmToggleButtonCallbackStruct *) cbs; netmode = pt->set; } /* * scopeCB - expose callback */ void scopeCB (Widget /*w*/, XtPointer /*cdata*/, XtPointer /*cbs*/) { scope.drawcirc(); } /* * wfCB callback - click to tune * uses button release event and pointer x position to change rx freq */ void wfCB (Widget w, XtPointer cdata, XtPointer cbs) { float newfreq; char freq_str[8]; int x; XmDrawingAreaCallbackStruct *ptr = (XmDrawingAreaCallbackStruct *) cbs; int button_number; if (ptr->event->xany.type == ButtonPress) { button_number = ptr->event->xbutton.button; x = ptr->event->xbutton.x; switch (button_number) { case Button1: newfreq = disp.new_fc(x); sprintf(freq_str, "%4.1f", newfreq); XmTextFieldSetString (pskwids.getRxFreqTF(), freq_str); /* Set new rx freq */ commControl(COMM_RXCH, COMM_FREQ, (int)(newfreq*100)); break; case Button3: open2Rx(x); /* create new RX decoder! */ break; } } } /* * openBtnCB callback - Opens secondary window at current rx freq. * */ void openBtnCB (Widget w, XtPointer cdata, XtPointer cbs) { Widget wid; char *text; int rtn; rtn = open2Rx (DISPLAY_WIDTH/2); if (rtn != -1) /* If we got a decoder */ { wid = pskwids.getRxText(); text = XmTextGetString(wid); XmTextSetString(decoderWids[rtn].getTextWid(), text); /* Problem - What if main has been scrolled? */ } } /* * Open Secondary Rx decoder - creates a secondary decoder. * Used by wfCB with Button 3 pressed and openBtnCB * Return == ch, or -1 if none available */ int open2Rx (int x) { float freq = disp.new_fc (x); int ch; Boolean qpsk; for(ch=0; ch= MAX_DECODERS) { fprintf (stderr, "error: no free decoder channel!\n"); return -1; } else { int channel = ch+3; decoderWids[ch].commChannel = channel; // redundand commControl(channel, COMM_MODE, MO_NORMAL); // init channel commControl(channel, COMM_DCDLEVEL, 15); /* Start new sub windows with QPSK=off LSB=off and AFC=on */ /* OK, but lets not default the QPSK value - TJW */ qpsk = pskwids.getQPSK(); decoderWids[ch].setQPSK(qpsk); commControl(channel, COMM_QPSK, qpsk); /* commControl(channel, COMM_QPSK, 0); */ commControl(channel, COMM_LSB, 0); commControl(channel, COMM_AFC, 1); commControl(channel, COMM_FREQ, (int)(freq*100)); decoderWids[ch].updateDisplay(freq,0,0); /* clear text content! */ XmTextSetString(decoderWids[ch].getTextWid(), ""); decoderWids[ch].visible = 1; #if 0 /* this moves decoder to a fixed location */ /* Instead, the position is set in Decoder::buildWid */ int x,y,w; XtVaGetValues(XtParent(pskwids.get_mainform()), XmNx, &x, XmNy, &y, XmNwidth, &w, NULL); decoderWids[ch].move(x+w+4, y+ch*197); #endif XtPopup (decoderWids[ch].getMainWid(), XtGrabNone); XtVaSetValues (decoderWids[ch].getMainWid(), XmNmwmDecorations, MWM_DECOR_ALL | MWM_DECOR_MENU, NULL); return ch; } } /* * audioCB - sets audio level for main, line in, and line out on mixer * client data is 'm', 'i', and 'o' for main, line in, and line out */ void audioCB (Widget /*w*/, XtPointer cdata, XtPointer cbs) { char which = (int) cdata; XmScaleCallbackStruct *ptr = (XmScaleCallbackStruct *)cbs; /* set stereo levels */ int level = (ptr->value<<8) + ptr->value; switch (which) { case 'm': setLevel (SOUND_MIXER_VOLUME, level); break; case 'p': setLevel (SOUND_MIXER_PCM, level); break; case 'i': setLevel (SOUND_MIXER_LINE, level); setLevel (SOUND_MIXER_MIC, level); break; } } /* * setLevel - sets level in mixer * used by audioCB callback and build_widgets() for initialization */ void setLevel(int device, int level) { int mixer_fd; /* Open the Mixer Device */ if ((mixer_fd = open ("/dev/mixer", O_RDWR)) < 0) { fprintf (stderr, "Can't open mixer\n"); perror ("Error: mixer open"); } /* write new values to device */ if (ioctl (mixer_fd, MIXER_WRITE (device), &level) < 0) { perror ("Error: mixer write"); close (mixer_fd); } close (mixer_fd); } /* * dcdCB - Squelch value changed callback * sets dcd to opposite of button state(set) */ void dcdCB (Widget w, XtPointer cdata, XtPointer cbs) { XmToggleButtonCallbackStruct *ptr = (XmToggleButtonCallbackStruct *) cbs; int set = ptr->set; commControl(COMM_RXCH, COMM_DCD, !set); } /* * fftScaleCB - handles FFT speed */ void fftScaleCB (Widget w, XtPointer cdata, XtPointer cbs) { XmScaleCallbackStruct *ptr = (XmScaleCallbackStruct *)cbs; int val = ptr->value; disp.fft_setup(-1, val); } /* * qpskCB - enable/disable qpsk mode */ void qpskCB (Widget w, XtPointer cdata, XtPointer cbs) { XmToggleButtonCallbackStruct *ptr = (XmToggleButtonCallbackStruct *) cbs; commControl(COMM_RXCH, COMM_QPSK, ptr->set); commControl(COMM_TXCH, COMM_QPSK, ptr->set); } /* * lsbCB - enable/disable lsb */ void lsbCB (Widget w, XtPointer cdata, XtPointer cbs) { XmToggleButtonCallbackStruct *ptr = (XmToggleButtonCallbackStruct *) cbs; commControl(COMM_RXCH, COMM_LSB, ptr->set); commControl(COMM_TXCH, COMM_LSB, ptr->set); } /* * bwCB - changed bandwidth displayed */ void bwCB (Widget w, XtPointer cdata, XtPointer cbs) { int samp = (int) cdata; XmToggleButtonCallbackStruct *pt = (XmToggleButtonCallbackStruct *) cbs; if (pt->set == True) { disp.set_samples(samp); } } /* * fileCB - Main menu File buttons callback. * Builds the pathname for the text file and * starts a work process to send the file text. */ void fileCB (Widget w, XtPointer cdata, XtPointer cbs) { char *filepath, *home, *filename; char *filetext; XtAppContext ac = XtWidgetToApplicationContext(w); XtVaGetValues (w, /* Get the file name */ XmNuserData, &filename, NULL); /* malloc space for path to twpskDir + fileName */ /* and build the pathname for the text file */ home = getenv ("HOME"); filepath = (char *) malloc (strlen (home) + strlen ("/twpskDir/") + strlen (filename)); strcpy (filepath, home); strcat (filepath, "/twpskDir/"); strcat (filepath, filename); /* read the file */ filetext = getFile(filepath); /* procFileText must free this! */ /* start a work proc */ XtAppAddWorkProc (ac, procFileText, (XtPointer) filetext); free (filepath); /* Clean house */ } /* * quitCB - QRT time! */ void quitCB (Widget w, XtPointer cdata, XtPointer cbs) { int i; Position x, y; for (i=0; i= 0) /* if it was used */ { /* get its loc */ XtVaGetValues (decoderWids[i].getMainWid(), XmNx, &x, XmNy, &y, NULL); if (decoderWids[i].visible == 1) /* if it is visible */ { /* save its loc */ winlocs[i][0] = x; winlocs[i][1] = y; } else /* else it was closed */ { /* so account for border */ winlocs[i][0] = x + twpskCB.getBorderX(); winlocs[i][1] = y + twpskCB.getBorderY(); } } } /* write the array to ini file */ iniProc ('w'); exit (0); } /* * rxFreqFocusCB - rxFreqTF focus callback * used by main window and subwindows! */ void rxFreqFocusCB (Widget w, XtPointer cdata, XtPointer cbs) { int focusFlag = 0; XmAnyCallbackStruct *ptr = (XmAnyCallbackStruct *) cbs; switch (ptr->reason) { case XmCR_FOCUS: XtVaSetValues (w, XmNforeground, WhitePixelOfScreen(XtScreen(w)), NULL); focusFlag = 1; break; case XmCR_LOSING_FOCUS: XtVaSetValues (w, XmNforeground, BlackPixelOfScreen(XtScreen(w)), NULL); focusFlag = 0; break; default: fprintf (stderr, "rxFreqFocusCB: gain/losing focus error\n"); break; } /* set focusFlag in main or 2nd rx win object */ if (cdata==(XtPointer)&pskwids) pskwids.setRxFreqFocus(focusFlag); else { DecoderWid *dec = (DecoderWid *)cdata; dec->setFreqFocus(focusFlag); } } /* * rxScrollBarCB - clears/sets rxScrollFlag to * enable/disable rxText scrolling */ void rxScrollBarCB (Widget w, XtPointer cdata, XtPointer cbs) { int max, position, slider; int scrollMode; Widget rxText; DecoderWid *dec = (DecoderWid *)(cdata); /* Get the rxText widget of the Object that called us! */ if (cdata == (XtPointer)&pskwids) /* for the main window */ rxText = pskwids.getRxText(); else /* for the secondary windows */ rxText = dec->getRxText(); /* get some values from the scrollbar */ XtVaGetValues (w, XmNmaximum, &max, XmNvalue, &position, XmNsliderSize, &slider, NULL); /* Set scroll mode off */ if (max - position - slider == 0) { XtVaSetValues (rxText, /* Go to normal mode if at the botton */ XmNbackground, lightBG, NULL); scrollMode = 0; } else /* Set scroll mode on */ { XtVaSetValues (rxText, XmNbackground, darkBG, NULL); scrollMode = 1; } /* Set scroll mode to object */ if (cdata == (XtPointer)&pskwids) { pskwids.setRxScrollFlag (scrollMode); /* for the main window */ } else { dec->setRxScrollFlag (scrollMode); /* for the secondary windows */ } } /* * brightnessCB - sets disp.brightness equal to scale value */ void brightCB (Widget w, XtPointer cdata, XtPointer cbs) { XmScaleCallbackStruct *ptr = (XmScaleCallbackStruct *)cbs; disp.brightness = ptr->value; } /* * popupDiagCB - pops up the setup Dialog */ void popupDiagCB (Widget w, XtPointer cdata, XtPointer cbs) { Widget form6 = (Widget) cdata; XtManageChild (form6); } /* * closeDiagCB - pops down the setup Dialog */ void closeDiagCB (Widget w, XtPointer cdata, XtPointer cbs) { Widget form6 = (Widget) cdata; XtUnmanageChild (form6); } /* * popupHandler - Event handler to popup clear text menu */ void popupHandler (Widget w, XtPointer cdata, XEvent *event, Boolean *cont) { Widget menuWid = (Widget)cdata; if (event->type == ButtonPress && event->xbutton.button == Button3) { XmMenuPosition (menuWid, &(event->xbutton)); XtManageChild (menuWid); } } /* * clrTextCB - clears the text in the Rx and Tx window */ void clrTextCB (Widget w, XtPointer cdata, XtPointer cbs) { Widget wid; DecoderWid *dec; Pixel bg; XtVaGetValues (XtParent(w), /* Get rowColumn (menu) wid */ XmNuserData, &wid, /* userData is ID of text widget */ XmNbackground, &bg, NULL); XtVaSetValues (wid, XmNvalue, "", /* clear the text widget */ XmNcursorPosition,(XmTextPosition) 0, XmNbackground, bg, /* and make sure bg is correct */ NULL); /* make sure the scrollFlag gets cleared too - this way for main window */ if (wid == pskwids.getRxText() || wid == pskwids.getTxText()) { pskwids.setRxScrollFlag(0); } else /* or this way for the secondary windows */ { XtVaGetValues (wid, XmNuserData, &dec, /* Get userData (this ptr) */ NULL); dec->setRxScrollFlag(0); } } /* * sendOver Action - gets the other call from shared memory, * gets your call, builds the "over" string, and sends it. * If there is no call - just send de mycall */ void sendOver (Widget w, XEvent *e, String args[], Cardinal *nargs) { char *ch; if ((ch = getHisCall()) != (char *)0) /* get his call */ { /* got it */ procMacroText(ch); /* send his call, */ shmdt ((void *)ch); /* detach shm */ } procMacroText ("de"); /* send de */ procMacroText (appRes.call); /* and send my call */ } /* * sendHisCall Action - send the call from twlog */ void sendHisCall (Widget w, XEvent *e, String args[], Cardinal *nargs) { char *ch; if ((ch = getHisCall()) != (char *)0) /* get his call */ { /* got it */ procMacroText(ch); /* send his call, */ shmdt ((void *)ch); /* detach shm */ } } /* * sendMacro Action - send all the action arguments */ void sendMacro (Widget w, XEvent *e, String args[], Cardinal *nargs) { int i; for (i=0; i<(int)*nargs; i++) { procMacroText (args[i]); } } /* * getHisCall - attach the shared menory if running twlog and returns * a char * to his call * Used by sendOver and sendCall */ #define KEY 6146 /* must match Twlog's value */ #define SHMSIZE 40 char *getHisCall () { int shmid; void *pt; if ((shmid = shmget ((key_t) KEY, SHMSIZE, 0600)) < 0) { fprintf (stderr, "No twlog!\n"); return ((char*) 0); } if ((pt = shmat (shmid, NULL, 0)) == (void *) -1) { perror ("twpsk - shmat failed"); return ((char *) 0); } return ((char *)pt); } /* * procMacroText - sends a string to appendTXtext */ void procMacroText (char *ch) { int i; for (i=0; ch[i] != '\0'; i++) { appendTXtext (ch[i], appRes.zero); /* append the text */ } appendTXtext (' ', appRes.zero); /* append a space */ } /* * seekCB - adds a timeout routine for seek */ #define TIMER 100 XtIntervalId id=0; int first = 1; int haltFlag = 0; int seeking = 0; void seekCB (Widget w, XtPointer cdata, XtPointer cbs) { if (seeking == 1) { haltFlag = 1; return; } first = 1; seeking = 1; XtVaSetValues (pskwids.getRxFreqTF(), XmNforeground, WhitePixelOfScreen(XtScreen(pskwids.getRxFreqTF())), NULL); id = XtAppAddTimeOut (ac, TIMER, (XtTimerCallbackProc) seekTimeOut, cdata); } /* * haltCB - removes the timeout */ void haltCB (Widget w, XtPointer cdata, XtPointer cbs) { if (seeking) { haltFlag = 1; } } /* * seekTimeOut - */ #define STEP1 50.0 #define STEP2 20.0 void seekTimeOut (XtPointer cdata, XtIntervalId id) { String str=""; float freq; int rtn; float step = STEP1; if (!first) /* Not the first time, so check data */ { step = STEP2; rtn = disp.find_center(DISPLAY_WIDTH/2); if (rtn != -1) /* Found one, so */ { freq = disp.new_fc(rtn); commControl(COMM_RXCH, COMM_FREQ, (int)(freq*100)); first = 1; seeking = 0; XtVaSetValues (pskwids.getRxFreqTF(), XmNforeground, BlackPixelOfScreen(XtScreen(pskwids.getRxFreqTF())), NULL); return; /* and don't sked another timeout */ } } /* on everytime .... */ first = 0; str = XmTextGetString (pskwids.getRxFreqTF()); freq = atof (str); if ((int)cdata == 'U') { freq = freq + step; } if ((int)cdata == 'D') { freq = freq - step; } sprintf (str, "%4.1f", freq); /* See if we should halt or about to go over the edge of the world */ if ( (haltFlag == 1) || (freq < 0.0) || (freq > 4000.0) ) { first = 1; haltFlag = 0; seeking = 0; XtVaSetValues (pskwids.getRxFreqTF(), XmNforeground, BlackPixelOfScreen(XtScreen(pskwids.getRxFreqTF())), NULL); } else { XmTextFieldSetString (pskwids.getRxFreqTF(), str); commControl(COMM_RXCH, COMM_FREQ, (int)(freq*100)); id = XtAppAddTimeOut(ac, TIMER, (XtTimerCallbackProc) seekTimeOut, cdata); } }