1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! Utility macros for use in the rest of penrose.
//! Not intended for general use

/// log the reason why we we're dying and immediately exit
#[macro_export]
macro_rules! die(
    ($msg:expr) => ({
        eprintln!("FATAL :: {}", $msg);
        ::std::process::exit(42);
     });

    ($fmt:expr, $($arg:expr),*) => ({
        eprintln!("FATAL :: {}", format!($fmt, $($arg,)*));
        ::std::process::exit(42);
     });
);

/// Log a WARN level message to stderr
#[macro_export]
macro_rules! warn(
    ($msg:expr) => { eprintln!("WARN :: {}", $msg); };
    ($fmt:expr, $($arg:tt),*) => {
        eprintln!("WARN :: {}", format!($fmt, $($arg)*));
    };
);

/// Log an INFO level message to stderr
#[macro_export]
macro_rules! log(
    ($msg:expr) => { eprintln!("INFO :: {}", $msg); };
    ($fmt:expr, $($arg:expr),*) => {
        eprintln!("INFO :: {}", format!($fmt, $($arg,)*));
    };
);

/// Log an DBUG level message to stderr if we were compiled in debug
#[macro_export]
macro_rules! debug(
    ($msg:expr) => {
        if cfg!(debug_assertions) {
            eprintln!("DBUG :: {}", $msg);
        }
    };
    ($fmt:expr, $($arg:expr),*) => {
        if cfg!(debug_assertions) {
            eprintln!("DBUG :: {}", format!($fmt, $($arg,)*));
        }
    };
);

/// use notify-send to trigger a pop up window with a message (used for debugging)
#[macro_export]
macro_rules! notify(
    ($msg:expr) => {
        ::std::process::Command::new("notify-send").arg($msg).spawn().unwrap();
    };

    ($fmt:expr, $($arg:expr),*) => {
        ::std::process::Command::new("notify-send")
            .arg(format!($fmt, $($arg,)*))
            .spawn()
            .unwrap();
    };
);

/// kick off an external program as part of a key/mouse binding.
/// explicitly redirects stderr to /dev/null
#[macro_export]
macro_rules! run_external(
    ($cmd:tt) => {
        {
            Box::new(move |_: &mut $crate::manager::WindowManager| {
                $crate::helpers::spawn($cmd);
            }) as $crate::data_types::FireAndForget
        }
    };
);

/// kick off an internal method on the window manager as part of a key/mouse binding
#[macro_export]
macro_rules! run_internal(
    ($func:ident) => {
        Box::new(|wm: &mut $crate::manager::WindowManager| {
            debug!("calling method ({})", stringify!($func));
            wm.$func();
        })
    };

    ($func:ident, $($arg:tt),+) => {
        Box::new(move |wm: &mut $crate::manager::WindowManager| {
            debug!("calling method ({}) with argument ({})", stringify!($func), $($arg)+);
            wm.$func($($arg),+);
        })
    };
);

/// make creating a hash-map a little less verbose
#[macro_export]
macro_rules! map(
    {} => { ::std::collections::HashMap::new(); };

    { $($key:expr => $value:expr),+, } => {
        {
            let mut _map = ::std::collections::HashMap::new();
            $(_map.insert($key, $value);)+
            _map
        }
    };
);

/// make creating all of the key bindings less verbose
#[macro_export]
macro_rules! gen_keybindings(
    {
        $($binding:expr => $action:expr),+;
        forall_workspaces: $ws_array:expr => { $($ws_binding:expr => $ws_action:tt),+, }
    } => {
        {
            let mut _map = ::std::collections::HashMap::new();
            let keycodes = $crate::helpers::keycodes_from_xmodmap();

            $(
                match $crate::helpers::parse_key_binding($binding, &keycodes) {
                    None => die!("invalid key binding: {}", $binding),
                    Some(key_code) => _map.insert(key_code, $action),
                };
            )+

            for i in 0..$ws_array.len() {
                $(
                    let for_ws = format!($ws_binding, i+1);
                    match $crate::helpers::parse_key_binding(for_ws.clone(), &keycodes) {
                        None => die!("invalid key binding: {}", for_ws),
                        Some(key_code) => _map.insert(key_code, run_internal!($ws_action, i)),
                    };
                )+
            }

            _map
        }
    };
);