LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Blogs > rainbowsally
User Name
Password

Notices


Rate this Entry

mini-term in qt4

Posted 01-17-2013 at 03:34 AM by rainbowsally
Updated 08-06-2014 at 07:58 AM by rainbowsally

mini-term in qt4.

Today's features:
  • A simple terminal-like application built from a qt4 class that can be used for other stuff too.
  • The present application can run shell commands and has copy/paste (ctrl-c, ctrl-v) capabilitity.
  • Another example of the Windows-like api so that C/C++ code can run in Qt4.
  • Runs the custom code (terminal in this case) inside a QT 'exec' loop... sorta. We call it 'run()'.

Screenshot:
http://rainbowsally.org/rainbowsally...iterm-test.png

If you want to try this, be forewarned:
Run
Code:
make ui
and then
Code:
make
So that all the moc_&.cpp files are created before you 'make' the app itself.

[I won't go into depth on the api thing, but with four parameters Windows gives strong clues as to typing without enforcing overly-strict typing rules. And integer will go into wparam. A pointer or a struct will go into lparam. Messages identify it more completely and tell what to do with it. It's intuitive by nature and one of the few features of Windows that I like better than any linux gui toolkits I've tried so far.]

The self extractor (near the bottom) contains all the files including the Makefile and the mc2.def that created the Makefile but let's take look at the api, which is the layer between our custom code and the Designer-generated gui code.

file: miniterm-test/app-main.cpp
purpose: source file
Code:
#include <QtGui/QApplication>
#include "lqminiterm.h"
#include "ui_lqminiterm.h"
#include <ctype.h> // alnum()
#include <stdio.h>

void dbg(){}

static bool cmd_set;
static char* cmd;
static bool text_mode;

static void term_print(lqMiniTerm* term, const char* buf)
{
  text_mode = true;
  term->ui->plainTextEdit->appendPlainText(buf);
  text_mode = false;
  term->ui->plainTextEdit->textCursor().movePosition(QTextCursor::End);
  term->last_pos = 
      term->ui->plainTextEdit->textCursor().position();

}

static void prompt(lqMiniTerm* term)
{
  char buf[256];
  sprintf(buf, "%s", getenv("PWD"));
  int pathlen = strlen(buf);
  // trim path down to 40 chars
  if(pathlen > 40)
    sprintf(buf + 18, "...%s", buf + pathlen - 19);
  
  strcat(buf, "$>");
  term_print(term, buf);
}

// user programmable loop func in app-main()
// this just does shell commands.
void loop_func(lqMiniTerm* term)
{
  // only operates in command mode
  if(text_mode)
    return;
  
  char* cmdptr = cmd;
  int slen;
  
  if(!cmd_set)
    return;
  
  cmd_set = false;

  // queue up text
  while(isspace(*cmdptr))
    cmdptr++;
  
  if(!*cmdptr)
    return;
  
  
  ////////////////////////////////////////////
  // A couple of keywords we handle ourselves
  // 'cd' <path> | 'exit'
  
  char firstword[256];
  sscanf(cmdptr, "%s", firstword);
  
  if(strcmp(firstword, "cd") == 0)
  {
    cmdptr += 3;
    while(isspace(*cmdptr))
      cmdptr++;
        
    char* cwd;
    chdir(cmdptr);
    cwd = getcwd(0, 0);
    setenv("PWD", cwd, true);
    free(cwd);
    prompt(term);
    return;
  }
  else 
    if(strcmp(firstword, "exit") == 0)
    {
      term->onClose();
    }
  
  ////////////////////////////////////////
  // piped shell command
  char* buf = (char*)malloc(256);
  size_t bufsize = 256;
  sprintf(buf, "%s 2>&1", cmdptr);
  FILE* p = popen(buf, "r");
  while(!feof(p))
  {
    *buf = 0;
    getline(&buf, &bufsize, p);
    slen = strlen(buf);
    if(!slen)
      break;
    buf[slen-1] = 0;
    term_print(term, buf);
  }
  fclose(p);
  free(buf);
  prompt(term);
}


#define UNUSED(x) x=x
void handler(lqMiniTerm* hwnd, uint msg, long wparam, void* lparam)
{
  UNUSED(lparam);
  switch(msg)
  {
    case msg_init:
      text_mode = false;
      break;
    case msg_onClose:
      // printf("Handled: Closing\n");
      hwnd->hide(); // signal to runner we can quit
      hwnd->close();
      break;
    case msg_onNewline:
    {
      // to get the newly entered text we take the text edit's buffer
      // from last_pos to cur_pos and update last_pos in the class
      int last_pos = hwnd->last_pos;
      int cur_pos = hwnd->ui->plainTextEdit->textCursor().position();
      if(!text_mode && (cur_pos >= last_pos))
      {
        QString str = hwnd->ui->plainTextEdit->document()->toPlainText();
        const char* s = str.right(cur_pos - last_pos);
        int len = strlen(s);
        if(len && !cmd_set)
        {
          cmd = (char*)realloc(cmd, len);
          memcpy(cmd, s, len);
          cmd[len-1] = 0;
          cmd_set = true;
          printf("Text: %s\n", cmd);
        }
      }
      // and... only if cur_pos > last_pos
      hwnd->last_pos = cur_pos;
      // printf("Handled: Newline, block = %d\n", (int)wparam);
      break;
    }
    case msg_onCursorPositionChanged:
    {
      // printf("Handled: Cursor Position: pos=%d\n",(int)wparam);
      int new_pos = (int)wparam;
      if(new_pos < hwnd->last_pos)
        hwnd->ui->plainTextEdit->setReadOnly(true);
      else
        hwnd->ui->plainTextEdit->setReadOnly(false);
      break;
    }
  }
}

int main(int argc, char *argv[])
{
  dbg();
  
  // this sets the global qApp instance
  new QApplication (argc, argv);
  
  lqMiniTerm w(loop_func, handler);
  w.show();
  prompt(&w);

  // return qApp->exec();
  return w.run();
}
Take a look at the definition of
Code:
void handler(lqMiniTerm* hwnd, uint msg, long wparam, void* lparam)
in the source above.

The enums are identical to the 'slot' names plus a prefix of 'msg_'.

These slots are never polymorphic, so this is a reliable system for identifying calls and their parameters.

Here are some snips from the header.
Code:
enum{
  msg_init = 0,               // 0 (obj,0,0,0)
  msg_onClose,                // 1 (obj,1,0,0)
  msg_onNewline,              // 2 (obj,2,0,0)
  msg_onCursorPositionChanged // 3 (obj,3,int,0)
};
There's the enums (above). And here's the class functions from the cpp file (below) and you'll notice that the call types are all the same and the resemblance to the Windows WNDPROC is no accident.

Code:
void lqMiniTerm::onClose()
{
  handler(this, msg_onClose, 0, 0);
}

void lqMiniTerm::onNewline(int argA)
{
  handler(this, msg_onNewline, argA, 0);  
}

void lqMiniTerm::onCursorPositionChanged()
{
  QTextCursor cursor = ui->plainTextEdit->textCursor();
  int pos = cursor.position();  
  handler(this, msg_onCursorPositionChanged, pos, 0);
}

void lqMiniTerm::init()
{
  handler(this, msg_init, 0, 0);
}
All these 'slots' do is translate from QT slots to generic calls to handler(). As you can see it would be pretty difficult to pass the wrong type of parameter in the wrong parameter position.

Another interesting feature in the app-main.cpp file (i.e. coded independently from the ui code) is its definition of
Code:
void loop_func(lqMiniTerm* term)
That code runs every 20 milliseconds by default, but can be set to run slower or faster, either at setup time or when you need the speed.

It's not a message loop. It's better in some ways due to its simplicity.

This code, the application, and the interface to the ui can be used to do software "breadboarding".

Doncha just HATE those sockets tutorials where you have to open two terminals to run the things?

Sockets code can run in these loops. No second thread, no mutex, no timing issues. And no dependency on QT threads, so I'm thinking this will be great for really understanding sockets... when I get those done.

The key to this mutability is in the code here.
Code:
// return qApp->exec();
return w.run();
where 'run()' is defined as follows.

Code:
int lqMiniTerm::run()
{
  for(;;)
  {
    qApp->processEvents();
    if(!isVisible())
      break;
    loopFunc(this);
    usleep(loop_timeout * 1000);
  }
  return 0;
}
And that loopFunc is the same loop_func() in the app-main source above. It's the function that curretnly is designed reads input from the text edit widget and decides how to execute it.

Interested? Here's the self extractor.

file: miniterm-test.sfxz
purpose: utility (executable)
Code:
#!/bin/sh
# base64 self extractor
# file: miniterm-test

filename=miniterm-test

# don't allow user to click on the file
if ! tty >/dev/null; then
  xmessage -center "
  $(basename $0)
  must be run in a terminal 
  "
  exit
fi

# create and/or clear out tmp dir
mkdir -p $HOME/tmp/sfxz
rm -rf $HOME/tmp/sfxz/*
base64 -d << _BEOF >$HOME/tmp/sfxz/$filename.xz
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
_BEOF

(cd $HOME/tmp/sfxz && tar -xaf miniterm-test.xz)
rm -f $HOME/tmp/sfxz/miniterm-test.xz
 
cat << _BEOF > $HOME/tmp/sfxz/post-extract
#!/bin/sh

is_yes() # returns OK if first char is Y or y
{
  local key=`echo $1 | cut -b1 | sed 's/y/Y/; /Y/!d'`
  [ "$key" == 'Y' ] && return 0 # true
  return 1 # false
}

if [ -e miniterm-test ]; then
  printf "
  Overwrite existing file(s)? [N/y]:"
  read key
  if ! is_yes $key ;then
  echo "Aborting.."
    exit 0
  fi
fi

mv $HOME/tmp/sfxz/miniterm-test .
_BEOF

sh $HOME/tmp/sfxz/post-extract
rm -rf $HOME/tmp/sfxz/*
rmdir $HOME/tmp/sfxz 2>/dev/null || true
rmdir $HOME/tmp 2>/dev/null || true
Once again, be aware that you have to 'make ui' before you 'make' the application. That's how we keep the sizes reasonable.

Good luck!

PS. If you click on the app it opens in the default directory. And there appears to be some confusion about what that is! PWD says your home dir. Qt or KDE says it's Documents. "cd .." to get to your REAL home dir or add code to make it open where it was clicked on or something.

If you have libLQ and mc2, type 'lq-find appdir' if you want to see some code for opening it in the folder where it was clicked on. (uses getpid() and readlink())

The Computer Mad Science Team

:-)
Posted in Uncategorized
Views 1072 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 05:37 AM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration