1

I am developing a C++ application, under Ubuntu, and need to broadcast the outputs into several terminals. I need to do this programmatically, calling (for instance) bash commands from the C++ application and directing the output to the corresponding terminal. And I cannot install any "multi-terminal" already developed tool (like "terminator", or others); instead, I need to use standard bash commands.
So:

process A -> will show its output in terminal A.
process B -> will show its output in terminal B.
process C -> will show its output in terminal C.

Note, then:

  • I will be broadcasting to several terminal simultaneously, different information, and specific information, to specific terminal.
  • Have you ever seen aircrack working? I remembered that app showing three different terminals at once, each one positioned at specific x,y coordinates of the screen, and each of them showing different information. Well, I think that is what I need.
  • Browsing, I have found the following "gnome-terminal" command, and I adapted it to run 3 terminals:

    gnome-terminal --geometry=45x20+10+10; gnome-terminal --geometry=45x20+505+10; gnome-terminal --geometry=45x20+950+10
    

Some details:

  • the terminals do not need to be gnome ones. They can be just simple consoles, xterms; whichever Ubuntu provides by default.
  • I do not need to start the three terminals at once (as the above sample command). But, when the corresponding process needs to broadcast to its terminal, the terminal must be open.
  • How will the program know to which terminal broadcast the output? May be using the pid of the terminal? If affirmative, having the terminal pid, how I would be redirecting the output to that terminal?
  • I was trying to get the pid of each terminal; for instance, like this:

    gnome-terminal --geometry=45x20+10+10 &
    

and looking for some way to redirect the pid to a variable (do not find yet...).

1
  • The pid won't help you generally, and in case of gnome-terminal all the terminal windows/tabs are handled by a single process (single pid).
    – egmont
    Jun 5, 2016 at 6:42

3 Answers 3

2

Unix sessions are handled by TTY, which should be your starting point. If you use the same user account for all those sessions, then you should be able to send the output directly to the TTY that you want.

So you would simply have to call your program with the different TTYs that you want to use in the output and it would be able to open those for output. I just tried it on Gentoo and Centos without any problem.

To find the TTY of a session, use the tty command.

Another option that I prefer because it has less security implications when dealing with other users is to do it in a client-server approach where the client terminals would connect to your server process. This could be as simple as using named pipes for each of the 3 output terminals.

1

If you simply open a terminal emulator and send some data to it, you'll have to be aware that the user's default shell (most likely bash) will also be running there. This has some consequences that are most likely undesired in your use case. The output's first column will be unaligned due to the prompt (unless you take care of clearing the screen). Whatever the user types will further mess up the screen, and more importantly, will be executed as a shell command which is especially misleading since the user probably doesn't see the prompt there anymore. Also, should you also want to read from the terminal, you wouldn't be able to do this reliably (for each keypress it'll be random whether it arrives to the shell or to you application.

If I understand the context of your question correctly, this is undesirable for you. The terminals you open should solely be used for displaying your app's output, and they shouldn't run a shell in the mean time. As such, you'll have to specify a custom command to launch, rather than the default shell. This custom command could easily be a simple script (or C++ utility) that sends the terminal's line number (the output of the tty command) back to your application, perhaps change some terminal and signal settings (e.g. turn off local echo (stty), disable signals (stty or trap)), and finally enter a giant sleep.

There can be many ways to send back the tty number to your main app. Just be aware that firing up these terminals and the script within is asynchronous from your app's point of view. E.g. if you place tty's output in a temporary file with a fixed filename, you'll have to make sure that the app won't prematurely read this file's previous version. You might e.g. create a unique random filename each time, and wait in your main app for this to appear.

Let me recommend you a completely different approach to consider.

gnome-terminal's (and most (if not all) other Gtk+-based terminal emulator's) actual terminal emulation is done by the VTE widget. If you write an application using the Gtk+ toolkit, adding a VTE widget is just as simple as adding let's say a checkbox.

