diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..75673eb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,36 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 100 + +[meson.build] +indent_size = 2 +tab_size = 2 +indent_style = space + +[*.{c,h,c.in,h.in,vala}] +indent_size = 2 +tab_size = 2 +indent_style = space + +[*.css] +indent_size = 2 +tab_size = 2 +indent_style = space + +[*.json] +indent_size = 2 +tab_size = 2 +indent_style = space + +[*.{xml,ui}] +indent_size = 2 +tab_size = 2 +indent_style = space + +[NEWS] +max_line_length = 72 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..1f40123 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,92 @@ +--- +include: + - project: 'guidog/meta-phosh' + ref: 'a7ec8974bb14258191146c791d8c614322dfd9e1' + file: '/ci/phosh-common-jobs.yml' + - project: 'Infrastructure/Mirrors/lorry-mirrors/gitlab_freedesktop_org/freedesktop/ci-templates' + ref: 'd03cddbcff35f26861429fc816c00323f48e99af' + file: '/templates/ci-fairy.yml' + +stages: + - build + - style-checks + +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + # Don't trigger a branch pipeline if there is an open MR + - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS + when: never + - if: $CI_COMMIT_TAG + - if: $CI_COMMIT_BRANCH + +default: + # Protect CI infra from rogue jobs + timeout: 15 minutes + # Allow jobs to be caneled on new commits + interruptible: true + # Retry on infra hickups automatically + retry: + max: 1 + when: + - 'api_failure' + - 'runner_system_failure' + - 'scheduler_failure' + - 'stuck_or_timeout_failure' + +variables: + # For ci-fairy + FDO_UPSTREAM_REPO: guidog/phosh-vala-plugins + DEBIAN_IMAGE: debian:trixie + DEBIAN_DEPS: gettext meson libphosh-0.45-dev valac + +build:native-debian-trixie: + stage: build + image: ${DEBIAN_IMAGE} + before_script: + - export DEBIAN_FRONTEND=noninteractive + - apt -y update + - apt -y install $DEBIAN_DEPS + script: + - meson setup _build + - meson compile -C _build + +check-consistency: + stage: style-checks + extends: .phosh-check-consistency + +check-commit-log: + extends: + - .fdo.ci-fairy + stage: style-checks + variables: + GIT_DEPTH: "100" + needs: [] + script: | + ci-fairy check-commits --signed-off-by --junit-xml=commit-message-junit-report.xml + artifacts: + reports: + junit: commit-message-junit-report.xml + rules: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH' + +check-markdown: + stage: style-checks + extends: .phosh-check-markdown + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + changes: + paths: + - "*.md" + +check-style: + stage: style-checks + extends: .phosh-format-check + allow_failure: true + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + +check-meson: + stage: style-checks + extends: + - .phosh-check-meson diff --git a/.gitlab-ci/check-consistency b/.gitlab-ci/check-consistency new file mode 100755 index 0000000..6fd1fb0 --- /dev/null +++ b/.gitlab-ci/check-consistency @@ -0,0 +1,102 @@ +#!/bin/bash +# +# Copyright (C) 2024 The Phosh developers +# SPDX-License-Identifier: GPL-3.0-or-later +# Author: Guido Günther +# +# Check if NEWS, changelog, meson and metainfo are in sync + +set -e + +COLOR= +if [ -n "${TERM}" ] && [ "${TERM}" != "dumb" ]; then + COLOR=1 +fi + +function log +{ + local level="${1}" + local fd=2 + local use_color + + shift + if [ -n "${COLOR}" ]; then + [ "${level}" == warn ] || [ "${level}" == error ] || fd=1 + ! [ -t "${fd}" ] || use_color=1 + + if [ -n "${use_color}" ]; then + case "${level}" in + warn) + tput setaf 1 + ;; + error) + tput bold; tput setaf 1 + ;; + info) + tput setaf 2 + ;; + esac + fi + fi + + echo "$@" + + [ -z "${use_color}" ] || tput sgr0 +} + + +if [ -f debian/changelog ]; then + log info "Fetching version from d/changelog" + VERSION=$(dpkg-parsechangelog -SVersion) +elif [ -f meson.build ]; then + log info "Fetching version from meson build file" + VERSION=$(sed -n "s/.*version\s*:\s*'\([0-9].*\)'.*/\1/p" meson.build) +else + log error "E: Don't know how to get version information" + exit 1 +fi + +echo "I: Checking for '${VERSION}'" + +# News +if ! head -1 NEWS | grep -E -qs "\s+${VERSION}\s*$"; then + log error "E: Version ${VERSION} not in NEWS file" + if [[ "${VERSION}" =~ (~|-)dev ]]; then + log info "I: Unreleased development version, no need to check NEWS" + else + exit 1 + fi +else + log info "I: Found matching news entry" +fi + +# meson.build +MESON_VERSION="${VERSION/\~/.}" +if [ -f meson.build ]; then + if ! grep -qs "version\s*:\s*'$MESON_VERSION'" meson.build; then + log error "E: Version ${MESON_VERSION} not in meson.build file" + exit 1 + else + log info "I: Found matching meson version entry" + fi +else + log info "I: no meson project" +fi + +# appstream info +METAINFO=$(ls data/*metainfo.xml.in* 2>/dev/null || true) +if [ -z "${METAINFO}" ]; then + log warn "W: No metainfo" + exit 0 +fi + +if ! grep -qs "$MESON_VERSION\"" "${METAINFO}"; then + log error "E: Version ${MESON_VERSION} not in metainfo ${METAINFO}" + if [[ "${VERSION}" =~ (~|-)(alpha|beta|dev|rc) ]]; then + log info "I: Not a stable release, no metainfo is fine" + else + exit 1 + fi +else + log info "I: Found matching metainfo entry" +fi diff --git a/.gitlab-ci/check-meson b/.gitlab-ci/check-meson new file mode 100755 index 0000000..3f48adc --- /dev/null +++ b/.gitlab-ci/check-meson @@ -0,0 +1,39 @@ +#!/bin/bash +# +# Copyright (C) 2025 The Phosh developers +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Author: Guido Günther + +ret=0 + +TMPDIR=$(mktemp -d) + +# We check files individually so we can print the diff: +while IFS= read -r -d '' file; do + if ! meson format -e --check-only "$file"; then + echo + echo "Meson file '${file}' needs reformat:" + meson format -e "$file" > "${TMPDIR}/meson.build" + diff -u "$file" "${TMPDIR}/meson.build" + rm -f "${TMPDIR}/meson.build" + ret=1 + fi +done < <(find . -name '*.build' -print0) + +if [ -n "$TMPDIR" ]; then + rmdir "${TMPDIR}" +fi + +if [ $ret -ne 0 ]; then + cat < + +cd po/ || exit 1 +# barf on untranslated C files. Seems intltool +# can't be told to exit with non-zero exit status +# in this case + +if intltool-update -m 2>&1 | grep -E -qs '/.*\.(c|ui|in)'; then + intltool-update -m + exit 1 +fi + +# Check for broken po files +for file in *.po; do + echo -n "Checking ${file}: " + msgfmt -v -c "${file}" + # Check for errors, msgfmt returns 0 on errors too + if msgfmt -c "${file}" 2>&1 | grep -qs 'fatal error'; then + exit 1 + fi +done diff --git a/.gitlab-ci/check-style.py b/.gitlab-ci/check-style.py new file mode 100755 index 0000000..5783866 --- /dev/null +++ b/.gitlab-ci/check-style.py @@ -0,0 +1,185 @@ +#!/bin/env python3 +# +# Based on check-style.py by +# Carlos Garnacho + +import argparse +import os +import re +import subprocess +import sys +import tempfile + +# Path relative to this script +uncrustify_cfg = ".gitlab-ci/uncrustify.cfg" + + +def run_diff(sha): + proc = subprocess.run( + ["git", "diff", "-U0", "--function-context", sha, "HEAD"], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + encoding="utf-8", + ) + return proc.stdout.strip().splitlines() + + +def find_chunks(diff): + file_entry_re = re.compile(r"^\+\+\+ b/(.*)$") + diff_chunk_re = re.compile(r"^@@ -\d+,\d+ \+(\d+),(\d+)") + file = None + chunks = [] + + for line in diff: + match = file_entry_re.match(line) + if match: + file = match.group(1) + + match = diff_chunk_re.match(line) + if match: + start = int(match.group(1)) + len = int(match.group(2)) + end = start + len + + if len > 0 and ( + file.endswith(".c") or file.endswith(".h") or file.endswith(".vala") + ): + chunks.append({"file": file, "start": start, "end": end}) + + return chunks + + +def reformat_chunks(chunks, rewrite, dry_run): + # Creates temp file with INDENT-ON/OFF comments + def create_temp_file(file, start, end): + with open(file) as f: + tmp = tempfile.NamedTemporaryFile() + if start > 1: + tmp.write(b"/** *INDENT-OFF* **/\n") + for i, line in enumerate(f, start=1): + if i == start - 1: + tmp.write(b"/** *INDENT-ON* **/\n") + + tmp.write(bytes(line, "utf-8")) + if i == end - 1: + tmp.write(b"/** *INDENT-OFF* **/\n") + tmp.seek(0) + return tmp + + # Removes uncrustify INDENT-ON/OFF helper comments + def remove_indent_comments(output): + tmp = tempfile.NamedTemporaryFile() + for line in output: + if line != b"/** *INDENT-OFF* **/\n" and line != b"/** *INDENT-ON* **/\n": + tmp.write(line) + + tmp.seek(0) + return tmp + + changed = None + for chunk in chunks: + # Add INDENT-ON/OFF comments + tmp = create_temp_file(chunk["file"], chunk["start"], chunk["end"]) + + # uncrustify chunk + proc = subprocess.run( + ["uncrustify", "-c", uncrustify_cfg, "-f", tmp.name], + stdout=subprocess.PIPE, + ) + reindented = proc.stdout.splitlines(keepends=True) + if proc.returncode != 0: + continue + + tmp.close() + + # Remove INDENT-ON/OFF comments + formatted = remove_indent_comments(reindented) + + if dry_run is True: + # Show changes + proc = subprocess.run( + ["diff", "-up", "--color=always", chunk["file"], formatted.name], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + encoding="utf-8", + ) + diff = proc.stdout + if diff != "": + output = re.sub("\t", "↦\t", diff) + print(output) + changed = True + else: + # Apply changes + diff = subprocess.run( + ["diff", "-up", chunk["file"], formatted.name], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + subprocess.run(["patch", chunk["file"]], input=diff.stdout) + + formatted.close() + + return changed + + +def main(argv): + parser = argparse.ArgumentParser( + description="Check code style. Needs uncrustify installed." + ) + parser.add_argument( + "--sha", metavar="SHA", type=str, help="SHA for the commit to compare HEAD with" + ) + parser.add_argument( + "--dry-run", + "-d", + type=bool, + action=argparse.BooleanOptionalAction, + help="Only print changes to stdout, do not change code", + ) + parser.add_argument( + "--rewrite", + "-r", + type=bool, + action=argparse.BooleanOptionalAction, + help="Whether to amend the result to the last commit (e.g. 'git rebase --exec \"%(prog)s -r\"')", + ) + + if not os.path.exists(".git"): + print("Not in toplevel of a git repository", fille=sys.stderr) + return 1 + + args = parser.parse_args(argv) + sha = args.sha or "HEAD^" + + diff = run_diff(sha) + chunks = find_chunks(diff) + changed = reformat_chunks(chunks, args.rewrite, args.dry_run) + + if args.dry_run is not True and args.rewrite is True: + proc = subprocess.run(["git", "add", "-p"]) + if proc.returncode == 0: + # Commit the added changes as a squash commit + subprocess.run( + ["git", "commit", "--squash", "HEAD", "-C", "HEAD"], + stdout=subprocess.DEVNULL, + ) + # Delete the unapplied changes + subprocess.run(["git", "reset", "--hard"], stdout=subprocess.DEVNULL) + return 0 + elif args.dry_run is True and changed is True: + print( + f""" +Issue the following commands in your local tree to apply the suggested changes: + + $ git rebase {sha} --exec "./.gitlab-ci/check-style.py -r" + $ git rebase --autosquash {sha} + +Don't trust uncrustify unconditionally. +""" + ) + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:])) diff --git a/.gitlab-ci/commit-rules.yml b/.gitlab-ci/commit-rules.yml new file mode 100644 index 0000000..0125df2 --- /dev/null +++ b/.gitlab-ci/commit-rules.yml @@ -0,0 +1,20 @@ +patterns: + deny: + - regex: '^$CI_MERGE_REQUEST_PROJECT_URL/(-/)?merge_requests/$CI_MERGE_REQUEST_IID$' + message: Commit message must not contain a link to its own merge request + - regex: '^[^:]+: [a-z]' + message: "Commit description in commit message subject should be properly Capitalized. E.g. 'monitor: Avoid crash on unplug'" + where: subject + - regex: '^\S*\.(c|h|ui):' + message: Commit message subject prefix should not include .c, .h etc. + where: subject + - regex: '([^.]\.|[:,;])\s*$' + message: Commit message subject should not end with punctuation + where: subject + - regex: '^[A-Z]\S*:' + message: "Identifier in commit message subject should start lowercase 'monitor: Avoid crash on unplug'" + where: subject + require: + - regex: '^[a-z0-9,\.\+\-/#=_]+:' + message: "Commit message should start with a lowercase identifier 'monitor: Avoid crash on unplug'" + where: subject diff --git a/.gitlab-ci/uncrustify.cfg b/.gitlab-ci/uncrustify.cfg new file mode 100644 index 0000000..98a3a81 --- /dev/null +++ b/.gitlab-ci/uncrustify.cfg @@ -0,0 +1,148 @@ +# +# Uncrustify config for phosh and related projects +# + +# A span is the number of lines considered +# A threshold is the maximum number of columns an item is moved + +# Indent by two spaces +indent_columns = 2 +# No tabs +indent_with_tabs = 0 +# Line length +code_width = 100 +# Whether to remove superfluous semicolons +mod_remove_extra_semicolon = true +# indent goto by 1 (or -1 brace level) +indent_label = -1 +# don't indent case after switch +indent_switch_case = 0 + +# +# Keywords and operators +# +# Add between 'do' and '{'. +sp_do_brace_open = add +# Add space between '}' and 'while'. +sp_brace_close_while = add +# Add 'while' and '('. +sp_while_paren_open = add +# Add or remove space around boolean operators '&&' and '||'. +sp_bool = add +# Ternary operator +sp_cond_ternary_short = remove +# Remove newline between 'struct and '{'. +nl_struct_brace = remove +# Remove newline between 'if' and '{'. +nl_if_brace = remove +# Remove newline between '}' and 'else'. +nl_brace_else = remove +# Remove newline between 'else' and '{'. +nl_else_brace = remove +# Remove newline between 'else' and 'if'. +nl_else_if = remove +# Add or remove newline between 'for' and '{'. +nl_for_brace = remove +# Add or remove newline between 'while' and '{'. +nl_while_brace = remove +# Treat iterators as for loops: +set FOR wl_list_for_each wl_list_for_each_reverse wl_list_for_each_safe +# Remove braces on single line if/for/while statements +mod_full_brace_if = remove +mod_full_brace_for = remove +mod_full_brace_while = remove +# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed. +mod_full_brace_if_chain = 1 +# Remove braces around case (when there are no variables declarations) +mod_case_brace = remove +# Don't remove branches if the statement has more than one line +mod_full_brace_nl = 2 + +# +# Function declarations, definitions and calls +# +# Add space between function name and '(' on function declaration. +sp_func_proto_paren = add +# Add or remove space between function name and '()' on function declaration +# without parameters. +sp_func_proto_paren_empty = add +# Add space between function name and '(' on function definition. +sp_func_def_paren = add +# Add or remove space between function name and '(' on function calls. +sp_func_call_paren = add +# Specialcase i18n macros +set func_call_user _ N_ C_ +sp_func_call_user_paren = remove + +# Whether to force indentation of function definitions to start in column 1. +indent_func_def_force_col1 = true +# Add newline between return type and function name in a function definition. +nl_func_type_name = add +# Add newline between function signature and '{'. +nl_fdef_brace = add +# Whether to align variable definitions in prototypes and functions. +align_func_params = true +# The span for aligning function prototypes. +align_func_proto_span = 8 +# Add space between 'decltype(...)' and word. +sp_after_decltype = add +# Add or remove space after a pointer star '*', if followed by a function +# prototype or function definition. +sp_after_ptr_star_func = remove +# Add or remove newline between a function call's ')' and '{', as in +# 'list_for_each(item, &list) { }'. +nl_fcall_brace = add + +# +# Typedefs +# +# Add space between '}' and the name of a typedef on the same line. +sp_brace_typedef = add + +# +# Comments +# +# Add space after the opening of a C++ comment, i.e. '// A' vs. '//A'. +sp_cmt_cpp_start = add + +# +# Preprocessor +# +# Add or remove space between #else or #endif and a trailing comment. +sp_endif_cmt = add +# Offset value that controls the indentation of the body of a multiline #define +pp_multiline_define_body_indent = 2 + +# Newlines at the start and end of the file. +nl_start_of_file = remove +nl_end_of_file = add +nl_end_of_file_min = 1 + +# +# Variable definitions +# +# How to align the '*' in variable definitions. +# +# 0: Part of the type 'void * foo;' (default) +# 1: Part of the variable 'void *foo;' +# 2: Dangling 'void *foo;' +# Dangling: the '*' will not be taken into account when aligning. +align_var_def_star_style = 2 +# Same for typedefs +align_typedef_star_style = 2 +# The gap for aligning struct/union member definitions. +align_var_struct_gap = 1 +# The span for aligning struct/union member definitions. +align_var_struct_span = 4 +# The threshold for aligning struct/union member definitions. +align_var_struct_thresh = 8 + +# Remove space between pointer stars '*'. +sp_between_ptr_star = remove +# Add space before '(' of control statements ('if', 'for', 'switch', 'while', etc.) +sp_before_sparen = add + +# Add spaces around assignments and arithmethic operators +sp_assign = add +sp_arith = add + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..24feead --- /dev/null +++ b/NEWS @@ -0,0 +1,3 @@ +phosh-vala-plugins 0.48.0 +------------------------- +* Initial release diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..31d36c2 --- /dev/null +++ b/meson.build @@ -0,0 +1,42 @@ +project( + 'phosh-vala-plugins', + 'vala', + version: '0.48.0', + license: 'GPL-3.0-or-later', + meson_version: '>= 1.2.0', + default_options: ['warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11'], +) + +prefix = get_option('prefix') +libdir = prefix / get_option('libdir') +datadir = prefix / get_option('datadir') + +vapi_dir = meson.project_source_root() / 'vapi' +add_project_arguments(['--vapidir', vapi_dir], language: 'vala') + +gnome = import('gnome') +i18n = import('i18n') +pkgconfig = import('pkgconfig') + +phosh_dep = dependency('phosh-plugins', version: '>= 0.45') +lockscreen_plugins_dir = phosh_dep.get_variable('lockscreen_plugins_dir') +quick_setting_plugins_dir = phosh_dep.get_variable('quick_setting_plugins_dir') + +common_deps = [ + dependency('gio-2.0'), + dependency('gtk+-3.0'), + dependency('libphosh-0.45'), + # For our bundles phosh-0.45 vapi + dependency('gnome-desktop-3.0'), + dependency('libnm'), +] + +common_c_args = ['-include', 'phosh-vala-plugins-config.h', '-DG_LOG_USE_STRUCTURED'] + +conf = configuration_data() +conf.set_quoted('G_LOG_DOMAIN', meson.project_name()) +configure_file(output: 'phosh-vala-plugins-config.h', configuration: conf) + +subdir('po') +# The example plugin +subdir('vala-quick-setting') diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..e69de29 diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..e69de29 diff --git a/po/POTFILES.skip b/po/POTFILES.skip new file mode 100644 index 0000000..018d023 --- /dev/null +++ b/po/POTFILES.skip @@ -0,0 +1,3 @@ +vala-quick-setting/qs.ui +vala-quick-setting/simple-custom-quick-setting.c +vala-quick-setting/simple-custom-quick-setting.desktop.in.in diff --git a/po/meson.build b/po/meson.build new file mode 100644 index 0000000..79c6233 --- /dev/null +++ b/po/meson.build @@ -0,0 +1,2 @@ +i18n = import('i18n') +i18n.gettext(meson.project_name(), preset: 'glib') diff --git a/vala-quick-setting/meson.build b/vala-quick-setting/meson.build new file mode 100644 index 0000000..b9bb85e --- /dev/null +++ b/vala-quick-setting/meson.build @@ -0,0 +1,36 @@ +name = 'vala-quick-setting' + +vala_quick_setting_resources = gnome.compile_resources( + 'phosh-plugin-vala-quick-setting-resources', + 'phosh-plugin-vala-quick-setting.gresources.xml', + c_name: 'phosh_plugin_vala_quick_setting', +) + +vala_quick_setting_plugin_sources = files('phosh-plugin-vala-quick-setting.vala') + +phosh_vala_quick_setting_plugin = shared_module( + 'phosh-plugin-vala-quick-setting', + vala_quick_setting_plugin_sources, + vala_quick_setting_resources, + dependencies: [common_deps], + c_args: common_c_args, + install: true, + install_dir: quick_setting_plugins_dir, +) + +pluginconf = configuration_data() +pluginconf.set('name', name) +pluginconf.set('plugins_dir', quick_setting_plugins_dir) + +i18n.merge_file( + input: configure_file( + input: name + '.desktop.in.in', + output: name + '.desktop.in', + configuration: pluginconf, + ), + output: name + '.plugin', + po_dir: join_paths(meson.project_source_root(), 'po'), + install: true, + install_dir: quick_setting_plugins_dir, + type: 'desktop', +) diff --git a/vala-quick-setting/phosh-plugin-vala-quick-setting.gresources.xml b/vala-quick-setting/phosh-plugin-vala-quick-setting.gresources.xml new file mode 100644 index 0000000..33a6948 --- /dev/null +++ b/vala-quick-setting/phosh-plugin-vala-quick-setting.gresources.xml @@ -0,0 +1,6 @@ + + + + qs.ui + + diff --git a/vala-quick-setting/phosh-plugin-vala-quick-setting.vala b/vala-quick-setting/phosh-plugin-vala-quick-setting.vala new file mode 100644 index 0000000..4e951c5 --- /dev/null +++ b/vala-quick-setting/phosh-plugin-vala-quick-setting.vala @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2025 The Phosh Developers + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Author: Guido Günther + */ + +using Phosh; +using GLib; + + +[GtkTemplate (ui = "/mobi/phosh/plugins/vala-quick-setting/qs.ui")] +public class ValaQuickSetting : QuickSetting +{ + [GtkChild] + private unowned StatusIcon info; + + [GtkCallback] + private void + on_clicked (Phosh.QuickSetting qs) + { + bool active = get_active (); + + if (active) { + info.set_icon_name ("face-shutmouth-symbolic"); + info.set_info ("I'm Inactive"); + } else { + info.set_icon_name ("face-smile-big-symbolic"); + info.set_info ("I'm Active"); + } + + set_active (!active); + } + + construct { + info.set_icon_name ("face-shutmouth-symbolic"); + info.set_info ("I'm Inactive"); + } +} + + +[ModuleInit] +public void +g_io_phosh_plugin_vala_quick_setting_load (GLib.TypeModule module) +{ + GLib.IOExtensionPoint.implement ("phosh-quick-setting-widget", + typeof(ValaQuickSetting), + "vala-quick-setting", + 10); +} + + +public void +g_io_phosh_plugin_vala_quick_setting_unload (GLib.IOModule module) +{ +} + + +public string[] +g_io_phosh_plugin_vala_quick_setting_query () +{ + StrvBuilder builder = new StrvBuilder (); + + builder.add ("phosh-quick-setting-widget"); + return builder.end (); +} diff --git a/vala-quick-setting/qs.ui b/vala-quick-setting/qs.ui new file mode 100644 index 0000000..0cdc4ce --- /dev/null +++ b/vala-quick-setting/qs.ui @@ -0,0 +1,40 @@ + + + + + + 1 + 16 + + + 1 + Quick Setting Example + placeholder + footer + + + 1 + face-angel-symbolic + label + + + 1 + Im' written in Vala! + + + 1 + 1 + + + + 1 + end + Open Plugin Settings + + + + diff --git a/vala-quick-setting/vala-quick-setting.desktop.in.in b/vala-quick-setting/vala-quick-setting.desktop.in.in new file mode 100644 index 0000000..a380997 --- /dev/null +++ b/vala-quick-setting/vala-quick-setting.desktop.in.in @@ -0,0 +1,7 @@ +[Plugin] +# Translators: This is an internal id, no need to translate it +Id=@name@ +Name=Vala Quick Setting Example +Types=quick-setting; +Comment=A simple quick setting written in vala. +Plugin=@plugins_dir@/libphosh-plugin-@name@.so diff --git a/vapi/libphosh-0.45.vapi b/vapi/libphosh-0.45.vapi new file mode 100644 index 0000000..a9f03f5 --- /dev/null +++ b/vapi/libphosh-0.45.vapi @@ -0,0 +1,251 @@ +/* libphosh-0.45.vapi generated by vapigen, do not modify. */ + +[CCode (cprefix = "Phosh", gir_namespace = "Phosh", gir_version = "0", lower_case_cprefix = "phosh_")] +namespace Phosh { + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_dbus_screenshot_proxy_get_type ()")] + public class DBusScreenshotProxy : GLib.DBusProxy, GLib.AsyncInitable, GLib.DBusInterface, GLib.Initable, Phosh.DBusScreenshot { + [CCode (cname = "phosh_dbus_screenshot_proxy_new", has_construct_function = false)] + public async DBusScreenshotProxy (GLib.DBusConnection connection, GLib.DBusProxyFlags flags, string? name, string object_path, GLib.Cancellable? cancellable) throws GLib.Error; + [CCode (cname = "phosh_dbus_screenshot_proxy_new_for_bus", has_construct_function = false)] + public async DBusScreenshotProxy.for_bus (GLib.BusType bus_type, GLib.DBusProxyFlags flags, string name, string object_path, GLib.Cancellable? cancellable) throws GLib.Error; + [CCode (has_construct_function = false, type = "PhoshDBusScreenshot*")] + public DBusScreenshotProxy.for_bus_sync (GLib.BusType bus_type, GLib.DBusProxyFlags flags, string name, string object_path, GLib.Cancellable? cancellable = null) throws GLib.Error; + [CCode (has_construct_function = false, type = "PhoshDBusScreenshot*")] + public DBusScreenshotProxy.sync (GLib.DBusConnection connection, GLib.DBusProxyFlags flags, string? name, string object_path, GLib.Cancellable? cancellable = null) throws GLib.Error; + } + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_dbus_screenshot_skeleton_get_type ()")] + public class DBusScreenshotSkeleton : GLib.DBusInterfaceSkeleton, GLib.DBusInterface, Phosh.DBusScreenshot { + [CCode (has_construct_function = false, type = "PhoshDBusScreenshot*")] + public DBusScreenshotSkeleton (); + } + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_layer_surface_get_type ()")] + public class LayerSurface : Gtk.Window, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected LayerSurface (); + [NoAccessorMethod] + public uint anchor { get; set; } + [NoAccessorMethod] + public uint configured_height { get; } + [NoAccessorMethod] + public uint configured_width { get; } + [NoAccessorMethod] + public int exclusive_zone { get; set; } + [NoAccessorMethod] + public uint height { get; set; } + [NoAccessorMethod] + public bool kbd_interactivity { get; set; } + [NoAccessorMethod] + public uint layer { get; set construct; } + [NoAccessorMethod] + public void* layer_shell { get; set; } + [NoAccessorMethod] + public int margin_bottom { get; set; } + [NoAccessorMethod] + public int margin_left { get; set; } + [NoAccessorMethod] + public int margin_right { get; set; } + [NoAccessorMethod] + public int margin_top { get; set; } + [NoAccessorMethod] + public string @namespace { owned get; set; } + [NoAccessorMethod] + public uint width { get; set; } + [NoAccessorMethod] + public void* wl_output { get; set; } + public virtual signal void configured (); + } + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_lockscreen_get_type ()")] + public class Lockscreen : Phosh.LayerSurface, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + protected Lockscreen (); + public void add_extra_page (Gtk.Widget widget); + public void clear_pin_entry (); + public Phosh.LockscreenPage get_page (); + public unowned string get_pin_entry (); + public void set_default_page (Phosh.LockscreenPage page); + public void set_page (Phosh.LockscreenPage page); + public void set_unlock_status (string status); + public void shake_pin_entry (); + [NoWrapper] + public virtual void unlock_submit (); + public Phosh.LockscreenPage page { get; } + [NoAccessorMethod] + public bool require_unlock { get; set; } + public signal void lockscreen_unlock (); + public signal void wakeup_output (); + } + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_lockscreen_manager_get_type ()")] + public class LockscreenManager : GLib.Object { + [CCode (has_construct_function = false)] + protected LockscreenManager (); + public int64 get_active_time (); + public bool get_locked (); + public unowned Phosh.Lockscreen? get_lockscreen (); + public Phosh.LockscreenPage get_page (); + public void set_locked (bool state); + public bool set_page (Phosh.LockscreenPage page); + public bool locked { get; set; } + public signal void wakeup_outputs (); + } + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_quick_setting_get_type ()")] + public class QuickSetting : Gtk.Box, Atk.Implementor, Gtk.Buildable, Gtk.Orientable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public QuickSetting (Phosh.StatusPage status_page); + public bool get_active (); + public bool get_can_show_status (); + public unowned string get_long_press_action_name (); + public unowned string get_long_press_action_target (); + public bool get_showing_status (); + public unowned Phosh.StatusIcon get_status_icon (); + public unowned Phosh.StatusPage get_status_page (); + public void set_active (bool active); + public void set_can_show_status (bool can_show_status); + public void set_long_press_action_name (string action_name); + public void set_long_press_action_target (string action_target); + public void set_showing_status (bool showing_status); + public void set_status_icon (Phosh.StatusIcon status_icon); + public void set_status_page (Phosh.StatusPage status_page); + public bool active { get; set; } + public bool can_show_status { get; set; } + public string long_press_action_name { get; set; } + public string long_press_action_target { get; set; } + public bool showing_status { get; set; } + public Phosh.StatusIcon status_icon { get; set; } + public Phosh.StatusPage status_page { get; set; } + public signal void clicked (); + public signal void hide_status (); + public signal void long_pressed (); + public signal void show_status (); + } + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_screenshot_manager_get_type ()")] + public class ScreenshotManager : Phosh.DBusScreenshotSkeleton, GLib.DBusInterface, Phosh.DBusScreenshot { + [CCode (has_construct_function = false)] + public ScreenshotManager (); + public bool take_screenshot (Gdk.Rectangle? area, string? filename, bool copy_to_clipboard, bool include_cursor); + } + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_shell_get_type ()")] + public class Shell : GLib.Object, GLib.ActionGroup, GLib.ActionMap { + [CCode (has_construct_function = false)] + public Shell (); + public void fade_out (uint timeout); + public static unowned Phosh.Shell get_default (); + public bool get_locked (); + public unowned Phosh.LockscreenManager get_lockscreen_manager (); + public virtual GLib.Type get_lockscreen_type (); + public unowned Phosh.ScreenshotManager get_screenshot_manager (); + public void get_usable_area (out int x, out int y, out int width, out int height); + public void set_default (); + [NoAccessorMethod] + public bool docked { get; set; } + [NoAccessorMethod] + public bool locked { get; set; } + [NoAccessorMethod] + public bool overview_visible { get; set; } + [Version (since = "0.11.0")] + public signal void ready (); + } + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_status_icon_get_type ()")] + public class StatusIcon : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false, type = "GtkWidget*")] + public StatusIcon (); + public unowned Gtk.Widget? get_extra_widget (); + public string get_icon_name (); + [Version (deprecated = true, deprecated_since = "0.47")] + public Gtk.IconSize get_icon_size (); + public string get_info (); + public uint get_pixel_size (); + [NoWrapper] + public virtual void idle_init (); + public void set_extra_widget (Gtk.Widget widget); + public void set_icon_name (string icon_name); + [Version (deprecated = true, deprecated_since = "0.47")] + public void set_icon_size (Gtk.IconSize size); + public void set_info (string info); + public void set_pixel_size (uint size); + public Gtk.Widget extra_widget { get; set; } + public string icon_name { owned get; set; } + public Gtk.IconSize icon_size { get; set; } + public string info { owned get; set; } + public uint pixel_size { get; set; } + } + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_status_page_get_type ()")] + public class StatusPage : Gtk.Bin, Atk.Implementor, Gtk.Buildable { + [CCode (has_construct_function = false)] + public StatusPage (); + public unowned Gtk.Widget get_content (); + public unowned Gtk.Widget get_footer (); + public unowned Gtk.Widget get_header (); + public unowned string get_title (); + public void set_content (Gtk.Widget content); + public void set_footer (Gtk.Widget footer); + public void set_header (Gtk.Widget header); + public void set_title (string title); + public Gtk.Widget content { get; set; } + public Gtk.Widget footer { get; set; } + public Gtk.Widget header { get; set; } + public string title { get; set; } + public signal void done (); + } + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_wall_clock_get_type ()")] + public class WallClock : GLib.Object { + [CCode (has_construct_function = false)] + public WallClock (); + public virtual unowned string get_clock (bool time_only); + public static unowned Phosh.WallClock get_default (); + [NoWrapper] + public virtual int64 get_time_t (); + public string local_date (); + public void set_default (); + public string string_for_datetime (GLib.DateTime datetime, GDesktop.ClockFormat clock_format, bool show_full_date); + [NoAccessorMethod] + public string date_time { owned get; } + [NoAccessorMethod] + public string time { owned get; } + } + [CCode (cheader_filename = "libphosh.h", type_id = "phosh_dbus_screenshot_get_type ()")] + public interface DBusScreenshot : GLib.Object { + public async bool call_flash_area (int arg_x, int arg_y, int arg_width, int arg_height, GLib.Cancellable? cancellable) throws GLib.Error; + public bool call_flash_area_sync (int arg_x, int arg_y, int arg_width, int arg_height, GLib.Cancellable? cancellable = null) throws GLib.Error; + [CCode (async_result_pos = 2.1)] + public async bool call_pick_color (GLib.Cancellable? cancellable, out GLib.Variant out_result) throws GLib.Error; + public bool call_pick_color_sync (out GLib.Variant out_result, GLib.Cancellable? cancellable = null) throws GLib.Error; + [CCode (async_result_pos = 3.1)] + public async bool call_screenshot (bool arg_include_cursor, bool arg_flash, string arg_filename, GLib.Cancellable? cancellable, out bool out_success, out string out_filename_used) throws GLib.Error; + [CCode (async_result_pos = 3.1)] + public async bool call_screenshot_area (int arg_x, int arg_y, int arg_width, int arg_height, bool arg_flash, string arg_filename, GLib.Cancellable? cancellable, out bool out_success, out string out_filename_used) throws GLib.Error; + public bool call_screenshot_area_sync (int arg_x, int arg_y, int arg_width, int arg_height, bool arg_flash, string arg_filename, out bool out_success, out string out_filename_used, GLib.Cancellable? cancellable = null) throws GLib.Error; + public bool call_screenshot_sync (bool arg_include_cursor, bool arg_flash, string arg_filename, out bool out_success, out string out_filename_used, GLib.Cancellable? cancellable = null) throws GLib.Error; + [CCode (async_result_pos = 3.1)] + public async bool call_screenshot_window (bool arg_include_frame, bool arg_include_cursor, bool arg_flash, string arg_filename, GLib.Cancellable? cancellable, out bool out_success, out string out_filename_used) throws GLib.Error; + public bool call_screenshot_window_sync (bool arg_include_frame, bool arg_include_cursor, bool arg_flash, string arg_filename, out bool out_success, out string out_filename_used, GLib.Cancellable? cancellable = null) throws GLib.Error; + [CCode (async_result_pos = 5.1)] + public async bool call_select_area (GLib.Cancellable? cancellable, out int out_x, out int out_y, out int out_width, out int out_height) throws GLib.Error; + public bool call_select_area_sync (out int out_x, out int out_y, out int out_width, out int out_height, GLib.Cancellable? cancellable = null) throws GLib.Error; + public void complete_flash_area (owned GLib.DBusMethodInvocation invocation); + public void complete_pick_color (owned GLib.DBusMethodInvocation invocation, GLib.Variant result); + public void complete_screenshot (owned GLib.DBusMethodInvocation invocation, bool success, string filename_used); + public void complete_screenshot_area (owned GLib.DBusMethodInvocation invocation, bool success, string filename_used); + public void complete_screenshot_window (owned GLib.DBusMethodInvocation invocation, bool success, string filename_used); + public void complete_select_area (owned GLib.DBusMethodInvocation invocation, int x, int y, int width, int height); + public static unowned GLib.DBusInterfaceInfo interface_info (); + public static uint override_properties (GLib.ObjectClass klass, uint property_id_begin); + public virtual signal bool handle_flash_area (GLib.DBusMethodInvocation invocation, int arg_x, int arg_y, int arg_width, int arg_height); + public virtual signal bool handle_pick_color (GLib.DBusMethodInvocation invocation); + public virtual signal bool handle_screenshot (GLib.DBusMethodInvocation invocation, bool arg_include_cursor, bool arg_flash, string arg_filename); + public virtual signal bool handle_screenshot_area (GLib.DBusMethodInvocation invocation, int arg_x, int arg_y, int arg_width, int arg_height, bool arg_flash, string arg_filename); + public virtual signal bool handle_screenshot_window (GLib.DBusMethodInvocation invocation, bool arg_include_frame, bool arg_include_cursor, bool arg_flash, string arg_filename); + public virtual signal bool handle_select_area (GLib.DBusMethodInvocation invocation); + } + [CCode (cheader_filename = "libphosh.h", cprefix = "PHOSH_LOCKSCREEN_PAGE_", type_id = "phosh_lockscreen_page_get_type ()")] + public enum LockscreenPage { + INFO, + EXTRA, + UNLOCK + } + [CCode (cheader_filename = "libphosh.h")] + [Version (replacement = "DBusScreenshot.interface_info")] + public static unowned GLib.DBusInterfaceInfo dbus_screenshot_interface_info (); + [CCode (cheader_filename = "libphosh.h")] + [Version (replacement = "DBusScreenshot.override_properties")] + public static uint dbus_screenshot_override_properties (GLib.ObjectClass klass, uint property_id_begin); +}