Xfce Forum

Sub domains
 

You are not logged in.

#1 2020-11-14 08:18:18

Danielsan
Member
Registered: 2017-11-22
Posts: 89

Opening an application on a specific monitor and a specific workspace

Hi guys,

I tried to create a couple of commands that open Thunderbird maximized on the left monitor on the default workspace. They worked however those look like a bit cumbersome and I wonder if I can improve the commands.

The panel launcher from the left monitor uses this command:

sh -c '/usr/bin/thunderbird & sleep 3 && wmctrl -r thunderbird -t 0 | wmctrl -r thunderbird -b add,maximized_vert,maximized_horz'

The panel launcher from the right monitor uses this other command:

sh -c '/usr/bin/thunderbird & sleep 3 && wmctrl -r thunderbird -b remove,maximized_vert,maximized_horz && wmctrl -r thunderbird -t 0 | wmctrl -r thunderbird -e "0,290,0,-1,-1" && sleep 1 && wmctrl -r thunderbird -b add,maximized_vert,maximized_horz'

Especially the latter looks like very amateur... What do you think?

Thanks,

D.

Last edited by Danielsan (2020-11-14 08:18:57)


Debian ~ Devuan & FreeBSD + XFCE = <3

Offline

#2 2020-11-14 13:18:40

alcornoqui
Member
Registered: 2014-07-28
Posts: 832

Re: Opening an application on a specific monitor and a specific workspace

Can you install Gdevilspie? It's a GUI for devilspie2 that (I heard) makes those operations easier to achieve.

Offline

#3 2020-11-15 16:02:28

Danielsan
Member
Registered: 2017-11-22
Posts: 89

Re: Opening an application on a specific monitor and a specific workspace

The problem I have with devilspie it is because I don't want a daemon running in background just to open a bunch a of programs in certain way, many WMs have those features by default, XFCE should provide the same features as well...


Debian ~ Devuan & FreeBSD + XFCE = <3

Offline

#4 2020-11-15 19:35:43

gusnan
Member
Registered: 2011-07-12
Posts: 3

Re: Opening an application on a specific monitor and a specific workspace

alcornoqui wrote:

Can you install Gdevilspie? It's a GUI for devilspie2 that (I heard) makes those operations easier to achieve.

No, that is a GUI for devilspie (without the 2) - I am the developer of devilspie2 (and neither 1 or 2 is under development any longer unfortunately). I don't know of any similar GUI tool for devilspie2.

Offline

#5 2020-11-16 07:31:48

Signy
Member
Registered: 2020-10-20
Posts: 52

Re: Opening an application on a specific monitor and a specific workspace

I use the same approach with wmctrl with one difference: I made a script my_windows_move which moves windows. Script itself is:

#!/bin/bash
# Move working windows into its correct desktops

# Input file - SRC data
inpf=~/bin/$(basename $0).input

while IFS='' read -r line || [[ -n "$line" ]]; do
  #echo "Text read from file: $line"
  #desknum=$(echo $line| sed -r 's/^([0-9]+) .*$/\1/')
  #echo "Desknum: $desknum"
  
  # Pattern for correct input line
  pat="^[0-9]+ .+"
  if [[ $line =~ $pat ]]; then
    desknum=$(echo $line| sed -r 's/^([0-9]+) .*$/\1/')
    title=$(echo $line| sed -r 's/^[0-9]+ (.+)$/\1/')
    echo "Desknum: $desknum, title: $title"

    # Get title id from title substring
    tid=$(wmctrl -l | grep "$title" | cut -d ' ' -f1)
    for n in $tid ; do
      echo "Found id: $n, moving..."
      wmctrl -i -r $n -t $desknum
    done
  fi
done < "$inpf"

and this script reads data from a config file with the same name as the script + ".input" my_windows_move.input. The input file looks like this:

# Configuration file for my_windows_move
# Format:
#  desktop_number window_substring
#
# window_substring - can have non backslashed spaces
#
# desktop_number in wmctrl:
#      0 | 1 | 2
#      ---------
#      3 | 4 | 5
#

5 Thunderbird
3 SSL/SSH VNC Viewer
1 gFTP

I have another script which runs all applications I use most of days (the 3 above are just an example) and once all of them are running (some of them need me to type a password) I click on a shortcut and move windows into desired desktops.
For your purpose there would be necessary to add reading and using position coordinates of windows... Something like this I use only for Firefox and Vivaldi - I am bothered by the fact that XFCE can open many Thunar windows on proper desktops and positions, but it is not able to do the same with FireFox and Vivaldi (which is probably the applications fault). So I made another script, which I call before logout (I made a button which calls my personal logout script and then it makes shutdown/logout/reboot):

