# Contributing

- [Introduction](#introduction)
- [Reporting issues and bugs](#reporting-issues-and-bugs)
- [Debugging](#debugging)
- [Upversion](#upversion)
- [Add new config variables](#add-new-config-variables)
- [Testing](#testing)
- [Architecture](#architecture)
- [Grammar and Language](#grammar-and-language)
- [Git](#git)
- [Overview of src/ files](#overview-of-src-files)
- [Stack Traces](#stack-traces)

## Introduction

First of all, thanks for contributing or considering to contribute.

We have two high level development rules:

- Friendship, ideas and code are valued in said order
- There are no deadlines

## Reporting issues and bugs

Reporting issues and bugs is a very helpful contribution. The preferred route
for reporting these is to raise github issues, but we are happy with any method
including forums threads and e-mails. If you are able to help resolve them,
that is also greatly appreciated.

It would be useful if you could simply start by describing what you did and
what happened. It may help if you could also do the following:

1. Run jgmenu from the terminal and copy/paste any output

2. Provide the output of `jgmenu --version`

3. Provide the output of `type jgmenu` (i.e. the location of the binary)

4. Provide the command you used to run jgmenu

5. Provide the config file

6. Provide some basic information about your system (e.g. distribution, window
   manager, composite manager)

7. Run `jgmenu_run init -i` then choose 'check' and report any warnings

## Debugging

This list is by no means exhaustive, but may provide some ideas for
things to try.

1. Make use of the modular design of jgmenu to isolate the root cause.
   For example, if you are using jgmenu with the 'lx' module, run
   `jgmenu_run lx > foo` and analyse the output. Then try `jgmenu
   --csv-file=foo`.  This approach might help find the root cause of the
   issue.

2. If the menu data is causing the issue (e.g. foo above), try to
   comment out a section at a time or write a script to cycle through
   individual items. The command line option --die-when-loaded can be
   useful for this.

3. If using the 'pmenu' module, `jgmenu_run pmenu` will output the
   .desktop file corresponding to each menu item. This can be useul to
   analyse specific items.

4. strace can be used to understand what what system calls are made.
   For example, to analyse which .desktop files were opened, try:
   `strace -f -o foo jgmenu_run lx ; grep '.desktop' foo`
   If you experience a crash, `strace` can also be particularly useful
   for analysing which system calls were made, including their return
   values.

5. Revert to a default configuration file and gradually change options
   until the bug occurs.

6. The file ./scripts/enable-error-messages.sh contains a number of
   environment variables which can be set for verbose output relating to
   specific topics.

## Upversion

- update `default_version` in scripts/version-gen.sh
- run `dch` and update debian/changelog
- create docs/relnotes/X.Y.txt
- update NEWS.md
- add and commit the above files
- git tag -a 'vX.Y' (using the release notes as the commit message)

## Add new config variables

Any new config variables need to be added to the following:

-   config.c
-   config.h
-   src/jgmenu-config.c
-   docs/manual/jgmenu.1.md

## Testing

- `make ex` to launch a few menus specifically designed to test various
  features.

- `make check` to check coding style and perform some static analysis on all
  files in `src/`. Files can be checked on an individual basis by running
  `./scripts/check <file>`

- `make test` to run unit tests

## Architecture

`jgmenu_run <command>` is a wrapper script which calls `jgmenu-<command>`.

This architecture is inspired by git and has a number of advantages over
putting all `jgmenu-<command>` in `$prefix/bin`:

- It ensures that the correct module is called if multiple version of jgmenu
  are installed on the system.
- It avoids putting programs, that are not meant to be called by the user, in
  `$prefix/bin`.
- It saves the user having to remember script file extensions whilst making
  it simple for the developer to know which are binary, shell, python, etc.

## Grammar and Language

jgmenu is always written with a lowercase "j". It should be obvious from
the context if we refer to the entire application or just the binary
file.

The language used in documentation shall follow British English rules.
Although, for variable names and configuration options, US spelling is
used (e.g. color and center)

## Git

Keep commit messages lines to 74 characters.

## Overview of src/ files

jgmenu.c
- x11-ui.c - interface with X11
- icon.c - load icons
  * cache.c - manage icon cache on harddisk
  * icon-find.c - find icons
  * xpm-loader.c - load xpm icons (png/svg use cairo)
- config.c - read config file
- geometry.c - calculate positions and dimensions
- filter.c - search support
- theme.c + font.c - set icon theme and font from xsettings, tint2rc, etc
  * xsettings-helper.c - read xsettings variables
  * gtkconf.c - read gtk3.0 config file variables

jgmenu-apps.c
- desktop.c - parse desktopp files

jgmenu-ob.c

## Stack traces

If jgmenu crashes with the message 'Segmentation fault' or 'Abort', a stack
trace (also known as backtrace) is often the most useful starting point.  A
stack trace tells us where the program stopped and how that point was reached
through all the functions up to main(). A useful stack trace provides filenames
and line numbers.

You can provide a stack trace using one of the methods listed below.

<b>Method 1 - ASAN</b>

AddressSanitizer (ASAN) is a tool that detects memory error bugs and has
been implemented in GCC since v4.8. It is invoked by simply compiling
and linking with `--fsanitize=address` flag.

This method is the easiest if you are prepared to compile jgmenu. You
might balk at this, but jgmenu is very fast and simple to build,
compared to many other software packages.  See INSTALL.md for details of
build dependencies and then take the following steps and report the
output.

    git clone https://github.com/johanmalm/jgmenu
    cd jgmenu
    make ASAN=1
    ./jgmenu

The `ASAN=1` variable enables ASAN and sets some flags for a useful stack
trace. Upon a crash, you will see something like this:

    #0 0x4a1ad2 in build_tree /home/johan/src/jgmenu/jgmenu.c:1099
    #1 0x4aa077 in main /home/johan/src/jgmenu/jgmenu.c:2441
    #2 0xb686d285 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18285)
    #3 0x499a70  (/home/johan/src/jgmenu/jgmenu+0xba70)

<b>Method 2 - gdb</b>

In order to get a useful stack trace with gdb, you need binaries with
debug symbols. Release packages have generally been 'stripped' of these,
so you have two options:

-   Install a package with debug symbols (e.g. jgmenu-dbgsym on
    BunsenLabs Linux). This option has the advantage of not needing to
    build the binaries.

-   Compile with `-g` and `-Og' flags as a minimum.
    jgmenu CFLAGS are set in `Makefile.inc`

There are two ways of producing a stack trace with gdb. Either run the
programme in gdb and trigger the crash;

    gdb jgmenu
    (gdb) handle SIG64 noprint nostop  # or similar
    (gdb) run
    # wait for crash
    (gdb) backtrace

or analyse a core dump after a crash.

gdb <exec> <core>
(gdb) backtrace

When using the `gdb jgmenu` approach, be aware that jgmenu grabs the
keyboard and pointer, so interaction with gdb is not straight forward.
If you get it wrong, you may need to log into a different tty (e.g.
ctrl+alt+F2) and `killall jgmenu ; killall xterm` (or whatever terminal
you use).

With both approaches, remember that the jgmenu package contains many
binary files, so it's important to run gdb on the one with the issue.
For example, if the 'ob' modules caused a segfault and core dump, you
need to run

    gdb jgmenu-ob <core>

In order to use the `gdb <exec> <core>` method, your system needs to be
configured to core dump and you need the filename and location of the
core dump file. Consult your OS/distribution documentation for details
on this.

The segfault/abort error message will indicate if the core has been
dumped, e.g: `Segmentation fault (core dumped)`.

If you system has not been setup to core dump, you can use the command
`ulimit -c unlimited` to force a core dump in a specific shell session.
In this scenario, the core will be dumped in the current working
directory.

<b>Method 3 - coredumpctl</b>

If your system is set up to core dump and you have coredumpctl installed,
you can run the following and include the output in your bug report.

   sudo coredumpctl info jgmenu

