How can I open a work space from the command line in i3? - workspace

I'd like to script opening a workspace with the 'next' available number and then have open in that workspace maybe a two windows each already pointed at a specific view. Any pointers on how to do that? Is i3 actually scriptable in this regard? I have only just started using i3 and loving it, just want to now have it do things I need on a regular basis ;-)

All of i3's "scripting" that isn't already in the config is done through i3-msg
i3-msg sends messages to i3 window manager. It's mostly config lines(or IPC, which is a bit harder).
How can I open a work space from the command line in i3
How do you open it in your config?
bindsym Mod4+1 workspace $ws1
Something like that right? Now, using i3-msg to move to workspace 1:
i3-msg workspace 1
Simple, right?
The rest of your question is pretty unclear, but I'll do my best:
I'd like to script opening a workspace with the "next" available number"
How you'll start out with doing that is(after doing man i3-msg):
i3-msg -t get_workspaces
This returns a json(if you've done any coding you'll feel warm inside and if not you're going to be scared by the output). Then I'm going to ask you to read up on this:
https://i3wm.org/docs/ipc.html#_receiving_replies_from_i3
Using jq or something like json.sh to parse through the output with bash, you should get which workspaces are "active", example:
[{"num":3,"name":"3","visible":true,"focused":false,"rect":{"x":0,"y":0,"width":1920,"height":1080},"output":"HDMI-1","urgent":false},{"num":2,"name":"2","visible":true,"focused":false,"rect":{"x":3520,"y":0,"width":1920,"height":1080},"output":"VGA-1","urgent":false},{"num":1,"name":"1","visible":true,"focused":true,"rect":{"x":1920,"y":32,"width":1600,"height":868},"output":"eDP-1","urgent":false},{"num":5,"name":"5","visible":false,"focused":false,"rect":{"x":1920,"y":32,"width":1600,"height":868},"output":"eDP-1","urgent":false}]
Reading through the website I gave you, you can see, workspaces 1,2,3 and 5 are "active" aka have windows in them. After parsing the actual json you'll end up with an array or something of this. If you want to spawn on 4(the real "next" desktop) or 6 (aka biggest number + 1) is up to you. You didn't mention what you want to script it in, so I'll leave that to you to figure out.
maybe two windows each already pointed at a specific view
I'm not sure what you mean. You probably want 2 windows of X(we'll use a terminal in this case) in the workspace we've determined as "next" ?
Let's go back to i3-msg for a bit.
Imagine you doing whatever you're trying to do, manually, as a list of commands you're firing to i3.
"Go to workspace X" : i3-msg workspace 4
"Spawn a program called kitty there": kitty
"Split vertically and spawn another program": i3-msg split v
"Spawn another kitty window": kitty
After that you can get back to your current workspace(I suggest saving it in a variable and just reusing i3-msg workspace $curr_workspace).
As I said, the question wasn't about the actual scripting so I left that out to figure it out on your own, but don't hesitate to ask a concrete question under the bash tag. :). Hopefully I didn't completely misunderstand your question.
Welcome to the i3 community.

#Nephilim's post is excellent. Just to add a trick to the toolbox...
Sometimes you might want to script some action relative to a particular window. Like:
Give me a test environment next to this browser.
You can get the window ID by running xwininfo and clicking the window that you want to anchor your automation to. The window ID can be used as a parameter to i3-msg.
For example, running the command below will let you select a window and then will set that window's width to 1000:
i3-msg "[id=$(
xwininfo \
| sed -n 's/.*Window id: \(0x[0-9a-f]*\).*/\1/p'
)] resize set 1000"

Related

Redirecting input to script running in background

I wrote a script for resizing windows, which require orientation and value in form of fraction, like so:
resize.sh -h 1/2
and it works as expected.
I also added -k flag, which means that script require user input, like so:
resize.sh -k -h
and in the script:
read -rsn 2 fraction
which I parse to get values for numerator and denominator.
This works great from command line, but idea behind this is to bind resize.sh -k -h to some key combination, and pass following two keys as input. But when I run script from keyboard, it run as a background process which is not associated with any tty, so read could not get its input. Is there any way to redirect global input to background process, after running it from keyboard.
What I tried so far:
Redirection to /proc/$$/fd/0, which didn't work.
Redirectiong currently active tty stdin to read, like so:
read -rsn 2 fraction < /dev/pts/0
which actually worked, but problem is that not all windows are terminal, e.g. web browser.
If my question is unclear, please feel free to ask for additional clarifications or details, and thanks in advance :)
You can use a named pipe for the process communication.
I made am example script where the background proces is a function.
#!/bin/bash
pipe_name=/tmp/mypipe$$
mkfifo "${pipe_name}"
resize()
{
read fraction < "${pipe_name}"
echo "Resize window to fraction=${fraction}"
}
resize &
read -p "Enter your fraction: "
echo "${REPLY}" > "${pipe_name}"
rm "${pipe_name}"
thank you both for providing very useful information. The solution is combination of both, actually.
First I modified read command in resize.sh to get input from named pipe, as Walter suggested, than I wrote a new, kinda "wrapper" script, which executes resize.sh in background, and than, since Barmar pointed I need a gui window, it starts very small terminal window running read and passing input to named pipe. Further more, using wmctrl I manage to place small terminal window right where currently active window begins, and hide it below (thanks to openbox per-application properties), so it's technically not visible at all :)
It's really too hacky for my liking, but it was really the only option I could think of at this moment, so until I find the better way, this gets the job done.
Once again, thank you both for directing me toward solution, I really appreciate it, cheers :)