Instead of using gnome-terminal or xterm or whatever, your application itself might present a graphical window containing multiple VTE widgets, or multiple graphical windows with a single VTE inside each, whichever you prefer. Or if you don't want to have Gtk+ dependency in your actual application, you might easily create a separate tiny helper app for this task (you might even consider Python instead of C/C++).

In this case there's no shell launched by default (you'd have to explicitly do that with the vte_terminal_spawn_sync() method which you'll be happy not to do). You can just get the terminal line with vte_pty_get_fd(), convert it to a string with ptsname() and pass it back to your main app. Or if you do this in a single application then you might even vte_terminal_feed() the data to be displayed.

0

The problem should be simple: get a listing from w or who, which gives you usernames and terminal names, like this:

$ w
 19:34:00 up  7:17,  5 users,  load average: 0.14, 0.08, 0.06
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
tom      pts/1    michener:S.0     14:07    3:21m 15.16s 15.08s vile /tmp/foo
tom      pts/4    michener:S.1     12:34    2.00s  0.22s  0.00s w
tom      pts/5    michener:S.2     13:00    9:48   3.13s  2.79s vile /usr/build
thomas   :0                        19:32   ?xdm?  47.31s  0.34s fvwm2 -f /usr/b
thomas   pts/3    :0               19:33    7.00s  0.04s  0.04s bash
$ who
tom      pts/1        2016-06-04 14:07 (michener:S.0)
tom      pts/4        2016-06-04 12:34 (michener:S.1)
tom      pts/5        2016-06-04 13:00 (michener:S.2)
thomas   :0           2016-06-04 19:32
thomas   pts/3        2016-06-04 19:33 (:0)

However, not all terminals have working support for utmp (where this information is stored). If you limit yourself to Linux, then you can get some usable information in /dev/pts, i.e., the devices with ownership information:

$ ls -l /dev/pts
total 0
crw--w---- 1 tom    tty  136, 0 Jun  4 19:34 0
crw--w---- 1 tom    tty  136, 1 Jun  4 16:12 1
crw--w---- 1 thomas tty  136, 2 Jun  4 19:33 2
crw--w---- 1 thomas tty  136, 3 Jun  4 19:33 3
crw--w---- 1 tom    tty  136, 4 Jun  4 19:34 4
crw--w---- 1 tom    tty  136, 5 Jun  4 19:24 5
c--------- 1 root   root   5, 2 Jun  4 12:16 ptmx

A script could easily inspect these, determine which are the intended users, and write to those (terminal) devices.

Notes:

  • Regarding "How will the program know to which terminal broadcast the output?", the usual approach taken is to run a client on each of the terminals that you want to distinguish, making them communicate to your server who they are.

  • A comment asked how will the program know where the clients are on the screen. You can obtain that using the window properties, e.g., starting with a window-id and using xwininfo. There are differences between types of terminal emulator and which window-id is appropriate (or usable). But the WINDOWID environment variable in each terminal is the usual way to obtain this information (via the client that seems to be needed, if you do not simply want to broadcast). Here's sample output using that approach:

    xwininfo: Window id: 0x400023 "[!xwininfo] - vile"

      Absolute upper-left X:  0
      Absolute upper-left Y:  23
      Relative upper-left X:  0
      Relative upper-left Y:  22
      Width: 486
      Height: 551
      Depth: 24
      Visual: 0x22
      Visual Class: TrueColor
      Border width: 0
      Class: InputOutput
      Colormap: 0x21 (installed)
      Bit Gravity State: NorthWestGravity
      Window Gravity State: NorthWestGravity
      Backing Store State: NotUseful
      Save Under State: no
      Map State: IsViewable
      Override Redirect State: no
      Corners:  +0+23  -794+23  -794-428  +0-428
      -geometry 80x40+0+1

Further reading:

2
  • It's not clear to me how it's possible to get which terminal was opened with which geometry (and even to get which terminals were opened right now by the app, vs. previously interactively by the user).
    – egmont
    Jun 5, 2016 at 6:44
  • That aspect was implied in an aside by OP, but was not a requirement. Jun 5, 2016 at 9:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .