1project(
2    'waybar', 'cpp', 'c',
3    version: '0.9.12',
4    license: 'MIT',
5    meson_version: '>= 0.49.0',
6    default_options : [
7        'cpp_std=c++17',
8        'buildtype=release',
9        'default_library=static'
10    ],
11)
12
13compiler = meson.get_compiler('cpp')
14
15cpp_args = []
16cpp_link_args = []
17
18if get_option('libcxx')
19    cpp_args += ['-stdlib=libc++']
20    cpp_link_args += ['-stdlib=libc++', '-lc++abi']
21endif
22
23if compiler.has_link_argument('-lc++fs')
24    cpp_link_args += ['-lc++fs']
25elif compiler.has_link_argument('-lc++experimental')
26    cpp_link_args += ['-lc++experimental']
27elif compiler.has_link_argument('-lstdc++fs')
28    cpp_link_args += ['-lstdc++fs']
29endif
30
31git = find_program('git', native: true, required: false)
32
33if not false
34    add_project_arguments('-DVERSION="0.9.12"'.format(meson.project_version()), language: 'cpp')
35else
36    git_path = run_command([git.path(), 'rev-parse', '--show-toplevel']).stdout().strip()
37    if meson.source_root() == git_path
38        git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags']).stdout().strip()
39        git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']).stdout().strip()
40        version = '"@0@ (branch \'@1@\')"'.format(git_commit_hash, git_branch)
41        add_project_arguments('-DVERSION=@0@'.format(version), language: 'cpp')
42    else
43        add_project_arguments('-DVERSION="0.9.12"'.format(meson.project_version()), language: 'cpp')
44    endif
45endif
46
47if not compiler.has_header('filesystem')
48    if compiler.has_header('experimental/filesystem')
49        add_project_arguments('-DFILESYSTEM_EXPERIMENTAL', language: 'cpp')
50    else
51        add_project_arguments('-DNO_FILESYSTEM', language: 'cpp')
52        warning('No filesystem header found, some modules may not work')
53    endif
54endif
55
56code = '''
57#include <langinfo.h>
58#include <locale.h>
59int main(int argc, char** argv) {
60    locale_t locale = newlocale(LC_ALL, "en_US.UTF-8", nullptr);
61    char* str;
62    str = nl_langinfo_l(_NL_TIME_WEEK_1STDAY, locale);
63    str = nl_langinfo_l(_NL_TIME_FIRST_WEEKDAY, locale);
64    freelocale(locale);
65    return 0;
66}
67'''
68if compiler.links(code, name : 'nl_langinfo with _NL_TIME_WEEK_1STDAY, _NL_TIME_FIRST_WEEKDAY')
69    add_project_arguments('-DHAVE_LANGINFO_1STDAY', language: 'cpp')
70endif
71
72add_global_arguments(cpp_args, language : 'cpp')
73add_global_link_arguments(cpp_link_args, language : 'cpp')
74
75is_linux = host_machine.system() == 'linux'
76is_dragonfly = host_machine.system() == 'dragonfly'
77is_freebsd = host_machine.system() == 'freebsd'
78is_netbsd = host_machine.system() == 'netbsd'
79is_openbsd = host_machine.system() == 'openbsd'
80
81thread_dep = dependency('threads')
82fmt = dependency('fmt', version : ['>=7.0.0'], fallback : ['fmt', 'fmt_dep'])
83spdlog = dependency('spdlog', version : ['>=1.8.5'], fallback : ['spdlog', 'spdlog_dep'], default_options : ['external_fmt=true'])
84wayland_client = dependency('wayland-client')
85wayland_cursor = dependency('wayland-cursor')
86wayland_protos = dependency('wayland-protocols')
87gtkmm = dependency('gtkmm-3.0', version : ['>=3.22.0'])
88dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk'))
89giounix = dependency('gio-unix-2.0', required: (get_option('dbusmenu-gtk').enabled() or get_option('logind').enabled()))
90jsoncpp = dependency('jsoncpp')
91sigcpp = dependency('sigc++-2.0')
92libepoll = dependency('epoll-shim', required: false)
93libnl = dependency('libnl-3.0', required: get_option('libnl'))
94libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl'))
95libpulse = dependency('libpulse', required: get_option('pulseaudio'))
96libudev = dependency('libudev', required: get_option('libudev'))
97libevdev = dependency('libevdev', required: get_option('libevdev'))
98libmpdclient = dependency('libmpdclient', required: get_option('mpd'))
99xkbregistry = dependency('xkbregistry')
100
101libsndio = compiler.find_library('sndio', required: get_option('sndio'))
102if libsndio.found()
103    if not compiler.has_function('sioctl_open', prefix: '#include <sndio.h>', dependencies: libsndio)
104        if get_option('sndio').enabled()
105            error('libsndio is too old, required >=1.7.0')
106        else
107            warning('libsndio is too old, required >=1.7.0')
108            libsndio = dependency('', required: false)
109        endif
110    endif
111endif
112
113gtk_layer_shell = dependency('gtk-layer-shell-0',
114        required: get_option('gtk-layer-shell'),
115        fallback : ['gtk-layer-shell', 'gtk_layer_shell_dep'])
116systemd = dependency('systemd', required: get_option('systemd'))
117tz_dep = dependency('date',
118    required: false,
119    default_options : [ 'use_system_tzdb=true' ],
120    modules : [ 'date::date', 'date::date-tz' ],
121    fallback: [ 'date', 'tz_dep' ])
122
123prefix = get_option('prefix')
124sysconfdir = get_option('sysconfdir')
125conf_data = configuration_data()
126conf_data.set('prefix', prefix)
127
128add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir)), language : 'cpp')
129
130if systemd.found()
131  user_units_dir = systemd.get_pkgconfig_variable('systemduserunitdir')
132
133  configure_file(
134    configuration: conf_data,
135    input: './resources/waybar.service.in',
136    output: '@BASENAME@',
137    install_dir: user_units_dir
138  )
139endif
140
141src_files = files(
142    'src/factory.cpp',
143    'src/AModule.cpp',
144    'src/ALabel.cpp',
145    'src/AIconLabel.cpp',
146    'src/modules/custom.cpp',
147    'src/modules/disk.cpp',
148    'src/modules/idle_inhibitor.cpp',
149    'src/modules/temperature.cpp',
150    'src/main.cpp',
151    'src/bar.cpp',
152    'src/client.cpp',
153    'src/config.cpp',
154    'src/group.cpp',
155    'src/util/ustring_clen.cpp'
156)
157
158if is_linux
159    add_project_arguments('-DHAVE_CPU_LINUX', language: 'cpp')
160    add_project_arguments('-DHAVE_MEMORY_LINUX', language: 'cpp')
161    src_files += files(
162        'src/modules/battery.cpp',
163        'src/modules/cpu/common.cpp',
164        'src/modules/cpu/linux.cpp',
165        'src/modules/memory/common.cpp',
166        'src/modules/memory/linux.cpp',
167    )
168elif is_dragonfly or is_freebsd or is_netbsd or is_openbsd
169    add_project_arguments('-DHAVE_CPU_BSD', language: 'cpp')
170    add_project_arguments('-DHAVE_MEMORY_BSD', language: 'cpp')
171    src_files += files(
172        'src/modules/cpu/bsd.cpp',
173        'src/modules/cpu/common.cpp',
174        'src/modules/memory/bsd.cpp',
175        'src/modules/memory/common.cpp',
176    )
177endif
178
179add_project_arguments('-DHAVE_SWAY', language: 'cpp')
180src_files += [
181    'src/modules/sway/ipc/client.cpp',
182    'src/modules/sway/bar.cpp',
183    'src/modules/sway/mode.cpp',
184    'src/modules/sway/language.cpp',
185    'src/modules/sway/window.cpp',
186    'src/modules/sway/workspaces.cpp'
187]
188
189if true
190    add_project_arguments('-DHAVE_WLR', language: 'cpp')
191    src_files += 'src/modules/wlr/taskbar.cpp'
192    src_files += 'src/modules/wlr/workspace_manager.cpp'
193    src_files += 'src/modules/wlr/workspace_manager_binding.cpp'
194endif
195
196if true
197    add_project_arguments('-DHAVE_RIVER', language: 'cpp')
198    src_files += 'src/modules/river/tags.cpp'
199endif
200
201if libnl.found() and libnlgen.found()
202    add_project_arguments('-DHAVE_LIBNL', language: 'cpp')
203    src_files += 'src/modules/network.cpp'
204endif
205
206if libpulse.found()
207    add_project_arguments('-DHAVE_LIBPULSE', language: 'cpp')
208    src_files += 'src/modules/pulseaudio.cpp'
209endif
210
211if dbusmenu_gtk.found()
212    add_project_arguments('-DHAVE_DBUSMENU', language: 'cpp')
213    src_files += files(
214        'src/modules/sni/tray.cpp',
215        'src/modules/sni/watcher.cpp',
216        'src/modules/sni/host.cpp',
217        'src/modules/sni/item.cpp'
218    )
219endif
220
221if libudev.found() and (is_linux or libepoll.found())
222    add_project_arguments('-DHAVE_LIBUDEV', language: 'cpp')
223    src_files += 'src/modules/backlight.cpp'
224endif
225
226if libevdev.found() and (is_linux or libepoll.found())
227    add_project_arguments('-DHAVE_LIBEVDEV', language: 'cpp')
228    src_files += 'src/modules/keyboard_state.cpp'
229endif
230
231if libmpdclient.found()
232    add_project_arguments('-DHAVE_LIBMPDCLIENT', language: 'cpp')
233    src_files += 'src/modules/mpd/mpd.cpp'
234    src_files += 'src/modules/mpd/state.cpp'
235endif
236
237if gtk_layer_shell.found()
238    add_project_arguments('-DHAVE_GTK_LAYER_SHELL', language: 'cpp')
239endif
240
241if libsndio.found()
242    add_project_arguments('-DHAVE_LIBSNDIO', language: 'cpp')
243    src_files += 'src/modules/sndio.cpp'
244endif
245
246if (giounix.found() and not get_option('logind').disabled())
247    add_project_arguments('-DHAVE_GIO_UNIX', language: 'cpp')
248    src_files += 'src/modules/inhibitor.cpp'
249endif
250
251if get_option('rfkill').enabled()
252    if is_linux
253        add_project_arguments('-DWANT_RFKILL', language: 'cpp')
254        src_files += files(
255            'src/modules/bluetooth.cpp',
256            'src/util/rfkill.cpp'
257        )
258    endif
259endif
260
261if tz_dep.found()
262    add_project_arguments('-DHAVE_LIBDATE', language: 'cpp')
263    src_files += 'src/modules/clock.cpp'
264else
265    src_files += 'src/modules/simpleclock.cpp'
266endif
267
268if get_option('experimental')
269    add_project_arguments('-DUSE_EXPERIMENTAL', language: 'cpp')
270endif
271
272subdir('protocol')
273
274executable(
275    'waybar',
276    src_files,
277    dependencies: [
278        thread_dep,
279        client_protos,
280        wayland_client,
281        fmt,
282        spdlog,
283        sigcpp,
284        jsoncpp,
285        wayland_cursor,
286        gtkmm,
287        dbusmenu_gtk,
288        giounix,
289        libnl,
290        libnlgen,
291        libpulse,
292        libudev,
293        libepoll,
294        libmpdclient,
295        libevdev,
296        gtk_layer_shell,
297        libsndio,
298        tz_dep,
299		xkbregistry
300    ],
301    include_directories: [include_directories('include')],
302    install: true,
303)
304
305install_data(
306    './resources/config',
307    './resources/style.css',
308    install_dir: sysconfdir + '/xdg/waybar'
309)
310
311scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages'))
312
313if scdoc.found()
314    scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true)
315    sh = find_program('sh', native: true)
316
317    main_manpage = configure_file(
318        input: 'man/waybar.5.scd.in',
319        output: 'waybar.5.scd',
320        configuration: {
321            'sysconfdir': join_paths(prefix, sysconfdir)
322        }
323    )
324
325    main_manpage_path = join_paths(meson.build_root(), '@0@'.format(main_manpage))
326
327    mandir = get_option('mandir')
328    man_files = [
329        main_manpage_path,
330        'waybar-backlight.5.scd',
331        'waybar-battery.5.scd',
332        'waybar-clock.5.scd',
333        'waybar-cpu.5.scd',
334        'waybar-custom.5.scd',
335        'waybar-disk.5.scd',
336        'waybar-idle-inhibitor.5.scd',
337        'waybar-keyboard-state.5.scd',
338        'waybar-memory.5.scd',
339        'waybar-mpd.5.scd',
340        'waybar-network.5.scd',
341        'waybar-pulseaudio.5.scd',
342        'waybar-river-tags.5.scd',
343        'waybar-sway-language.5.scd',
344        'waybar-sway-mode.5.scd',
345        'waybar-sway-window.5.scd',
346        'waybar-sway-workspaces.5.scd',
347        'waybar-temperature.5.scd',
348        'waybar-tray.5.scd',
349        'waybar-states.5.scd',
350        'waybar-wlr-taskbar.5.scd',
351        'waybar-wlr-workspaces.5.scd',
352        'waybar-bluetooth.5.scd',
353        'waybar-sndio.5.scd',
354    ]
355
356    if (giounix.found() and not get_option('logind').disabled())
357        man_files += 'waybar-inhibitor.5.scd'
358    endif
359
360    foreach file : man_files
361        path = '@0@'.format(file)
362        basename = path.split('/')[-1]
363
364        topic = basename.split('.')[-3]
365        section = basename.split('.')[-2]
366        output = '@0@.@1@'.format(topic, section)
367
368        custom_target(
369            output,
370            # drops the 'man' if `path` is an absolute path
371            input: join_paths('man', path),
372            output: output,
373            command: [
374                sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output)
375            ],
376            install: true,
377            install_dir: '@0@/man@1@'.format(mandir, section)
378        )
379    endforeach
380endif
381
382catch2 = dependency(
383    'catch2',
384    fallback: ['catch2', 'catch2_dep'],
385    required: get_option('tests'),
386)
387if catch2.found()
388    subdir('test')
389endif
390
391clangtidy = find_program('clang-tidy', required: false)
392
393if clangtidy.found()
394    run_target(
395        'tidy',
396        command: [
397            clangtidy,
398            '-checks=*,-fuchsia-default-arguments',
399            '-p', meson.build_root()
400        ] + src_files)
401endif
402
403