windows_positions --save

and the next day, after Firefox and Vivaldi are started:

windows_positions --restore

and the script windows_positions itself:

#!/bin/bash
# Move working windows into its correct places

usage="Usage: $(basename "$0") operation\n Operations:\
\n   --save     - saves windows position\
\n   --restore  - restores windows position"
operation=$1;[ -z "$operation" ] && echo -e "$usage" && exit 0

# Basic configuration 
#
# Config file - same filename as current script name
cfgdir=~/.config/$(basename "$0")
cfg=$cfgdir/$(basename "$0").cfg
cfgt=$cfg.tmp
hostname=$(hostname)

# Array of applications to be saved (exact class, not only substring)
applications=("Navigator.Firefox" "vivaldi-stable.Vivaldi-stable")

# Diff between save and restore positions via wmctrl (what the hell???)
# (subtract diff before restoration)
diff_x=10
diff_y=44
#
# End of basic configuration

save_cfg () {
  if [[ ! -d $cfgdir ]]; then
    mkdir "$cfgdir"
  fi
  echo "Saving configuration to $cfg..."
  { echo -e "# This is windows position config file for script $(basename "$0")"
    echo -e "# Saved positions for wmctrl command"
    echo -e "# Generated by: $(basename "$0") --save\n"
    echo -e "# Class must be defined first, followed by its titles until the next class.\n"
    echo -e "# Format:"
    echo -e "# minimized desktop_number position_x position_y width height win_title\n" 
  } > "$cfgt"

  local p title a states minim i

  for app in "${applications[@]}"; do
    { echo -e "\n# Application class: $app"
      echo -e "class=$app"
    } >> "$cfgt"

    # Separator \n, separated lines into an array
    IFS=$'\n' props=( $(wmctrl -lGx | grep "$app") )
    # $p format (wmctrl -lGx):    id desknum x y width height class hostname title
    # $a format                    0    1    2 3   4     5       6     7      8-x
    # Pattern to remove anything except title
    # Format: id        gravity   x       y      width   height class  hostname  title
    pat="^0x[0-9a-f]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +$app +$hostname +(.+)$"
    for p in "${props[@]}"; do
      title=$(sed -r "s/$pat/\1/" <<< "$p")
      #echo "Title:    $title"

      # Convert line to array
      IFS=' ' a=($p)
      # echo "ID okna: ${a[0]}"
      # Get state (minimized/non-minimized) of ${a[0]} window
      states=( $(xprop -id "${a[0]}" | grep "window state") )
      # echo "State: ${states[2]}"
      # Window state Iconic = minimized
      if [[ ${states[2]} == Iconic ]]; then
        minim=1
      else
        minim=0
      fi
      #echo "State: ${states[2]}, minimized: $minim"
      # Save minim desknum   x      y       width   height title
      echo "$minim ${a[1]} ${a[2]} ${a[3]} ${a[4]} ${a[5]} $title" >> "$cfgt"
    done
  done
  # Rotate 5+1 backup files
  if [[ -f "$cfgt" ]]; then
    for i in {5..1..-1}; do
      if [[ -f "$cfg.$i" ]]; then
        #echo "mv $cfg.$i $cfg.$(( i+1 ))"
        mv "$cfg.$i" "$cfg.$(( i+1 ))"
      fi
    done
    if [[ -f "$cfg" ]]; then
      #echo "cp $cfg $cfg.1"
      cp "$cfg" "$cfg.1"
    fi
    # Move tmp config file into current config file
    #echo "mv $cfgt $cfg"
    mv "$cfgt" "$cfg"
  fi
  echo "Configuration saved."
}

process_window () {
  # Params: id desknum winvar
  # Minimize a unminize must be first, the can move a window to current desktop
  if [[ $minimized -eq 1 ]]; then 
    xwit -iconify -id "$1"
  else
    xwit -pop -id "$1"
  fi
  # Resize (-e) and move (-t) window must be done separately
  # echo "wmctrl -i -r $n -e $3"
  wmctrl -i -r "$1" -e "$3"
  wmctrl -i -r "$1" -t "$2"
}