Can GNOME Shell extensions move the pointer? If so, how?

I want to write an extension that does the opposite of the "focus-follows mouse" setting in GNOME Shell: I want to make my pointer move to the center of the currently focused window.
Can this be done in a GNOME Shell extension? I see some GNOME code that wraps xfixes cursor, but I can't find any references to programmatic pointer updates in either the core Javascript or any existing extensions. (Am I just bad at Google?)
Valid answers include (1) example code that does it or (2) citation of a canonical source that says it can't be done.
Found this code in overview.js
Gdk = imports.gi.Gdk
let display = Gdk.Display.get_default();
let deviceManager = display.get_device_manager();
let pointer = deviceManager.get_client_pointer();
let [screen, pointerX, pointerY] = pointer.get_position();
pointer.warp(screen, 10, 10);
Are you willing to write your own script? If you are, I have found three tools, which, if used together, can get the job done for you.
First, use xprop to get the PID of the window you have clicked on.
Next, use xwininfo to get the dimensions and position information of the window based on its process ID.
Finally, use xdotool to calculate the center position of said window and move the cursor to that exact position.
Hope this helps. I don't have enough time write now to write the script (sorry), but this should be enough to get you started.
EDIT: Based on your comment, you want to stay in GNOME js. Totally understandable. You can call xdotool (which is the most efficient way of changing the position of the cursor on screen) from within GNOME js by use of something like:
const Util = imports.misc.util;
Util.spawn(['/bin/bash', '-c', "xrandr --query | awk 'something'"]) # replace the code here wih your own
This code was found at this thread.

How to automatically open prompts, ssh, and do things using a script?

I have to connect to a linux server from my own Ubuntu machine and operate directly on the server.
A dozen of folder names are listed in a LIST file. How to write sth. (like a bash script?) to carry out the following procedures?
for fold_name in LIST {
/******on my own Ubuntu*******/
-- open 2 new tabs of prompt terminal
-- run an ssh command in both
-- then input passwd and log in automatically in both
/******on the linux server*******/
-- cd to directory xxx/fold_name in both
-- run aaa.exe in 1st tab
-- vim sth in the 2nd tab
}
Once the loop of open-tab-login is solved, I guess the second part is routine as simple bash script except that I don't know how to specify between 2 tabs, either.
The point is I want all tabs in the same terminal. To this end, manually, I often Ctrl+Alt+T to create a prompt and Ctrl+Shift+T to open many tabs within it. And ssh...cd...... in each one. You see how annoying and cumbersome it is!
There are a few things you might like to research, which will get you a little closer.
You can run an ssh without a password, if you use an ssh key. Check out ssh-keygen, and the -i option in ssh.
Opening up tabs in gnome-terminal can be done via the method described here: Open a new tab in gnome-terminal using command line
You can run specific commands (e.g. aaa.exe) on a remote box over ssh, by including the command after the ssh: ssh user#remotehost aaa.exe.
If you want multiple commands, try enclosing them in quotes: ssh user#remotehost "cd /xxx; aaa.exe". Vim does not need to be in the directory in question in most cases: ssh user#remotehost vim /xxx/filename"
If you want to do something interactive (like vim), include the -t flag in ssh.
The tabs will be independent of each other - I'd probably run half of the command in one window, the other (e.g. runnning aaa.exe in one window, using one command, and the vim in another window, using another command, that I just happen to run at the same time. This way I can resize the windows, and arrange them relative to each other, and see both at once.
-- open 2 new tabs of prompt terminal
This depends on which desktop you're using. For gnome, gnome-terminal takes the -e option to specify the script to execute in the new terminal window. So, for something like this, you would execute gnome-terminal -e $script &, placing each instance of gnome-terminal in the background.
If you're using a different desktop, other terminal applications typically have a similar option. So, you'd point the terminal application to a script that's going to run in the terminal, and complete the rest of your task for you.
-- run an ssh command in both
-- then input passwd and log in automatically in both
This is going to be more complicated. The classical solution is the expect utility. There might be other similar tools that do similar things, but expect is pretty much the usual way these kinds of things have been done in the past. When it comes to trying to automate an interactive application, expect is really the only way to go. Unfortunately, expect uses a somewhat arkane syntax, that first-time users typically find confusing, and hard to understand. I grumble, every time I see no other alternative but to use expect to automate something, but this is pretty much the only option that's usually available.

