This is the head task for creating the contributor's guide as decided on the November 2017 sprint.
Outline
- What can I do?
- Spread the word
- Create learning material
- Sort out bug reports
- Fix bugs, develop new features
- Test and report bugs
- Translate UI or docs to your language
- Discuss improvement ideas
- Maintain binary distributions
- Anything else you have the skills or resources for? If you're eager to help, there's always something to do
Getting in touch with others
- IRC
- Start here. Come and say hi.
- Don't be afraid to ask questions, but be patient
- Time of day: we're mostly Europeans
- Weekly meetings
- #krita-chat
- Phabricator
- https://community.kde.org/Infrastructure/Phabricator
- Task lifetime (link)
- Task discussions
- Patches
- Mailing list
- Bug tracker
- Triaging bugs
- Closing bugs
- Sprints
Testing new versions
- Getting a fresh version
- Building it yourself
- Appimages
- Pre-releases
- Testing tips
- How to find what needs attention right now
- See https://phabricator.kde.org/project/view/132/ column “Needs testing”
- Filing a good bug report
Writing documentation
Translating Krita
Building from source
- Point to a file on the source
- Compilation arguments (building with tests, asserts, ...)
- Using an IDE (QtCreator as example)
- Configuring QtCreator
- Use spaces instead of tabs
- Optional: disable compile/deploy before running
- Opening the project
- Compiling through QtCreator
- Running under debugger
- Useful shortcuts
Programming
- New to C++ / Qt / KDE? No problem, if you're willing to learn.
- C++: brief overview, links to useful resources (e.g. no garbage collection, developer is responsible for memory management)
- Qt: Quick intro, links to Qt documentation
- QObject, signals, slots
- https://wiki.qt.io/Qt_for_Beginners
- KDE frameworks?
- Krita?
- Fixing simple bugs or other small issues is a good way to get familiar with the code
- A brief tour of the source (important, stable concepts)
- Naming conventions
- Meanings of prefixes: Q-, K-, Ko-, Kis-, …
- Organization
- Top-level folders
- dockers, tools, paintops, filters, …?
- Important classes
- KisApplication, KisMainWindow, KisCanvas
- KisDocument, KisImage, KisNode, etc.
- KisPaintDevice
- (plugins)
- (strokes)
- (undo)
- Libraries used
- CMakeLists.txt
- Tips for finding the right file
- API documentation: https://api.kde.org/extragear-api/graphics-apidocs/krita/html/index.html
- Search for UI strings
- Start from a related file, follow symbols
- Git: blame, log, grep
- Ask on IRC
Debugging tips(?)
- Using gdb
- drmingw
- llldb
Writing code
- Note: there is a lot of old code. Expect to see violations of guidelines, but do try to avoid repeating the same mistakes.
- For specific coding conventions, refer to HACKING
- First, make it work and make it readable. Only consider anything clever or complicated if nothing else will do.
- E.g. if an optimization makes the code harder to understand (or write) make sure it is actually needed (measure)
- https://codeburst.io/good-code-vs-bad-code-35624b4e91bc
- https://www.toptal.com/software/six-commandments-of-good-code
- Use descriptive names.
- Avoid magic numbers. Name your constants
- Be consistent with existing style
- Prefer Qt classes for consistency (over std, boost, etc.)
- Exceptions
- Modern C++ features?
- Comments
- When feel you need a comment, see if the code can be made clearer first.
- Do not repeat in comment what the code already says. Use comments for what the code cannot express: intent, discarded design choices, etc.
- Write API documentation comments
- Object lifetime
- Memory management
- Ownership transfer
- “Smart” pointers: QScopedPointer, QSharedPointer, …
- Always initialize your members, variables
- Code reuse
- Try to use and extend existing code when possible
- Not by copy-pasting!
- Unit testing: https://community.kde.org/Krita/Docs/Unittests_in_Krita
- Why?
- Compiling and running tests
- Writing tests
- Introducing new features
- Start by discussing it
- IRC, Phabricator, mailing list (not Bugzilla)
- First, with artists (use cases, workflows, UX design, ...)
- Then, with developers (code design, related existing code, ...)
- Develop in a branch
- Keep up-to-date with master
- Sharing your changes
- Copyright, GPL? What’s that?
- Using git (links, tips)
- https://git-scm.com/book/en/v2/Getting-Started-Git-Basics
- https://www.tutorialspoint.com/git/
- https://www.learnenough.com/git-tutorial
- KDE identity
- Posting a patch for review
- Link to Arcanist document
- Commit messages
- Layout
- Link to KDE’s template
- Commit hooks (link)
- Getting push access
- Once you’ve demonstrated to us you can write code, follow https://community.kde.org/Infrastructure/Get_a_Developer_Account
- Branches
- Master
- What goes (directly) to master?
- String freeze, feature freeze
- Feature branches
- Backporting bugfixes
HACKING file suggestions
- Use const whenever applicable
- Private members (d-pointer): link to KDE docs
- Use QScopedPointer for private classes
- Exceptions: don’t throw, but catch from libraries
- Enum class: don’t use, or refactor to use everywhere
- auto: as little as possible. Only if the type is obvious
- nullptr? (TODO: investigate into clang-sanitizer)
- Don't use Q_ASSERT. Use KIS_ASSERT or KIS_SAFE_ASSERT
- Prefer QScopedPointer, QScopedArrayPointer, QSharedPointer to manual memory management
Polymorphism
- Mark overrides
- Use q_object_cast for QObjects, use static_cast if you’re certain of the class, reinterpret_cast, otherwise dynamic_cast followed by a null check or an assert
- Never C-style casting
The link http://techbase.kde.org/Policies/Kdelibs_Coding_Style is broken
Content drafts (WIP)
Memory management
Why do we care?
When we create an object using the new operator, a piece of memory is reserved to store the object in. Once the object is no longer needed, the memory should be freed to be used again. If we fail to do this, we will just keep on requesting more and more memory from the system as new object are needed. This is called a memory leak.
Many programming languages have a built-in garbage collector which periodically finds the objects no longer in use and releases those parts of the memory. In C++, however, it is the responsibility us programmers to clean up after ourselves.
How do we do it?
Traditionally, in C++ releasing the memory is done with the delete operator, which is the logical counterpart of new. It releases the object’s memory. The problem with this approach is that it is very easy to forget the delete, especially when the code gets more complicated.
The modern C++ approach is to use so called “smart pointers”. In Krita we use Qt’s implementation of this concept, mainly QScopedPointer and QSharedPointer.
QScopedPointer
A QScopedPointer automatically does the deletion for us when it gets destroyed itself.
The destruction can happen one of two ways. If the scoped pointer was as declared as a local variable, it happens when the program exits the block where the declaration is in. If declared as a field of an object, the scoped pointer is destroyed when the containing object is destroyed.
QSharedPointer
Often we want to refer to the same object from multiple places. If we try to use QScopedPointer, it would delete the object when the first reference is destroyed. This would leave the rest of the references falsely pointing to an area of memory which may now be used for something entirely different. This results in a crash at best, and silent data corruption at worst.
QSharedPointer solves this problem by keeping track of how many shared pointers refer to the object. When the count reaches zero, there should no longer be any reference to the object, so the shared pointer deletes the object.
QWeakSharedPointer?