2004-05-02 20:59:29 +00:00
// MenuCreator.cc for Fluxbox
// Copyright (c) 2004 Henrik Kinnunen (fluxgen at users.sourceforge.net)
// and Simon Bowden (rathnor at users.sourceforge.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
2004-06-10 11:43:24 +00:00
// $Id: MenuCreator.cc,v 1.9 2004/06/10 11:43:24 fluxgen Exp $
2004-05-02 20:59:29 +00:00
# include "MenuCreator.hh"
# include "Screen.hh"
# include "CommandParser.hh"
# include "fluxbox.hh"
# include "CommandParser.hh"
# include "Window.hh"
# include "FbMenu.hh"
# include "IconMenu.hh"
# include "WorkspaceMenu.hh"
# include "LayerMenu.hh"
# include "SendToMenu.hh"
# include "FbMenuParser.hh"
# include "StyleMenuItem.hh"
2004-06-07 11:46:05 +00:00
# include "FbTk/I18n.hh"
2004-05-02 20:59:29 +00:00
# include "FbTk/MultiButtonMenuItem.hh"
# include "FbTk/RefCount.hh"
# include "FbTk/MacroCommand.hh"
# include "FbTk/SimpleCommand.hh"
# include "FbTk/StringUtil.hh"
# include "FbTk/Directory.hh"
2004-06-07 22:23:50 +00:00
# include "FbTk/MenuSeparator.hh"
# include "FbTk/MenuIcon.hh"
2004-05-02 20:59:29 +00:00
# include <iostream>
using namespace std ;
template < >
void LayerMenuItem < FluxboxWindow > : : click ( int button , int time ) {
m_object - > moveToLayer ( m_layernum ) ;
}
2004-05-03 15:38:26 +00:00
static void createStyleMenu ( FbTk : : Menu & parent , const std : : string & label ,
2004-05-02 20:59:29 +00:00
const std : : string & directory ) {
// perform shell style ~ home directory expansion
string stylesdir ( FbTk : : StringUtil : : expandFilename ( directory ) ) ;
if ( ! FbTk : : Directory : : isDirectory ( stylesdir ) )
2004-05-03 15:38:26 +00:00
return ;
2004-05-02 20:59:29 +00:00
FbTk : : Directory dir ( stylesdir . c_str ( ) ) ;
// create a vector of all the filenames in the directory
// add sort it
std : : vector < std : : string > filelist ( dir . entries ( ) ) ;
for ( size_t file_index = 0 ; file_index < dir . entries ( ) ; + + file_index )
filelist [ file_index ] = dir . readFilename ( ) ;
std : : sort ( filelist . begin ( ) , filelist . end ( ) , less < string > ( ) ) ;
// for each file in directory add filename and path to menu
for ( size_t file_index = 0 ; file_index < dir . entries ( ) ; file_index + + ) {
std : : string style ( stylesdir + ' / ' + filelist [ file_index ] ) ;
// add to menu only if the file is a regular file, and not a
// .file or a backup~ file
if ( ( FbTk : : Directory : : isRegularFile ( style ) & &
( filelist [ file_index ] [ 0 ] ! = ' . ' ) & &
( style [ style . length ( ) - 1 ] ! = ' ~ ' ) ) | |
FbTk : : Directory : : isRegularFile ( style + " /theme.cfg " ) )
parent . insert ( new StyleMenuItem ( filelist [ file_index ] , style ) ) ;
}
// update menu graphics
parent . update ( ) ;
Fluxbox : : instance ( ) - > saveMenuFilename ( stylesdir . c_str ( ) ) ;
2004-05-03 15:38:26 +00:00
2004-05-02 20:59:29 +00:00
}
2004-06-10 11:43:24 +00:00
class ParseItem {
public :
explicit ParseItem ( FbTk : : Menu * menu ) : m_menu ( menu ) { }
inline void load ( Parser & p ) {
p > > m_key > > m_label > > m_cmd > > m_icon ;
}
inline const std : : string & icon ( ) const { return m_icon . second ; }
inline const std : : string & command ( ) const { return m_cmd . second ; }
inline const std : : string & label ( ) const { return m_label . second ; }
inline const std : : string & key ( ) const { return m_key . second ; }
inline FbTk : : Menu * menu ( ) { return m_menu ; }
private :
Parser : : Item m_key , m_label , m_cmd , m_icon ;
FbTk : : Menu * m_menu ;
} ;
static void translateMenuItem ( Parser & parse , ParseItem & item ) ;
2004-05-02 20:59:29 +00:00
static void parseMenu ( Parser & pars , FbTk : : Menu & menu ) {
2004-06-10 11:43:24 +00:00
ParseItem pitem ( & menu ) ;
2004-05-02 20:59:29 +00:00
while ( ! pars . eof ( ) ) {
2004-06-10 11:43:24 +00:00
pitem . load ( pars ) ;
if ( pitem . key ( ) = = " end " )
2004-05-02 20:59:29 +00:00
return ;
2004-06-10 11:43:24 +00:00
translateMenuItem ( pars , pitem ) ;
2004-05-02 20:59:29 +00:00
}
}
2004-06-10 11:43:24 +00:00
static void translateMenuItem ( Parser & parse , ParseItem & pitem ) {
if ( pitem . menu ( ) = = 0 )
throw string ( " translateMenuItem: We must have a menu in ParseItem! " ) ;
FbTk : : Menu & menu = * pitem . menu ( ) ;
const std : : string & str_key = pitem . key ( ) ;
const std : : string & str_cmd = pitem . command ( ) ;
const std : : string & str_label = pitem . label ( ) ;
2004-05-02 20:59:29 +00:00
const int screen_number = menu . screenNumber ( ) ;
2004-06-07 11:46:05 +00:00
_FB_USES_NLS ;
2004-06-10 11:43:24 +00:00
2004-05-02 20:59:29 +00:00
if ( str_key = = " end " ) {
return ;
} else if ( str_key = = " nop " ) {
menu . insert ( str_label . c_str ( ) ) ;
} else if ( str_key = = " icons " ) {
FbTk : : Menu * submenu = MenuCreator : : createMenuType ( " iconmenu " , menu . screenNumber ( ) ) ;
if ( submenu = = 0 )
return ;
if ( str_label . empty ( ) )
2004-06-07 11:46:05 +00:00
menu . insert ( _FBTEXT ( Menu , Icons , " Icons " , " Iconic windows menu title " ) ) ;
2004-05-02 20:59:29 +00:00
else
menu . insert ( str_label . c_str ( ) , submenu ) ;
} else if ( str_key = = " exit " ) { // exit
FbTk : : RefCount < FbTk : : Command > exit_cmd ( CommandParser : : instance ( ) . parseLine ( " exit " ) ) ;
if ( str_label . empty ( ) )
2004-06-07 11:46:05 +00:00
menu . insert ( _FBTEXT ( Menu , Exit , " Exit " , " Exit Command " ) , exit_cmd ) ;
2004-05-02 20:59:29 +00:00
else
menu . insert ( str_label . c_str ( ) , exit_cmd ) ;
} else if ( str_key = = " exec " ) {
// execute and hide menu
using namespace FbTk ;
RefCount < Command > exec_cmd ( CommandParser : : instance ( ) . parseLine ( " exec " + str_cmd ) ) ;
RefCount < Command > hide_menu ( new SimpleCommand < FbTk : : Menu > ( menu ,
& Menu : : hide ) ) ;
MacroCommand * exec_and_hide = new FbTk : : MacroCommand ( ) ;
exec_and_hide - > add ( hide_menu ) ;
exec_and_hide - > add ( exec_cmd ) ;
RefCount < Command > exec_and_hide_cmd ( exec_and_hide ) ;
menu . insert ( str_label . c_str ( ) , exec_and_hide_cmd ) ;
}
else if ( str_key = = " style " ) { // style
menu . insert ( new StyleMenuItem ( str_label , str_cmd ) ) ;
} else if ( str_key = = " config " ) {
BScreen * screen = Fluxbox : : instance ( ) - > findScreen ( screen_number ) ;
if ( screen ! = 0 )
menu . insert ( str_label . c_str ( ) , & screen - > configMenu ( ) ) ;
} // end of config
else if ( str_key = = " include " ) { // include
string newfile = FbTk : : StringUtil : : expandFilename ( str_label ) ;
// inject this file into the current menu
MenuCreator : : createFromFile ( newfile , menu ) ;
Fluxbox : : instance ( ) - > saveMenuFilename ( newfile . c_str ( ) ) ;
} // end of include
else if ( str_key = = " submenu " ) {
FbTk : : Menu * submenu = MenuCreator : : createMenu ( " " , screen_number ) ;
if ( submenu = = 0 )
return ;
if ( str_cmd . size ( ) )
submenu - > setLabel ( str_cmd . c_str ( ) ) ;
else
submenu - > setLabel ( str_label . c_str ( ) ) ;
parseMenu ( parse , * submenu ) ;
submenu - > update ( ) ;
menu . insert ( str_label . c_str ( ) , submenu ) ;
// save to screen list so we can delete it later
BScreen * screen = Fluxbox : : instance ( ) - > findScreen ( screen_number ) ;
if ( screen ! = 0 )
screen - > saveMenu ( * submenu ) ;
} // end of submenu
else if ( str_key = = " restart " ) {
FbTk : : RefCount < FbTk : : Command > restart_fb ( CommandParser : : instance ( ) .
parseLine ( " restart " ) ) ;
if ( str_label . empty ( ) )
2004-06-07 11:46:05 +00:00
menu . insert ( _FBTEXT ( Menu , Restart , " Restart " , " Restart Command " ) , restart_fb ) ;
2004-05-02 20:59:29 +00:00
else
menu . insert ( str_label . c_str ( ) , restart_fb ) ;
} // end of restart
else if ( str_key = = " reconfig " ) { // reconf
FbTk : : RefCount < FbTk : : Command >
reconfig_fb_cmd ( CommandParser : : instance ( ) .
parseLine ( " reconfigure " ) ) ;
2004-06-07 11:46:05 +00:00
if ( str_label . empty ( ) )
menu . insert ( _FBTEXT ( Menu , Reconfigure , " Reload Config " , " Reload all the configs " ) , reconfig_fb_cmd ) ;
else
menu . insert ( str_label . c_str ( ) , reconfig_fb_cmd ) ;
2004-05-02 20:59:29 +00:00
} else if ( str_key = = " stylesdir " | | str_key = = " stylesmenu " ) {
createStyleMenu ( menu , str_label ,
str_key = = " stylesmenu " ? str_cmd : str_label ) ;
} // end of stylesdir
else if ( str_key = = " workspaces " ) {
BScreen * screen = Fluxbox : : instance ( ) - > findScreen ( screen_number ) ;
if ( screen ! = 0 ) {
screen - > getWorkspacemenu ( ) . setInternalMenu ( ) ;
menu . insert ( str_label . c_str ( ) , & screen - > getWorkspacemenu ( ) ) ;
}
} else if ( str_key = = " separator " ) {
2004-06-07 22:23:50 +00:00
menu . insert ( new FbTk : : MenuSeparator ( ) ) ;
2004-06-10 11:43:24 +00:00
}
2004-06-07 22:23:50 +00:00
else { // ok, if we didn't find any special menu item we try with command parser
2004-05-02 20:59:29 +00:00
// we need to attach command with arguments so command parser can parse it
string line = str_key + " " + str_cmd ;
FbTk : : RefCount < FbTk : : Command > command ( CommandParser : : instance ( ) . parseLine ( line ) ) ;
if ( * command ! = 0 )
menu . insert ( str_label . c_str ( ) , command ) ;
}
2004-06-10 11:43:24 +00:00
if ( menu . numberOfItems ( ) ! = 0 ) {
FbTk : : MenuItem * item = menu . find ( menu . numberOfItems ( ) - 1 ) ;
if ( item ! = 0 & & ! pitem . icon ( ) . empty ( ) )
item - > setIcon ( pitem . icon ( ) . c_str ( ) , menu . screenNumber ( ) ) ;
}
2004-05-02 20:59:29 +00:00
}
static void parseWindowMenu ( Parser & parse , FbTk : : Menu & menu , FluxboxWindow & win ) {
2004-06-10 11:43:24 +00:00
ParseItem pitem ( & menu ) ;
2004-05-02 20:59:29 +00:00
while ( ! parse . eof ( ) ) {
2004-06-10 11:43:24 +00:00
pitem . load ( parse ) ;
if ( MenuCreator : : createWindowMenuItem ( pitem . key ( ) , pitem . label ( ) , menu , win ) )
2004-05-02 20:59:29 +00:00
continue ;
2004-06-10 11:43:24 +00:00
if ( pitem . key ( ) = = " end " ) {
2004-05-02 20:59:29 +00:00
return ;
2004-06-10 11:43:24 +00:00
} else if ( pitem . key ( ) = = " submenu " ) {
FbTk : : Menu * submenu = MenuCreator : : createMenu ( pitem . label ( ) , menu . screenNumber ( ) ) ;
2004-05-02 20:59:29 +00:00
parseWindowMenu ( parse , * submenu , win ) ;
submenu - > update ( ) ;
2004-06-10 11:43:24 +00:00
menu . insert ( pitem . label ( ) . c_str ( ) , submenu ) ;
2004-05-02 20:59:29 +00:00
} else { // try non window menu specific stuff
2004-06-10 11:43:24 +00:00
translateMenuItem ( parse , pitem ) ;
2004-05-02 20:59:29 +00:00
}
}
}
FbTk : : Menu * MenuCreator : : createMenu ( const std : : string & label , int screen_number ) {
BScreen * screen = Fluxbox : : instance ( ) - > findScreen ( screen_number ) ;
if ( screen = = 0 )
return 0 ;
FbTk : : Menu * menu = new FbMenu ( screen - > menuTheme ( ) ,
screen - > imageControl ( ) ,
* screen - > layerManager ( ) .
getLayer ( Fluxbox : : instance ( ) - > getMenuLayer ( ) ) ) ;
if ( ! label . empty ( ) )
menu - > setLabel ( label . c_str ( ) ) ;
return menu ;
}
bool getStart ( FbMenuParser & parser , std : : string & label ) {
2004-06-10 11:43:24 +00:00
ParseItem pitem ( 0 ) ;
2004-05-02 20:59:29 +00:00
while ( ! parser . eof ( ) ) {
// get first begin line
2004-06-10 11:43:24 +00:00
pitem . load ( parser ) ;
if ( pitem . key ( ) = = " begin " ) {
2004-05-02 20:59:29 +00:00
break ;
}
}
if ( parser . eof ( ) )
return false ;
2004-06-10 11:43:24 +00:00
label = pitem . label ( ) ;
2004-05-02 20:59:29 +00:00
return true ;
}
FbTk : : Menu * MenuCreator : : createFromFile ( const std : : string & filename , int screen_number ) {
2004-05-03 15:38:26 +00:00
std : : string real_filename = FbTk : : StringUtil : : expandFilename ( filename ) ;
FbMenuParser parser ( real_filename ) ;
2004-05-02 20:59:29 +00:00
if ( ! parser . isLoaded ( ) )
return 0 ;
std : : string label ;
if ( ! getStart ( parser , label ) )
return 0 ;
FbTk : : Menu * menu = createMenu ( label , screen_number ) ;
if ( menu ! = 0 )
parseMenu ( parser , * menu ) ;
return menu ;
}
void MenuCreator : : createFromFile ( const std : : string & filename ,
FbTk : : Menu & inject_into ) {
std : : string real_filename = FbTk : : StringUtil : : expandFilename ( filename ) ;
FbMenuParser parser ( real_filename ) ;
if ( ! parser . isLoaded ( ) )
return ;
std : : string label ;
if ( ! getStart ( parser , label ) )
return ;
parseMenu ( parser , inject_into ) ;
}
void MenuCreator : : createFromFile ( const std : : string & filename ,
FbTk : : Menu & inject_into ,
FluxboxWindow & win ) {
std : : string real_filename = FbTk : : StringUtil : : expandFilename ( filename ) ;
FbMenuParser parser ( real_filename ) ;
if ( ! parser . isLoaded ( ) )
return ;
std : : string label ;
if ( ! getStart ( parser , label ) )
return ;
parseWindowMenu ( parser , inject_into , win ) ;
}
FbTk : : Menu * MenuCreator : : createMenuType ( const std : : string & type , int screen_num ) {
BScreen * screen = Fluxbox : : instance ( ) - > findScreen ( screen_num ) ;
if ( screen = = 0 )
return 0 ;
if ( type = = " iconmenu " ) {
return new IconMenu ( * screen ) ;
} else if ( type = = " workspacemenu " ) {
return new WorkspaceMenu ( * screen ) ;
}
2004-05-03 21:37:01 +00:00
return 0 ;
2004-05-02 20:59:29 +00:00
}
bool MenuCreator : : createWindowMenuItem ( const std : : string & type ,
const std : : string & label ,
FbTk : : Menu & menu ,
FluxboxWindow & win ) {
typedef FbTk : : RefCount < FbTk : : Command > RefCmd ;
typedef FbTk : : SimpleCommand < FluxboxWindow > WindowCmd ;
2004-06-07 11:46:05 +00:00
_FB_USES_NLS ;
2004-05-02 20:59:29 +00:00
if ( type = = " shade " ) {
RefCmd shade_cmd ( new WindowCmd ( win , & FluxboxWindow : : shade ) ) ;
2004-06-07 11:46:05 +00:00
menu . insert ( label . empty ( ) ? _FBTEXT ( Windowmenu , Shade , " Shade " , " Shade the window " ) : label . c_str ( ) , shade_cmd ) ;
2004-05-02 20:59:29 +00:00
} else if ( type = = " maximize " ) {
RefCmd maximize_cmd ( new WindowCmd ( win , & FluxboxWindow : : maximizeFull ) ) ;
RefCmd maximize_vert_cmd ( new WindowCmd ( win , & FluxboxWindow : : maximizeVertical ) ) ;
RefCmd maximize_horiz_cmd ( new WindowCmd ( win , & FluxboxWindow : : maximizeHorizontal ) ) ;
2004-06-07 11:46:05 +00:00
FbTk : : MultiButtonMenuItem * maximize_item = new FbTk : : MultiButtonMenuItem ( 3 , label . empty ( ) ? _FBTEXT ( Windowmenu , Maximize , " Maximize " , " Maximize the window " ) : label . c_str ( ) ) ;
2004-05-02 20:59:29 +00:00
// create maximize item with:
// button1: Maximize normal
// button2: Maximize Vertical
// button3: Maximize Horizontal
maximize_item - > setCommand ( 1 , maximize_cmd ) ;
maximize_item - > setCommand ( 2 , maximize_vert_cmd ) ;
maximize_item - > setCommand ( 3 , maximize_horiz_cmd ) ;
menu . insert ( maximize_item ) ;
} else if ( type = = " iconify " ) {
RefCmd iconify_cmd ( new WindowCmd ( win , & FluxboxWindow : : iconify ) ) ;
2004-06-07 11:46:05 +00:00
menu . insert ( label . empty ( ) ? _FBTEXT ( Windowmenu , Iconify , " Iconify " , " Iconify the window " ) : label . c_str ( ) , iconify_cmd ) ;
2004-05-02 20:59:29 +00:00
} else if ( type = = " close " ) {
RefCmd close_cmd ( new WindowCmd ( win , & FluxboxWindow : : close ) ) ;
2004-06-07 11:46:05 +00:00
menu . insert ( label . empty ( ) ? _FBTEXT ( Windowmenu , Close , " Close " , " Close the window " ) : label . c_str ( ) , close_cmd ) ;
2004-05-02 20:59:29 +00:00
} else if ( type = = " lower " ) {
RefCmd lower_cmd ( new WindowCmd ( win , & FluxboxWindow : : lower ) ) ;
2004-06-07 11:46:05 +00:00
menu . insert ( label . empty ( ) ? _FBTEXT ( Windowmenu , Lower , " Lower " , " Lower the window " ) : label . c_str ( ) , lower_cmd ) ;
2004-05-02 20:59:29 +00:00
} else if ( type = = " raise " ) {
RefCmd raise_cmd ( new WindowCmd ( win , & FluxboxWindow : : raise ) ) ;
2004-06-07 11:46:05 +00:00
menu . insert ( label . empty ( ) ? _FBTEXT ( Windowmenu , Raise , " Raise " , " Raise the window " ) : label . c_str ( ) , raise_cmd ) ;
2004-05-02 20:59:29 +00:00
} else if ( type = = " stick " ) {
RefCmd stick_cmd ( new WindowCmd ( win , & FluxboxWindow : : stick ) ) ;
2004-06-07 11:46:05 +00:00
menu . insert ( label . empty ( ) ? _FBTEXT ( Windowmenu , Stick , " Stick " , " Stick the window " ) : label . c_str ( ) , stick_cmd ) ;
2004-05-02 20:59:29 +00:00
} else if ( type = = " extramenus " ) {
FluxboxWindow : : ExtraMenus : : iterator it = win . extraMenus ( ) . begin ( ) ;
FluxboxWindow : : ExtraMenus : : iterator it_end = win . extraMenus ( ) . end ( ) ;
for ( ; it ! = it_end ; + + it ) {
it - > second - > disableTitle ( ) ;
menu . insert ( it - > first , it - > second ) ;
}
} else if ( type = = " sendto " ) {
2004-06-08 13:15:30 +00:00
menu . insert ( label . empty ( ) ? _FBTEXT ( Windowmenu , SendTo , " Send To... " , " Send to menu item name " ) : label . c_str ( ) , new SendToMenu ( win ) ) ;
2004-05-02 20:59:29 +00:00
} else if ( type = = " layer " ) {
BScreen * screen = Fluxbox : : instance ( ) - > findScreen ( menu . screenNumber ( ) ) ;
if ( screen = = 0 )
return false ;
2004-05-02 22:28:45 +00:00
FbTk : : Menu * submenu = new LayerMenu < FluxboxWindow > ( screen - > menuTheme ( ) ,
screen - > imageControl ( ) ,
* screen - > layerManager ( ) .
getLayer ( Fluxbox : : instance ( ) - > getMenuLayer ( ) ) ,
& win ,
false ) ;
submenu - > disableTitle ( ) ;
2004-06-07 11:46:05 +00:00
menu . insert ( label . empty ( ) ? _FBTEXT ( Windowmenu , Layer , " Layer ... " , " Layer menu " ) : label . c_str ( ) , submenu ) ;
2004-05-02 22:28:45 +00:00
2004-05-02 20:59:29 +00:00
2004-05-02 22:17:00 +00:00
} else if ( type = = " separator " ) {
2004-06-07 22:23:50 +00:00
menu . insert ( new FbTk : : MenuSeparator ( ) ) ;
2004-05-02 22:17:00 +00:00
} else
2004-05-02 20:59:29 +00:00
return false ;
return true ;
}