#!/usr/bin/perl # (c) Denis Kaganovich, Anarchy or GPLv2 # OpenBox3 pipe menu v0.20 # ob3menu {-- {params}} # --slow [ [XxY]] # --compact # --autostart {profile} # --include {menu to include} # --profile {profile} # --mime {dirs} # --launcher <~/.cache/ya/desk.+.jpg> <~/.cache/ya/desk-sh> [ []] # geometry = x,y,vert?,xx,yy,spliceX,spliceY,left?,bottom? # --tint2 [] # --tint2launcher # --dock # --multiserver # --svg # --low [{unwanted} [+ {preferred}]] # --theme {theme} # "--slow" - +keybinds, 3.5.0+ menu icons, better with cache. # # OnlyShowIn is specified, but I newer want it. But you can think else. # Consensus: listed as "? ..." # # Launcher: starting to do fullscreen trendy "desktop", I see I don't need it, but need # small launcher near tint2... So, fast partial... $bin='/usr/bin/'; $HOME=$ENV{HOME}; #@xinerama=('--xinerama-index','0'); @xinerama=('--no-xinerama'); # pan $SIG{__DIE__}=sub{ print STDERR ($e=join('',"$0: ",@_)); exists($ENV{DBUS_SESSION_BUS_ADDRESS}) && exec($bin.'notify-send','-t',6000,$e); }; $tint2font=1; # = ob MenuItem, *fontsize $monitor='all'; $panel_size2=2; # *fontsize my (%ico,%key,%cat,%cat1,%dir,@prof,$prof); #$misc='Other'; $misc='misc'; %base=%cc=( # http://standards.freedesktop.org/menu-spec/menu-spec-1.1.html 'AudioVideo'=>10000, 'Audio'=>10000, 'Video'=>10000, 'Development'=>10000, 'Education'=>10000, 'Game'=>10000, 'Graphics'=>10000, 'Network'=>10000, 'Office'=>10000, 'Settings'=>10000, 'System'=>10000, 'Utility'=>10000, # 'Autostart'=>0, 'Other'=>-1, $misc=>-1, ); %cname=( 'Multimedia'=>'AudioVideo', 'Utility'=>'Accessories', 'Accessories'=>'Utility', 'Other'=>'Application', 'InternetAndNetwork'=>'Network', ); %xml_=('<'=>'lt','>'=>'gt',"'"=>'apos','"'=>'quot','&'=>'amp'); $xml_='<>\'"&'; %notify=( 'true'=>'yes', 'false'=>'no' ); %ico_=( 'fs'=>['mount-point'], 'umount'=>['usbpendrive_unmount','gdu-unmount'], 'mount'=>['xfce-mount','gdu-mount'], ); $ma='Apps'; $mimemenu='_app'; %CatMime=( 'WebBrowser'=>['x-scheme-handler/http','x-scheme-handler/https'], # 'seamonkey.desktop'=>[], ); @conf=(['showIcons'],['dock',['position'],['direction']],['font place="MenuItem"',['name'],['size'],['weight'],['slant']]); $id=0; %noico=('svg'=>1,'xpm'=>1); %prefico=('svg'=>1); $defapps={}; %mimeapps=('Default Applications'=>$defapps); for(@ARGV){ if($_=~s/^--//){ undef $P{$i=$_}; }else{ push(@{$P{$i}},$_); } } for($ENV{LANG}=~/([a-zA-Z0-9]+)?(_\w+)?(\.[\w-]+)?(\@\w+)?/){ $lang.='(?:'.quotemeta($_).')?' if(defined($_)); } $lang='(?:\['.$lang.'\])?' if($lang); @path=split(/:/,$ENV{PATH}); if(exists($P{profile})){ $prof=join('|',@{$P{profile}}); }elsif($prof=$ENV{YA_PROFILE}){ $prof=~s/[, ]+/|/g; } sub eXist{ if(index($_[0],'/')>=0){ stat($_[0]); return(-x _ && -f _); } for(@path){ stat("$_/$_[0]"); return 1 if(-x _ && -f _); } 0; } sub icons{ opendir(my $D,$_[0])||return; my @d=readdir($D); closedir($D); my $l=$_[2]+1; if($l<4){ @d=$low?%low? sort{$low{$b}<=>$low{$a} || length($b)<=>length($a) || $b cmp $a} @d: sort{length($b)<=>length($a) || $b cmp $a} @d: sort{length($a)<=>length($b) || $a cmp $b} @d; } if($_[1]){ for(@d){ my $p=$_[0].$_; if(my ($i,$j)=$_=~/^(.*)\.(...)$/){ $ico1{$_}=$p; $ico1{$i}=$p if(!exists($noico{$j})); }elsif(!($_=~/^\.*$/)){ icons("$p/",1,$l); } } }else{ for(@d){ my $p=$_[0].$_; if(my ($i,$j)=$_=~/^(.*)\.(...)$/){ $ico{$_}=$p; $ico{$i}=$p if(!exists($noico{$j})); }elsif(!($_=~/^\.*$/)){ icons("$p/",$_=~/$THEME/,$l); } } } } sub ico{ for(@_){ for(@{$ico_{$_}},$_){ return " icon='$ico{$_}'" if(exists($ico{$_})); } } } sub _read{ open(my $F,$_[0])||return; my $l=$_[1]; if(!defined($l)){ flock($F,1); $l=-s $F; } my $s; if($l){ sysread($F,$s,$l); }else{ while(defined(my $x=<$F>)){$s.=$x}; } close($F); $s; } sub _write{ my $f=$_[0]; my $l=length($_[1]); return 2 if($l eq (-s $f) && _read($f,$l) eq $_[1]); open(my $F,'>',$f.='$$$')||return; flock($F,2); $_[2] && chmod($_[2],$F); (syswrite($F,$_[1],$l) eq $l && close($F) && rename($f,$_[0])) && 1; } sub _fork{ fork() && return 1; close(STDOUT); open STDOUT,">&2"; 0; } sub _restart{ # xkill don't properly close tray [on some X], so tray icons not restarting # try to kill by pid first my ($p,$get,@p)=@_; return if(!$get && _fork()); my $d=quotemeta($ENV{'DISPLAY'}); my ($w,$chk); my $p1="$p @p"; my $n=$p; $n=~s/^.*\///g; if (!@PIDS) { for(glob('/proc/*/environ')){ next if (! -r $_); my ($pid)=$_=~/^\/proc\/([0-9]+)/; my $s=_read("/proc/$pid/cmdline",0); $s=~s/\0/ /gs; $s=~s/ $//gs; if ($s eq $p1){ $chk=1; }else{ $s=~s/ .*//gs; next if ($s ne $p); } push @PIDS,$pid if(_read($_,0)=~/(?:^|\x0)DISPLAY=$d(?:\x0|\$)/s); } } return if($get && ($chk || _fork())); if(@PIDS){ system('kill',@PIDS); while(map{-e "/proc/$_" || ()}@PIDS){sleep(1)}; } if($^O eq 'linux' || !($ENV{'DISPLAY'}=~/^\:0\.?/) || exists($P{multiserver})){ system($bin.'xkill','-id',$w) if(($w)=`${bin}xwininfo -name $n`=~/ Window id: (0x\S+) /s); }else{ system('killall','-w',$p,'-u',$ENV{'USER'}); } sleep(1) if(@PIDS || $w); # font exec($p,@p); die $!; } sub tint2set{ my $v=$_[0]; $tint2_=~s/^[ ]*($v)[ ]*\=[ ]*([^\n]*?)[ ]*$/ my @x=$_[1]==-1?(0):split(\/\s+\/,$2); $x[$_[1]]=$_[2]; "$1 = @x" /emg; $t2d.="@_ " if(!$_[3]); } sub tint2get{ my $x=$_[0]; ($x)=$tint2_=~/^[ ]*$x[ ]*=[ ]*([^\n]*?)[ ]*$/m; $x=$_[1]==-1?$x:(split(/\s+/,$x))[$_[1]]; $x; } # CRC32 code derived from work by Gary S. Brown. sub crc32{ my $c=$_[1] ^ 0xffffffff; $c=$crc[($c ^ ord(substr($_[0],$_,1))) & 0xFF] ^ ($c >> 8) for(0..length($_[0])-1); $c ^ 0xffffffff; } # cache-style hashed group naming sub newname{ my ($name,$key)=@_; # utf8::encode($key); $key=crc32($key); $_[0]=~s/\+/kEy.$DSP2.$key/gs or return 1; return 0 if(-e $_[0]); # exists if($DSP2 eq $DSP){ # by display my $d=$name; $d=~s/\+/kEy.*.$key/gs; if(my @d=glob($d)){ link($d[0],$_[0])|| ($_[0]=$d[0]); return 2; # same file for other head } } $name=~s/\.[a-z0-9]*$//i; $name=~s/\+/kEy.$DSP2.*/gs; my @l=glob($name); die "Deleting '$name': $!\n" if(@l && !unlink(@l)); 1; } sub _tag{ my $i1=my $i=$_[2]; $i1=~s/\s.*$//g; my ($s)=$_[0]=~/<$i>(.*?)<\/$i1>/s; # $i=$_[1].'.'.$i; $i=$_[1].'.'.$i1; # now ok just 'font' if($#_==2){ $conf{$i}=$s; }else{ _tag($s,$i,@$_) for(@_[3..$#_]); } } sub prop{ if(!defined($prop)){ $prop={}; # obxprop deadloop on window my $s=defined($_[1])?"xprop -id $_[1]":'obxprop --root'; $s=`$bin$s`; $s=~s/^([A-Z0-9_]*)\([A-Z0-9_]*\) = (\"[^\"]*\"(?:, \"[^\"]*\")*|[^\n]*)$/$prop->{$1}=$2;''/gme; } $prop->{$_[0]}; } sub _xdg_mime{ my ($a,$d,@t)=@_; my $f="$HOME/.local/share/applications/mimeapps.list"; my $s=_read($f); my $p0='Default Applications'; my $p=$p0; my $i; if(!defined($s)){ mkdir($i.=$_) for("$HOME/.local",'/share','/applications'); } while(@t){ $s=~s/^(\[$p\]\n[^\[]*)$/ my $x=$1; for(@t){ $i=quotemeta($_); $x=~s\/\n$i=[^\n]*\/\/sg; } $x; /mge; if($a ne '-'){ $s.="\n[$p]\n" if(!($s=~/^\[$p\]$/m)); $i=($a=~/\d/)?$a:''; $s=~s/((?:^|\n)\[$p\]\n(?:\_[^\n]*\n){0,$i})/$1$_=$d\n/s for(@t); $a='-'; }elsif($p eq $p0){ $i=quotemeta($d); if(!($s=~/\[$p\][^\[]*\=$i$/m)){ @t=("$mimemenu/$d") }elsif(@t=grep(/^$mimemenu\//,@t)){ $a='+' } } last if($p ne $p0); $p='Removed Associations'; } _write($f,$s); } sub fontsize2{ my $s=tint2get('panel_size',1)-tint2get($_[0].'_padding',1); # *2, but see not differences by simple change tint2set($_[1],'[12]_font',-1,$_[2].($s>>1)); } sub tint2{ defined($tint2_)||return; if($tint2font){ my $f=$conf{'.font.name'}.' '.$conf{'.font.weight'}.' '.$conf{'.font.slant'}.' '; $f=~s/normal //g; fontsize2('clock','time',$f); fontsize2('battery','bat',$f); fontsize2('execp','execp',$f); $f.=int($conf{'.font.size'}*$tint2font); tint2set('(?:task|tooltip)_font',-1,$f); } _restart($bin.'tint2',_write($tint2[-1],$tint2_)!=1,'-c',$tint2[-1]); $tint2_=undef; } if(exists($P{$ma})){ if(@{$P{$ma}}){ _xdg_mime(@{$P{$ma}}); exit; } $mapps=1; $ID=join(':',$ma,$P{$ma},''); } $subcmd.=" --slow"; if(exists($P{slow})){ $mapps=1; if(!exists($P{$ma})){ $configs{$_}=1 for(glob("${0}_*")); } ($fconf,@XY)=@{$P{slow}}; ($X[$_],$Y[$_],$X1[$_],$Y1[$_])=split(/[x\+]/,$XY[$_]) for(0..$#XY); $X=shift @X; $Y=shift @Y; shift @X1; shift @Y1; if(!($fconf && $X && $Y)) { ($X,$Y)=prop('_NET_DESKTOP_GEOMETRY')=~/(\d+), (\d+)/; ($fconf)=prop('_OB_CONFIG_FILE')=~/\"(.*)\"/; } # first or growing ($XX,$YY)=($X[0],$Y[0]); if($#Y>0){ @xi=@xinerama; $monitor=1; for(0..$#Y){ if($X==$XY[$_] && $Y==$XY[$_]){ ($monitor,$XX,$YY,@xi)=($i); last; } } } $XX||=$X; $YY||=$Y; ($X,$Y)=($X[0],$Y[0]) if($#xi==1); # wallpaper id $DSP2=$X.'x'.$Y; $subcmd.=" "$fconf""; if(defined(my $s=_read("<$fconf"))){ _tag($s,'',@$_) for(@conf); $P{'slow'}=$conf{'.showIcons'} eq 'yes'; $s=~s/\s*.*?(.*?)<\/command>/$key{$2}=$1;''/gse; $fconf=~s/[^\/]*$//g; $vanilla=$fconf=~/\/openbox$/; } $THEME='(?:'.join('|',@{$P{'theme'}}).')'; for(keys %noico){ if(exists($P{$_})){ delete($noico{$_}); }else{ delete($prefico{$_}); } } if($low=exists($P{'low'})){ my ($i,$s)=($#ARGV,-1); for(@{$P{'low'}}){ if($_ eq '+'){ ($i,$s)=(-$#ARGV,1); }else{ $low{$_}=$i+=$s; } } } icons('/usr/share/icons/'); icons('/usr/share/pixmaps/'); icons($HOME.'/.local/share/icons/'); icons($HOME.'/.local/share/pixmaps/'); if(%prefico){ my @l=keys %prefico; my $l=$#l?'(?:'.join('|',@l).')':$l[0]; for $i ('ico','ico1'){ for(grep(/\.$l$/,keys %{$i})){ ${$i}{substr($_,0,-4)}=${$i}{$_} if(exists(${$i}{$_})); } } } if(%noico){ my @l=keys %noico; my $l=$#l?'(?:'.join('|',@l).')':$l[0]; for $i ('ico','ico1'){ for(grep(/\.$l$/,keys %{$i})){ my $n=substr($_,0,-4); ${$i}{$_}=${$i}{$n} if(exists(${$i}{$n})); } } } %ico=(%ico,%ico1) if(%ico1); } if(($X && $Y) || $mapps){ for(split(/\s+/,$ENV{YA_APP}),split(/\s*[\r\n]+\s*/,_read('<'.$fconf.'preferred-apps'))){ if(substr($_,-8) eq '.desktop'){ $defapps->{$_}=undef; }else{ my $x=$_; push(@apps,($x=~s/.*\///gs)?[$x,$_,$_]:[$_,$x="/usr/bin/$x",$_]); $apps{$x}=$apps{$_}=undef; } } for(map{("$_/mimeapps.list","$_/defaults.list")}("$HOME/.local/share/applications",'/usr/share/applications')){ my ($x,$i); open(my $F,'<',$_) or next; while(defined($s=<$F>)){ if($s=~s/^\s*\[(.*)\]\s*$/$1/){ $x=$s; $i=0; }elsif(($m,$s)=$s=~/^(.*)=(.*?)\s*$/m){ $mimeapps{$x}->{$m}->{$_}=$mimeapps{$x}->{$_}->{$m}=++$i for(split(/;/,$s)); } } close($F); } $napps=scalar(grep(/^$mimemenu\//,keys %$defapps)) if($mapps); if (exists($P{tint2launcher})){ my %a; for(grep(/\.desktop$/,keys %$defapps)){ my $i=$_; $i=~s/^.*\///s; $a{$i}=undef; delete($defapps->{$_}); } $tint2l=join("\n",'',(map{"launcher_item_app = $_"} sort keys %a),'') if(%a); } } for $f(map{glob $_}('{/usr,~/.local}/share/applications/{,*/}*.desktop','/usr/share/ya-layout/Desktop/{,exit/}*.desktop','/etc/xdg/autostart/*.desktop','{/usr,~/.local}/share/desktop-directories/*.directory')){ my (%d,%dd,%en,$F,$c); if(($i)=$f=~/\/([^\/]*)\.directory$/){ if($prof){ $i=~s/^(?:$prof)-//i or next; }else{ $i=~s/^[^-]*-//i; } $i=join('',map{ucfirst($_)}(split(/-/,$i))); open($F,"<$f")||next; while(<$F>){ if(($k,$l,$v)=$_=~/^\s*([^#\s=\[\]#]+)($lang)\s*=([^#\n\r]*)/is){ $dd{$c}->{$k}->{$l}=$v; }elsif(($k)=$_=~/^\s*\[(.*)\]\s*/s){ $c=$k; } } close($F); %d=%{$dd{'Desktop Entry'}}; $en{$i}=$en{$d{Name}->{''}}=1; # same can be in next block (else) too, but fixme: # in all known *.desktop "Name=" come before "Name[...]=". So, just can use more CPU. # Here we need "Name=" too. $_=$_->{(sort keys %$_)[-1]} for(values %d); }else{ open($F,"<$f")||next; while(<$F>){ if(($k,$v)=$_=~/^\s*([^#\s=\[\]#]+)$lang\s*=([^#\n\r]*)/is){ $dd{$c}->{$k}=$v; }elsif(($k)=$_=~/^\s*\[(.*)\]\s*/s){ $c=$k; } } close($F); %d=%{$dd{'Desktop Entry'}}; exists($d{Exec}) || next; } next if(exists($d{TryExec}) && !eXist($d{TryExec})); $d{Exec}="${bin}ya-session --run +$d{Exec}" if($d{Terminal} && lc($d{Terminal}) ne 'false'); if(!exists($d{Name})){ for(Comment,Exec){ if(exists($d{$_})){ $d{Name}=$d{$_}; goto N; } } next; } N: if($prof && exists($d{OnlyShowIn}) && !($d{OnlyShowIn}=~/(?:^|;)(?:$prof)(?:;$)/i)){ $d{Name}="? $d{Name}" } $i=''; ~s/([$xml_])/\&$xml_{$1};/g for(values %d); $icon=undef; if(exists($P{slow}) && exists($d{Icon})){ $i=$d{Icon}; $i=~s/.*\///g; $i=" icon='$i'" if($i=$icon=$ico{$i}||(index($i,'/')>=0?$i:undef)); } if(substr($f,0,4) eq '/etc'){ $d{Categories}='Autostart'; if(exists($P{autostart})){ my $i; if(($i=join('|',@{$P{autostart}})||$prof) && !exists($d{OnlyShowIn}) || grep(/^(?:$i)$/i,split(';',$d{OnlyShowIn}))){ print STDERR "$d{Exec} &\n"; $d{Name}="+ $d{Name}"; } } } if($d{Type} eq 'Application'){ my (@def,@m1,@m2,$ff,$l); $ff=$f; $ff=~s/.*\///g; $_=[split(/;/,$_)] for($d{Categories}); $mimeapps{'Added Associations'}->{$ff}->{$_}=$mimeapps{'Added Associations'}->{$_}->{$ff}=1 for(split(/;/,$d{MimeType}),"$mimemenu/$ff",map{@{$CatMime{$_}}}@{$d{Categories}},$ff); for my $x(keys %{$mimeapps{'Removed Associations'}->{$ff}}){ delete($_->{$ff}->{$x}) && delete($_->{$x}->{$ff}) for($mimeapps{'Added Associations'},$defapps); %{$defapps->{$x}} || delete($defapps->{$x}); } %{$defapps->{$ff}} || delete($defapps->{$ff}); $d{MimeType}=[keys %{$mimeapps{'Added Associations'}->{$ff}}]; $d{Exec}=~s/\s+%\w$//; $d{Name}.=" [$key{$d{Exec}}]" if(exists($key{$d{Exec}})); if($mapps){ for(sort @{$d{MimeType}}){ if(!exists($defapps->{$_})){ push @def,$_; }elsif(!exists($defapps->{$_}->{$ff})){ push @m2,"$0 --$ma + $ff $_"; next; } if($_ eq "$mimemenu/$ff"){ push @m1,join('',"", (map{"$0 --$ma $_ $ff $mimemenu/$ff"}'-',0..$napps), ''); $id++; }else{ push @m1,"$0 --$ma - $ff $_" } } } if(exists($P{$ma})){ $i="$0 --$ma + $ff @def"; }else{ $i="$d{Exec}".$notify{lc($d{StartupNotify})}.'' } if(!exists($apps{$d{Exec}})){ goto NOAPPS if(!exists($defapps->{$ff})); if(!($l=exists($defapps->{"$mimemenu/$ff"}))){ push @m2,"$0 --$ma + $ff $mimemenu/$ff"; push @apps,[$d{Exec}] if($l=exists($P{$ma})); }else{ splice(@apps,$defapps->{"$mimemenu/$ff"}->{$ff}-1,0,[$d{Exec}]); } }else{ $l=1 } if(exists($P{$ma}) && ($i=~s/^.*$//)){ $id++; $i.="@m1@m2"; } if(@def){ $defapps->{$_}->{$ff}=$defapps->{$ff}->{$_}=1 for(@def); _xdg_mime('+',$ff,@def); } substr($i,13,0)=' ☑'; $apps{$d{Exec}}=[$icon,$d{Exec},$i] if($l); NOAPPS: $cat{$i}->{$_}++ || $cc{$_}++ for(@{$d{Categories}}); $cat{$i}=undef if(!exists($cat{$i})); if(exists($P{mime})){ push @{$mime{$_}},$i for(@{$d{MimeType}}); } }elsif($d{Type} eq 'Directory'){ my $d; for(keys %en){ $en{$d}||=0 if($d=$cname{$_}); $en{$d}||=0 if((($d)=$_=~/^(.*)s$/) && exists($cc{$d})); } while(my ($n,$c)=each %en){ if(($d=$d{Name}) ne $n){ $c+=2000; }elsif($i){ $c+=1000; }else{ next; } $dir_{$n}=length($d); $dir{$n}->{"$d'$i"}++; $cc{$n}+=$c; $base{$_}||=1; } } } ($_)=(sort{$_->{$a}<=>$_->{$b}||-($dir_{$a}<=>$dir_{$b})}keys %$_)[-1] for(values %dir); $_=defined($_)?[sort{$cc{$a} <=> $cc{$b}}(keys %{$_})]:[$misc] for(values %cat); push @{$cat1{pop @{$cat{$_}}}},$_ for(keys %cat); for(keys %cat){ for $i (@{delete($cat{$_})}){ push @{$cat1{$i}},$_ if(exists($cat1{$i}) && $base{$i}>0); } } $dir{$_}||="$_'" for(keys %cc); $set=$dir{'Settings'}; if(exists($P{$ma})){ print ''; }else{ print ''; } if(exists($P{tint2})){ @tint2=@{$P{tint2}}; $t2v="$HOME/.config/tint2/tint2rc"; unshift @tint2,$vanilla?($t2v):("$fconf/tint2rc"),"/etc/xdg/$prof/tint2rc",'/etc/xdg/ya/tint2rc','/etc/xdg/tint2/tint2rc' if(!$tint2[0]); for(@tint2){ if($_ && defined($tint2_=_read($_))){ $panel_items0=$panel_items=tint2get('panel_items',-1); for(glob($fconf.'/tint2add-*')){ my ($s,$i); next if(!defined($s=_read($_))); $tint2_.=$s; $panel_items.=$i if(($i)=$s=~/^#:([A-Z:]*)/s); } if(defined($tint2l)){ $tint2_.=$tint2l; $panel_items='L'.$panel_items if (!($panel_items=~/L/)); } tint2set('panel_items',-1,$panel_items) if($panel_items ne $panel_items0); $t2d=crc32($tint2_); if($_ ne $t2v){ my $s=int($conf{'.font.size'}*$panel_size2); tint2set('panel_size',1,int($conf{'.font.size'}*$panel_size2)); tint2set('panel_monitor',0,$monitor,1); tint2set('systray_icon_size',-1,"$s $s"); tint2set('task_maximum_size',-1,($s<<4)." $s"); } last; } } } if(@apps){ #if(@apps || exists($P{tint2})){ my $ico=$ico{'image-missing'}||$ico{'application-other'}||$ico{'application-x-executable'}; @apps=map{$apps{$_->[2]}||$apps{$_->[0]}||$apps{$_->[1]}||[$ico{$_->[0]}||$ico,$_->[2]]}@apps; } if(exists($P{launcher})){ umask(077); @crc=map{for(my $i=8;$i>0;$i--){$_=($_&1)?($_>>1)^0xedb88320:($_>>1)};$_}(0..255); $DSP=$ENV{'DISPLAY'}; $DSP=~s/[\\\/\*]/_/gs; $DSP.='.0' if(($DSP=~/:/) && !($DSP=~/:.*\./)); $DSP2||=$DSP; $DSP1=$DSP; $DSP1=join(',',$DSP,(map{$DSP1=~s/$_.*?$//;$DSP1}'\.','\:'),''); if(!exists($P{dock}) && !exists($P{tint2}) && (my $pid=prop('_OPENBOX_PID'))){ if(defined(my $c=_read("/proc/$pid/cmdline",0))){ my @c=split(/\x0/,$c); for(@c){ if($_=~s/(?:^|\S*\/)tint2\s+-c\s+//){ $P{tint2}->[0]=$_; unshift @{$P{tint2}},'' if(!index($_,"$HOME/.cache/")); last; } } } } my ($a,@m,$m); my ($img,$sh,$geo,@wp)=@{$P{launcher}}; my ($x,$y,$vert,$xx,$yy,$spliceX,$spliceY,$left,$bottom)=my @geo=split(/\,/,$geo,-1); my $n=($xx*$yy)||scalar(@apps); my ($sx,$sy)=($x*$xx,$y*$yy); $geo=0; $geo+=($_ ne '') for(@geo); goto NOGEO if($geo>=9); $sx||=$X-$spliceX if($spliceX); $sy||=$Y-$spliceY if($spliceY); if(!$sx && !$sy){ my ($p,$sz); if(exists($P{dock})){ $p=$conf{'.dock.position'}.$conf{'.dock.direction'}; $x=$y=66 if(!$x && !$y); }elsif(defined($tint2_)){ $sz=tint2get('panel_size',1); $p=tint2get('panel_position',-1); } if($p){ $vert=($p=~/vertical/i)||0 if($vert eq ''); goto nolauncher if(!($bottom=$p=~/bottom/i) && !($p=~/top/i)); $sz=int($sz/2) if(!($left=$p=~/left/i) && !($p=~/right/i)); ($sx,$sy)=$vert?($sz,0):(0,$sz); } if(!$sx && !$sy){ my @splice=prop('_NET_WORKAREA')=~/(\d+), (\d+), (\d+), (\d+)/; $splice[2]=$X-$splice[0] if($splice[2]>$X); $splice[3]=$Y-$splice[1] if($splice[3]>$Y); if($vert ne 1 && ($sy=$splice[1])){ }elsif($vert ne 0 && ($sx=$splice[0])){ }elsif($vert ne 1 && ($sy=$Y-$splice[3])){ $bottom=1; $spliceY=$splice[3]; }elsif($vert ne 0 && ($sx=$X-$splice[2])){ $left=1; $spliceX=$splice[2]; }elsif(exists($P{dock})){ ($sx,$sy)=$vert?(66,0):(0,66); }else{ goto nolauncher; } } } $vert=$sx && !$sy if($vert eq ''); $xx||=int($sx/$x) if($x); $yy||=int($sy/$y) if($y); $n||=$xx*$yy; # $n||goto nolauncher; $xx||=$yy?int($n/$yy)+($n%$yy!=0):$vert?1:$n; $yy||=$xx?int($n/$xx)+($n%$xx!=0):$vert?$n:1; $x=int($sx/$xx) if(!$x && $xx); $y=int($sy/$yy) if(!$y && $yy); $x||=$y; $y||=$x; $sx||=$x*$xx; $sy||=$y*$yy; NOGEO: $spliceX=($vert xor $left)?$X-$sx:0 if($spliceX eq ''); $spliceY=($vert xor $bottom)?$Y-$sy:0 if($spliceY eq ''); if(substr($sh,-2) eq 'sh'){ $a.=q([ "${DISPLAY%.0}" = ':0' ] || { . "$0.${DISPLAY//[\/\\\\_*]/_}" exit 1 } ); if($DSP ne ':0.0'){ _write($sh,$a,0700) if(!-x $sh); $a=''; $sh.='.'.$DSP } } my ($a,$c,$p,$xy)=$vert?($a.'[ $1 -lt '.($spliceX+$sx),$y,'$2',$spliceY):($a.'[ $2 -lt '.($spliceY+$sy),$x,'$1',$spliceX); $a.=($spliceX?" -a \$1 -gt $spliceX":'').($spliceY?" -a \$2 -gt $spliceY":'')." ] && {\n"; for(@apps){ $_->[0]||next; push @m,$_->[0]; $xy+=$c; $a.=" [ $p -lt $xy ] && exec $_->[1]\n"; } $a.=(@m?'':"false\n")."}\n"; @wp=() if(!@wp && ! -r ($wp[0]=(glob("$fconf/wallpaper{$DSP1}.*"))[0])); # for top-left & !composite & !svg cmd use feh, else - ImageMagick # todo: since openbox support svg, think about un-feh. bud feh still thin if(!@m){ @m=($bin.'feh','-m','-s','-W',$X,'-H',$Y,'-y',0,'-E',0,$wp[0],'-b',$wp[0],'-O') if($wp[0]); }elsif(!$spliceX && !$spliceY && $yy==1 && ($#wp<1||$wp[1] eq '-a') && ! grep(/\.svg$/,@m)){ # $wp[0]||='trans'; # artefacts @wp && unshift(@wp,'-b'); @m=($bin.'feh','-m','-s','-W',$X,'-H',$Y,'-y',$x,'-E',$y,@m,@wp,'-O'); }else{ my $f='miff:-'; if(@wp){ $m=" $f |${bin}composite -background none -compose atop $f -resize ${X}x$Y! @wp"; } $m="${bin}montage -background none -geometry ${x}x$y -tile ${xx}x$yy @m $f |${bin}convert -background none -splice ${spliceX}x$spliceY $f -extent ${X}x$Y$m"; } if(defined($tint2_)){ my $sz; my @margin=(0,0);; my $pad=0; @wp || tint2set('disable_transparency',0,1); if(tint2get('autohide',0) && !tint2get('panel_background_id',0)){ if($vert){ $sz=$YY+$sy; $margin[1]=-($pad=$sy); }else{ $sz=$XX+$sx; $margin[0]=-($pad=$sx); } tint2set('wm_menu',0,1); }else{ $sz=$vert?$YY-$sy:$XX-$sx; } if($pad || tint2get('panel_size',0)>($vert?$Y:$X)){ tint2set('panel_margin',$_,$margin[$_]) for(0,1); tint2set('panel_padding',0,$pad); } tint2set('panel_size',0,$sz-2) if($sz>1); } $?=0; $i=newname($img,($m||"@m").$img.$t2d)||(-e $sh ?0:2); $i && _fork() && goto NOFORK; tint2(); goto (nolauncher,NEWIMG,NEWSH,DRAW)[$i]; NEWIMG: unlink($sh); if($m){ $out=`( $m $img ) 2>&1`; }elsif(@m){ system(@m,$img); }else{ $img=undef; } NEWSH: if($?){ system($bin.'notify-send',$out='Picture montage failed: '.($m||"@m")." $img \n$out"); print STDERR $out,"\n"; exit; }elsif(!_write($sh,$a,0700)){ exit; } DRAW: system($bin.'xsetroot','-solid','black') if(!$img || $#xi==1); $img && ( (@xi && !system($bin.'feh','--no-fehbg',@xi,'--bg-center',$img)) || system($bin.'feh','--no-fehbg','--bg-tile',$img) ); exit; NOFORK: $tint2_=undef; }else{ if (exists($P{compact})){ print ""; $id++; } print((map{ if($#$_==1){ $_->[1]=~s/([$xml_])/\&$xml_{$1};/g; $_->[2]="$_->[1]"; } $_->[2]; }@apps)); exists($P{compact}) && print ""; print ''; } nolauncher: tint2(); for(sort{$dir{$a} cmp $dir{$b}}keys %cat1){ print ""; $id++; } print ''; } if(exists($P{$ma})){ print ''; exit; } for(map{glob $_}(@{$P{include}})){ if(open(my $F,(-x $_)?"$_|":"<$_")){ print('',(<$F>)); close($F); } } if(defined($P{mime})){ for(values %mime){ for(@$_){ ($_=~s/(){ chomp($s); ($i,$t)=split(/:/,$s); $g{$t}->{$i}=undef if(exists($mime{$i})); } close($F); print ""; while(($t,$i)=each %g){ for $i(keys %$i){ $m{$t}->{$_}=undef for(@{$mime{$i}}); } } %g=(); while(($t,$i)=each %m){ $g{join('',sort keys %$i)}->{$t}=undef; } my $fold=ico('folder'); open($F,'>',$t=shift(@{$P{mime}}))||die $!; for my $D(@{$P{mime}}){ # ( -r $D ) && print ""; $id++; } $i=1; if($> && open($FF,'<','/etc/fstab')){ $i=0; while(<$FF>){ if($_=~/^(?:[^\s#]+\s+){3}(?:\S*,)?users?(?:,\S*)?\s/g){ $i=1; last; } } close($FF); } print map{""}('fs',$i?('mount','umount'):()); print $F q(#/bin/bash xml(){ x="${f//&/&}" x="${x///>}" x="${x//\'/'}" x="${x//\"/"}" } f="${1%/}" xml # avoid automount on ls|stat symlinks a=false case "$f" in /mnt/auto/disk/*/*\);; /mnt/auto/disk/*\)a=true;f="/dev${f#/mnt/auto}";; esac echo "" for f in "$f"/*; do if $a; then i=`readlink -f "$f"` && grep -qs "\":$i\"$" /var/run/auto.dev || continue f="/mnt/auto${f#/dev}" fi xml X="${x//\\/\\\\}" X="${X//\$/\\\$}" X="${X//"/\\"}" F="${X##*/}" X=""$X"" if $a || [ -d "$f" ]; then $a || [ -e "$f" ] && echo "" else ( [ -x "$f" ] && echo "${bin}ya-session --run +$X" ) || [ -r "$f" ] && case "${f,,}" in ); while(($i,$t)=each %g){ print $F lc(join('|',keys %$t)),")echo \"$i\";;&\n"; } print $F 'esac fi done echo ""'; close($F); } `${bin}tint2 -c $P{tint2}->[0] >&2 &` if(exists($P{'init'}) && exists($P{'tint2'})); print ''; for(sort keys %configs){ $i=substr($_,length($0)+1); print ""; $id++ } $i="/usr/bin/xkbswitch"; $i="$i" if (-x $i); print qq( $i );