From dfeb19b0a83b8ce57d28bf94a4f8d129993d1064 Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Mon, 12 Jan 2026 23:06:20 +0100 Subject: Initial commit --- .clang-format | 315 +++++++++++++++++++++++ .clang-tidy | 2 + .dir-locals.el | 13 + meson.build | 94 +++++++ src/args.cc | 389 ++++++++++++++++++++++++++++ src/args.hh | 64 +++++ src/dbus_common.cc | 7 + src/dbus_common.hh | 14 ++ src/find_desktop.cc | 152 +++++++++++ src/find_desktop.hh | 10 + src/main.cc | 59 +++++ src/monitor.cc | 626 ++++++++++++++++++++++++++++++++++++++++++++++ src/monitor.hh | 13 + src/notify.cc | 59 +++++ src/notify.hh | 12 + src/xcb_atoms.cc | 81 ++++++ src/xcb_atoms.hh | 57 +++++ src/xcb_colors.cc | 96 +++++++ src/xcb_colors.hh | 57 +++++ src/xcb_connection.cc | 25 ++ src/xcb_connection.hh | 28 +++ src/xcb_event.hh | 30 +++ src/xcb_resource.cc | 41 +++ src/xcb_resource.hh | 99 ++++++++ src/xcb_resources.hh | 35 +++ src/xcb_resources_none.cc | 37 +++ src/xcb_resources_xrm.cc | 74 ++++++ src/xcb_xkb.cc | 167 +++++++++++++ src/xcb_xkb.hh | 30 +++ 29 files changed, 2686 insertions(+) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .dir-locals.el create mode 100644 meson.build create mode 100644 src/args.cc create mode 100644 src/args.hh create mode 100644 src/dbus_common.cc create mode 100644 src/dbus_common.hh create mode 100644 src/find_desktop.cc create mode 100644 src/find_desktop.hh create mode 100644 src/main.cc create mode 100644 src/monitor.cc create mode 100644 src/monitor.hh create mode 100644 src/notify.cc create mode 100644 src/notify.hh create mode 100644 src/xcb_atoms.cc create mode 100644 src/xcb_atoms.hh create mode 100644 src/xcb_colors.cc create mode 100644 src/xcb_colors.hh create mode 100644 src/xcb_connection.cc create mode 100644 src/xcb_connection.hh create mode 100644 src/xcb_event.hh create mode 100644 src/xcb_resource.cc create mode 100644 src/xcb_resource.hh create mode 100644 src/xcb_resources.hh create mode 100644 src/xcb_resources_none.cc create mode 100644 src/xcb_resources_xrm.cc create mode 100644 src/xcb_xkb.cc create mode 100644 src/xcb_xkb.hh diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..aa4a4dc --- /dev/null +++ b/.clang-format @@ -0,0 +1,315 @@ +--- +Language: Cpp +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: true + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseArrows: false + AlignCaseColons: false +AlignConsecutiveTableGenBreakingDAGArgColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenCondOperatorColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenDefinitionColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Never +AllowShortCaseExpressionOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AllowShortNamespacesOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: BinPack +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BracedInitializerIndentWidth: 2 +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakAfterReturnType: None +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakBinaryOperations: Never +BreakConstructorInitializers: BeforeColon +BreakFunctionDefinitionParameters: false +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +BreakTemplateDeclarations: Yes +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^<.*' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '([-_](lzma|z|test|unittest))?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExportBlock: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: AfterHash +IndentRequiresClause: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: false + AtStartOfFile: true +KeepFormFeed: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MainIncludeChar: Quote +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: NextLine +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakBeforeMemberAccess: 150 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +PPIndentWidth: 1 +QualifierAlignment: Leave +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: pb + BasedOnStyle: google +ReferenceAlignment: Pointer +ReflowComments: IndentOnly +RemoveBracesLLVM: false +RemoveEmptyLinesInUnwrappedLines: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + ExceptDoubleParentheses: false + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TableGenBreakInsideDAGArg: DontBreak +TabWidth: 8 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +WrapNamespaceBodyWithEmptyLines: Leave +... + diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..27aad9a --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,2 @@ +--- +Checks: 'bugprone-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-bugprone-easily-swappable-parameters,-bugprone-unchecked-optional-access,-misc-non-private-member-variables-in-classes,-misc-const-correctness,-misc-no-recursion,-modernize-avoid-c-arrays,-modernize-use-trailing-return-type,-readability-magic-numbers,-readability-identifier-length,-readability-braces-around-statements,-readability-function-cognitive-complexity,-readability-redundant-inline-specifier,-readability-implicit-bool-conversion,-readability-qualified-auto,-misc-header-include-cycle' diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..b834c07 --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,13 @@ +;;; Directory Local Variables -*- no-byte-compile: t; -*- +;;; For more information see (info "(emacs) Directory Variables") + +((c++-mode . ((eval + . + (let ((project-path + (locate-dominating-file default-directory ".dir-locals.el"))) + (setq-local flycheck-clangcheck-build-path + (concat project-path "build")) + (setq-local flycheck-clang-language-standard "c++23") + (setq-local flycheck-cppcheck-standards '("c++23")) + (setq-local flycheck-clang-definitions '("HAVE_CONFIG_H")) + (setq-local flycheck-clang-include-path '("../src" "../build"))))))) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..0146e90 --- /dev/null +++ b/meson.build @@ -0,0 +1,94 @@ +project( + 'claudemon', + 'cpp', + version : '0.1', + meson_version : '>= 1.3.0', + default_options : [ + 'warning_level=3', + 'cpp_std=c++23', + 'cpp_rtti=false', + ], +) + +cpp_optional_flags = [ + # Redefining explicit to be able to include xkb.h + '-Wno-keyword-macro', +] + +cpp_flags = [ + '-DVERSION="' + meson.project_version() + '"' +] +if get_option('buildtype') == 'release' + # If asserts are disabled parameters and variables used for only that + # end up causing warnings + cpp_optional_flags += ['-Wno-unused-parameter', '-Wno-unused-variable', + '-Wno-unused-but-set-variable'] + + cpp_flags += '-DNDEBUG' +endif + +cpp = meson.get_compiler('cpp') +cpp_flags += cpp.get_supported_arguments(cpp_optional_flags) +add_project_arguments(cpp_flags, language: 'cpp') + +thread_dep = dependency('threads') + +xcb_dep = [dependency('xcb', version: '>= 1.14'), + dependency('xcb-xkb', version: '>= 1.14'), + dependency('xcb-event', version: '>= 0.4.0'), + dependency('xcb-icccm', version: '>= 0.4.1'), + dependency('xcb-keysyms', version: '>= 0.4.0'), + dependency('xkbcommon-x11', version: '>= 1.0.3')] + +xcb_xrm_dep = dependency('xcb-xrm', version: '>= 1.0', required: false) + +dbus_dep = dependency('sdbus-c++', version: '>= 2.0.0') + +json_dep = dependency('RapidJSON', version: '>= 1.1.0') + +dependencies = [ + dbus_dep, + json_dep, + thread_dep, + xcb_dep, + xcb_xrm_dep, +] + +sources = [ + 'src/args.cc', + 'src/args.hh', + 'src/dbus_common.cc', + 'src/dbus_common.hh', + 'src/find_desktop.cc', + 'src/find_desktop.hh', + 'src/main.cc', + 'src/monitor.cc', + 'src/monitor.hh', + 'src/notify.cc', + 'src/notify.hh', + 'src/xcb_atoms.cc', + 'src/xcb_atoms.hh', + 'src/xcb_colors.cc', + 'src/xcb_colors.hh', + 'src/xcb_connection.cc', + 'src/xcb_connection.hh', + 'src/xcb_resource.cc', + 'src/xcb_resource.hh', + 'src/xcb_xkb.cc', + 'src/xcb_xkb.hh', +] + +if xcb_xrm_dep.found() + sources += 'src/xcb_resources_xrm.cc' +else + sources += 'src/xcb_resources_none.cc' +endif + +exe = executable( + 'claudemon', + sources, + install : true, + dependencies : dependencies, +) + +test('basic', exe) diff --git a/src/args.cc b/src/args.cc new file mode 100644 index 0000000..1794941 --- /dev/null +++ b/src/args.cc @@ -0,0 +1,389 @@ +#include "args.hh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +std::string kEmpty; + +class OptionImpl : public Args::OptionArgument { + public: + enum Type : uint8_t { + NoArgument, + RequiredArgument, + OptionalArgument, + }; + + OptionImpl(Type type, char shortname, std::string longname, std::string arg, + std::string help) + : type(type), + shortname(shortname), + longname(std::move(longname)), + arg(std::move(arg)), + help(std::move(help)) {} + + const Type type; + const char shortname; + const std::string longname; + const std::string arg; + const std::string help; + + [[nodiscard]] bool is_set() const override { return is_set_; } + + [[nodiscard]] bool has_argument() const override { + return value_.has_value(); + } + + [[nodiscard]] const std::string& argument() const override { + if (value_.has_value()) + return value_.value(); + assert(false); + return kEmpty; + } + + void clear() { + is_set_ = false; + value_.reset(); + } + + void set_argument(std::string value) { + assert(type == Type::RequiredArgument || type == Type::OptionalArgument); + is_set_ = true; + value_ = std::move(value); + } + + void set_no_argument() { + assert(type == Type::NoArgument || type == Type::OptionalArgument); + is_set_ = true; + value_.reset(); + } + + private: + bool is_set_{false}; + std::optional value_; +}; + +class ArgsImpl : public Args { + public: + explicit ArgsImpl(std::string prgname) : prgname_(std::move(prgname)) {} + + std::shared_ptr