Linux(Ubuntu) Terminal-how to view previous pages not visible anymore

When you scroll up, say to see a log, the first portion of it will not be visible since the terminal only supports a limited no. of lines. So if you want to scroll up and be able to see everything, at least a few pages up, how do you do it?
Use Shift+Page Up and Shift+Page Down.
Piping the output to a pager like the following is a better choice:
command | less
command | more
You can enable unlimited scroll back (or a huge amount if you want).
To do this, go to
File → Profile preferences → Scrolling [tab]
Then, check Unlimited, or set the number of lines desired. And of course, it only applies to the next typed lines.
Some tricks I use-
some terminal applications (gnome-terminal) allow you to increase the scroll-back buffer size
pipe output to a file:
command > file.log
pipe your command to less:
command | less
tail log and pipe to grep to reduce output
tail -f example.log | grep 'search text'
An alternative to screen is using tee to copy all output to a file while still printing it on the terminal:
yourcommand | tee output.txt
Try using the screen command, and set its scrollback buffer to a larger size.
screen has many other benefits and wonderful features.
If all you're doing is looking at a log, you could alternately use a pager such as less
If you want to scroll line by line, you can use
Control+Shift+Up/Down Arrows.
If you are using gnome-term (the default), then you can change your settings. Either set the no. of lines to unlimited, or to a much larger buffer size than the default.
Essentially seconding to #zerick's solution but if you're on gnome-terminal you can modify its config. See this.
If you are in tmux (can create multiple terminal sessions in a single terminal session, highly recommended), you can easily use your normal navigation keys to scroll around after you do Ctrl-b then [, for more details let's take a look at: How do I scroll in tmux?
None of these answer the original question. All answers are how to make new terminal windows (or current one) start behaving a certain way. The question is about how to see whats already scrolled away.
To answer this, each terminal session should have it's own "history" file (not to be confused with what command history is) containing all the stuff that relates to stdin/stdout displayed. I could be wrong but this may be different depending on the terminal emulator you use. Some just trash it when you close the window/ end the session.
I am trying to get this figured out myself so here is the more direct answer in a different thread.
https://unix.stackexchange.com/questions/145050/what-exactly-is-scrollback-and-scrollback-buffer
From what this tells me, I suspect best advice you can get is, for whatever terminal emulator you use, look for where it stores the scrollback buffer and that might be your only hope. It's what I am going to try right now. (and that is IF the session is currently still open, not closed terminal windows)

Can you rename a shell session by command in linux?

I like to keep my shell sessions named with useful titles as I work, this helps me keep track of what I'm using each of the many tabs for.
Currently to rename a session I double click its name on the tabbed part of the console - is there any command that I can use to do this from within the shell? It would save me a bit of time.
thanks in advance
edit :-
I am using KDE's Konsole shell.
The article How to change the title of an xterm should help.
Currently to rename a session I double click its name on the tabbed part of the console
This sounds like you're using KDE's Konsole. Is this true?
If so, in KDE 3:
dcop $KONSOLE_DCOP_SESSION renameSession "I am renamed!"
In KDE 4, the old DCOP interfaces haven't been ported over to the new D-BUS IPC yet, but you can change the settings for tabnames to follow the window name set by each screen, and set the window name as described by the other answers.
According to this page, you should be able to use something like this:
echo -n "\033]0;New Window Title\007"
I'm not in Linux at the moment, so this is untested. I do know that it is possible to change the window title under program control, so this seems likely to work.
For /usr/bin/konsole
you can change the title of a konsole terminal from the menu:
Settings->Edit Current Profile->Tabs
edit "Tab title format" to be whatever you want. After interacting with the shell, the title will reset to what you put.
for /usr/bin/xterm running in xorg-server 2:1.10.1-1ubuntu1
echo -ne "\033]0;My Fun X-Terminal\007"
The answer to this really depends on the terminal program you're using.
However, I'll just assume it's sensible, and emulates an xterm enough that it respects xterm escape codes - in which case, you probably want to look here : http://www.faqs.org/docs/Linux-mini/Xterm-Title.html#s3
Note: unwind's example below requires echo to be called like this "echo -ne", otherwise the '\' characters are echoed literally.
For the default terminal on Ubuntu (I'm still on 10.04) try xtitle.
$> sudo apt-get install xtitle
...
$> xtitle --title wow it worked!
or simply
$> xtitle this is great

Resources