restore_cfg () {
  echo "Restoring widows from $cfg..."
  local cpat cpati lpat tpat cfgvar maxdesk line class appwindows
  local patlx a minimized desknum pos_x pos_y winvar ctitle 
  local lwindow twindow tid
  # Pattern for class defining line
  cpat="^class="
  cpati=${cpat}.+
  # Pattern for correct input line
  lpat="^[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ .+"
  # Pattern what remove to get title from config file
  tpat="^[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +(.+)$"

  # Preprocess config file $cfg into $cfgvar
  # Remove comments and empty lines
  cfgvar=$(grep -v '^[[:space:]]*#' "$cfg" | grep -v -e '^[[:space:]]*$')
  #echo -e "Cfgvar:\n$cfgvar"

  # Maximal number of running desktops
  maxdesk=$(wmctrl -d | tail -n 1 | cut -d ' ' -f1)

  # Go through pre-processed config variable
  while IFS='' read -r line || [[ -n "$line" ]]; do
    # Only lines with defined pattern will be processed
    if [[ $line =~ $cpati ]]; then
      # Find new class and its running application windows
      class=$(sed -r "s/$cpat//" <<< "$line")
      echo -e "\nNew class: $class"
      # Find running application windows (based on class)
      appwindows=$(wmctrl -lx | grep -F "$class")
      #echo -e "Appwindows: \n$appwindows\n"
      # Pattern to remove anything except title from wmctrl -lx
      # Format: id        desknum class  hostname  title
      patlx="^0x[0-9a-f]+ +[0-9]+ +$class +$hostname +(.+)$"

    elif [[ $line =~ $lpat && ! -z $appwindows ]]; then
      # Convert cfg line to array
      IFS=' ' a=($line)
      minimized=${a[0]}
      desknum=${a[1]}
      # Apply diff between save and restore via wmctrl
      pos_x=$(( a[2]-diff_x ))
      pos_y=$(( a[3]-diff_y ))
      # winvar for wmctrl = gravity,x,y,width,height    gravity=0
      winvar="0,$pos_x,$pos_y,${a[4]},${a[5]}"
      # Title from cfg
      ctitle=$(sed -r "s/$tpat/\1/" <<< "$line")
      echo -e "\nNew window from cfg:"
      echo -e "Minimized: $minimized, desknum: $desknum, cfg title: $ctitle"
      #echo "Win variables: $winvar"
      if [[ $desknum -gt $maxdesk ]]; then
        desknum=$maxdesk
        echo "Desknum exceeded number of desktops, fixed to: $desknum"
      fi
      echo " "

      # Go throuth all appwindows with the title (grep substing)
      # Processed window is in lwindow (List window)
      while read -r lwindow; do
        # Real window title
        rtitle=$(sed -r "s/$patlx/\1/" <<< "$lwindow")
        echo -e "Going to exact compare of real title: $rtitle"
        if [[ "$ctitle" == "$rtitle"  ]]; then
          # Exact title found, save it and stop searching
          twindow=$lwindow
          break
        fi
      done <<< "$(grep -F "$ctitle" <<< "$appwindows")"

      # If a running window was found, process it.
      if [[ ! -z $twindow ]]; then
        echo "Running twindow found: $twindow"
        tid=$(cut -d ' ' -f1 <<< "$twindow")
        # Once twindow processed, empty variable
        unset twindow
        echo -e "Found id: $tid, moving..."
        process_window $tid $desknum $winvar
        # Remove processed line (identified by $tid) from $appwindows
        appwindows=$(grep -v "^$tid" <<< "$appwindows")
        #echo -e "\nCurrent appwindows:\n$appwindows\n"
      else
        echo "Exact title from cfg was not found among running windows."
      fi
    fi
  done <<< "$cfgvar"
}

###      Main run
if [[ "$operation" == --save ]]; then
  save_cfg
  exit 1
elif [[ "$operation" == --restore ]]; then
  restore_cfg
  exit 1
fi
exit 0

It is not perfect but it works well with pages which does not change title before --save and --restore.

These scripts are probably just for inspiration and probably not sufficient for your purpose.

Another approach could be a script which could read info from ~/.cache/sessions/xfwm4-*.state and restore windows according saved session info...

Offline

Registered users online in this topic: 0, guests: 1
[Bot] ClaudeBot

Board footer

Powered by FluxBB
Modified by Visman

[ Generated in 0.007 seconds, 12 queries executed - Memory usage: 577.08 KiB (Peak: 594.05 KiB) ]